diff --git a/.changeset/noble-elks-chatter.md b/.changeset/noble-elks-chatter.md new file mode 100644 index 000000000..b988337b9 --- /dev/null +++ b/.changeset/noble-elks-chatter.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 2443 +--- +**`check.decision-coverage-plan` no longer false-blocks on decisions cited in ``/``/``/``/``** — the gate scanned only ``/``/``/`` tag bodies while its remediation message claimed "(or body)". A decision faithfully cited in any of the five other planner-canonical tags (the natural place for "read this CONTEXT decision before editing" pointers, verification steps, acceptance criteria, etc.) was reported as uncovered with a misleading fix-hint that sent the fixer to "the body" — where a re-citation still failed. The scan now covers all nine planner-canonical tag bodies AND the message names the surfaces it actually scans, so message and behavior cannot drift apart again. (#2372) diff --git a/agents/gsd-planner.md b/agents/gsd-planner.md index e5b2a51ad..06b67efbf 100644 --- a/agents/gsd-planner.md +++ b/agents/gsd-planner.md @@ -66,7 +66,7 @@ The orchestrator provides user decisions in `` tags from `/gsd:d **Self-check before returning:** For each plan, verify: - [ ] Every locked decision (D-01, D-02, etc.) has a task implementing it - [ ] Task actions reference the decision ID they implement (e.g., "per D-03") - (The decision-coverage gate `check.decision-coverage-plan` reads D-NN citations from ``, ``, ``, and `` tag bodies, as well as markdown headings and front-matter `must_haves`/`truths`/`objective` keys — citing D-NN in any of these locations counts toward coverage.) + (The decision-coverage gate `check.decision-coverage-plan` reads D-NN citations from ``, ``, ``, ``, ``, ``, ``, ``, and `` tag bodies, as well as `## must_haves`/`truths`/`tasks`/`objective` markdown headings and front-matter `must_haves`/`truths`/`objective` keys — citing D-NN in any of these locations counts toward coverage.) - [ ] No task implements a deferred idea - [ ] Discretion areas are handled reasonably diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index a5d640bdc..37f174b97 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -927,7 +927,9 @@ plans and shipped code (issue #2492). existing requirements coverage gate, before plans are committed. For each trackable decision in ``, it checks that the decision id (`D-NN`) or its text appears in at least one plan's `must_haves`, -`truths`, or body. A miss surfaces the missing decision by id and refuses +`truths`, or `objective` (front-matter), a `## must_haves`/`truths`/`tasks`/`objective` +heading, or an ``/``/``/``/``/``/``/``/`` +tag body. A miss surfaces the missing decision by id and refuses to mark the phase planned. **Verify-phase validation gate (NON-BLOCKING).** Runs alongside the other diff --git a/docs/USER-GUIDE.md b/docs/USER-GUIDE.md index 5da3aaa31..7ccb3765e 100644 --- a/docs/USER-GUIDE.md +++ b/docs/USER-GUIDE.md @@ -231,7 +231,7 @@ See [docs/workflow-discuss-mode.md](workflow-discuss-mode.md) for the full discu The discuss-phase captures implementation decisions in CONTEXT.md under a `` block as numbered bullets (`- **D-01:** …`). Two gates ensure those decisions survive into plans and shipped code. -**Plan-phase translation gate (blocking).** After planning, GSD refuses to mark the phase planned until every trackable decision appears in at least one plan's `must_haves`, `truths`, or body. +**Plan-phase translation gate (blocking).** After planning, GSD refuses to mark the phase planned until every trackable decision appears in at least one plan's scanned surfaces: front-matter `must_haves`/`truths`/`objective`, a `## must_haves`/`truths`/`tasks`/`objective` heading, or an ``/``/``/``/``/``/``/``/`` tag body. **Verify-phase validation gate (non-blocking).** During verification, GSD searches plans, SUMMARY.md, modified files, and recent commit messages for each trackable decision. Misses are logged to VERIFICATION.md as a warning section; verification status is unchanged. diff --git a/src/check-command-router.cts b/src/check-command-router.cts index 613ab1b77..c0d8f59a1 100644 --- a/src/check-command-router.cts +++ b/src/check-command-router.cts @@ -139,7 +139,30 @@ function loadPlanContents(phaseDir: string): string[] { } const DESIGNATED_HEADINGS_RE = /^#{1,6}\s+(?:must[_ ]haves?|truths?|tasks?|objective)\b/i; -const XML_DECISION_TAGS_RE = /<(?:objective|tasks?|action)(?:\s[^>]{0,1000})?>((?:(?!<(?:objective|tasks?|action)[\s>])[\s\S])*?)<\/(?:objective|tasks?|action)>/gi; +// #2372: scanned-tag set must match the planner-canonical surfaces where a D-NN citation +// is meaningful. ``/``/``/`` are the historical core. The +// planner is also explicitly told (plan-phase.md) to cite decisions in ``, +// ``, ``, ``, and `` — those are now scanned too, +// so the gate no longer reports a false coverage gap when a decision is cited in any of them. +// +// Implementation: per-tag matching, NOT a single wide alternation. A single alternation +// like `<(?:a|b|c)>...<\/(?:a|b|c)>` halts the outer tag's body capture at any inner tag +// in the set, dropping any citation in the outer tag's prefix prose — e.g. +// `per D-05 npm test` would lose D-05 because `` +// halts the `` body before the citation. Per-tag matching avoids this: each tag's +// body terminates only at its OWN closing tag, so `` inside `` is absorbed +// into ``'s body (D-05 caught) AND `` is matched separately on its own pass. +// Each per-tag regex keeps the ReDoS-safe negative-lookahead tempering (#2128). +const XML_DECISION_TAG_NAMES = ['objective', 'tasks', 'task', 'action', 'read_first', 'behavior', 'verify', 'acceptance_criteria', 'done'] as const; + +function buildXmlDecisionTagRegex(tagName: string): RegExp { + // Per-tag: body tempering stops only at the SAME tag's reopening or closing — other + // scanned tags pass through as text into this body. Non-greedy `*?` to first close. + return new RegExp( + `<${tagName}(?:\\s[^>]{0,1000})?>((?:(?!<${tagName}[\\s>])[\\s\\S])*?)<\\/${tagName}>`, + 'gi', + ); +} function stripCommentsAndFences(text: string): string { // HTML-comment stripping stays caller-side (the seam does not strip HTML comments). @@ -167,8 +190,11 @@ function extractYamlBlock(frontmatter: string, key: string): string { function extractXmlTagBodies(text: string): string { const parts: string[] = []; - for (const match of text.matchAll(XML_DECISION_TAGS_RE)) { - if (match[1]) parts.push(match[1]); + for (const tagName of XML_DECISION_TAG_NAMES) { + const re = buildXmlDecisionTagRegex(tagName); + for (const match of text.matchAll(re)) { + if (match[1]) parts.push(match[1]); + } } return parts.join('\n'); } @@ -219,7 +245,10 @@ function buildPlanMessage(uncovered: UncoveredItem[]): string { '', ...uncovered.map((item) => `- **${item.id}** (${item.category || 'uncategorized'}): ${item.text}`), '', - 'Resolve by citing `D-NN:` in a relevant plan\'s `must_haves`/`truths` (or body),', + 'Resolve by citing `D-NN:` in any of the scanned plan surfaces: front-matter', + '`must_haves`/`truths`/`objective`, a `## must_haves`/`truths`/`tasks`/`objective`', + 'heading, or an ``/``/``/``/``/``/``/``/``', + 'tag body. Other locations (prose outside those headings, comments, other XML tags) are not scanned.', 'OR move the decision to `### Claude\'s Discretion` / tag it `[informational]` if it should not be tracked.', ].join('\n'); } diff --git a/tests/agent-size-baseline.json b/tests/agent-size-baseline.json index 204f13417..f76215dc0 100644 --- a/tests/agent-size-baseline.json +++ b/tests/agent-size-baseline.json @@ -23,7 +23,7 @@ "gsd-pattern-mapper.md": 12487, "gsd-phase-researcher.md": 40866, "gsd-plan-checker.md": 44780, - "gsd-planner.md": 49172, + "gsd-planner.md": 49294, "gsd-project-researcher.md": 22242, "gsd-research-synthesizer.md": 13847, "gsd-roadmapper.md": 22273, diff --git a/tests/decisions.test.cjs b/tests/decisions.test.cjs index 8b626f42b..6b75b2cc8 100644 --- a/tests/decisions.test.cjs +++ b/tests/decisions.test.cjs @@ -922,3 +922,205 @@ describe('parseDecisions — titled-colon bullet form (#1639)', () => { assert.equal(out.length, 13, 'all 13 titled-colon decisions must parse (not vacuously 0)'); }); }); + +// ─── #2372: decision-coverage-plan must scan planner-canonical tag bodies ───── +// +// Bug: buildPlanMessage() told the user to cite decisions "(or body)" but +// extractPlanDesignatedSections() only scanned ///. +// A decision cited in , , , , +// or was invisible — false BLOCKING coverage gap, and the message sent the +// fixer to "the body", where a re-citation still failed. Fix widens the scan to +// the planner-canonical tag set AND corrects the message to name scanned surfaces. + +describe('check.decision-coverage-plan — planner-canonical tag scanning (#2372)', () => { + let tmpDir; + let planningDir; + let phaseDir; + + beforeEach(() => { + tmpDir = createTempProject('gsd-2372-'); + planningDir = path.join(tmpDir, '.planning'); + phaseDir = path.join(planningDir, 'phases', '01-init'); + fs.mkdirSync(phaseDir, { recursive: true }); + }); + + afterEach(() => cleanup(tmpDir)); + + // Common CONTEXT.md with a single trackable decision D-01. + const CONTEXT_WITH_D01 = [ + '# Context', + '', + '', + '- **D-01:** Use OAuth 2.0 for authentication', + '', + ].join('\n'); + + // Helper: write CONTEXT + a PLAN whose body wraps `innerTagBody` in `tagName`. + function writeContextAndPlan(tagName, innerTagBody) { + writeContextFile(phaseDir, CONTEXT_WITH_D01); + writePlanFile(phaseDir, '01', `# Plan\n\n\n\n <${tagName}>\n${innerTagBody}\n \n\n\n`); + } + + const cases = [ + { tag: 'read_first', citation: '- path/to/CONTEXT.md (D-01 — auth decision)' }, + { tag: 'behavior', citation: 'Honor D-01: redirect unauthenticated users to OAuth flow.' }, + { tag: 'verify', citation: 'Verify D-01: token exchange returns 200 with access_token.' }, + { tag: 'acceptance_criteria', citation: 'D-01 honored: every protected route requires a valid OAuth token.' }, + { tag: 'done', citation: 'D-01 implemented — OAuth 2.0 flow live.' }, + ]; + + for (const { tag, citation } of cases) { + test(`D-NN cited in <${tag}> body → covered (no false gap)`, () => { + writeContextAndPlan(tag, citation); + + const contextPath = path.join(phaseDir, 'CONTEXT.md'); + const result = runDecisionCoveragePlan(phaseDir, contextPath, tmpDir); + const parsed = JSON.parse(result.output || '{}'); + + assert.strictEqual(parsed.total, 1, `expected total=1, got ${JSON.stringify(parsed)}`); + assert.strictEqual(parsed.covered, 1, `D-01 cited in <${tag}> must count as covered. Got: ${JSON.stringify(parsed)}`); + assert.strictEqual(parsed.passed, true, `gate must pass when D-01 is cited in <${tag}>. Got: ${JSON.stringify(parsed)}`); + assert.strictEqual(parsed.uncovered.length, 0, `uncovered must be empty. Got: ${JSON.stringify(parsed.uncovered)}`); + }); + } + + test('control: D-NN cited nowhere → still uncovered (no false green from widening)', () => { + writeContextFile(phaseDir, CONTEXT_WITH_D01); + writePlanFile(phaseDir, '01', '# Plan\n\n\n\n \n Implement the feature.\n \n\n\n'); + + const contextPath = path.join(phaseDir, 'CONTEXT.md'); + const result = runDecisionCoveragePlan(phaseDir, contextPath, tmpDir); + const parsed = JSON.parse(result.output || '{}'); + + assert.strictEqual(parsed.total, 1); + assert.strictEqual(parsed.covered, 0); + assert.strictEqual(parsed.passed, false); + assert.strictEqual(parsed.uncovered.length, 1); + assert.strictEqual(parsed.uncovered[0].id, 'D-01'); + }); + + // Message/extractor parity: the remediation text must name ONLY the surfaces the + // extractor actually scans. Asserts no "(or body)" claim it doesn't back, AND + // that every newly-scanned tag is named in the message — so the two cannot drift + // apart again. The reporter's bug was exactly this drift. + test('buildPlanMessage names every scanned surface (no "(or body)" drift, #2372)', () => { + writeContextFile(phaseDir, CONTEXT_WITH_D01); + writePlanFile(phaseDir, '01', '# Plan\nNo decision citation in any scanned surface.\n'); + + const contextPath = path.join(phaseDir, 'CONTEXT.md'); + const result = runDecisionCoveragePlan(phaseDir, contextPath, tmpDir); + const parsed = JSON.parse(result.output || '{}'); + + assert.strictEqual(parsed.passed, false, 'fixture intentionally leaves D-01 uncovered'); + const msg = parsed.message || ''; + + // The misleading "(or body)" clause that promised a scope the extractor didn't implement is gone. + assert.ok(!/\(or body\)/i.test(msg), `message must not claim "(or body)" — that was the bug. Got: "${msg}"`); + + // Every surface the extractor now scans MUST appear by name in the message — if any is + // missing, the message has drifted from the scan again. + const requiredSurfaceNames = [ + 'must_haves', 'truths', 'objective', + '', '', '', '', + '', '', '', '', '', + ]; + for (const surface of requiredSurfaceNames) { + assert.ok( + msg.includes(surface), + `message must name scanned surface "${surface}" — otherwise the message/extractor drift apart. Got: "${msg}"` + ); + } + }); + + // Reviewer-driven edge cases (code review on the initial widening flagged these): + // + // 1. Nested scanned tag inside another scanned tag: a citation in the OUTER tag's + // prefix prose must still count. Initial widening used a single alternation whose + // negative lookahead halted the outer tag's body at any inner scanned tag — losing + // the prefix citation. Switched to per-tag matching so each tag's body terminates + // only at its own closing tag (other scanned tags pass through as text into this body). + // 2. Non-scanned tag bearing a D-NN citation must NOT count toward coverage — guards + // against future over-widening. + // 3. Self-closing form `` has no body and must not error or match. + // 4. Attribute form `D-01` is the canonical planner + // shape for and must match. + // 5. CRLF newlines inside tag bodies must not break capture. + + test('D-NN in outer scanned tag prefix is not lost when inner scanned tag follows (per-tag capture)', () => { + writeContextFile(phaseDir, CONTEXT_WITH_D01); + // The bug shape: per D-01 ... — D-01 lives in 's prefix. + writePlanFile(phaseDir, '01', [ + '# Plan', + '', + '', + '', + ' ', + ' Implement per D-01 — OAuth 2.0 flow.', + ' token exchange returns 200', + ' ', + '', + '', + ].join('\n')); + + const contextPath = path.join(phaseDir, 'CONTEXT.md'); + const result = runDecisionCoveragePlan(phaseDir, contextPath, tmpDir); + const parsed = JSON.parse(result.output || '{}'); + + assert.strictEqual(parsed.covered, 1, `D-01 in prefix must be caught (per-tag capture). Got: ${JSON.stringify(parsed)}`); + assert.strictEqual(parsed.passed, true); + }); + + test('D-NN inside a non-scanned tag body does NOT count toward coverage', () => { + writeContextFile(phaseDir, CONTEXT_WITH_D01); + // is not in the scanned set — citation here must not be picked up. + writePlanFile(phaseDir, '01', '# Plan\n\nper D-01\n'); + + const contextPath = path.join(phaseDir, 'CONTEXT.md'); + const result = runDecisionCoveragePlan(phaseDir, contextPath, tmpDir); + const parsed = JSON.parse(result.output || '{}'); + + assert.strictEqual(parsed.total, 1); + assert.strictEqual(parsed.covered, 0, 'non-scanned tag body must not count. Got: ' + JSON.stringify(parsed)); + assert.strictEqual(parsed.passed, false); + assert.strictEqual(parsed.uncovered.length, 1); + }); + + test('self-closing scanned tag form is safely ignored (no body to scan)', () => { + writeContextFile(phaseDir, CONTEXT_WITH_D01); + // Self-closing form has no body. The gate must not crash and must not match the (absent) body. + writePlanFile(phaseDir, '01', '# Plan\n\n\n\n\nImplement feature.\n\n\n'); + + const contextPath = path.join(phaseDir, 'CONTEXT.md'); + const result = runDecisionCoveragePlan(phaseDir, contextPath, tmpDir); + const parsed = JSON.parse(result.output || '{}'); + + assert.strictEqual(parsed.total, 1); + assert.strictEqual(parsed.covered, 0); + assert.strictEqual(parsed.passed, false); + }); + + test('attribute form `D-NN` is scanned (canonical planner shape)', () => { + writeContextFile(phaseDir, CONTEXT_WITH_D01); + writePlanFile(phaseDir, '01', '# Plan\n\n\n\nRun npm test per D-01\n\n\n'); + + const contextPath = path.join(phaseDir, 'CONTEXT.md'); + const result = runDecisionCoveragePlan(phaseDir, contextPath, tmpDir); + const parsed = JSON.parse(result.output || '{}'); + + assert.strictEqual(parsed.covered, 1, 'attribute form on scanned tag must match. Got: ' + JSON.stringify(parsed)); + assert.strictEqual(parsed.passed, true); + }); + + test('CRLF newlines inside scanned tag body do not break capture', () => { + writeContextFile(phaseDir, CONTEXT_WITH_D01); + const planBody = ['# Plan', '', '', '', ' ', ' Implement per D-01.', ' ', '', '', ''].join('\r\n'); + fs.writeFileSync(path.join(phaseDir, '01-PLAN.md'), planBody); + + const contextPath = path.join(phaseDir, 'CONTEXT.md'); + const result = runDecisionCoveragePlan(phaseDir, contextPath, tmpDir); + const parsed = JSON.parse(result.output || '{}'); + + assert.strictEqual(parsed.covered, 1, 'CRLF body must not break capture. Got: ' + JSON.stringify(parsed)); + assert.strictEqual(parsed.passed, true); + }); +}); diff --git a/tests/fixtures/golden-install-parity/antigravity.json b/tests/fixtures/golden-install-parity/antigravity.json index 9e5063073..deef91ac9 100644 --- a/tests/fixtures/golden-install-parity/antigravity.json +++ b/tests/fixtures/golden-install-parity/antigravity.json @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "e62ee90d39084802", "agents/gsd-phase-researcher.md": "cff1196c8e8bb4fa", "agents/gsd-plan-checker.md": "dd1e7cdc837d8f3e", - "agents/gsd-planner.md": "6a442501f9d4caa8", + "agents/gsd-planner.md": "e2ad6fa2952fe88f", "agents/gsd-project-researcher.md": "85de7f562872ee9b", "agents/gsd-research-synthesizer.md": "18a2e1b30ff7ae3a", "agents/gsd-roadmapper.md": "7a8465ac6d4dd29e", diff --git a/tests/fixtures/golden-install-parity/augment.json b/tests/fixtures/golden-install-parity/augment.json index 12f9fcc55..afd7ff427 100644 --- a/tests/fixtures/golden-install-parity/augment.json +++ b/tests/fixtures/golden-install-parity/augment.json @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "43c6021cf7caabfa", "agents/gsd-phase-researcher.md": "f1f6fd6a3e67c7a8", "agents/gsd-plan-checker.md": "bf1a4e636f2390de", - "agents/gsd-planner.md": "55cc953c6a52ae05", + "agents/gsd-planner.md": "86f6cfd300125965", "agents/gsd-project-researcher.md": "4531b7cc8f5e5f7d", "agents/gsd-research-synthesizer.md": "4a4f68e6c75b133a", "agents/gsd-roadmapper.md": "bb2f57695dbab32c", diff --git a/tests/fixtures/golden-install-parity/claude-local.json b/tests/fixtures/golden-install-parity/claude-local.json index 8024e118d..844e1cba5 100644 --- a/tests/fixtures/golden-install-parity/claude-local.json +++ b/tests/fixtures/golden-install-parity/claude-local.json @@ -24,7 +24,7 @@ "agents/gsd-pattern-mapper.md": "b45b5e106775bec1", "agents/gsd-phase-researcher.md": "4772d9eada32e8bd", "agents/gsd-plan-checker.md": "75851b147f35354a", - "agents/gsd-planner.md": "4636f48b1b7ca1f6", + "agents/gsd-planner.md": "44a04bdebe044114", "agents/gsd-project-researcher.md": "d7f355894519f9fe", "agents/gsd-research-synthesizer.md": "1c738df9932d325a", "agents/gsd-roadmapper.md": "453e9471ad27c7ea", diff --git a/tests/fixtures/golden-install-parity/claude.json b/tests/fixtures/golden-install-parity/claude.json index 97615fa4d..6ec3b1595 100644 --- a/tests/fixtures/golden-install-parity/claude.json +++ b/tests/fixtures/golden-install-parity/claude.json @@ -24,7 +24,7 @@ "agents/gsd-pattern-mapper.md": "b45b5e106775bec1", "agents/gsd-phase-researcher.md": "85217c69c1ed2ac6", "agents/gsd-plan-checker.md": "c70134c61b969589", - "agents/gsd-planner.md": "3098091aa1f0756d", + "agents/gsd-planner.md": "0ec11dd0d673f828", "agents/gsd-project-researcher.md": "f468e96f8339d1e0", "agents/gsd-research-synthesizer.md": "7be02e47f4fd901b", "agents/gsd-roadmapper.md": "8a7f1f1256a6aed5", diff --git a/tests/fixtures/golden-install-parity/cline.json b/tests/fixtures/golden-install-parity/cline.json index 2c720c03b..0792ab037 100644 --- a/tests/fixtures/golden-install-parity/cline.json +++ b/tests/fixtures/golden-install-parity/cline.json @@ -28,7 +28,7 @@ "agents/gsd-pattern-mapper.md": "b526065fd2efa19c", "agents/gsd-phase-researcher.md": "c507db2ba66038f4", "agents/gsd-plan-checker.md": "a609245dbdc4ef2b", - "agents/gsd-planner.md": "c2ab476257cd07cf", + "agents/gsd-planner.md": "6f390cd0f07473a7", "agents/gsd-project-researcher.md": "049f816c6caa4316", "agents/gsd-research-synthesizer.md": "2f7dcbff50371d4c", "agents/gsd-roadmapper.md": "bbb23d3097911516", diff --git a/tests/fixtures/golden-install-parity/codebuddy.json b/tests/fixtures/golden-install-parity/codebuddy.json index f55be6556..763bd989e 100644 --- a/tests/fixtures/golden-install-parity/codebuddy.json +++ b/tests/fixtures/golden-install-parity/codebuddy.json @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "92cfa2e6c2a06bf3", "agents/gsd-phase-researcher.md": "6338474da1a5d65e", "agents/gsd-plan-checker.md": "e704c083b02e8c35", - "agents/gsd-planner.md": "8e3e314f962711cd", + "agents/gsd-planner.md": "50f9d7d12d8268af", "agents/gsd-project-researcher.md": "e43c59f7f1f2f37a", "agents/gsd-research-synthesizer.md": "87955470c3c129b2", "agents/gsd-roadmapper.md": "20b69eff61a7a9fa", diff --git a/tests/fixtures/golden-install-parity/codex.json b/tests/fixtures/golden-install-parity/codex.json index c8421ecaa..0cbe08530 100644 --- a/tests/fixtures/golden-install-parity/codex.json +++ b/tests/fixtures/golden-install-parity/codex.json @@ -120,8 +120,8 @@ "agents/gsd-phase-researcher.toml": "44a3d510cd0ce3bd", "agents/gsd-plan-checker.md": "e7f02c10ea788aee", "agents/gsd-plan-checker.toml": "6f8ceb421d0ad721", - "agents/gsd-planner.md": "cb3ff2ef2c58617c", - "agents/gsd-planner.toml": "ac51638704036f71", + "agents/gsd-planner.md": "19969475e4e38175", + "agents/gsd-planner.toml": "f5f4f3876767d323", "agents/gsd-project-researcher.md": "959f2e57c3d69ed8", "agents/gsd-project-researcher.toml": "f395e8e8c4baf1ed", "agents/gsd-research-synthesizer.md": "497f85adf53259ef", diff --git a/tests/fixtures/golden-install-parity/copilot.json b/tests/fixtures/golden-install-parity/copilot.json index 751eeaff6..e56507f99 100644 --- a/tests/fixtures/golden-install-parity/copilot.json +++ b/tests/fixtures/golden-install-parity/copilot.json @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.agent.md": "b1f488b0fa6a2395", "agents/gsd-phase-researcher.agent.md": "03cfb510a766fe93", "agents/gsd-plan-checker.agent.md": "c50a5b008ddcbfad", - "agents/gsd-planner.agent.md": "8f5f400efea5e446", + "agents/gsd-planner.agent.md": "1721f5ace5c95434", "agents/gsd-project-researcher.agent.md": "d73bdbe986ffa8a6", "agents/gsd-research-synthesizer.agent.md": "f03eed4aa89e47c5", "agents/gsd-roadmapper.agent.md": "322048cf8ddcb4e5", diff --git a/tests/fixtures/golden-install-parity/cursor.json b/tests/fixtures/golden-install-parity/cursor.json index d8af931f1..12198837f 100644 --- a/tests/fixtures/golden-install-parity/cursor.json +++ b/tests/fixtures/golden-install-parity/cursor.json @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "1229c215677f740d", "agents/gsd-phase-researcher.md": "982d59921bed463d", "agents/gsd-plan-checker.md": "ba51999876d40cf2", - "agents/gsd-planner.md": "c788d7fb84cf5433", + "agents/gsd-planner.md": "71c6e41403d6bc63", "agents/gsd-project-researcher.md": "beeac940d3a10e76", "agents/gsd-research-synthesizer.md": "6315f016d55176f4", "agents/gsd-roadmapper.md": "d28e7d4bac46dde2", diff --git a/tests/fixtures/golden-install-parity/hermes.json b/tests/fixtures/golden-install-parity/hermes.json index 834ba3dd0..f93b37645 100644 --- a/tests/fixtures/golden-install-parity/hermes.json +++ b/tests/fixtures/golden-install-parity/hermes.json @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "cea092600aeb3978", "agents/gsd-phase-researcher.md": "2bd0402f33d757ca", "agents/gsd-plan-checker.md": "4b4e2b475bf5b5c3", - "agents/gsd-planner.md": "d5fa8236f975aacd", + "agents/gsd-planner.md": "5f5fa906f62643b6", "agents/gsd-project-researcher.md": "425a7df7f37a5c06", "agents/gsd-research-synthesizer.md": "9d31c87fc2c87ffa", "agents/gsd-roadmapper.md": "64dce5d5f9fa5654", diff --git a/tests/fixtures/golden-install-parity/kilo.json b/tests/fixtures/golden-install-parity/kilo.json index 731b57f31..95fcc14c6 100644 --- a/tests/fixtures/golden-install-parity/kilo.json +++ b/tests/fixtures/golden-install-parity/kilo.json @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "6a5408fd11d70391", "agents/gsd-phase-researcher.md": "94818f28c498bb26", "agents/gsd-plan-checker.md": "56164206242c8caf", - "agents/gsd-planner.md": "13c4b6db72b6bbb3", + "agents/gsd-planner.md": "282aa34e2e8bc267", "agents/gsd-project-researcher.md": "60573a38d3dfd9fe", "agents/gsd-research-synthesizer.md": "1f7cd286c5783c86", "agents/gsd-roadmapper.md": "277e0a3252553ab7", diff --git a/tests/fixtures/golden-install-parity/kimi.json b/tests/fixtures/golden-install-parity/kimi.json index 0478e6f14..0bf7a9d27 100644 --- a/tests/fixtures/golden-install-parity/kimi.json +++ b/tests/fixtures/golden-install-parity/kimi.json @@ -79,7 +79,7 @@ "agents/subagents/gsd-phase-researcher.yaml": "7633c8e82617e7cc", "agents/subagents/gsd-plan-checker.md": "bd302afc01ed40f0", "agents/subagents/gsd-plan-checker.yaml": "8295181071121db8", - "agents/subagents/gsd-planner.md": "d29376ff9f57cc60", + "agents/subagents/gsd-planner.md": "285c6a21227787f9", "agents/subagents/gsd-planner.yaml": "2e83ee194bcd7fbd", "agents/subagents/gsd-project-researcher.md": "39bc2ec5a8b18283", "agents/subagents/gsd-project-researcher.yaml": "ce12586b0347e2dc", diff --git a/tests/fixtures/golden-install-parity/opencode.json b/tests/fixtures/golden-install-parity/opencode.json index 26dff0c7f..364129c7d 100644 --- a/tests/fixtures/golden-install-parity/opencode.json +++ b/tests/fixtures/golden-install-parity/opencode.json @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "7c6d1d9817a9c1e7", "agents/gsd-phase-researcher.md": "9874110700b41f48", "agents/gsd-plan-checker.md": "28ca3dc43669894f", - "agents/gsd-planner.md": "87d1aa910eb02ad5", + "agents/gsd-planner.md": "5234ac4f1afce5dc", "agents/gsd-project-researcher.md": "dae210ae0b3c6e2b", "agents/gsd-research-synthesizer.md": "e02c6ad5d1b74171", "agents/gsd-roadmapper.md": "1658a40b20d8b575", diff --git a/tests/fixtures/golden-install-parity/qwen.json b/tests/fixtures/golden-install-parity/qwen.json index 05e222031..2c071c038 100644 --- a/tests/fixtures/golden-install-parity/qwen.json +++ b/tests/fixtures/golden-install-parity/qwen.json @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "83c66c7722e8b165", "agents/gsd-phase-researcher.md": "284e55a86ae46d7f", "agents/gsd-plan-checker.md": "c8a8fcc8ed38eff0", - "agents/gsd-planner.md": "f0a5bede90f23be4", + "agents/gsd-planner.md": "c38e99d7be01a728", "agents/gsd-project-researcher.md": "b5baac64a15c85e2", "agents/gsd-research-synthesizer.md": "6cd9b501dc97bd50", "agents/gsd-roadmapper.md": "c357a77ab919e9e5", diff --git a/tests/fixtures/golden-install-parity/trae.json b/tests/fixtures/golden-install-parity/trae.json index ad8948f07..f2e165dc1 100644 --- a/tests/fixtures/golden-install-parity/trae.json +++ b/tests/fixtures/golden-install-parity/trae.json @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "b5d7a4abb1baecb9", "agents/gsd-phase-researcher.md": "2256f1f82212c757", "agents/gsd-plan-checker.md": "523119bd5d6599fe", - "agents/gsd-planner.md": "fb330c599b9c1dac", + "agents/gsd-planner.md": "ddfd810f17d39eb6", "agents/gsd-project-researcher.md": "ddf7794e81300032", "agents/gsd-research-synthesizer.md": "a124b00271748d07", "agents/gsd-roadmapper.md": "493ef92b42b12cf4", diff --git a/tests/fixtures/golden-install-parity/windsurf.json b/tests/fixtures/golden-install-parity/windsurf.json index 4f2de3298..e4cc3f06b 100644 --- a/tests/fixtures/golden-install-parity/windsurf.json +++ b/tests/fixtures/golden-install-parity/windsurf.json @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "ada0c169daa2f0ec", "agents/gsd-phase-researcher.md": "2a45ebde829555ec", "agents/gsd-plan-checker.md": "33fbf70b7b24eb1e", - "agents/gsd-planner.md": "61ac0bd59b5b836a", + "agents/gsd-planner.md": "f98cfbc92bfff334", "agents/gsd-project-researcher.md": "f6697b316b5995ba", "agents/gsd-research-synthesizer.md": "04036f38c1d373ea", "agents/gsd-roadmapper.md": "fb62e1e3de84b5f9", diff --git a/tests/fixtures/golden-install-parity/zcode.json b/tests/fixtures/golden-install-parity/zcode.json index f615d8d69..4f9ff39c2 100644 --- a/tests/fixtures/golden-install-parity/zcode.json +++ b/tests/fixtures/golden-install-parity/zcode.json @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "68ecefd60811a669", "agents/gsd-phase-researcher.md": "2235f61764d8e969", "agents/gsd-plan-checker.md": "bb38f345d3d41edc", - "agents/gsd-planner.md": "42f6e9832d5c2edc", + "agents/gsd-planner.md": "1e904e38cccc5dc4", "agents/gsd-project-researcher.md": "f572892f138734ff", "agents/gsd-research-synthesizer.md": "29949bf3f049a8f1", "agents/gsd-roadmapper.md": "840ac933e3b094f9",