#!/usr/bin/env node /** * Check the G7 review queue against the live corpus. * * Exit 0 = every open entry still anchors to real text; exit 1 = drift or a * schema fault. Drift is a finding, never a silent pass: an entry that stops * matching is exactly the case G7 exists to prevent — a real defect leaving the * programme unnoticed because someone edited around it. * * Read-only. Nothing in the queue is machine-appliable; resolution is a human * review act (form b, ratified 2026-08-03). * * node scripts/kb-eval/check-g7-queue.mjs [--json] */ import { readFileSync } from 'node:fs'; import { validateQueue } from './lib/g7-queue.mjs'; const QUEUE = 'scripts/kb-eval/data/g7-review-queue.json'; const asJson = process.argv.includes('--json'); let queue; try { queue = JSON.parse(readFileSync(QUEUE, 'utf8')); } catch (err) { console.error(`cannot read ${QUEUE}: ${err.message}`); process.exit(1); } const entries = queue.entries ?? []; const { ok, findings } = validateQueue(entries, (p) => readFileSync(p, 'utf8')); const open = entries.filter((e) => e.status === 'open'); const resolved = entries.filter((e) => e.status === 'resolved'); if (asJson) { console.log(JSON.stringify({ ok, open: open.length, resolved: resolved.length, findings }, null, 2)); process.exit(ok ? 0 : 1); } console.log(`G7 review queue — ${open.length} open, ${resolved.length} resolved\n`); const byClass = (cls) => open.filter((e) => e.class === cls); for (const cls of ['multi-locator', 'replacement']) { const rows = byClass(cls); if (rows.length === 0) continue; console.log(` ${cls} (${rows.length}):`); for (const e of rows) { console.log(` ${e.id.padEnd(8)} ${e.file.split('/').pop()}`); } console.log(); } if (findings.length > 0) { console.log(`FINDINGS (${findings.length}):`); for (const f of findings) { console.log(` [${f.kind}] ${f.id ?? ''} ${f.message}`); } console.log('\nA drifted anchor means the file changed under a queued defect.'); console.log('Re-derive the anchor from the live file — do not delete the entry.'); process.exit(1); } console.log('All open entries still anchor to live corpus text. exit 0');