import { describe, test } from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; // Lint-test for the editorial-reviewer fasit fixture. // Mirrors the structure-only discipline of persona-reviewer-fixture.test.mjs and // fact-checker-fixture.test.mjs: this test asserts the SHAPE of the fixture — // the two judging axes, all ten checks (P1–P5 + A1–A5), the three severities, // and the eight Del 4 cases that form the gold standard. Whether the agent's // live flags actually reproduce the fasit directions is [GATE]/[OPERATØR], // never self-certified here. const FIXTURE_PATH = fileURLToPath( new URL('./fixtures/editorial-reviewer-cases.md', import.meta.url) ); const fixture = readFileSync(FIXTURE_PATH, 'utf8'); // The ten checks: five prose-craft (P1–P5) + five narrative-architecture (A1–A5). const PROSE_CHECKS = ['P1', 'P2', 'P3', 'P4', 'P5']; const ARCH_CHECKS = ['A1', 'A2', 'A3', 'A4', 'A5']; // The two axis names (Norwegian, as the agent and the writing contract use them). const AXES = ['prosa-håndverk', 'narrativ-arkitektur']; // The three-rung severity scale. const SEVERITIES = ['BLOCK', 'REWORK', 'NICE']; describe('editorial-reviewer fixture structure', () => { test('names both judging axes', () => { for (const axis of AXES) { assert.ok( new RegExp(axis, 'i').test(fixture), `fixture must name the axis "${axis}"` ); } }); test('documents all ten checks (P1–P5 + A1–A5)', () => { for (const check of [...PROSE_CHECKS, ...ARCH_CHECKS]) { assert.ok( fixture.includes(check), `fixture must reference the check "${check}"` ); } }); test('defines the three-rung severity scale', () => { for (const sev of SEVERITIES) { assert.ok( fixture.includes(sev), `fixture must define the severity "${sev}"` ); } }); test('documents the eight Del 4 cases', () => { const cases = fixture.match(/^###\s+Case\s+\d+\b/gim) || []; assert.equal( cases.length, 8, `fixture must document exactly 8 Del 4 cases (found ${cases.length})` ); }); test('ties the checklist to the Maskinrommet §C2 truth source', () => { assert.ok( /§C2|C2/.test(fixture), 'fixture must reference the §C2 writing-contract truth source' ); }); test('keeps the jury-judges-writer-writes boundary (direction, not copy)', () => { assert.ok( /direction, not rewritten copy/i.test(fixture), 'fixture must state the direction-not-copy boundary' ); }); test('records the persona-blindspot rationale (≈6/8 editorial-only)', () => { assert.ok( /blindsone/i.test(fixture) && /6\/8/.test(fixture), 'fixture must record why the gate exists (blind spots, ~6/8 editorial-only)' ); }); });