* fix(#3724): stop advisory Dimension 3b findings from forcing the revision loop Dimension 3b (undeclared/temporal coupling, #1954) is spec'd "never a blocker" but tagged severity: warning — the tier plan-phase's revision loop counts as must-fix — and the planner is never taught the rule, so every multi-wave phase touching shared mutable state replans at least once, and intentionally coupled plans re-flag identically every iteration to the stall prompt. Three coordinated changes: - gsd-plan-checker: retag 3b to severity: info, the tier references/revision-loop.md already exempts by design; recognize a coupling_justified frontmatter declaration in the Do-NOT-flag list so deliberate pairs converge. Additions are offset by trimming 3b motivation prose — the checker sits 45 bytes under its LARGE hard cap. - plan-phase step 12: INFO-only accept — an issues block with zero BLOCKER/WARNING entries accepts the plan and surfaces the advisories instead of re-entering the revision loop. Real blockers and warnings still gate unconditionally. - gsd-planner: slim pointer in assign_waves to the new progressive-disclosure reference gsd-core/references/planner-coupling.md (the planner sits 19 chars under its own cap), which carries the shared-mutable-state rule and the coupling_justified escape hatch so first-pass plans avoid the finding when the coupling is unintentional. Documented the coupling_justified field in docs/reference/plan-md.md. Growth acks per #2914; inventory manifest and install-tree fixtures regenerated for the new reference file. Closes #3724 Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * test(#3724): pin Dimension 3b at severity: info The severity retag makes the old assertion (severity: warning) stale; lock the advisory tier from both directions — info must be present, warning must not — so a future edit cannot silently re-arm the revision-loop trigger. Refs #3724 Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * chore(#3724): changeset fragment for PR #3758 Refs #3724 Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * docs(#3724): roster planner-coupling.md in docs/INVENTORY.md The new reference was enumerated in the manifest and all 19 install-tree fixtures but missing its row in the Modular Planner Decomposition table — the roster half the manifest-sync test cannot check. (Review Blocker.) Refs #3724 Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * test(#3724): cover all four acceptance criteria (review round 1) - plan-checker-coupling: the 3b severity assertion is now a PARITY check deriving the exempt tier from revision-loop.md's flow instead of hardcoding info — editing either side alone reds the suite. New describe pins the other three criteria: plan-phase's INFO-only accept clause (proven failing-first), the BLOCKER + WARNING count staying intact, the coupling_justified Do-NOT-flag exemption + fix_hint, and the planner pointer + planner-coupling.md content. - ack fragment: $comment's plan-phase figure corrected to +79B; the 2775 pin note carried forward into the gsd-planner.md entry, updated for upstream's #3761/#3764 Rule-paragraph anchor (which this diff leaves verbatim). The parallel-dependent-plans re-anchor this commit originally carried was superseded by upstream #3764 during review; this branch no longer touches that file. Refs #3724 Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * fix(#3724): review round 2 — align the stance enumeration, complete the template contract MAJOR: <adversarial_stance>'s severity enumeration gains the INFO bullet so it agrees with Dimension 3b's 'ALWAYS INFO' mandate instead of contradicting it. Funded by extracting the inline <examples> block to the new progressive- disclosure reference gsd-core/references/plan-checker-examples.md (@-inlined from the same spot; #1949 precedent), which also restores the 3b motivation clause round 1 traded away (Nit 4) and nets the agent file SMALLER than base (49107 -> 48486) — the extraction the byte pressure was owed. MINOR: gsd-core/templates/phase-prompt.md now carries coupling_justified, and the field's shape becomes one 'plan-id: reason' string per coupled peer so a plan justified against two peers can express it; docs/reference/plan-md.md's Type column names the shape. NIT: the 3409 ack's plan-phase entry no longer calls the #1168 workflow ratchet an 'XL tier'. Acks and derived artifacts updated accordingly (checker entry removed — a shrink needs no ack; INVENTORY roster row + regen:derived for the new file). Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * test(#3724): derive the 3b negative severity assertion (review round 2) Every severity token in the 3b span must BE the tier revision-loop.md exempts, replacing the hardcoded severity:warning negative — if the loop's exemption ever moves, the failure names the real conflict instead of blaming the agent file with a mutually-unsatisfiable pair. Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * fix(#3724): refit the planner coupling pointer under the char cap Upstream #3299 (PR #3390) grew agents/gsd-planner.md to 49146 chars at the base, leaving 5 chars of headroom where the +16-char pointer was measured against 13 more. The pointer prose shortens to 'Non-file coupling:' — 49150 chars, back under the strict 49152-char cap — and the ack figures follow. The @-path the tests pin is unchanged. Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * fix(#3724): re-home the plan-phase ack after the #3823 spent-fragment sweep Upstream #3078/#3823 deleted all fully-spent ack fragments, including 3409-unreachable-guard-arms.json, which carried this PR's plan-phase.md +79B append. Per the collision remedy that sweep added: take the deletion and home the still-live entry in this PR's own fragment. Figures re-measured at this merge base (90871 -> 90950 LF bytes). Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * fix(#3724): absorb the spent #3172 plan-phase fragment into this PR's ack Upstream #3825 shipped 3172-stated-failing-direction.json naming only plan-phase.md, now spent at the base — colliding with this PR's live plan-phase entry. Per the #3003 pattern the fully-spent single-path fragment is deleted and this fragment stays the path's one source; figures re-measured at this base (93073 -> 93152 LF bytes). Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * fix(#3724): review round 3 — true up the ack figures, restore the wave comment The fragment's absolute sizes are re-measured and anchored to basee40e9670(planner 47259 -> 47330 chars, checker 45537 -> 44916 B, plan-phase 91186 -> 91265 LF bytes), with a note that absolutes rot as next moves — the deltas are the durable claims. The round-1 removal of the '# Implicit dependency: files_modified overlap forces a later wave.' pseudocode comment offset headroom base drift had already returned, so it is restored (findings 2-3). Changeset gains the (#3724) backlink (finding 4). Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * fix(#3724): review round 4 — close the verify-work surface, harden the boundaries BLOCKER: verify-work.md's verify_gap_plans is the second multi-plan consumer of the checker's sentinels, and its ISSUES FOUND handler entered revision_loop with zero severity parsing — the guaranteed replan #3724 fixed in plan-phase, alive on the gap-closure surface. The handler now counts BLOCKER + WARNING and accepts INFO-only returns with advisories displayed. The checker's INFO stance bullet is reworded to the claim that is true everywhere ('revision gates count only BLOCKER + WARNING'). Minor 1: plan-phase's iteration_count >= 3 arm recounts severities, so an INFO-only third check accepts instead of halting on a '0 issues remain' user gate. Minor 2: the coupling_justified exemption now requires the entry to NAME the other plan, closing the blanket-suppression reading. Nit 1: INVENTORY row states the extraction buys cap headroom, not context. Nit 2: the advisory display gains a concrete format on both surfaces. Ack fragment re-anchored at baseddde001a: verify-work.md +264B (new entry), plan-phase.md +395B, checker still net negative (-512B). Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * test(#3724): pin the verify-work accept and the iteration-cap boundary (review round 4) Two wiring assertions: verify_gap_plans' ISSUES FOUND handler gates on BLOCKER + WARNING and accepts INFO-only blocks, and plan-phase's iteration_count >= 3 arm recounts severities instead of gating advisories — the limit+1 boundary of the gate this PR fixes. Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * fix(#3724): review round 5 — fail closed at the gates, surface the advisory Blocker 1: the checker's step-10 status rule routes an INFO-only result to ## ISSUES FOUND (with a new ### Advisories (info) template section and a severity-aware recommendation) so the orchestrator receives the block and displays the advisory instead of silently accepting a bare PASSED. Blockers 2+3: all three gate surfaces (plan-phase step 12 both arms, verify-work verify_gap_plans) carry one canonical clause verbatim — an entry whose severity is missing or unrecognized counts as a BLOCKER (fail closed) — making the accept condition an explicit-INFO whitelist while keeping issue_count coherent for stall math. Major 1: the INFO stance bullet scopes its claim to the plan-phase and verify-work gates (quick mode's loop still revises on any ISSUES FOUND). Major 2: INVENTORY row and ack $comment state the extraction's real trade (readability, +0.6 KB eager runtime context), not a cap remedy. Minor 1: plan-md.md marks coupling_justified as prompt convention, unvalidated. Nit 1: ack absolutes re-anchored at base 1e67ec97; checker now +120B and acked. Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * test(#3724): pin the round-5 contract — fail-closed parity, INFO-only return shape New: three-surface verbatim parity test for the fail-closed clause (Blockers 2+3); checker return-contract test for the INFO-only ## ISSUES FOUND route and advisories section (Blocker 1). All seven newly pinned tokens are absent at f3a5682d, so each new assertion fails pre-fix. Updated: accept-clause regexes track the explicit-INFO whitelist wording; the severity sweep scopes to the span's fenced yaml examples via yamlSeverityTiers (round-5 Minor 3, applied to the blocker negative too); the iteration-cap comment states it is a prose pin, not an executed boundary check (Minor 4); splitLines call sites document the line-pin coupling (Nit 2). Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * fix(#3724): adopt next's line wrap in the 3b motivation clause — drops a wrap-only hunk from the diff Byte-identical content; the wrap difference was an artifact of the round-1 base adaptation predating upstream's #3003 landing. Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM * fix(#3724): review round 7 — gate every checker consumer, not just the two audited ones Blocker: quick/steps/plan-checker-loop.md (issue-named in #3724) gets the same canonical fail-closed clause and explicit-INFO whitelist accept as plan-phase/verify-work — an INFO-only result proceeds instead of entering quick mode's revision loop. Major: import.md plan_validate handles the checker return by severity (INFO-only never blocks an import) and is added to agent-contracts.md's consumer enumeration, which had omitted it. The checker's INFO stance bullet drops the quick-mode carve-out — the claim is universally true again now that every consuming gate is severity-aware. Minor: an applied coupling_justified exemption is surfaced as its own info advisory so a stale one-sided declaration stays observable. Nit: plan-phase's revision-iteration Display line is explicitly conditioned on not having already proceeded to step 13. Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM Emitted-Drift-Ack-Growth: import.md — #3724 round 7: the plan_validate step's checker-return handler becomes severity-aware — counts BLOCKER + WARNING failing closed and accepts an explicitly-INFO-only return with advisories displayed instead of blocking the import * test(#3724): pin the round-7 surfaces — five-gate parity, quick/import accepts, exemption visibility The verbatim fail-closed parity test extends to quick/steps/plan-checker-loop.md and import.md plan_validate; new assertions pin quick mode's INFO-only proceed, import's never-blocks accept, import.md's presence in agent-contracts.md's consumer row, and the surfaced coupling_justified exemption advisory. All four newly pinned token families are absent at the pre-fix head, so each new assertion fails first. Claude-Session: https://claude.ai/code/session_01GshUzpGjoxiw6uNRiFMHvM --------- Co-authored-by: Tom Boucher <trekkie@nomorestars.com>
19 KiB
Phase Prompt Template
Note: Planning methodology is in
agents/gsd-planner.md. This template defines the PLAN.md output format that the agent produces.
Template for .planning/phases/XX-name/{phase}-{plan}-PLAN.md - executable phase plans optimized for parallel execution.
Naming: Use {phase}-{plan}-PLAN.md format (e.g., 01-02-PLAN.md for Phase 1, Plan 2)
File Template
---
phase: XX-name
plan: NN
type: execute
wave: N # Execution wave (1, 2, 3...). Pre-computed at plan time.
depends_on: [] # Plan IDs this plan requires (e.g., ["01-01"]).
files_modified: [] # Files this plan modifies.
files_deleted: [] # OPTIONAL. Files this plan REMOVES. Declaring a path here is what
# lets worktree cleanup-wave merge the branch that deletes it; an
# undeclared deletion still blocks. Exact paths, not globs or dirs.
coupling_justified: [] # OPTIONAL. Deliberate, order-independent same-wave couplings: one
# "plan-id: reason" string per coupled peer, e.g.
# ["03-02: both append independent config keys"]. Exempts the pair
# from the plan-checker's Dimension 3b advisory (#3724).
autonomous: true # false if plan has checkpoints requiring user interaction
requirements: [] # REQUIRED — Requirement IDs from ROADMAP this plan addresses. MUST NOT be empty.
user_setup: [] # Human-required setup Claude cannot automate (see below)
# Goal-backward verification (derived during planning, verified after execution)
must_haves:
truths: [] # Observable behaviors that must be true for goal achievement
artifacts: [] # Files that must exist with real implementation
key_links: [] # Critical connections between artifacts
---
<objective>
[What this plan accomplishes]
Purpose: [Why this matters for the project]
Output: [What artifacts will be created]
</objective>
<execution_context>
@~/.claude/gsd-core/workflows/execute-plan.md
@~/.claude/gsd-core/templates/summary.md
[If plan contains checkpoint tasks (type="checkpoint:*"), add:]
@~/.claude/gsd-core/references/checkpoints.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
# Only reference prior plan SUMMARYs if genuinely needed:
# - This plan uses types/exports from prior plan
# - Prior plan made decision that affects this plan
# Do NOT reflexively chain: Plan 02 refs 01, Plan 03 refs 02...
[Relevant source files:]
@src/path/to/relevant.ts
</context>
<tasks>
<task type="auto">
<name>Task 1: [Action-oriented name]</name>
<files>path/to/file.ext, another/file.ext</files>
<read_first>path/to/reference.ext, path/to/source-of-truth.ext</read_first>
<action>[Specific implementation - what to do, how to do it, what to avoid and WHY. Include CONCRETE values: exact identifiers, parameters, expected outputs, file paths, command arguments. Never say "align X with Y" without specifying the exact target state.]</action>
<verify>[Command or check to prove it worked]</verify>
<acceptance_criteria>
- [Grep-verifiable condition: "file.ext contains 'exact string'"]
- [Measurable condition: "output.ext uses 'expected-value', NOT 'wrong-value'"]
</acceptance_criteria>
<done>[Measurable acceptance criteria]</done>
</task>
<task type="auto">
<name>Task 2: [Action-oriented name]</name>
<files>path/to/file.ext</files>
<read_first>path/to/reference.ext</read_first>
<action>[Specific implementation with concrete values]</action>
<verify>[Command or check]</verify>
<acceptance_criteria>
- [Grep-verifiable condition]
</acceptance_criteria>
<done>[Acceptance criteria]</done>
</task>
<!-- For checkpoint task examples and patterns, see @~/.claude/gsd-core/references/checkpoints.md -->
<task type="checkpoint:decision" gate="blocking">
<decision>[What needs deciding]</decision>
<context>[Why this decision matters]</context>
<options>
<option id="option-a"><name>[Name]</name><pros>[Benefits]</pros><cons>[Tradeoffs]</cons></option>
<option id="option-b"><name>[Name]</name><pros>[Benefits]</pros><cons>[Tradeoffs]</cons></option>
</options>
<resume-signal>Select: option-a or option-b</resume-signal>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<what-built>[What Claude built] - server running at [URL]</what-built>
<how-to-verify>Visit [URL] and verify: [visual checks only, NO CLI commands]</how-to-verify>
<resume-signal>Type "approved" or describe issues</resume-signal>
</task>
</tasks>
<verification>
Before declaring plan complete:
- [ ] [Specific test command]
- [ ] [Build/type check passes]
- [ ] [Behavior verification]
</verification>
<success_criteria>
- All tasks completed
- All verification checks pass
- No errors or warnings introduced
- [Plan-specific criteria]
</success_criteria>
<output>
After completion, create `.planning/phases/XX-name/{phase}-{plan}-SUMMARY.md`
</output>
Frontmatter Fields
| Field | Required | Purpose |
|---|---|---|
phase |
Yes | Phase identifier (e.g., 01-foundation) |
plan |
Yes | Plan number within phase (e.g., 01, 02) |
type |
Yes | Always execute for standard plans, tdd for TDD plans |
wave |
Yes | Execution wave number (1, 2, 3...). Pre-computed at plan time. |
depends_on |
Yes | Array of plan IDs this plan requires. |
files_modified |
Yes | Files this plan touches. |
autonomous |
Yes | true if no checkpoints, false if has checkpoints |
requirements |
Yes | MUST list requirement IDs from ROADMAP. Every roadmap requirement MUST appear in at least one plan. |
user_setup |
No | Array of human-required setup items (external services) |
must_haves |
Yes | Goal-backward verification criteria (see below) |
Wave is pre-computed: Wave numbers are assigned during /gsd:plan-phase. Execute-phase reads wave directly from frontmatter and groups plans by wave number. No runtime dependency analysis needed.
Must-haves enable verification: The must_haves field carries goal-backward requirements from planning to execution. After all plans complete, execute-phase spawns a verification subagent that checks these criteria against the actual codebase.
Parallel vs Sequential
<parallel_examples>
Wave 1 candidates (parallel):
# Plan 01 - User feature
wave: 1
depends_on: []
files_modified: [src/models/user.ts, src/api/users.ts]
autonomous: true
# Plan 02 - Product feature (no overlap with Plan 01)
wave: 1
depends_on: []
files_modified: [src/models/product.ts, src/api/products.ts]
autonomous: true
# Plan 03 - Order feature (no overlap)
wave: 1
depends_on: []
files_modified: [src/models/order.ts, src/api/orders.ts]
autonomous: true
All three run in parallel (Wave 1) - no dependencies, no file conflicts.
Sequential (genuine dependency):
# Plan 01 - Auth foundation
wave: 1
depends_on: []
files_modified: [src/lib/auth.ts, src/middleware/auth.ts]
autonomous: true
# Plan 02 - Protected features (needs auth)
wave: 2
depends_on: ["01-01"]
files_modified: [src/features/dashboard.ts]
autonomous: true
Plan 02 in Wave 2 waits for Plan 01 in Wave 1 - genuine dependency on auth types/middleware.
Checkpoint plan:
# Plan 03 - UI with verification
wave: 3
depends_on: ["01-01", "01-02"]
files_modified: [src/components/Dashboard.tsx]
autonomous: false # Has checkpoint:human-verify
Wave 3 runs after Waves 1 and 2. Pauses at checkpoint, orchestrator presents to user, resumes on approval.
</parallel_examples>
Context Section
Parallel-aware context:
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
# Only include SUMMARY refs if genuinely needed:
# - This plan imports types from prior plan
# - Prior plan made decision affecting this plan
# - Prior plan's output is input to this plan
#
# Independent plans need NO prior SUMMARY references.
# Do NOT reflexively chain: 02 refs 01, 03 refs 02...
@src/relevant/source.ts
</context>
Bad pattern (creates false dependencies):
<context>
@.planning/phases/03-features/03-01-SUMMARY.md # Just because it's earlier
@.planning/phases/03-features/03-02-SUMMARY.md # Reflexive chaining
</context>
Scope Guidance
Plan sizing:
- 2-3 tasks per plan
- ~50% context usage maximum
- Complex phases: Multiple focused plans, not one large plan
When to split:
- Different subsystems (auth vs API vs UI)
-
3 tasks
- Risk of context overflow
- TDD candidates - separate plans
Vertical slices preferred:
PREFER: Plan 01 = User (model + API + UI)
Plan 02 = Product (model + API + UI)
AVOID: Plan 01 = All models
Plan 02 = All APIs
Plan 03 = All UIs
TDD Plans
TDD features get dedicated plans with type: tdd.
Heuristic: Can you write expect(fn(input)).toBe(output) before writing fn?
→ Yes: Create a TDD plan
→ No: Standard task in standard plan
See ~/.claude/gsd-core/references/tdd.md for TDD plan structure.
Task Types
| Type | Use For | Autonomy |
|---|---|---|
auto |
Everything Claude can do independently | Fully autonomous |
checkpoint:human-verify |
Visual/functional verification | Pauses, returns to orchestrator |
checkpoint:decision |
Implementation choices | Pauses, returns to orchestrator |
checkpoint:human-action |
Truly unavoidable manual steps (rare) | Pauses, returns to orchestrator |
Checkpoint behavior in parallel execution:
- Plan runs until checkpoint
- Agent returns with checkpoint details + agent_id
- Orchestrator presents to user
- User responds
- Orchestrator resumes agent with
resume: agent_id
Examples
Autonomous parallel plan:
---
phase: 03-features
plan: 01
type: execute
wave: 1
depends_on: []
files_modified: [src/features/user/model.ts, src/features/user/api.ts, src/features/user/UserList.tsx]
autonomous: true
---
<objective>
Implement complete User feature as vertical slice.
Purpose: Self-contained user management that can run parallel to other features.
Output: User model, API endpoints, and UI components.
</objective>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Create User model</name>
<files>src/features/user/model.ts</files>
<action>Define User type with id, email, name, createdAt. Export TypeScript interface.</action>
<verify>tsc --noEmit passes</verify>
<done>User type exported and usable</done>
</task>
<task type="auto">
<name>Task 2: Create User API endpoints</name>
<files>src/features/user/api.ts</files>
<action>GET /users (list), GET /users/:id (single), POST /users (create). Use User type from model.</action>
<verify>fetch tests pass for all endpoints</verify>
<done>All CRUD operations work</done>
</task>
</tasks>
<verification>
- [ ] npm run build succeeds
- [ ] API endpoints respond correctly
</verification>
<success_criteria>
- All tasks completed
- User feature works end-to-end
</success_criteria>
<output>
After completion, create `.planning/phases/03-features/03-01-SUMMARY.md`
</output>
Plan with checkpoint (non-autonomous):
---
phase: 03-features
plan: 03
type: execute
wave: 2
depends_on: ["03-01", "03-02"]
files_modified: [src/components/Dashboard.tsx]
autonomous: false
---
<objective>
Build dashboard with visual verification.
Purpose: Integrate user and product features into unified view.
Output: Working dashboard component.
</objective>
<execution_context>
@~/.claude/gsd-core/workflows/execute-plan.md
@~/.claude/gsd-core/templates/summary.md
@~/.claude/gsd-core/references/checkpoints.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/03-features/03-01-SUMMARY.md
@.planning/phases/03-features/03-02-SUMMARY.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Build Dashboard layout</name>
<files>src/components/Dashboard.tsx</files>
<action>Create responsive grid with UserList and ProductList components. Use Tailwind for styling.</action>
<verify>npm run build succeeds</verify>
<done>Dashboard renders without errors</done>
</task>
<!-- Checkpoint pattern: Claude starts server, user visits URL. See checkpoints.md for full patterns. -->
<task type="auto">
<name>Start dev server</name>
<action>Run `npm run dev` in background, wait for ready</action>
<verify>fetch http://localhost:3000 returns 200</verify>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<what-built>Dashboard - server at http://localhost:3000</what-built>
<how-to-verify>Visit localhost:3000/dashboard. Check: desktop grid, mobile stack, no scroll issues.</how-to-verify>
<resume-signal>Type "approved" or describe issues</resume-signal>
</task>
</tasks>
<verification>
- [ ] npm run build succeeds
- [ ] Visual verification passed
</verification>
<success_criteria>
- All tasks completed
- User approved visual layout
</success_criteria>
<output>
After completion, create `.planning/phases/03-features/03-03-SUMMARY.md`
</output>
Anti-Patterns
Bad: Reflexive dependency chaining
depends_on: ["03-01"] # Just because 01 comes before 02
Bad: Horizontal layer grouping
Plan 01: All models
Plan 02: All APIs (depends on 01)
Plan 03: All UIs (depends on 02)
Bad: Missing autonomy flag
# Has checkpoint but no autonomous: false
depends_on: []
files_modified: [...]
# autonomous: ??? <- Missing!
Bad: Vague tasks
<task type="auto">
<name>Set up authentication</name>
<action>Add auth to the app</action>
</task>
Bad: Missing read_first (executor modifies files it hasn't read)
<task type="auto">
<name>Update database config</name>
<files>src/config/database.ts</files>
<!-- No read_first! Executor doesn't know current state or conventions -->
<action>Update the database config to match production settings</action>
</task>
Bad: Vague acceptance criteria (not verifiable)
<acceptance_criteria>
- Config is properly set up
- Database connection works correctly
</acceptance_criteria>
Good: Concrete with read_first + verifiable criteria
<task type="auto">
<name>Update database config for connection pooling</name>
<files>src/config/database.ts</files>
<read_first>src/config/database.ts, .env.example, docker-compose.yml</read_first>
<action>Add pool configuration: min=2, max=20, idleTimeoutMs=30000. Add SSL config: rejectUnauthorized=true when NODE_ENV=production. Add .env.example entry: DATABASE_POOL_MAX=20.</action>
<acceptance_criteria>
- database.ts contains "max: 20" and "idleTimeoutMillis: 30000"
- database.ts contains SSL conditional on NODE_ENV
- .env.example contains DATABASE_POOL_MAX
</acceptance_criteria>
</task>
Guidelines
- Always use XML structure for Claude parsing
- Include
wave,depends_on,files_modified,autonomousin every plan - Prefer vertical slices over horizontal layers
- Only reference prior SUMMARYs when genuinely needed
- Group checkpoints with related auto tasks in same plan
- 2-3 tasks per plan, ~50% context max
User Setup (External Services)
When a plan introduces external services requiring human configuration, declare in frontmatter:
user_setup:
- service: stripe
why: "Payment processing requires API keys"
env_vars:
- name: STRIPE_SECRET_KEY
source: "Stripe Dashboard → Developers → API keys → Secret key"
- name: STRIPE_WEBHOOK_SECRET
source: "Stripe Dashboard → Developers → Webhooks → Signing secret"
dashboard_config:
- task: "Create webhook endpoint"
location: "Stripe Dashboard → Developers → Webhooks → Add endpoint"
details: "URL: https://[your-domain]/api/webhooks/stripe"
local_dev:
- "stripe listen --forward-to localhost:3000/api/webhooks/stripe"
The automation-first rule: user_setup contains ONLY what Claude literally cannot do:
- Account creation (requires human signup)
- Secret retrieval (requires dashboard access)
- Dashboard configuration (requires human in browser)
NOT included: Package installs, code changes, file creation, CLI commands Claude can run.
Result: Execute-plan generates {phase}-USER-SETUP.md with checklist for the user.
See ~/.claude/gsd-core/templates/user-setup.md for full schema and examples
Must-Haves (Goal-Backward Verification)
The must_haves field defines what must be TRUE for the phase goal to be achieved. Derived during planning, verified after execution.
Structure:
must_haves:
truths:
- "User can see existing messages"
- "User can send a message"
- "Messages persist across refresh"
artifacts:
- path: "src/components/Chat.tsx"
provides: "Message list rendering"
min_lines: 30
- path: "src/app/api/chat/route.ts"
provides: "Message CRUD operations"
exports: ["GET", "POST"]
- path: "prisma/schema.prisma"
provides: "Message model"
contains: "model Message"
key_links:
- from: "src/components/Chat.tsx"
to: "src/app/api/chat/route.ts"
via: "fetch in useEffect — calls /api/chat endpoint"
pattern: "fetch.*api/chat"
- from: "src/app/api/chat/route.ts"
to: "prisma/schema.prisma"
via: "database query via prisma.message"
pattern: "prisma\\.message\\.(find|create)"
Field descriptions:
| Field | Purpose |
|---|---|
truths |
Observable behaviors from user perspective. Each must be testable. |
artifacts |
Files that must exist with real implementation. |
artifacts[].path |
File path relative to project root. |
artifacts[].provides |
What this artifact delivers. |
artifacts[].min_lines |
Optional. Minimum lines to be considered substantive. |
artifacts[].exports |
Optional. Expected exports to verify. |
artifacts[].contains |
Optional. Pattern that must exist in file. |
key_links |
Critical connections between artifacts. |
key_links[].from |
Source file (relative path from project root). Describe components or symbols in via:. |
key_links[].to |
Target file (relative path from project root). Describe endpoints, APIs, or modules in via:. |
key_links[].via |
How they connect, including any endpoint or symbol name (e.g. fetch in useEffect — calls /api/chat, Prisma query via prisma.message). |
key_links[].pattern |
Optional. Regex to verify connection exists. |
Why this matters:
Task completion ≠ Goal achievement. A task "create chat component" can complete by creating a placeholder. The must_haves field captures what must actually work, enabling verification to catch gaps before they compound.
Verification flow:
- Plan-phase derives must_haves from phase goal (goal-backward)
- Must_haves written to PLAN.md frontmatter
- Execute-phase runs all plans
- Verification subagent checks must_haves against codebase
- Gaps found → fix plans created → execute → re-verify
- All must_haves pass → phase complete