Skip to content

Commit 2670c24

Browse files
authored
Fix native approach alignment proof (#94)
* fix: enforce native approach alignment proof * fix: align native plan checker schema * fix: harden native approach proof gates * fix: require canonical approach proof fields * fix: align canonical approach proof schema * fix: align checker severity schema * fix: align planner checker contracts * fix: align checker status examples * fix: escalate unresolved checker warnings
1 parent 4d085dc commit 2670c24

17 files changed

Lines changed: 418 additions & 53 deletions

agents/approach-explorer.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Your job:
1010
- capture decisions concrete enough that downstream agents never re-ask the user
1111
- classify gray areas as taste, technical, or hybrid — and adapt your approach accordingly
1212
- write APPROACH.md for the planner and plan-checker to consume
13+
- when `workflow.discuss: true`, record explicit alignment proof in APPROACH.md before planning can proceed
1314

1415
The user is the visionary. You are the thinking partner. Ask about vision and implementation choices. Do NOT ask about codebase patterns, technical risks, or architecture — those are the researcher's and planner's jobs.
1516

@@ -22,6 +23,8 @@ Do NOT:
2223
- Present options without research backing (for technical gray areas)
2324
- Accept vague answers without probing ("it should be nice" → push for specifics)
2425
- Skip areas because you think you know best
26+
- Treat "No questions needed" as valid under `workflow.discuss: true` unless the user explicitly approved a skip
27+
- Hide user-alignment proof in chat memory, PLAN metadata, or agent discretion instead of APPROACH.md
2528
- Ask about technical implementation details (planner's job)
2629
- Expand scope during discussion (phase boundary is FIXED)
2730
- Fire questions without building on previous answers
@@ -48,10 +51,12 @@ Read only the explicit inputs provided. Extract only what you need:
4851
- **Phase research** (if exists): skim for findings relevant to gray area identification
4952
- **Codebase files** (if provided): existing patterns and conventions that inform approach choices
5053
- **Existing APPROACH.md** (if updating): load current decisions as starting point
54+
- **Project config** (if provided from `.planning/config.json`): check `workflow.discuss` to decide whether alignment proof is mandatory
5155
</input_contract>
5256

5357
<output_contract>
5458
- **Artifact:** `{padded_phase}-APPROACH.md` in the phase directory, using the approach template
59+
- **Alignment proof:** when `workflow.discuss: true`, APPROACH.md must include `alignment_status: user_confirmed` or `alignment_status: approved_skip` with the canonical fields `alignment_method`, `user_confirmed_at`, `explicit_skip_approved`, `skip_scope`, `skip_rationale`, and `confirmed_decisions`. `Agent's Discretion` is not alignment proof.
5560
- **Downstream consumers:**
5661
- Planner reads locked decisions to constrain implementation choices
5762
- Plan-checker verifies plans implement chosen approaches (approach_alignment dimension)
@@ -118,6 +123,8 @@ Present each gray area individually with:
118123

119124
If the user delegates an area, mark it as "Agent's Discretion" and move to the next.
120125

126+
If the whole phase appears to need no discussion under `workflow.discuss: true`, ask the user to approve that skip explicitly. Record it as `alignment_status: approved_skip` with `explicit_skip_approved: true`, `alignment_method`, `user_confirmed_at`, `skip_scope`, `skip_rationale`, and `confirmed_decisions: ["N/A - approved skip"]`. Do not create a proofless APPROACH.md.
127+
121128
## Step 5: Adaptive Deep-Dive
122129

123130
For each area the user chose to discuss:
@@ -165,6 +172,7 @@ Before writing the final APPROACH.md, verify:
165172
- [ ] Taste decisions reflect actual user statements, not agent assumptions
166173
- [ ] Scope stayed within phase boundary
167174
- [ ] All "Agent's Discretion" areas are explicitly marked
175+
- [ ] If `workflow.discuss: true`, APPROACH.md records `alignment_status: user_confirmed` or `alignment_status: approved_skip`; proofless, missing, or agent-discretion-only alignment is invalid
168176

169177
If any check fails, address it with the user before proceeding.
170178

@@ -298,6 +306,7 @@ Ready for assumptions?"
298306
- Scope creep is captured as deferred ideas, never acted on
299307
- Assumptions are surfaced with honest confidence levels
300308
- "Agent's Discretion" areas are explicitly marked
309+
- Under `workflow.discuss: true`, user alignment is proven in APPROACH.md with `user_confirmed` or explicit `approved_skip` metadata
301310
</quality_guarantees>
302311

303312
<research_subagent_prompt>

agents/planner.md

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ When APPROACH.md exists for the target phase, the orchestrator passes it as inpu
5050
Honor the user's choice from APPROACH.md. Note the tension in the plan's Notes section so the user is aware, but do not override their decision.
5151

5252
**If no APPROACH.md exists:**
53-
Plan using SPEC.md and research only. The plan-checker will skip the approach_alignment dimension.
53+
If the orchestrator indicates `workflow.discuss: true`, stop and request approach exploration or an approved skip before planning. Otherwise plan using SPEC.md and research only under `reduced_alignment`; the plan-checker may skip the approach_alignment dimension only in that reduced-alignment mode.
5454
</approach_decisions>
5555

5656
<goal_backward>
@@ -182,7 +182,7 @@ Wave rule:
182182
Write one or more `PLAN.md` files to the phase directory.
183183

184184
Keep the current GSDD schema exactly:
185-
- frontmatter keys: `phase`, `plan`, `type`, `wave`, `depends_on`, `files-modified`, `autonomous`, `requirements`, `must_haves`
185+
- frontmatter keys: `phase`, `plan`, `type`, `wave`, `runtime`, `assurance`, `depends_on`, `files-modified`, `autonomous`, `requirements`, `non_goals`, `hard_boundaries`, `escalation_triggers`, `approval_gates`, `anti_regression_targets`, `known_unknowns`, `high_leverage_surfaces`, `second_pass_required`, `closure_claim_limit`, `parallelism_budget`, `leverage`, `must_haves`
186186
- typed tasks with `files`, `action`, `verify`, and `done`
187187

188188
Typed frontmatter example:
@@ -192,13 +192,37 @@ phase: 01-foundation
192192
plan: 01
193193
type: execute
194194
wave: 1
195+
runtime: claude-code
196+
assurance: self_checked
195197
depends_on: []
196198
files-modified:
197199
- src/lib/auth.ts
198200
- src/routes/session.ts
199201
autonomous: true
200202
requirements:
201203
- REQ-AUTH-01
204+
non_goals:
205+
- Do not redesign auth UX beyond the scoped sign-in flow.
206+
hard_boundaries:
207+
- Do not touch signup, billing, or unrelated session consumers in this plan.
208+
escalation_triggers:
209+
- Stop if the request expands beyond the approved phase success criteria.
210+
approval_gates:
211+
- Ask before destructive migrations or external delivery actions.
212+
anti_regression_targets:
213+
- Existing session middleware behavior remains unchanged for already-supported routes.
214+
known_unknowns:
215+
- Exact copy wording for auth errors may still need product confirmation.
216+
high_leverage_surfaces: []
217+
second_pass_required: false
218+
closure_claim_limit: Do not claim phase completion until verification satisfies the evidence contract for the scoped truths.
219+
parallelism_budget:
220+
max_concurrent_plans: 1
221+
safe_parallelism: []
222+
leverage:
223+
lost: Slightly more planning ceremony for this plan.
224+
kept: Existing auth/session architecture and repo conventions.
225+
gained: Explicit anti-drift boundaries and fail-closed escalation.
202226
must_haves:
203227
truths:
204228
- "User can sign in with email and password"
@@ -239,7 +263,12 @@ Before returning, self-check against the checker dimensions:
239263
6. must-have quality
240264
7. context compliance
241265
8. goal achievement
242-
9. approach alignment (when APPROACH.md exists)
266+
9. scope boundaries
267+
10. anti-regression capture
268+
11. escalation integrity
269+
12. closure honesty
270+
13. high-leverage review
271+
14. approach alignment (when APPROACH.md exists)
243272
244273
Task completeness rules:
245274
- every task has files, action, verify, and done

bin/adapters/claude.mjs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,22 +61,24 @@ Execution flow:
6161
2. Resolve the target phase from the command arguments. If no phase is provided, choose the first roadmap phase that is not complete.
6262
3. **Approach exploration** (before planning):
6363
a. Check \`.planning/config.json\` for \`workflow.discuss\`. If \`false\` or missing, skip to step 4 and report \`reduced_alignment\` in the summary.
64-
b. Check if \`{phase_dir}/{padded_phase}-APPROACH.md\` exists. If it does, offer the user: "Use existing" / "Update it" / "View it". If "Use existing", load decisions and skip to step 4.
65-
c. If no APPROACH.md exists (or user chose "Update"): invoke the native \`gsdd-approach-explorer\` subagent with the phase goal, requirement IDs, SPEC locked decisions, phase research, and relevant codebase files.
64+
b. Check if \`{phase_dir}/{padded_phase}-APPROACH.md\` exists. If it does, offer the user: "Use existing" / "Update it" / "View it". If "Use existing", load decisions, then validate the alignment proof before step 4; proofless or invalid existing APPROACH.md must be updated, not silently trusted.
65+
c. If no APPROACH.md exists (or user chose "Update"): invoke the native \`gsdd-approach-explorer\` subagent with the phase goal, requirement IDs, project config from \`.planning/config.json\` (especially \`workflow.discuss\`), SPEC locked decisions, phase research, and relevant codebase files.
6666
d. The explorer runs a GSD-style interactive conversation with the user (gray areas, research, deep-dive questions, assumptions) and writes APPROACH.md.
67-
e. Load APPROACH.md decisions as locked constraints alongside SPEC.md decisions.
67+
e. Before planning, confirm APPROACH.md records all canonical proof fields: \`alignment_status\`, \`alignment_method\`, \`user_confirmed_at\`, \`explicit_skip_approved\`, \`skip_scope\`, \`skip_rationale\`, and \`confirmed_decisions\`. For \`alignment_status: user_confirmed\`, \`confirmed_decisions\` must name the locked decisions and skip fields may be \`false\`/\`N/A\`; for \`alignment_status: approved_skip\`, \`explicit_skip_approved: true\`, \`skip_scope\`, and \`skip_rationale\` must be substantive. Agent-only "No questions needed" is not valid proof under \`workflow.discuss: true\`.
68+
f. Load APPROACH.md decisions as locked constraints alongside SPEC.md decisions.
6869
4. Produce the initial phase plan according to \`.agents/skills/gsdd-plan/SKILL.md\`. Pass APPROACH.md decisions (if any) as locked constraints to the planner.
69-
5. If \`.planning/config.json\` has \`workflow.planCheck: false\`, stop after planner self-check and explicitly report reduced assurance.
70+
5. If \`.planning/config.json\` has \`workflow.planCheck: false\`, stop after planner self-check and explicitly report reduced assurance. This only skips the independent checker; it does not skip the step 3 alignment-proof gate when \`workflow.discuss: true\`.
7071
6. If \`workflow.planCheck: true\`, invoke the native \`gsdd-plan-checker\` subagent with fresh context.
7172
7. Pass only explicit inputs to the checker:
7273
- target phase goal and requirement IDs
7374
- relevant locked decisions / deferred items from \`.planning/SPEC.md\`
75+
- project config from \`.planning/config.json\`, especially \`workflow.discuss\` and \`workflow.planCheck\`
7476
- approach decisions from \`.planning/phases/*-APPROACH.md\` (if exists)
7577
- relevant phase research file(s)
7678
- produced \`.planning/phases/*-PLAN.md\` file(s)
7779
8. Require the checker to return a single JSON object with this shape:
7880
{
79-
"status": "passed",
81+
"status": "issues_found",
8082
"summary": "One sentence overall assessment",
8183
"issues": [
8284
{
@@ -89,10 +91,10 @@ Execution flow:
8991
}
9092
]
9193
}
92-
Status must be either "${CHECKER_STATUSES[0]}" or "${CHECKER_STATUSES[1]}".
94+
Status must be either "${CHECKER_STATUSES[0]}" or "${CHECKER_STATUSES[1]}". Use "passed" only when "issues": []; any blocker or warning must use "issues_found".
9395
9. If the checker returns \`passed\`, finish and summarize.
9496
10. If the checker returns \`issues_found\`, revise the existing plan files only where needed, then run the checker again.
95-
11. Maximum ${MAX_CHECKER_CYCLES} checker cycles total. If blockers remain after cycle ${MAX_CHECKER_CYCLES}, stop and escalate to the user instead of pretending the plan is ready.
97+
11. Maximum ${MAX_CHECKER_CYCLES} checker cycles total. If any blockers or warnings remain after cycle ${MAX_CHECKER_CYCLES}, stop and escalate to the user instead of pretending the plan is ready.
9698
9799
Return a concise orchestration summary:
98100
- target phase

bin/adapters/opencode.mjs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -169,22 +169,24 @@ Execution flow:
169169
2. Resolve the target phase from the command arguments. If no phase is provided, choose the first roadmap phase that is not complete.
170170
3. **Approach exploration** (before planning):
171171
a. Check \`.planning/config.json\` for \`workflow.discuss\`. If \`false\` or missing, skip to step 4 and report \`reduced_alignment\` in the summary.
172-
b. Check if \`{phase_dir}/{padded_phase}-APPROACH.md\` exists. If it does, offer the user: "Use existing" / "Update it" / "View it". If "Use existing", load decisions and skip to step 4.
173-
c. If no APPROACH.md exists (or user chose "Update"): invoke the \`gsdd-approach-explorer\` subagent with the phase goal, requirement IDs, SPEC locked decisions, phase research, and relevant codebase files.
172+
b. Check if \`{phase_dir}/{padded_phase}-APPROACH.md\` exists. If it does, offer the user: "Use existing" / "Update it" / "View it". If "Use existing", load decisions, then validate the alignment proof before step 4; proofless or invalid existing APPROACH.md must be updated, not silently trusted.
173+
c. If no APPROACH.md exists (or user chose "Update"): invoke the \`gsdd-approach-explorer\` subagent with the phase goal, requirement IDs, project config from \`.planning/config.json\` (especially \`workflow.discuss\`), SPEC locked decisions, phase research, and relevant codebase files.
174174
d. The explorer runs a GSD-style interactive conversation with the user (gray areas, research, deep-dive questions, assumptions) and writes APPROACH.md.
175-
e. Load APPROACH.md decisions as locked constraints alongside SPEC.md decisions.
175+
e. Before planning, confirm APPROACH.md records all canonical proof fields: \`alignment_status\`, \`alignment_method\`, \`user_confirmed_at\`, \`explicit_skip_approved\`, \`skip_scope\`, \`skip_rationale\`, and \`confirmed_decisions\`. For \`alignment_status: user_confirmed\`, \`confirmed_decisions\` must name the locked decisions and skip fields may be \`false\`/\`N/A\`; for \`alignment_status: approved_skip\`, \`explicit_skip_approved: true\`, \`skip_scope\`, and \`skip_rationale\` must be substantive. Agent-only "No questions needed" is not valid proof under \`workflow.discuss: true\`.
176+
f. Load APPROACH.md decisions as locked constraints alongside SPEC.md decisions.
176177
4. Produce the initial phase plan according to \`.agents/skills/gsdd-plan/SKILL.md\`. Pass APPROACH.md decisions (if any) as locked constraints to the planner.
177-
5. If \`.planning/config.json\` has \`workflow.planCheck: false\`, stop after planner self-check and explicitly report reduced assurance.
178+
5. If \`.planning/config.json\` has \`workflow.planCheck: false\`, stop after planner self-check and explicitly report reduced assurance. This only skips the independent checker; it does not skip the step 3 alignment-proof gate when \`workflow.discuss: true\`.
178179
6. If \`workflow.planCheck: true\`, invoke the hidden \`gsdd-plan-checker\` subagent with fresh context.
179180
7. Pass only explicit inputs to the checker:
180181
- target phase goal and requirement IDs
181182
- relevant locked decisions / deferred items from \`.planning/SPEC.md\`
183+
- project config from \`.planning/config.json\`, especially \`workflow.discuss\` and \`workflow.planCheck\`
182184
- approach decisions from \`.planning/phases/*-APPROACH.md\` (if exists)
183185
- relevant phase research file(s)
184186
- produced \`.planning/phases/*-PLAN.md\` file(s)
185187
8. Require the checker to return a single JSON object with this shape:
186188
{
187-
"status": "passed",
189+
"status": "issues_found",
188190
"summary": "One sentence overall assessment",
189191
"issues": [
190192
{
@@ -197,10 +199,10 @@ Execution flow:
197199
}
198200
]
199201
}
200-
Status must be either "${CHECKER_STATUSES[0]}" or "${CHECKER_STATUSES[1]}".
202+
Status must be either "${CHECKER_STATUSES[0]}" or "${CHECKER_STATUSES[1]}". Use "passed" only when "issues": []; any blocker or warning must use "issues_found".
201203
9. If the checker returns \`passed\`, finish and summarize.
202204
10. If the checker returns \`issues_found\`, revise the existing plan files only where needed, then run the checker again.
203-
11. Maximum ${MAX_CHECKER_CYCLES} checker cycles total. If blockers remain after cycle ${MAX_CHECKER_CYCLES}, stop and escalate to the user instead of pretending the plan is ready.
205+
11. Maximum ${MAX_CHECKER_CYCLES} checker cycles total. If any blockers or warnings remain after cycle ${MAX_CHECKER_CYCLES}, stop and escalate to the user instead of pretending the plan is ready.
204206
205207
Return a concise orchestration summary:
206208
- target phase

bin/lib/plan-constants.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ export const PLAN_CHECK_DIMENSIONS = [
77
'must_have_quality',
88
'context_compliance',
99
'goal_achievement',
10+
'scope_boundaries',
11+
'anti_regression_capture',
12+
'escalation_integrity',
13+
'closure_honesty',
14+
'high_leverage_review',
1015
'approach_alignment',
1116
];
1217

distilled/DESIGN.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,7 @@ Both paths produce identical output: `{padded_phase}-APPROACH.md` in the phase d
13651365
| Questioning style | Rigid 4-question batched loop | Adaptive convergence (2-6 questions depending on complexity) | Fixed batch sizes don't match decision complexity. Some areas resolve in 2 questions, others need 6 |
13661366
| Pre-question research | No research before asking | Research subagent per technical area returns structured summary before asking | Users make better decisions when presented with researched options and trade-offs |
13671367
| Quality gate | None | Self-check before writing APPROACH.md (concrete decisions, no vague language, source backing, scope compliance) | Prevents weak outputs that force re-asking during planning |
1368+
| Alignment proof gate | None | `APPROACH.md` records `alignment_status: user_confirmed` or explicit `approved_skip`, and planning validates this before goal-backward planning when `workflow.discuss: true` | Prevents native or existing-artifact paths from turning mandatory discussion into artifact theater |
13681369
| Intermediate persistence | No persistence until final output | Confirmed decisions written to disk incrementally | Protects against context limits in long conversations |
13691370
| Context loading | "Read everything" | JIT extraction guidance (e.g., "From SPEC.md read ONLY locked decisions") | Prevents context pollution with irrelevant content |
13701371
| Plan-checker integration | None | New `approach_alignment` dimension in plan-checker | Verifies plans honor approach decisions, not just requirements |
@@ -1398,11 +1399,11 @@ Isolating research in subagents and returning compressed summaries follows the C
13981399

13991400
**Trade-offs:**
14001401

1401-
- Benefit: planner receives locked user decisions instead of guessing approaches; plan-checker can verify approach alignment; context stays lean via research isolation
1402+
- Benefit: planner receives locked user decisions instead of guessing approaches; plan-checker can verify approach alignment; existing APPROACH artifacts are not trusted unless their alignment proof is valid; context stays lean via research isolation
14021403
- Cost: adds one interactive step before planning (~5-15 minutes of user time per phase); hybrid architecture is more complex than a single monolithic workflow
14031404
- Mitigation: `workflow.discuss: true|false` toggle in `.planning/config.json` allows skipping with explicit `reduced_alignment` reporting; taste areas skip research entirely. Default is `false` (opt-in) to stay consistent with GSDD's stripped-down identity; users enable it explicitly
14041405

1405-
**GSDD implementation:** `agents/approach-explorer.md` (role contract), `distilled/templates/delegates/approach-explorer.md` (thin delegate), `distilled/templates/approach.md` (output template), `distilled/workflows/plan.md` (`<approach_exploration>` section), `agents/planner.md` (`<approach_decisions>` section), `distilled/templates/delegates/plan-checker.md` (`approach_alignment` dimension), `bin/adapters/claude.mjs` + `bin/adapters/opencode.mjs` + `bin/adapters/codex.mjs` (native agent rendering)
1406+
**GSDD implementation:** `agents/approach-explorer.md` (role contract), `distilled/templates/delegates/approach-explorer.md` (thin delegate), `distilled/templates/approach.md` (output template), `distilled/workflows/plan.md` (`<approach_exploration>` section), `agents/planner.md` (`<approach_decisions>` section), `distilled/templates/delegates/plan-checker.md` (`approach_alignment` dimension), `bin/adapters/claude.mjs` + `bin/adapters/opencode.mjs` + `bin/adapters/codex.mjs` (native agent rendering), `tests/gsdd.guards.test.cjs`, `tests/gsdd.plan.adapters.test.cjs`, and `tests/gsdd.scenarios.test.cjs` (alignment-proof propagation coverage)
14061407

14071408
---
14081409

0 commit comments

Comments
 (0)