/** * G7 review queue — the named queue into the human review phase. * * G7 is the gap for corrections that are RIGHT but larger than the O2 envelope * (one locator + deletion-only). Measured in R11 §9.6: of the four subtractions * applied in 957ebef, two left a residue. Residues are the normal by-product of * a delete-only envelope, not an exception — and two of the five members are * replacements rather than multi-locator cases, which a deletion-oriented O4 * class would not have fixed. Hence a queue (form b), ratified 2026-08-03. * * This module validates the queue. It deliberately does NOT apply anything: * every entry here is by definition outside the machine-appliable envelope. * * Anchors are verbatim strings, never line numbers — line numbers drift, and * §9.4 measured `line` ≠ `real_line` in 9 of 17 records. An open entry whose * anchor no longer occurs is reported as drift rather than quietly passing, * because the whole purpose of the queue is that a defect cannot fall out of * the programme unnoticed. */ export const ENTRY_CLASSES = new Set(['multi-locator', 'replacement']); export const ENTRY_STATES = new Set(['open', 'resolved']); const REQUIRED = ['id', 'file', 'class', 'status', 'raised', 'summary', 'evidence', 'anchors']; /** * @param {unknown} entries queue entries * @param {(path: string) => string} readFile * @returns {{ ok: boolean, findings: Array<{id?: string, kind: string, message: string}> }} */ export function validateQueue(entries, readFile) { const findings = []; if (!Array.isArray(entries)) { return { ok: false, findings: [{ kind: 'schema', message: 'queue must be an array of entries' }] }; } const seen = new Set(); for (const entry of entries) { const id = typeof entry?.id === 'string' ? entry.id : ''; const missing = REQUIRED.filter((f) => entry?.[f] === undefined); if (missing.length > 0) { findings.push({ id, kind: 'schema', message: `missing required field(s): ${missing.join(', ')}` }); continue; } if (seen.has(entry.id)) { findings.push({ id, kind: 'schema', message: `duplicate id: ${entry.id}` }); continue; } seen.add(entry.id); if (!ENTRY_CLASSES.has(entry.class)) { findings.push({ id, kind: 'schema', message: `unknown class: ${entry.class}` }); continue; } if (!ENTRY_STATES.has(entry.status)) { findings.push({ id, kind: 'schema', message: `unknown status: ${entry.status}` }); continue; } // A resolved entry has to say what closed it. Without that, "resolved" is // indistinguishable from "quietly dropped" — the exact failure G7 exists to // prevent. Resolved entries are exempt from anchor checking, since a real // fix is expected to have changed the text the anchor pointed at. if (entry.status === 'resolved') { if (typeof entry.resolution !== 'string' || entry.resolution.trim() === '') { findings.push({ id, kind: 'schema', message: 'a resolved entry must record a resolution' }); } continue; } if (!Array.isArray(entry.anchors) || entry.anchors.length === 0) { findings.push({ id, kind: 'schema', message: 'an open entry must carry at least one anchor' }); continue; } let text; try { text = readFile(entry.file); } catch { findings.push({ id, kind: 'file_unreadable', message: `cannot read ${entry.file}` }); continue; } const gone = entry.anchors.filter((a) => !text.includes(a)); if (gone.length > 0) { findings.push({ id, kind: 'anchor_drift', message: `anchor no longer occurs in ${entry.file}: ${gone.map((g) => JSON.stringify(g)).join(', ')}`, }); } } return { ok: findings.length === 0, findings }; }