fix(#3797): make the roadmapper's role, output, and checklist match its write-first execution flow (#4008)
* test(#3797): the roadmapper must follow one write-first contract * fix(#3797): make the roadmapper's role, output, and checklist match its write-first execution flow The roadmapper contradicted itself: role blurb, output format, and completion checklist described an approve-first flow while its execution flow said "Write Files Immediately" with reactive-only revision (#3797). The approval gate belongs to the ORCHESTRATOR — both callers read the written ROADMAP.md, present it, and gate on approval (with an auto-mode bypass a subagent cannot host) — so write-first is the contract. All approve-first text now describes the write-then-return reality, the old "Draft Presentation Format" (whose ## ROADMAP DRAFT header matched no orchestrator branch) is folded into the ## ROADMAP CREATED structured return as a preview block, and the duplicate checklist lines are merged. A structural guard pins the single contract. Emitted-Drift-Ack-Growth: gsd-roadmapper.md — #3797: +bytes — approve-first wording replaced with write-first descriptions; the DRAFT presentation template folded into the ROADMAP CREATED return as a preview block * chore(#3797): changeset fragment (pr number backfilled after PR creation) * chore(#3797): backfill changeset PR number (4008) --------- Co-authored-by: sim <sim@local>
This commit is contained in:
@@ -105,7 +105,7 @@ const BARE_COMMAND_RE = new RegExp(
|
||||
const PROSE_ALLOWLIST = [
|
||||
{ file: 'agents/gsd-executor.md', line: 795, reason: 'describes the SDK return envelope of `gsd-tools query commit`; not an instruction to run the bare word' },
|
||||
{ file: 'agents/gsd-phase-researcher.md', line: 33, reason: 'package-legitimacy provenance rule names the command as the source of an OK verdict; descriptive' },
|
||||
{ file: 'agents/gsd-roadmapper.md', line: 642, reason: 'parenthetical "e.g." naming SDK queries a user *could* run; not an agent instruction' },
|
||||
{ file: 'agents/gsd-roadmapper.md', line: 647, reason: 'parenthetical "e.g." naming SDK queries a user *could* run; not an agent instruction' },
|
||||
{ file: 'agents/gsd-intel-updater.md', line: 40, reason: 'cross-platform note names the `gsd-tools intel <subcommand>` CLI surface descriptively ("CLI invocations go through..."); not an agent instruction' },
|
||||
{ file: 'gsd-core/workflows/execute-plan.md', line: 419, reason: 'describes the downstream SDK validation step (`validated downstream by ...`); names the mechanism, does not instruct the agent to type it' },
|
||||
];
|
||||
|
||||
57
tests/roadmapper-contract-guard.test.cjs
Normal file
57
tests/roadmapper-contract-guard.test.cjs
Normal file
@@ -0,0 +1,57 @@
|
||||
'use strict';
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// #3797 — gsd-roadmapper must follow ONE contract: write-first.
|
||||
//
|
||||
// The agent's role blurb, output format, and completion checklist described
|
||||
// an approve-first flow ("Return structured draft for user approval",
|
||||
// "Awaiting / Approve roadmap", "Files written (after approval)") while its
|
||||
// execution flow said "Write Files Immediately ... Write files first, then
|
||||
// return" with reactive-only revision. The approval gate belongs to the
|
||||
// ORCHESTRATOR (new-project.md reads the written ROADMAP.md, presents it,
|
||||
// and gates on approval/auto-mode itself — a subagent cannot host the user
|
||||
// loop). The agent's write-first execution flow is the intentional contract
|
||||
// (explicit durability rationale; the #2255 write-guard arming in the same
|
||||
// Step 7); the approve-first text is a leftover and must not return.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const { test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const ROADMAPPER = path.join(__dirname, '..', 'agents', 'gsd-roadmapper.md');
|
||||
|
||||
// agents/*.md is shipped agent text — the bytes ARE what the runtime loads;
|
||||
// a structural scan over it tests the deployed contract.
|
||||
test('#3797: the roadmapper follows one write-first contract (approval is the orchestrator\'s)', () => {
|
||||
const md = fs.readFileSync(ROADMAPPER, 'utf-8');
|
||||
assert.ok(
|
||||
!/for (user )?approval/i.test(md),
|
||||
'#3797: the agent cannot host a user approval loop — approve-first phrasing must not return',
|
||||
);
|
||||
assert.ok(
|
||||
!/Awaiting \/ Approve/.test(md),
|
||||
'#3797: the Awaiting/Approve output footer is the old contract; revision is the orchestrator\'s gate plus Step 9 re-runs',
|
||||
);
|
||||
assert.ok(
|
||||
!/^## ROADMAP DRAFT/m.test(md),
|
||||
'#3797: the agent returns ## ROADMAP CREATED — a DRAFT header matches no orchestrator branch (they branch on CREATED/BLOCKED only)',
|
||||
);
|
||||
assert.ok(
|
||||
/Files written immediately/.test(md),
|
||||
'the checklist must pin the write-first ordering',
|
||||
);
|
||||
assert.ok(
|
||||
/^## Step 7: Write Files Immediately$/m.test(md),
|
||||
'the write-first execution flow (durability rationale) is the intended contract and must stay',
|
||||
);
|
||||
assert.ok(
|
||||
!/\(after approval\)/.test(md),
|
||||
'#3797: the checklist must not claim files are written after an approval the agent never hosts',
|
||||
);
|
||||
assert.ok(
|
||||
/^## Step 9: Handle Revision \(if needed\)$/m.test(md),
|
||||
'reactive revision (Step 9) stays — it is the revision path under the write-first contract too',
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user