Operatør-ratifisert 2026-08-03. G7 var gapet for korreksjoner som er RIKTIGE men større enn O2-konvolutten (én lokator + kun-sletting). Uten eier falt de stille ut: O2-triagen avviser dem, O3 dekker dem ikke, og review-sporet hadde ingen inngangskø. Formvalget ble tatt på §9.6-målingen, ikke på preferanse: - 2 av 4 anvendte subtraksjoner etterlot en rest -> rester er delete-only- konvoluttens NORMALE biprodukt, ikke et unntak. - 2 av 5 medlemmer (idx 17, 33) er ERSTATNINGER, ikke fler-lokator. En delete-orientert O4-klasse med egen retur-kontrakt ville ikke fikset dem — altså feil dimensjonert mot evidensen. Køen absorberer begge klasser. Artefakter (TDD, test-først): - data/g7-review-queue.json — 6 entries, tracked - lib/g7-queue.mjs — validateQueue, lukkede vokabular - check-g7-queue.mjs — exit 1 ved drift eller skjemafeil - tests/kb-eval/test-g7-queue.test.mjs — 15 tester Kontrakten: ankere er ORDRETTE strenger, aldri linjenummer (line != real_line i 9 av 17 R11-records). En åpen entry hvis anker slutter å matche gir anchor_drift og exit 1 — den kan ikke falle stille ut, som er hele hensikten. En resolved entry MÅ føre resolution, ellers er "resolved" ikke til å skille fra "stille droppet". Ingenting i køen er maskin-anvendbart per definisjon. Innhold: 5 åpne (26, 27, 33, 36, 18), 1 lukket (17). idx 27 kom hit ved å falle ut av O2 på cond 3; idx 26 ved operatørens avvisning av delvis fiks. Suite 1047/1047. [skip-docs]
128 lines
5 KiB
JavaScript
128 lines
5 KiB
JavaScript
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { validateQueue, ENTRY_CLASSES, ENTRY_STATES } from '../../scripts/kb-eval/lib/g7-queue.mjs';
|
|
|
|
// A queue entry is the ONLY thing standing between a real defect and silent loss,
|
|
// so the checks here are deliberately unforgiving about shape and about anchors
|
|
// that no longer exist in the corpus.
|
|
|
|
const okEntry = () => ({
|
|
id: 'idx-99',
|
|
file: 'skills/x/references/y.md',
|
|
class: 'multi-locator',
|
|
status: 'open',
|
|
raised: '2026-08-03',
|
|
summary: 'Something the file asserts in two places.',
|
|
evidence: 'docs/r11-pilot-results.md §9.6',
|
|
anchors: ['the exact text'],
|
|
});
|
|
|
|
const stub = (contents) => (p) => {
|
|
if (!(p in contents)) throw new Error(`ENOENT ${p}`);
|
|
return contents[p];
|
|
};
|
|
|
|
test('a well-formed open entry whose anchor is present passes', () => {
|
|
const r = validateQueue([okEntry()], stub({ 'skills/x/references/y.md': 'aaa the exact text bbb' }));
|
|
assert.equal(r.ok, true);
|
|
assert.deepEqual(r.findings, []);
|
|
});
|
|
|
|
test('vocabularies are closed', () => {
|
|
assert.deepEqual([...ENTRY_CLASSES].sort(), ['multi-locator', 'replacement']);
|
|
assert.deepEqual([...ENTRY_STATES].sort(), ['open', 'resolved']);
|
|
});
|
|
|
|
test('unknown class is rejected', () => {
|
|
const e = { ...okEntry(), class: 'deletion' };
|
|
const r = validateQueue([e], stub({ 'skills/x/references/y.md': 'the exact text' }));
|
|
assert.equal(r.ok, false);
|
|
assert.match(r.findings[0].message, /class/);
|
|
});
|
|
|
|
test('unknown status is rejected', () => {
|
|
const e = { ...okEntry(), status: 'wontfix' };
|
|
const r = validateQueue([e], stub({ 'skills/x/references/y.md': 'the exact text' }));
|
|
assert.equal(r.ok, false);
|
|
assert.match(r.findings[0].message, /status/);
|
|
});
|
|
|
|
test('a missing required field is reported by name', () => {
|
|
const e = okEntry();
|
|
delete e.evidence;
|
|
const r = validateQueue([e], stub({ 'skills/x/references/y.md': 'the exact text' }));
|
|
assert.equal(r.ok, false);
|
|
assert.match(r.findings[0].message, /evidence/);
|
|
});
|
|
|
|
test('an open entry MUST carry at least one anchor', () => {
|
|
const e = { ...okEntry(), anchors: [] };
|
|
const r = validateQueue([e], stub({ 'skills/x/references/y.md': 'the exact text' }));
|
|
assert.equal(r.ok, false);
|
|
assert.match(r.findings[0].message, /anchor/i);
|
|
});
|
|
|
|
// The point of the whole mechanism: a defect must not be able to leave the queue
|
|
// just because someone edited the file around it.
|
|
test('an open entry whose anchor no longer occurs is a DRIFT finding, not a pass', () => {
|
|
const r = validateQueue([okEntry()], stub({ 'skills/x/references/y.md': 'nothing matching here' }));
|
|
assert.equal(r.ok, false);
|
|
assert.equal(r.findings[0].kind, 'anchor_drift');
|
|
assert.match(r.findings[0].message, /the exact text/);
|
|
});
|
|
|
|
test('every anchor is checked, not just the first', () => {
|
|
const e = { ...okEntry(), anchors: ['present', 'absent'] };
|
|
const r = validateQueue([e], stub({ 'skills/x/references/y.md': 'present only' }));
|
|
assert.equal(r.ok, false);
|
|
assert.equal(r.findings.length, 1);
|
|
assert.match(r.findings[0].message, /absent/);
|
|
});
|
|
|
|
test('a missing file is reported rather than thrown', () => {
|
|
const r = validateQueue([okEntry()], stub({}));
|
|
assert.equal(r.ok, false);
|
|
assert.equal(r.findings[0].kind, 'file_unreadable');
|
|
});
|
|
|
|
test('a resolved entry MUST record how it was resolved', () => {
|
|
const e = { ...okEntry(), status: 'resolved' };
|
|
const r = validateQueue([e], stub({ 'skills/x/references/y.md': 'whatever' }));
|
|
assert.equal(r.ok, false);
|
|
assert.match(r.findings[0].message, /resolution/);
|
|
});
|
|
|
|
test('a resolved entry is exempt from anchor checking', () => {
|
|
const e = { ...okEntry(), status: 'resolved', resolution: 'colon -> period, ratified 2026-08-03' };
|
|
const r = validateQueue([e], stub({ 'skills/x/references/y.md': 'anchor is long gone' }));
|
|
assert.equal(r.ok, true);
|
|
});
|
|
|
|
test('duplicate ids are rejected', () => {
|
|
const r = validateQueue([okEntry(), okEntry()], stub({ 'skills/x/references/y.md': 'the exact text' }));
|
|
assert.equal(r.ok, false);
|
|
assert.match(r.findings[0].message, /duplicate/i);
|
|
});
|
|
|
|
test('findings from several entries are all reported', () => {
|
|
const a = { ...okEntry(), id: 'idx-1' };
|
|
const b = { ...okEntry(), id: 'idx-2', anchors: ['gone'] };
|
|
const r = validateQueue([a, b], stub({ 'skills/x/references/y.md': 'the exact text' }));
|
|
assert.equal(r.ok, false);
|
|
assert.equal(r.findings.length, 1);
|
|
assert.equal(r.findings[0].id, 'idx-2');
|
|
});
|
|
|
|
test('a non-array queue is rejected without throwing', () => {
|
|
const r = validateQueue({ entries: [] }, stub({}));
|
|
assert.equal(r.ok, false);
|
|
assert.match(r.findings[0].message, /array/i);
|
|
});
|
|
|
|
test('the real queue file validates against the live corpus', async () => {
|
|
const { readFileSync } = await import('node:fs');
|
|
const queue = JSON.parse(readFileSync('scripts/kb-eval/data/g7-review-queue.json', 'utf8'));
|
|
const r = validateQueue(queue.entries, (p) => readFileSync(p, 'utf8'));
|
|
assert.deepEqual(r.findings, [], `G7 queue drifted: ${JSON.stringify(r.findings, null, 2)}`);
|
|
assert.equal(r.ok, true);
|
|
});
|