From 3f57a13ccf91725cdbe9c3c8f066426fd382b5ae Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Tue, 5 May 2026 15:02:03 -0400 Subject: [PATCH] fix(#3087): restore 10 demoted directive phrases in gsd-planner.md (#3138) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(#3087): restore 10 demoted directive phrases in gsd-planner.md CRITICAL/MANDATORY/ALWAYS/MUST emphasis was systematically removed in v1.38.4 (PR #2489) without documentation. Conflicts with PR #2489's own stated intent (sycophancy-hardening). Downstream effect: weaker adherence to user decisions and requirement coverage in v1.38.4-v1.40.x. Restored: CRITICAL: User Decision Fidelity (heading) CRITICAL: Never Simplify User Decisions (heading) Multi-Source Coverage Audit (MANDATORY in every plan set) Audit ALL four source types before finalizing Discovery is MANDATORY unless you can prove... ALWAYS split if: requirements MUST list requirement IDs from ROADMAP CRITICAL: Every requirement ID MUST appear in at least one plan ALWAYS use the Write tool to create files CRITICAL — File naming convention (enforced) Regression test: tests/bug-3087-planner-directive-language.test.cjs (10 assertions, one per restored directive — all pass). Suite: 6983/6983. Closes #3087. * fix(changeset+test): fix pr field to 3138, wrap readFileSync in try/catch --- .../fix-3087-planner-directive-language.md | 5 ++ agents/gsd-planner.md | 20 ++++---- ...g-3087-planner-directive-language.test.cjs | 46 +++++++++++++++++++ 3 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 .changeset/fix-3087-planner-directive-language.md create mode 100644 tests/bug-3087-planner-directive-language.test.cjs diff --git a/.changeset/fix-3087-planner-directive-language.md b/.changeset/fix-3087-planner-directive-language.md new file mode 100644 index 000000000..83dd18d35 --- /dev/null +++ b/.changeset/fix-3087-planner-directive-language.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 3138 +--- +**`gsd-planner.md` directive language restored** — 10 instances of `CRITICAL`/`MANDATORY`/`ALWAYS`/`MUST` emphasis were silently removed in v1.38.4 (PR #2489) without documentation, conflicting with that release's stated sycophancy-hardening intent. Downstream effect: planner output in v1.38.4–v1.40.x exhibited weaker adherence to user decisions and requirement coverage, as observed in #3087. Restored: `CRITICAL: User Decision Fidelity`, `CRITICAL: Never Simplify User Decisions`, `Multi-Source Coverage Audit (MANDATORY in every plan set)`, `Audit ALL four source types`, `Discovery is MANDATORY`, `ALWAYS split if:`, `requirements MUST list`, `CRITICAL: Every requirement ID MUST appear`, `ALWAYS use the Write tool`, and `CRITICAL — File naming convention`. Closes #3087. diff --git a/agents/gsd-planner.md b/agents/gsd-planner.md index 6382cbae1..5f7ffbf39 100644 --- a/agents/gsd-planner.md +++ b/agents/gsd-planner.md @@ -49,7 +49,7 @@ Before planning, discover project context: -## User Decision Fidelity +## CRITICAL: User Decision Fidelity The orchestrator provides user decisions in `` tags from `/gsd-discuss-phase`. @@ -73,7 +73,7 @@ The orchestrator provides user decisions in `` tags from `/gsd-d -## Never Simplify User Decisions — Split Instead +## CRITICAL: Never Simplify User Decisions — Split Instead **PROHIBITED language/patterns in task actions:** - "v1", "v2", "simplified version", "static for now", "hardcoded for now" @@ -94,11 +94,11 @@ Do NOT silently omit features. Instead: 3. The orchestrator presents the split to the user for approval 4. After approval, plan each sub-phase within budget -## Multi-Source Coverage Audit +## Multi-Source Coverage Audit (MANDATORY in every plan set) @~/.claude/get-shit-done/references/planner-source-audit.md for full format, examples, and gap-handling rules. -Perform this audit for every plan set before finalizing. Check all four source types: **GOAL** (ROADMAP phase goal), **REQ** (phase_req_ids from REQUIREMENTS.md), **RESEARCH** (RESEARCH.md features/constraints), **CONTEXT** (D-XX decisions from CONTEXT.md). +Audit ALL four source types before finalizing: **GOAL** (ROADMAP phase goal), **REQ** (phase_req_ids from REQUIREMENTS.md), **RESEARCH** (RESEARCH.md features/constraints), **CONTEXT** (D-XX decisions from CONTEXT.md). Every item must be COVERED by a plan. If ANY item is MISSING → return `## ⚠ Source Audit: Unplanned Items Found` to the orchestrator with options (add plan / split phase / defer with developer confirmation). Never finalize silently with gaps. @@ -160,7 +160,7 @@ Plan -> Execute -> Ship -> Learn -> Repeat ## Mandatory Discovery Protocol -Discovery is required unless you can prove current context exists. +Discovery is MANDATORY unless you can prove current context exists. **Level 0 - Skip** (pure internal work, existing patterns only) - ALL work follows established codebase patterns (grep confirms) @@ -362,7 +362,7 @@ Plans should complete within ~50% context (not 80%). No context anxiety, quality ## Split Signals -**Split if any of these apply:** +**ALWAYS split if:** - More than 3 tasks - Multiple subsystems (DB + API + UI = separate plans) - Any task with >5 file modifications @@ -477,7 +477,7 @@ After completion, create `.planning/phases/XX-name/{phase}-{plan}-SUMMARY.md` | `depends_on` | Yes | Plan IDs this plan requires | | `files_modified` | Yes | Files this plan touches | | `autonomous` | Yes | `true` if no checkpoints | -| `requirements` | Yes | Requirement IDs from ROADMAP. Every roadmap requirement ID MUST appear in at least one plan. | +| `requirements` | Yes | **MUST** list requirement IDs from ROADMAP. Every roadmap requirement ID MUST appear in at least one plan. | | `user_setup` | No | Human-required setup items | | `must_haves` | Yes | Goal-backward verification criteria | @@ -582,7 +582,7 @@ Only include what Claude literally cannot do. ## The Process **Step 0: Extract Requirement IDs** -Read ROADMAP.md `**Requirements:**` line for this phase. Strip brackets if present (e.g., `[AUTH-01, AUTH-02]` → `AUTH-01, AUTH-02`). Distribute requirement IDs across plans — each plan's `requirements` frontmatter field lists the IDs its tasks address. Every requirement ID MUST appear in at least one plan. Plans with an empty `requirements` field are invalid. +Read ROADMAP.md `**Requirements:**` line for this phase. Strip brackets if present (e.g., `[AUTH-01, AUTH-02]` → `AUTH-01, AUTH-02`). Distribute requirement IDs across plans — each plan's `requirements` frontmatter field MUST list the IDs its tasks address. **CRITICAL:** Every requirement ID MUST appear in at least one plan. Plans with an empty `requirements` field are invalid. **Security (when `security_enforcement` enabled — absent = enabled):** Identify trust boundaries in this phase's scope. Map STRIDE categories to applicable tech stack from RESEARCH.md security domain. For each threat: assign disposition (mitigate if ASVS L1 requires it, accept if low risk, transfer if third-party). Every plan MUST include `` when security_enforcement is enabled. @@ -1056,9 +1056,9 @@ Present breakdown with wave structure. Wait for confirmation in interactive mode Use template structure for each PLAN.md. -Use the Write tool to create files — never use `Bash(cat << 'EOF')` or heredoc commands for file creation. +**ALWAYS use the Write tool to create files** — never use `Bash(cat << 'EOF')` or heredoc commands for file creation. -**File naming convention (enforced):** +**CRITICAL — File naming convention (enforced):** The filename MUST follow the exact pattern: `{padded_phase}-{NN}-PLAN.md` diff --git a/tests/bug-3087-planner-directive-language.test.cjs b/tests/bug-3087-planner-directive-language.test.cjs new file mode 100644 index 000000000..a54e5ffea --- /dev/null +++ b/tests/bug-3087-planner-directive-language.test.cjs @@ -0,0 +1,46 @@ +'use strict'; + +// Regression guard for bug #3087. +// +// Between v1.38.3 and v1.38.4, agents/gsd-planner.md had 10 instances of +// CRITICAL/MANDATORY/ALWAYS/MUST directive emphasis systematically removed. +// The change was undocumented and conflicts with the stated intent of PR #2489 +// (the sycophancy-hardening pass that shipped in the same release). This test +// enforces the restored directive language so the demotion cannot recur silently. + +const { test } = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); + +const ROOT = path.join(__dirname, '..'); +let src; +try { + src = fs.readFileSync(path.join(ROOT, 'agents', 'gsd-planner.md'), 'utf8'); +} catch (err) { + throw new Error(`agents/gsd-planner.md not found — was the file renamed? (${err.message})`); +} + +const directives = [ + { desc: 'User Decision Fidelity heading is CRITICAL', pattern: /## CRITICAL: User Decision Fidelity/ }, + { desc: 'Never Simplify heading is CRITICAL', pattern: /## CRITICAL: Never Simplify User Decisions/ }, + { desc: 'Multi-Source Audit heading is MANDATORY', pattern: /## Multi-Source Coverage Audit \(MANDATORY in every plan set\)/ }, + { desc: 'Source audit uses "Audit ALL" imperative', pattern: /Audit ALL four source types before finalizing/ }, + { desc: 'Discovery is MANDATORY', pattern: /Discovery is MANDATORY unless/ }, + { desc: 'Split signals use ALWAYS', pattern: /\*\*ALWAYS split if:\*\*/ }, + { desc: 'requirements field doc uses MUST', pattern: /\*\*MUST\*\* list requirement IDs from ROADMAP/ }, + { desc: 'Step 0 has CRITICAL requirement ID directive', pattern: /\*\*CRITICAL:\*\* Every requirement ID MUST appear/ }, + { desc: 'Write tool directive uses ALWAYS', pattern: /\*\*ALWAYS use the Write tool to create files\*\*/ }, + { desc: 'File naming convention heading is CRITICAL', pattern: /\*\*CRITICAL — File naming convention \(enforced\):\*\*/ }, +]; + +for (const { desc, pattern } of directives) { + test(`gsd-planner.md: ${desc}`, () => { + assert.ok( + pattern.test(src), + `Directive enforcement missing from gsd-planner.md: "${desc}" — pattern ${pattern} not found. ` + + `This language was demoted in v1.38.4 (PR #2489) without documentation, conflicting with ` + + `the sycophancy-hardening intent of that release. See bug #3087.`, + ); + }); +}