import { BaseCommand, flags } from '@adonisjs/core/ace' import { CommandOptions } from '@adonisjs/core/types/ace' import db from '@adonisjs/lucid/services/db' import GarbageFilter from '#services/GarbageFilter' /** * Learns the garbage upload signatures now (gc:scheduler does it every * GARBAGE_LEARN_INTERVAL_MS) and lists them (CONCEPT.md D42). --seed first * fills signature_probes from a sample of the files probed before it * existed, so there is something to learn from right away. */ export default class GarbageLearn extends BaseCommand { public static commandName = 'garbage:learn' public static description = 'Learns which upload signatures are garbage and lists them.' public static options: CommandOptions = { startApp: true, } @flags.number({ description: 'First add probed releases from TABLESAMPLE SYSTEM (percent) of files' }) declare seed?: number public async run() { if (this.seed) { const started = Date.now() const added = await GarbageFilter.seed(this.seed) this.logger.info(`Seeded ${added} probed releases from ${this.seed}% of files in ${Math.round((Date.now() - started) / 1000)} s.`) } const { signatures, dropped, changed } = await GarbageFilter.learn() for (const line of changed) this.logger.info(`Changed: ${line}`) const rows = await db.from('upload_signatures').orderBy('probed', 'desc').limit(40) for (const row of rows) { const rate = row.probed ? ((100 * row.named) / row.probed).toFixed(1) : '-' this.logger.info(`${row.dropped ? 'DROP' : 'keep'} ${row.tool.padEnd(10)} ${(row.group_name || '(no group)').padEnd(36)} ${String(row.named).padStart(6)}/${String(row.probed).padEnd(6)} named (${rate}%)`) } this.logger.info(`${dropped} of ${signatures} signatures dropped.`) } }