// tests/scripts/end-state-gate.test.mjs // The end-state gate counts the distance to "Voyage is finished" as five tallies: // open pipeline defects, unresolved experiments/opt-ins, dormant agents, open operator // decisions, and feat commits after the freeze tag. "Finished" = all five at 0 AND the // registry the gate counts from is intact against its frozen denominator. // // These tests pin the gate's MECHANICS in both directions — every tally can be 0 and can // be > 0 — against throwaway fixture trees. They deliberately do NOT assert that the real // repo is red today: the gate is supposed to go green, and a test that pins the current // distance would fail on the day the work is done. What they DO pin about the real repo // is the denominator itself (see "the frozen denominator" below). import { test } from 'node:test'; import { strict as assert } from 'node:assert'; import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, readFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join, dirname, resolve } from 'node:path'; import { spawnSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; import { evaluateCondition, evaluateCheck, measure, loadRegistry, loadFrozen, spawnedNames, checkSignature, verifyIntegrity, render, } from '../../scripts/end-state-gate.mjs'; const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..'); const GATE = join(ROOT, 'scripts', 'end-state-gate.mjs'); // --- the frozen denominator ------------------------------------------------ // Denominator frozen 2026-09-17 by the end-state work order, the day the end-state // direction was chosen. An entry may CLOSE; it may never be removed or have its check // changed, and the gate's agent/decision/freeze configuration may not move. To change // anything below you must change this test — say in the commit message who decided it. const FROZEN = { defects: { 'D-01': '48f7f5cca070091e8f9b9ca0c7cdb7a1880733691935c25d07ea1d3e8d508fc9', 'D-02': 'dfc94dba04a9116ae9be2097a0c5a9d8313b02c7de1ca6b49a472c1823a6d1e1', 'D-03': '41dea56c14764494ed6d555ca97311b6001b0542f4ab69fa1dfc405780a57c32', 'D-04': '721bdda19c0e98962acbfc78419bfb02790ee739694d1609b72d10481f0d6b62', 'D-05': '8fe6df52b43496c3302400507cb98002dcf8d2a12d92085e14bda4c7819bc7ba', 'D-06': '72a787c8154d1c18849e9856dcf1a67703d6b5541f88db81d6bab13cab14b418', 'D-07': '1bf3e0cd36c621720697475b0a3fd7db78611d66b58a9ce035e7695e57c69f1b', }, experiments: { 'E-01': 'f7718897cec8ace6879fe79f5f32760ec957c3642e7186f8aa1688ce77b3f4e8', 'E-02': 'c8ff12c504ba7a9ac36f11bb8f9b713263e9b4eb28c07d984d9e2115980e740d', 'E-03': '17153ad8808615a833a49ae0c3523264ce055aa690e5542a75bae1874495e7e8', }, agents: { dir: 'agents', spawnSites: 'commands/*.md', referenceMarker: 'Reference document, not a spawnable capability', }, decisions: { file: 'STATE.md', section: '## Åpne operatørbeslutninger', open: '^- \\[ \\] ', closed: '^- \\[x\\] ', }, freeze: { tag: 'end-state-freeze', featPattern: '^feat(\\(|!|:)' }, }; // --- helpers --------------------------------------------------------------- function fixture(files) { const dir = mkdtempSync(join(tmpdir(), 'end-state-gate-')); for (const [rel, body] of Object.entries(files)) { const p = join(dir, rel); mkdirSync(dirname(p), { recursive: true }); writeFileSync(p, body); } return dir; } const cleanup = (...dirs) => { for (const d of dirs) rmSync(d, { recursive: true, force: true }); }; const DECISIONS = { file: 'STATE.md', section: '## Open decisions', open: '^- \\[ \\] ', closed: '^- \\[x\\] ' }; const AGENTS = { dir: 'agents', spawnSites: 'commands/*.md', referenceMarker: 'Reference document, not a spawnable capability' }; const FREEZE = { tag: 'end-state-freeze', featPattern: '^feat(\\(|!|:)' }; function registry(overrides = {}) { return { defects: [], experiments: [], agents: AGENTS, decisions: DECISIONS, freeze: FREEZE, ...overrides }; } // A frozen manifest that matches `reg` exactly. function frozenFor(reg) { const sigs = (list) => Object.fromEntries(list.map((e) => [e.id, checkSignature(e.check)])); return { defects: sigs(reg.defects), experiments: sigs(reg.experiments), agents: reg.agents, decisions: reg.decisions, freeze: reg.freeze }; } function git(dir, ...args) { const r = spawnSync('git', [ '-c', 'user.name=fixture', '-c', 'user.email=fixture@example.invalid', '-c', 'core.hooksPath=/dev/null', '-c', 'commit.gpgsign=false', '-c', 'tag.gpgsign=false', ...args, ], { cwd: dir, encoding: 'utf8' }); assert.equal(r.status, 0, `git ${args.join(' ')}: ${r.stderr}`); return r.stdout; } function gitInit(dir) { git(dir, 'init', '-q'); git(dir, 'add', '-A'); git(dir, 'commit', '-q', '--allow-empty', '-m', 'chore: fixture baseline'); } function gitCommit(dir, subject) { git(dir, 'commit', '-q', '--allow-empty', '-m', subject); } const rowById = (result, id) => result.rows.find((r) => r.id === id); // --- conditions ----------------------------------------------------------- test('evaluateCondition: match / no-match on a single file, multiline regex', () => { const dir = fixture({ 'a.md': 'intro\n### Heading\nbody\n' }); try { assert.equal(evaluateCondition(dir, { path: 'a.md', pattern: '^### Heading', flags: 'm', expect: 'match' }), true); assert.equal(evaluateCondition(dir, { path: 'a.md', pattern: '^### Other', flags: 'm', expect: 'match' }), false); assert.equal(evaluateCondition(dir, { path: 'a.md', pattern: '^### Other', flags: 'm', expect: 'no-match' }), true); } finally { cleanup(dir); } }); test('evaluateCondition: globs (dir/*.ext, dir/**/*.ext) and path arrays match ANY file', () => { const dir = fixture({ 'commands/x.md': 'nothing here\n', 'lib/deep/y.mjs': 'const FLAG = process.env.SOME_FLAG;\n', }); try { assert.equal(evaluateCondition(dir, { path: 'commands/*.md', pattern: 'SOME_FLAG', expect: 'match' }), false); assert.equal(evaluateCondition(dir, { path: 'lib/**/*.mjs', pattern: 'SOME_FLAG', expect: 'match' }), true); assert.equal(evaluateCondition(dir, { path: ['commands/*.md', 'lib/**/*.mjs'], pattern: 'SOME_FLAG', expect: 'match' }), true); assert.equal(evaluateCondition(dir, { path: ['commands/*.md', 'lib/**/*.mjs'], pattern: 'SOME_FLAG', expect: 'no-match' }), false); } finally { cleanup(dir); } }); test('evaluateCondition: section scoping reads only from the heading to the next "## "', () => { const dir = fixture({ 'doc.md': '## 5. Design\nno status here\n## 6. PoC\n> **STATUS: RUN AND DECLINED**\n', }); try { const inFive = { path: 'doc.md', section: '## 5.', pattern: '^> \\*\\*STATUS:', flags: 'm', expect: 'no-match' }; const inSix = { ...inFive, section: '## 6.' }; assert.equal(evaluateCondition(dir, inFive), true, 'section 5 has no status block'); assert.equal(evaluateCondition(dir, inSix), false, 'section 6 has one'); } finally { cleanup(dir); } }); test('evaluateCondition: a literal NUL byte is detectable', () => { const dir = fixture({ 'nul.mjs': "const SEP = '\u0000';\n", 'clean.mjs': "const SEP = '\\x00';\n" }); try { assert.equal(evaluateCondition(dir, { path: 'nul.mjs', pattern: '\\u0000', expect: 'match' }), true); assert.equal(evaluateCondition(dir, { path: 'clean.mjs', pattern: '\\u0000', expect: 'match' }), false); } finally { cleanup(dir); } }); test('evaluateCondition: a missing file, a missing glob base or a missing section throws', () => { const dir = fixture({ 'a.md': 'x\n' }); try { assert.throws(() => evaluateCondition(dir, { path: 'missing.md', pattern: 'x', expect: 'no-match' }), /missing\.md/); assert.throws(() => evaluateCondition(dir, { path: 'nodir/*.md', pattern: 'x', expect: 'no-match' }), /nodir/); assert.throws(() => evaluateCondition(dir, { path: 'a.md', section: '## 9.', pattern: 'x', expect: 'no-match' }), /## 9\./); } finally { cleanup(dir); } }); test('evaluateCondition: a glob over an EXISTING dir with no matching files throws (no silent no-match)', () => { // In a no-match condition, "silently nothing matched" would read as the condition holding. const dir = fixture({ 'docs/readme.txt': 'x\n' }); try { assert.throws(() => evaluateCondition(dir, { path: 'docs/*.md', pattern: 'x', expect: 'no-match' }), /docs\/\*\.md/); assert.throws(() => evaluateCondition(dir, { path: 'docs/**/*.md', pattern: 'x', expect: 'no-match' }), /docs\/\*\*\/\*\.md/); } finally { cleanup(dir); } }); test('evaluateCheck: open only when ALL conditions hold; null check is not fellable', () => { const dir = fixture({ 'r.md': 'run the `### Bridge agent` block\n', 'fixed.md': 'run the `### Bridge agent` block\n### Bridge agent\n', }); const dangling = (file) => [ { path: file, pattern: '`### Bridge agent`', expect: 'match' }, { path: file, pattern: '^### Bridge agent', flags: 'm', expect: 'no-match' }, ]; try { assert.equal(evaluateCheck(dir, dangling('r.md')).status, 'open'); assert.equal(evaluateCheck(dir, dangling('fixed.md')).status, 'closed'); assert.equal(evaluateCheck(dir, null).status, 'not-fellable'); const broken = evaluateCheck(dir, dangling('gone.md')); assert.equal(broken.status, 'not-fellable'); assert.match(broken.detail, /gone\.md/); } finally { cleanup(dir); } }); // --- spawn instructions (what "referenced by a command" means) ------------- test('spawnedNames: a row of a table headed `Agent` is a spawn instruction; other tables are not', () => { const md = [ 'Launch the new agents:', '', '| Agent | Purpose |', '|-------|---------|', '| `alpha-agent` | does a |', '| `beta-agent` | does b |', '', '| Name | Purpose |', '|------|---------|', '| `gamma-agent` | just a list |', '', ].join('\n'); const names = spawnedNames(md); assert.ok(names.has('alpha-agent') && names.has('beta-agent')); assert.ok(!names.has('gamma-agent'), 'a table not headed "Agent" is not a roster'); }); test('spawnedNames: an imperative Launch/Spawn line names the agents it launches', () => { const md = [ 'Launch the **alpha-agent** agent:', '- Launch `beta-agent` (Agent tool) with the findings.', '3. Spawn `voyage:gamma-agent` in the background.', '**Launch** the `delta-agent` agent now.', 'launch `epsilon-agent` too', ].join('\n'); const names = spawnedNames(md); for (const n of ['alpha-agent', 'beta-agent', 'gamma-agent', 'delta-agent', 'epsilon-agent']) { assert.ok(names.has(n), `${n} should count as spawned`); } }); test('spawnedNames: an agent block with a Prompt: line is a spawn instruction; a bare bold name is not', () => { const md = [ '**alpha-agent** — adversarial review of the plan.', 'Prompt: "Review this plan."', '', '**beta-agent** — mentioned for context only.', 'It is not launched here.', ].join('\n'); const names = spawnedNames(md); assert.ok(names.has('alpha-agent')); assert.ok(!names.has('beta-agent')); }); test('spawnedNames: prose, negation, comments, fences and quotes are never spawn instructions', () => { const md = [ 'The alpha-agent is dormant and is never spawned.', 'Never launch `beta-agent`.', 'In quick mode we used to launch `gamma-agent`.', '', '', '```', 'Launch the `zeta-agent` agent', '| Agent |', '|---|', '| `eta-agent` |', '```', '> Launch the `theta-agent` agent', ].join('\n'); const names = spawnedNames(md); for (const n of ['alpha-agent', 'beta-agent', 'gamma-agent', 'delta-agent', 'epsilon-agent', 'zeta-agent', 'eta-agent', 'theta-agent']) { assert.ok(!names.has(n), `${n} must not count as spawned`); } }); // --- the tallies, both directions ------------------------------------------ test('defects tally: > 0 while a check holds, 0 once fixed; not-fellable counts as open', () => { const defect = { id: 'D-X', summary: 'removed tool still referenced', probe: 'phrase', check: [{ path: 'commands/plan.md', pattern: '\\bTeamCreate\\b', expect: 'match' }], }; const unfellable = { id: 'D-Y', summary: 'no runnable check yet', check: null }; const base = { 'STATE.md': '## Open decisions\n', 'agents/a.md': 'x\n', 'commands/plan.md': 'Launch `a`\n' }; const red = fixture({ ...base, 'commands/plan.md': 'Launch `a` and TeamCreate\n' }); const green = fixture(base); try { let row = rowById(measure(red, registry({ defects: [defect] })), 'defects'); assert.equal(row.open, 1); assert.equal(row.total, 1); row = rowById(measure(green, registry({ defects: [defect] })), 'defects'); assert.equal(row.open, 0); row = rowById(measure(green, registry({ defects: [defect, unfellable] })), 'defects'); assert.equal(row.open, 1, 'a defect without a runnable check stays open'); assert.equal(row.items.find((i) => i.id === 'D-Y').status, 'not-fellable'); } finally { cleanup(red, green); } }); test('experiments tally: an env-gated opt-in is open until its gate is gone', () => { const exp = { id: 'E-X', summary: 'default-off loop', probe: 'phrase', check: [{ path: ['commands/*.md', 'lib/**/*.mjs'], pattern: 'LOOP_ENABLED', expect: 'match' }], }; const base = { 'STATE.md': '## Open decisions\n', 'agents/a.md': 'x\n', 'commands/r.md': 'Launch `a`\n' }; const red = fixture({ ...base, 'lib/util/cap.mjs': 'if (process.env.LOOP_ENABLED) {}\n' }); const green = fixture({ ...base, 'lib/util/cap.mjs': 'export const x = 1;\n' }); try { assert.equal(rowById(measure(red, registry({ experiments: [exp] })), 'experiments').open, 1); assert.equal(rowById(measure(green, registry({ experiments: [exp] })), 'experiments').open, 0); } finally { cleanup(red, green); } }); test('dormant-agents tally: an agent no command spawns counts; reference docs never do', () => { const files = { 'STATE.md': '## Open decisions\n', 'agents/used-agent.md': '---\nname: used-agent\ndescription: |\n does work\n---\n', 'agents/idle-agent.md': '---\nname: idle-agent\ndescription: |\n never wired\n---\n', 'agents/some-orchestrator.md': '---\nname: some-orchestrator\ndescription: Reference document, not a spawnable capability — docs\n---\n', 'commands/run.md': 'Launch the **used-agent** agent.\n', }; const red = fixture(files); const green = fixture({ ...files, 'commands/other.md': 'Spawn `idle-agent` in parallel.\n' }); try { let row = rowById(measure(red, registry()), 'dormant-agents'); assert.equal(row.open, 1); assert.equal(row.total, 2, 'denominator = spawnable agents (reference docs excluded)'); assert.deepEqual(row.items.filter((i) => i.status === 'open').map((i) => i.id), ['idle-agent']); row = rowById(measure(green, registry()), 'dormant-agents'); assert.equal(row.open, 0); } finally { cleanup(red, green); } }); test('dormant-agents tally: a prose sentence or an HTML comment does not wake a dormant agent', () => { const files = { 'STATE.md': '## Open decisions\n', 'agents/idle-agent.md': '---\nname: idle-agent\ndescription: |\n never wired\n---\n', 'commands/plan.md': 'The idle-agent is dormant and is never spawned.\n', 'commands/end.md': '\nThe research-idle-agents phase.\n', }; const dir = fixture(files); try { assert.equal(rowById(measure(dir, registry()), 'dormant-agents').open, 1); } finally { cleanup(dir); } }); test('dormant-agents tally: an unmeasurable agents dir is n/a (null), never 0', () => { const dir = fixture({ 'STATE.md': '## Open decisions\n', 'commands/r.md': 'x\n' }); try { const result = measure(dir, registry()); const row = rowById(result, 'dormant-agents'); assert.equal(row.open, null); assert.equal(row.total, null); assert.match(row.detail, /not measurable/); assert.equal(result.green, false); } finally { cleanup(dir); } }); test('decisions tally: counts open markers inside the section only, and says it counts ticks', () => { const state = [ '# STATE', '- [ ] outside the section, ignored', '## Open decisions', '- [ ] first open', '- [x] already decided', '- [ ] second open', '## Next section', '- [ ] also ignored', '', ].join('\n'); const red = fixture({ 'STATE.md': state, 'agents/a.md': 'x\n', 'commands/r.md': 'Launch `a`\n' }); const green = fixture({ 'STATE.md': '## Open decisions\n- [x] done\n## Next\n', 'agents/a.md': 'x\n', 'commands/r.md': 'Launch `a`\n', }); try { let row = rowById(measure(red, registry()), 'decisions'); assert.equal(row.open, 2); assert.equal(row.total, 3); assert.match(row.detail, /tick/i, 'the output must say a tick is not verified as a decision'); row = rowById(measure(green, registry()), 'decisions'); assert.equal(row.open, 0); assert.equal(row.total, 1); } finally { cleanup(red, green); } }); test('decisions tally: a missing STATE.md or section is NOT MEASURABLE (null), never 0', () => { const noState = fixture({ 'agents/a.md': 'x\n', 'commands/r.md': 'Launch `a`\n' }); const noSection = fixture({ 'STATE.md': '# STATE\n- [ ] x\n', 'agents/a.md': 'x\n', 'commands/r.md': 'Launch `a`\n' }); try { for (const dir of [noState, noSection]) { const result = measure(dir, registry()); const row = rowById(result, 'decisions'); assert.equal(row.open, null); assert.ok(row.detail.length > 0, 'the reason is reported'); assert.equal(result.green, false, 'an unmeasurable tally keeps the gate red'); } } finally { cleanup(noState, noSection); } }); test('decisions tally: an unmarked list item in the section is format drift → NOT MEASURABLE', () => { // A STATE written without the marker convention must not read as "0 open". for (const item of ['1. **Some decision?** prose', '- plain bullet decision', '* star bullet']) { const dir = fixture({ 'STATE.md': `## Open decisions\n- [ ] marked\n${item}\n## Next\n`, 'agents/a.md': 'x\n', 'commands/r.md': 'Launch `a`\n', }); try { const row = rowById(measure(dir, registry()), 'decisions'); assert.equal(row.open, null, `unmarked "${item}" must make the tally unmeasurable`); assert.match(row.detail, /unmarked/); } finally { cleanup(dir); } } }); test('feat-after-freeze tally: not a git repo → n/a (red), never 0', () => { const dir = fixture({ 'STATE.md': '## Open decisions\n' }); try { const result = measure(dir, registry()); const row = rowById(result, 'feat-after-freeze'); assert.equal(row.open, null); assert.match(row.detail, /not measured/); assert.equal(result.green, false); } finally { cleanup(dir); } }); test('feat-after-freeze tally: no freeze tag yet → n/a (red), and the detail names the tag', () => { const dir = fixture({ 'STATE.md': '## Open decisions\n' }); try { gitInit(dir); const row = rowById(measure(dir, registry()), 'feat-after-freeze'); assert.equal(row.open, null); assert.match(row.detail, /end-state-freeze/); } finally { cleanup(dir); } }); test('feat-after-freeze tally: counts feat commits after the tag, 0 when there are none', () => { const dir = fixture({ 'STATE.md': '## Open decisions\n' }); try { gitInit(dir); gitCommit(dir, 'feat: before the freeze does not count'); git(dir, 'tag', 'end-state-freeze'); let row = rowById(measure(dir, registry()), 'feat-after-freeze'); assert.equal(row.open, 0); assert.equal(row.total, 0); gitCommit(dir, 'fix(x): a defect fix is allowed'); gitCommit(dir, 'feature: not a conventional feat'); row = rowById(measure(dir, registry()), 'feat-after-freeze'); assert.equal(row.open, 0); assert.equal(row.total, 2); gitCommit(dir, 'feat(research): a new capability'); gitCommit(dir, 'feat!: a breaking capability'); row = rowById(measure(dir, registry()), 'feat-after-freeze'); assert.equal(row.open, 2); assert.equal(row.total, 4); } finally { cleanup(dir); } }); // --- registry integrity (the judged party must not own the ledger) --------- const SAMPLE = registry({ defects: [ { id: 'D-01', summary: 'first defect', probe: 'phrase', check: [{ path: 'a.md', pattern: 'bad', expect: 'match' }] }, { id: 'D-02', summary: 'second defect', probe: 'phrase', check: [{ path: 'a.md', pattern: 'worse', expect: 'match' }] }, ], experiments: [ { id: 'E-01', summary: 'first experiment', probe: 'phrase', check: [{ path: 'a.md', pattern: 'FLAG', expect: 'match' }] }, { id: 'E-02', summary: 'second experiment', probe: 'phrase', check: [{ path: 'a.md', pattern: 'OPT', expect: 'match' }] }, ], }); const clone = (v) => JSON.parse(JSON.stringify(v)); test('verifyIntegrity: the frozen registry itself is intact; a new entry may be added', () => { const frozen = frozenFor(SAMPLE); assert.deepEqual(verifyIntegrity(SAMPLE, frozen), { ok: true, violations: [] }); const grown = clone(SAMPLE); grown.defects.push({ id: 'D-03', summary: 'found later', probe: 'phrase', check: [{ path: 'a.md', pattern: 'new', expect: 'match' }] }); assert.equal(verifyIntegrity(grown, frozen).ok, true); }); test('verifyIntegrity: every registry attack is a violation that names what moved', () => { const frozen = frozenFor(SAMPLE); const attacks = { 'delete a defect': (r) => { r.defects = r.defects.filter((d) => d.id !== 'D-02'); }, 'delete an experiment': (r) => { r.experiments = r.experiments.filter((e) => e.id !== 'E-01'); }, 'weaken a defect check': (r) => { r.defects[0].check[0].pattern = '^NEVER MATCHES$'; }, 'weaken an experiment check': (r) => { r.experiments[1].check[0].expect = 'no-match'; }, 'drop a condition': (r) => { r.defects[0].check = []; }, 'point spawnSites at agents': (r) => { r.agents = { ...r.agents, spawnSites: 'agents/*.md' }; }, 'change the reference marker': (r) => { r.agents = { ...r.agents, referenceMarker: 'DORMANT' }; }, 'move the decisions section': (r) => { r.decisions = { ...r.decisions, section: '## Elsewhere' }; }, 'change the open marker': (r) => { r.decisions = { ...r.decisions, open: '^NEVER' }; }, 'rename the freeze tag': (r) => { r.freeze = { ...r.freeze, tag: 'some-future-tag' }; }, 'duplicate an id': (r) => { r.defects.push(clone(r.defects[0])); }, }; for (const [name, attack] of Object.entries(attacks)) { const reg = clone(SAMPLE); attack(reg); const v = verifyIntegrity(reg, frozen); assert.equal(v.ok, false, `${name} must be caught`); assert.ok(v.violations.length > 0 && v.violations.every((s) => typeof s === 'string' && s.length > 0), name); } }); test('verifyIntegrity: spawnSites may never include agents/, even if the manifest says so', () => { const reg = clone(SAMPLE); reg.agents = { ...reg.agents, spawnSites: 'agents/*.md' }; const v = verifyIntegrity(reg, frozenFor(reg)); assert.equal(v.ok, false); assert.ok(v.violations.some((s) => /agents\//.test(s))); }); test('checkSignature: key order does not matter; every field of a condition does', () => { const a = [{ path: 'a.md', pattern: 'x', flags: 'm', expect: 'match' }]; const reordered = [{ expect: 'match', flags: 'm', pattern: 'x', path: 'a.md' }]; assert.equal(checkSignature(a), checkSignature(reordered)); for (const change of [{ path: 'b.md' }, { pattern: 'y' }, { flags: '' }, { expect: 'no-match' }, { section: '## 1.' }]) { assert.notEqual(checkSignature([{ ...a[0], ...change }]), checkSignature(a), JSON.stringify(change)); } assert.match(checkSignature(a), /^[0-9a-f]{64}$/); }); test('measure: a missing frozen manifest makes integrity n/a and keeps the gate red', () => { const dir = fixture({ 'STATE.md': '## Open decisions\n' }); try { const result = measure(dir, registry()); assert.equal(result.integrity.ok, null); assert.match(result.integrity.detail, /end-state-frozen\.json/); assert.equal(result.green, false); } finally { cleanup(dir); } }); // --- render ---------------------------------------------------------------- test('render: the header counts only tallies that ARE 0, never n/a ones', () => { const result = { green: false, integrity: { ok: true, violations: [], detail: '' }, rows: [ { id: 'defects', label: 'l', source: 's', open: 0, total: 1, target: 0, items: [], detail: '' }, { id: 'experiments', label: 'l', source: 's', open: null, total: null, target: 0, items: [], detail: 'not measurable: x' }, { id: 'dormant-agents', label: 'l', source: 's', open: 0, total: 3, target: 0, items: [], detail: '' }, ], }; const text = render(result); assert.match(text, /RED \(2 of 3 tallies at 0\)/); assert.match(text, /\| experiments \| n\/a \| n\/a \|/); }); test('render: open phrase probes are labelled, closed ids are listed, integrity is shown', () => { const result = { green: false, integrity: { ok: false, violations: ['D-02 removed from the registry'], detail: '' }, rows: [{ id: 'defects', label: 'open pipeline defects', source: 's', open: 1, total: 2, target: 0, detail: '', items: [ { id: 'D-01', summary: 'still open', probe: 'phrase', status: 'open', detail: '' }, { id: 'D-06', summary: 'fixed', probe: 'byte', status: 'closed', detail: '' }, ], }], }; const text = render(result); assert.match(text, /\[open · phrase probe\] D-01/); assert.match(text, /closed: D-06/); assert.match(text, /registry integrity: VIOLATED/); assert.match(text, /D-02 removed from the registry/); }); // --- CLI ------------------------------------------------------------------- function writeGateFiles(dir, reg, frozen = frozenFor(reg)) { mkdirSync(join(dir, 'scripts'), { recursive: true }); writeFileSync(join(dir, 'scripts', 'end-state-registry.json'), JSON.stringify(reg, null, 2)); mkdirSync(join(dir, 'tests', 'fixtures'), { recursive: true }); writeFileSync(join(dir, 'tests', 'fixtures', 'end-state-frozen.json'), JSON.stringify(frozen, null, 2)); } function runGate(dir, extra = []) { return spawnSync(process.execPath, [GATE, '--root', dir, ...extra], { encoding: 'utf8' }); } const ALL_IDS = ['defects', 'experiments', 'dormant-agents', 'decisions', 'feat-after-freeze']; test('CLI: all five tallies at 0 with an intact registry → green, exit 0; --json carries the rows', () => { const dir = fixture({ 'STATE.md': '## Open decisions\n- [x] done\n', 'agents/a.md': '---\nname: a\n---\n', 'commands/r.md': 'Spawn `a`\n', }); try { writeGateFiles(dir, registry()); gitInit(dir); git(dir, 'tag', 'end-state-freeze'); const r = runGate(dir, ['--json']); assert.equal(r.status, 0, r.stdout + r.stderr); const out = JSON.parse(r.stdout); assert.equal(out.green, true); assert.equal(out.integrity.ok, true); assert.deepEqual(out.rows.map((x) => x.id), ALL_IDS); assert.ok(out.rows.every((x) => x.open === 0 && x.target === 0 && typeof x.source === 'string')); } finally { cleanup(dir); } }); test('CLI: an intact registry with every measurable tally at 0 but no freeze tag → red, exit 1', () => { // n/a must never be read as 0 — also when nothing else is wrong. const dir = fixture({ 'STATE.md': '## Open decisions\n- [x] done\n', 'agents/a.md': '---\nname: a\n---\n', 'commands/r.md': 'Spawn `a`\n', }); try { writeGateFiles(dir, registry()); gitInit(dir); const r = runGate(dir, ['--json']); assert.equal(r.status, 1, r.stdout + r.stderr); const out = JSON.parse(r.stdout); assert.equal(out.integrity.ok, true); assert.equal(out.green, false); assert.equal(out.rows.find((x) => x.id === 'feat-after-freeze').open, null); assert.ok(out.rows.filter((x) => x.id !== 'feat-after-freeze').every((x) => x.open === 0)); } finally { cleanup(dir); } }); test('CLI: all tallies at 0 but a tampered registry → red, exit 1 (the combined green attack)', () => { const dir = fixture({ 'STATE.md': '## Open decisions\n- [x] ticked\n', 'agents/a.md': '---\nname: a\n---\n', 'commands/r.md': 'Spawn `a`\n', }); try { const honest = registry({ defects: [{ id: 'D-01', summary: 'a real defect', probe: 'phrase', check: [{ path: 'commands/r.md', pattern: 'Spawn', expect: 'match' }] }] }); const tampered = registry(); // the open defect simply left the ledger writeGateFiles(dir, tampered, frozenFor(honest)); gitInit(dir); git(dir, 'tag', 'end-state-freeze'); const r = runGate(dir); assert.equal(r.status, 1, r.stdout + r.stderr); assert.match(r.stdout, /RED/); assert.match(r.stdout, /VIOLATED/); assert.match(r.stdout, /D-01/); } finally { cleanup(dir); } }); test('CLI: any tally > 0 → red, exit 1; the table names every row', () => { const dir = fixture({ 'STATE.md': '## Open decisions\n- [ ] undecided\n', 'agents/a.md': '---\nname: a\n---\n', 'commands/r.md': 'Spawn `a`\n', }); try { writeGateFiles(dir, registry()); const r = runGate(dir); assert.equal(r.status, 1, r.stderr); for (const label of ALL_IDS) assert.match(r.stdout, new RegExp(label)); assert.match(r.stdout, /RED/); } finally { cleanup(dir); } }); test('CLI: an unreadable registry is a usage error (exit 2), not a verdict', () => { const dir = fixture({ 'STATE.md': '## Open decisions\n' }); try { const r = runGate(dir); assert.equal(r.status, 2); assert.match(r.stderr, /end-state-registry\.json/); } finally { cleanup(dir); } }); // --- the real repo: denominator pinned, state never pinned ----------------- test('the frozen denominator: tests/fixtures/end-state-frozen.json is exactly the literal above', () => { const file = loadFrozen(ROOT); const { why, ...rest } = file; assert.ok(typeof why === 'string' && why.length > 20, 'the manifest says why it is frozen'); assert.deepEqual(rest, FROZEN); }); test('the frozen denominator: the real registry is intact against it', () => { const v = verifyIntegrity(loadRegistry(ROOT), FROZEN); assert.deepEqual(v, { ok: true, violations: [] }, v.violations.join('\n')); }); test('real registry: every counted entry has an id, a summary, a probe kind and a check that RUNS here', () => { const reg = loadRegistry(ROOT); const entries = [...reg.defects, ...reg.experiments]; const ids = new Set(); for (const e of entries) { assert.match(e.id, /^[DE]-\d{2}$/, `bad id ${e.id}`); assert.ok(!ids.has(e.id), `duplicate id ${e.id}`); ids.add(e.id); assert.ok(typeof e.summary === 'string' && e.summary.length > 10, `${e.id} needs a summary`); assert.ok(['phrase', 'byte'].includes(e.probe), `${e.id} must declare its probe kind`); // A check that cannot evaluate against this very repo is a typo, not a finding. assert.notEqual(evaluateCheck(ROOT, e.check).status, 'not-fellable', `${e.id} check does not run here`); } }); test('real repo: five rows, open is a count or null, exit code agrees with rows + integrity', () => { const r = spawnSync(process.execPath, [GATE, '--json'], { encoding: 'utf8', cwd: ROOT }); assert.ok(r.status === 0 || r.status === 1, r.stderr); const out = JSON.parse(r.stdout); assert.deepEqual(out.rows.map((x) => x.id), ALL_IDS); for (const row of out.rows) { assert.ok(row.open === null || (Number.isInteger(row.open) && row.open >= 0), `${row.id}: ${row.open}`); } const green = out.rows.every((row) => row.open === 0) && out.integrity.ok === true; assert.equal(out.green, green); assert.equal(r.status, green ? 0 : 1); assert.ok(existsSync(join(ROOT, 'scripts', 'end-state-registry.json'))); assert.ok(readFileSync(join(ROOT, 'tests', 'fixtures', 'end-state-frozen.json'), 'utf8').length > 0); });