// allow-test-rule: source-text-is-the-product [#1949] // Agent .md, reference .md, and docs/reference/*.md files — their text IS what the // runtime loads. Per CONTRIBUTING.md exception matrix, asserting these files // document the contract tests the deployed surface, not derived // behavior. The behavioral test (cmdVerifyPlanStructure) asserts the validator // stays additive. Issue #1949. 'use strict'; const { describe, test } = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs'); const ROOT = path.resolve(__dirname, '..'); const PLANNER = path.join(ROOT, 'agents', 'gsd-planner.md'); const EXECUTOR = path.join(ROOT, 'agents', 'gsd-executor.md'); const PLAN_MD_DOC = path.join(ROOT, 'docs', 'reference', 'plan-md.md'); const PRECONDITIONS_REF = path.join(ROOT, 'gsd-core', 'references', 'planner-preconditions.md'); function read(rel) { return fs.readFileSync(rel, 'utf-8').replace(/\r\n/g, '\n').replace(/\r/g, '\n'); } // ─── Schema documentation (docs/reference/plan-md.md) ──────────────────────── describe('issue #1949: plan-md.md documents ', () => { test('plan-md.md mentions as an optional task element', () => { const doc = read(PLAN_MD_DOC); assert.match( doc, //, 'docs/reference/plan-md.md must document the element' ); }); test('plan-md.md states is optional and does not break plans that omit it', () => { const doc = read(PLAN_MD_DOC); assert.ok( /optional/.test(doc) && /precondition/.test(doc), 'plan-md.md must describe as optional' ); }); }); // ─── Planner emission contract (agents/gsd-planner.md) ────────────────────── describe('issue #1949: gsd-planner.md declares emission', () => { test('planner references the precondition reference file', () => { const planner = read(PLANNER); assert.ok( planner.includes('planner-preconditions.md'), 'gsd-planner.md must @-reference planner-preconditions.md (progressive disclosure)' ); }); test('planner is under the 49152-char cap after adding content', () => { const planner = read(PLANNER); assert.ok( planner.length < 49152, `gsd-planner.md is ${planner.length} chars, must be < 49152 (LF-normalized)` ); }); }); // ─── Planner-preconditions reference file (progressive disclosure) ─────────── describe('issue #1949: planner-preconditions.md exists with the three emission cases', () => { test('reference file exists', () => { assert.ok(fs.existsSync(PRECONDITIONS_REF), `Missing: ${PRECONDITIONS_REF}`); }); test('reference documents the user_setup emission case', () => { const ref = read(PRECONDITIONS_REF); assert.ok( /user_setup/.test(ref) || /external service setup/i.test(ref), 'planner-preconditions.md must document the user_setup / external-setup emission case' ); }); test('reference documents the prior-phase artifact emission case', () => { const ref = read(PRECONDITIONS_REF); assert.ok( /prior.?phase artifact/i.test(ref) || /artifact from (a )?prior/i.test(ref), 'planner-preconditions.md must document the prior-phase-artifact emission case' ); }); test('reference documents the env-var emission case', () => { const ref = read(PRECONDITIONS_REF); assert.ok( /env(ironment)? var/i.test(ref), 'planner-preconditions.md must document the env-var emission case' ); }); test('reference maps the contract triad (precondition / postcondition / invariant)', () => { const ref = read(PRECONDITIONS_REF); assert.ok( /postcondition||/.test(ref), 'planner-preconditions.md must map to existing postconditions (/)' ); }); }); // ─── Executor assertion contract (agents/gsd-executor.md) ──────────────────── describe('issue #1949: gsd-executor.md asserts before task execution', () => { test('executor mentions ', () => { const exec = read(EXECUTOR); assert.match( exec, //, 'gsd-executor.md must reference ' ); }); test('executor routes an unmet precondition through checkpoint machinery (halt, no partial commit)', () => { const exec = read(EXECUTOR); assert.ok( /precondition/i.test(exec) && /checkpoint/.test(exec), 'gsd-executor.md must route unmet through checkpoint machinery' ); }); test('executor treats a met/absent precondition as a no-op (does not change flow)', () => { const exec = read(EXECUTOR); assert.ok( /no.op|no visible change|continue/i.test(exec), 'gsd-executor.md must state that a met or absent precondition produces no visible change' ); }); test('executor is under the 49152-char cap after adding content', () => { const exec = read(EXECUTOR); assert.ok( exec.length < 49152, `gsd-executor.md is ${exec.length} chars, must be < 49152 (LF-normalized)` ); }); }); // ─── Behavioral test: validator stays additive (cmdVerifyPlanStructure) ────── // // `cmdVerifyPlanStructure` checks for PRESENCE of required tags. It must not // reject unknown optional tags. This is the "does not break plans that omit it" // plus "does not break plans that include it" guarantee from acceptance #1. // Pattern mirrors tests/tracer-bullet.test.cjs (companion feature #1945). function planWith({ precondition = null } = {}) { const lines = [ '', ' Task 1: Test', ]; if (precondition !== null) { lines.push(` ${precondition}`); } lines.push( ' src/x.ts', ' Do the thing.', ' echo ok', ' Done', '', '', ); return [ '---', 'phase: 01-test', 'plan: 01', 'type: execute', 'wave: 1', 'depends_on: []', 'files_modified: [src/x.ts]', 'autonomous: true', 'must_haves:', ' truths:', ' - "something is true"', '---', '', '', '', ...lines, '', ].join('\n'); } function verifyPlan(tmpDir, content) { const rel = path.join('.planning', 'phases', '01-test', '01-01-PLAN.md'); fs.mkdirSync(path.join(tmpDir, '.planning', 'phases', '01-test'), { recursive: true }); fs.writeFileSync(path.join(tmpDir, rel), content); const result = runGsdTools(`verify plan-structure ${rel}`, tmpDir); assert.ok(result.success, `verify plan-structure failed to run: ${result.error}`); return JSON.parse(result.output); } describe('issue #1949: cmdVerifyPlanStructure accepts (additive)', () => { test('plan with passes structural validation', (t) => { const tmp = createTempProject(); t.after(() => cleanup(tmp)); const out = verifyPlan(tmp, planWith({ precondition: 'OPENAI_API_KEY is set in the environment' })); assert.strictEqual(out.valid, true, `plan with must be valid, errors: ${JSON.stringify(out.errors)}`); assert.deepStrictEqual(out.errors, [], 'no validation path may reject a task'); assert.ok( !(out.warnings || []).some((w) => /precondition/i.test(w)), 'nothing may flag the element specifically', ); }); test('plan without still passes structural validation (back-compat)', (t) => { const tmp = createTempProject(); t.after(() => cleanup(tmp)); const out = verifyPlan(tmp, planWith({ precondition: null })); assert.strictEqual(out.valid, true, `plan without must be valid (back-compat), errors: ${JSON.stringify(out.errors)}`); }); }); // ─── Parity: docs/reference/plan-md.md and planner-preconditions.md agree ──── // // DEFECT.GENERATIVE-FIX-DIVERGENCE: two surfaces describing the same schema // must agree on the canonical tag spelling. This is the parity guard against // silent drift. describe('issue #1949: parity between plan-md.md and planner-preconditions.md', () => { test('both surfaces spell the canonical tag ', () => { const doc = read(PLAN_MD_DOC); const ref = read(PRECONDITIONS_REF); assert.ok(doc.includes(''), 'plan-md.md must spell '); assert.ok(ref.includes(''), 'planner-preconditions.md must spell '); }); });