gsdd-cli 0.19.0 → 0.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,9 +11,13 @@
11
11
  import { createHash } from 'crypto';
12
12
  import { existsSync, readFileSync, writeFileSync } from 'fs';
13
13
  import { join } from 'path';
14
+ import { output } from './cli-utils.mjs';
15
+ import { resolveWorkspaceContext } from './workspace-root.mjs';
14
16
 
15
17
  const FINGERPRINT_FILE = '.state-fingerprint.json';
16
18
  const FINGERPRINT_SOURCES = ['ROADMAP.md', 'SPEC.md', 'config.json'];
19
+ const FINGERPRINT_SCHEMA_VERSION = 2;
20
+ const FINGERPRINT_ALGORITHM = 'sha256:v2:exists-content';
17
21
 
18
22
  /**
19
23
  * Compute a SHA-256 fingerprint from the planning truth files.
@@ -23,15 +27,52 @@ const FINGERPRINT_SOURCES = ['ROADMAP.md', 'SPEC.md', 'config.json'];
23
27
  export function computeFingerprint(planningDir) {
24
28
  const hash = createHash('sha256');
25
29
  const sources = {};
30
+ const files = {};
26
31
  for (const file of FINGERPRINT_SOURCES) {
27
32
  const filePath = join(planningDir, file);
28
- const content = existsSync(filePath) ? readFileSync(filePath, 'utf-8') : '';
33
+ const exists = existsSync(filePath);
34
+ const content = exists ? readFileSync(filePath, 'utf-8') : '';
35
+ hash.update(`${file}:${exists ? 'exists' : 'missing'}:${content}\n`);
36
+ sources[file] = exists;
37
+ files[file] = {
38
+ exists,
39
+ hash: createHash('sha256').update(content).digest('hex'),
40
+ };
41
+ }
42
+ return { hash: hash.digest('hex'), sources, files };
43
+ }
44
+
45
+ function computeLegacyFingerprint(planningDir) {
46
+ const hash = createHash('sha256');
47
+ const sources = {};
48
+ for (const file of FINGERPRINT_SOURCES) {
49
+ const filePath = join(planningDir, file);
50
+ const exists = existsSync(filePath);
51
+ const content = exists ? readFileSync(filePath, 'utf-8') : '';
29
52
  hash.update(`${file}:${content}\n`);
30
- sources[file] = existsSync(filePath);
53
+ sources[file] = exists;
31
54
  }
32
55
  return { hash: hash.digest('hex'), sources };
33
56
  }
34
57
 
58
+ export function cmdSessionFingerprint(...args) {
59
+ const { args: normalizedArgs, planningDir, invalid, error } = resolveWorkspaceContext(args);
60
+ if (invalid) {
61
+ console.error(error);
62
+ process.exitCode = 1;
63
+ return;
64
+ }
65
+
66
+ const [action] = normalizedArgs;
67
+ if (action !== 'write') {
68
+ console.error('Usage: node .planning/bin/gsdd.mjs session-fingerprint write');
69
+ process.exitCode = 1;
70
+ return;
71
+ }
72
+
73
+ output({ operation: 'session-fingerprint write', fingerprint: writeFingerprint(planningDir) });
74
+ }
75
+
35
76
  /**
36
77
  * Read the stored fingerprint from .planning/.state-fingerprint.json.
37
78
  * Returns null if the file does not exist or is unparseable.
@@ -50,10 +91,13 @@ export function readStoredFingerprint(planningDir) {
50
91
  * Write the current fingerprint to .planning/.state-fingerprint.json.
51
92
  */
52
93
  export function writeFingerprint(planningDir) {
53
- const { hash, sources } = computeFingerprint(planningDir);
94
+ const { hash, sources, files } = computeFingerprint(planningDir);
54
95
  const data = {
96
+ schemaVersion: FINGERPRINT_SCHEMA_VERSION,
97
+ algorithm: FINGERPRINT_ALGORITHM,
55
98
  hash,
56
99
  sources,
100
+ files,
57
101
  timestamp: new Date().toISOString(),
58
102
  };
59
103
  writeFileSync(join(planningDir, FINGERPRINT_FILE), JSON.stringify(data, null, 2) + '\n');
@@ -69,27 +113,33 @@ export function writeFingerprint(planningDir) {
69
113
  */
70
114
  export function checkDrift(planningDir) {
71
115
  const stored = readStoredFingerprint(planningDir);
72
- const { hash: currentHash, sources: currentSources } = computeFingerprint(planningDir);
116
+ const { hash: currentHash, sources: currentSources, files: currentFiles } = computeFingerprint(planningDir);
73
117
 
74
118
  if (!stored) {
75
119
  return {
76
120
  drifted: false,
77
121
  noBaseline: true,
122
+ classification: 'no_baseline',
78
123
  details: ['No stored fingerprint found — first session or fingerprint was cleared.'],
79
124
  stored: null,
80
- current: { hash: currentHash, sources: currentSources },
125
+ current: { hash: currentHash, sources: currentSources, files: currentFiles },
126
+ files: [],
81
127
  };
82
128
  }
83
129
 
84
- const drifted = stored.hash !== currentHash;
130
+ const isLegacy = !stored.schemaVersion && !stored.files;
131
+ const comparison = isLegacy ? computeLegacyFingerprint(planningDir) : { hash: currentHash };
132
+ const drifted = stored.hash !== comparison.hash;
85
133
  const details = [];
134
+ const files = drifted
135
+ ? FINGERPRINT_SOURCES.map((file) => classifyFileDrift(file, stored, currentSources, currentFiles, { legacy: isLegacy }))
136
+ : FINGERPRINT_SOURCES.map((file) => ({ file, status: 'unchanged' }));
86
137
  if (drifted) {
87
- for (const file of FINGERPRINT_SOURCES) {
88
- const was = stored.sources?.[file] ?? false;
89
- const now = currentSources[file];
90
- if (was && !now) details.push(`${file} was removed`);
91
- else if (!was && now) details.push(`${file} was created`);
92
- else if (was && now) details.push(`${file} may have changed`);
138
+ for (const file of files) {
139
+ if (file.status === 'created') details.push(`${file.file} created`);
140
+ else if (file.status === 'removed') details.push(`${file.file} removed`);
141
+ else if (file.status === 'changed') details.push(`${file.file} changed`);
142
+ else if (file.status === 'unknown') details.push(`${file.file} may have changed`);
93
143
  }
94
144
  if (details.length === 0) {
95
145
  details.push('Planning state hash changed since last recorded session.');
@@ -99,8 +149,35 @@ export function checkDrift(planningDir) {
99
149
  return {
100
150
  drifted,
101
151
  noBaseline: false,
152
+ classification: drifted ? 'planning_state_drift' : 'clean',
153
+ compatibility: isLegacy ? 'legacy_v1' : null,
154
+ needsBaselineRefresh: isLegacy && !drifted,
102
155
  details,
103
- stored: { hash: stored.hash, timestamp: stored.timestamp },
104
- current: { hash: currentHash, sources: currentSources },
156
+ files,
157
+ stored: {
158
+ hash: stored.hash,
159
+ timestamp: stored.timestamp,
160
+ schemaVersion: stored.schemaVersion ?? null,
161
+ algorithm: stored.algorithm ?? null,
162
+ files: stored.files ?? null,
163
+ },
164
+ current: { hash: currentHash, sources: currentSources, files: currentFiles },
165
+ };
166
+ }
167
+
168
+ function classifyFileDrift(file, stored, currentSources, currentFiles, { legacy = false } = {}) {
169
+ const was = stored.sources?.[file] ?? false;
170
+ const now = currentSources[file];
171
+
172
+ if (was && !now) return { file, status: 'removed' };
173
+ if (!was && now) return { file, status: 'created' };
174
+ if (!was && !now) return { file, status: 'unchanged' };
175
+ if (legacy) return { file, status: 'unknown' };
176
+
177
+ const storedFile = stored.files?.[file];
178
+ if (!storedFile?.hash) return { file, status: 'unknown' };
179
+ return {
180
+ file,
181
+ status: storedFile.hash === currentFiles[file].hash ? 'unchanged' : 'changed',
105
182
  };
106
183
  }
@@ -69,6 +69,8 @@
69
69
  56. [Executable Brownfield Routing And Widen-Only Escalation](#d56---executable-brownfield-routing-and-widen-only-escalation)
70
70
  57. [Bounded Brownfield Growth And Context-Preserving Milestone Handoff](#d57---bounded-brownfield-growth-and-context-preserving-milestone-handoff)
71
71
  58. [Local Workflow Helper Launcher](#d58---local-workflow-helper-launcher)
72
+ 59. [Continuity Authority And Planning-State Drift](#d59---continuity-authority-and-planning-state-drift)
73
+ 60. [Release Closeout Contract](#d60---release-closeout-contract)
72
74
 
73
75
  ---
74
76
 
@@ -151,13 +153,13 @@ The same over-distillation pattern had also flattened `roadmapper.md`, `synthesi
151
153
 
152
154
  **Executor leverage audit (2026-03-13):**
153
155
 
154
- The executor was the last un-audited core lifecycle role. At 89 lines it was the most under-structured role contract in the system — no XML section boundaries, no mandatory initial read, no scope boundary, no typed output example, no auth-gate protocol, no completion checklist. The audit applied the same S12 hardening pattern.
156
+ The executor was the last un-audited core lifecycle role. At 89 lines it was the most under-structured role contract in the system — no XML section boundaries, no explicit context-intake tiers, no scope boundary, no typed output example, no auth-gate protocol, no completion checklist. The audit applied the same S12 hardening pattern.
155
157
 
156
- - **Executor kept from GSD:** mandatory initial-read discipline, explicit deviation-rule examples (null pointers, missing auth, missing dependency, new DB tables), auth-gate protocol (401/403 recognition, checkpoint return with exact auth steps), substantive summary quality gate, TDD RED/GREEN/REFACTOR steps with infrastructure detection, self-check discipline, and completion checklist.
158
+ - **Executor kept from GSD:** mandatory context-intake discipline, explicit deviation-rule examples (null pointers, missing auth, missing dependency, new DB tables), auth-gate protocol (401/403 recognition, checkpoint return with exact auth steps), substantive summary quality gate, TDD RED/GREEN/REFACTOR steps with infrastructure detection, self-check discipline, and completion checklist.
157
159
  - **Executor intentionally stripped:** wave-based parallelization, agent tracking journal, segment execution patterns A/B/C, auto-mode checkpoint routing (`auto_advance` config), per-task commit format `{type}({phase}-{plan}):`, `gsd-tools.cjs` CLI commands, template path references (`~/.claude/`), `user_setup` generation, `executor_model` selection, and codebase-map sync with dropped files (`STRUCTURE.md`, `INTEGRATIONS.md`).
158
160
  - **Executor gained in GSDD:** XML-bounded section structure, explicit scope boundary (plan-scoped, does not own planning/verification/milestone audit), typed SUMMARY.md output example with YAML frontmatter, portable auth-gate protocol (checkpoint:user with exact steps, not vendor-specific checkpoint return format), and execution-loop alignment with the current GSDD plan schema (`checkpoint:user`, `checkpoint:review`, change-impact discipline).
159
161
 
160
- The accompanying workflow alignment pass on `distilled/workflows/execute.md` added four targeted changes: mandatory read enforcement upgrade, auth-gate routing in the checkpoint protocol, concrete deviation-rule examples matching the role contract, and a substantive summary quality gate.
162
+ The accompanying workflow alignment pass on `distilled/workflows/execute.md` added four targeted changes: tiered context-intake enforcement, auth-gate routing in the checkpoint protocol, concrete deviation-rule examples matching the role contract, and a substantive summary quality gate.
161
163
 
162
164
  This hardening pass also clarified a reusable architectural rule: strict portable workflows are not enough if the canonical role contracts underneath them are flattened into prose. Role strictness and workflow strictness both matter.
163
165
 
@@ -581,7 +583,7 @@ Design principle unchanged: derive state from primary artifacts (ROADMAP.md, SPE
581
583
 
582
584
  **GSD:** No structural invariant tests. Framework correctness relies on manual review and ad-hoc checking.
583
585
 
584
- **GSDD:** 6 invariant suites (G1-G7, G2 reserved) with ~106 assertions enforce structural properties across all 29 framework markdown files. Every assertion message includes a `FIX:` instruction so CI agents can self-remediate.
586
+ **GSDD:** The guard and invariant suites enforce structural properties across framework markdown files. Every assertion message includes a `FIX:` instruction so CI agents can self-remediate.
585
587
 
586
588
  **Suite inventory:**
587
589
 
@@ -600,7 +602,7 @@ Design principle unchanged: derive state from primary artifacts (ROADMAP.md, SPE
600
602
 
601
603
  **Evidence:**
602
604
 
603
- - `tests/gsdd.invariants.test.cjs` lines 1015+ (6 suites, ~106 assertions)
605
+ - `tests/gsdd.invariants.test.cjs` and `tests/gsdd.guards.test.cjs` enforce structural drift checks with actionable `FIX:` messages
604
606
  - OpenAI Harness Engineering blog (Feb 2026): "error messages as enforcement mechanism"
605
607
  - External audit (2026-03-13): recommendation #4 "Mechanize the framework's invariants"
606
608
  - GSD source: no equivalent test infrastructure
@@ -954,6 +956,7 @@ Implementation lives under `bin/lib/`:
954
956
  | E6 | ERROR | `.planning/templates/research/` missing or empty |
955
957
  | E7 | ERROR | `.planning/templates/codebase/` missing or empty |
956
958
  | E8 | ERROR | `.planning/templates/` missing critical root files (`spec.md`, `roadmap.md`, `auth-matrix.md`) |
959
+ | E9 | ERROR | `.planning/templates/brownfield-change/` missing or missing critical files (`CHANGE.md`, `HANDOFF.md`, `VERIFICATION.md`) |
957
960
  | W1 | WARN | `generation-manifest.json` missing |
958
961
  | W2 | WARN | Template files modified locally (hash mismatch vs manifest) |
959
962
  | W3 | WARN | Template/role files missing from disk but listed in manifest |
@@ -963,8 +966,8 @@ Implementation lives under `bin/lib/`:
963
966
  | W7 | WARN | `distilled/DESIGN.md` health check table differs from implemented check IDs |
964
967
  | W8 | WARN | `distilled/README.md` workflow inventory differs from `distilled/workflows/` |
965
968
  | W9 | WARN | `.internal-research/gaps.md` references missing repo-local paths |
966
- | W10 | WARN | ROADMAP/SPEC requirement status drift |
967
- | W11 | WARN | Installed generated runtime surfaces drift from current render output |
969
+ | W10 | WARN | ROADMAP lifecycle status drift, including requirement checkbox and overview/detail phase status mismatches |
970
+ | W11 | WARN | Installed generated runtime/helper surfaces drift from current render output |
968
971
  | W12 | WARN | Planning state drifted since last recorded session (fingerprint mismatch) |
969
972
  | I1 | INFO | Generation manifest `frameworkVersion` differs from current `FRAMEWORK_VERSION` |
970
973
  | I2 | INFO | Phase completion count from ROADMAP |
@@ -987,15 +990,15 @@ Implementation lives under `bin/lib/`:
987
990
 
988
991
  3. **Pre-init guard.** If `.planning/config.json` doesn't exist, output a one-line message and exit 1. No partial checks — the workspace is simply not initialized.
989
992
 
990
- 4. **Split structural vs truth checks.** `bin/lib/health.mjs` keeps the structural workspace checks. `bin/lib/health-truth.mjs` holds the always-on cross-file truth checks (W7-W10) so the health surface can grow without turning the main command into one monolith.
993
+ 4. **Split structural vs truth checks.** `bin/lib/health.mjs` keeps the structural workspace checks. `bin/lib/health-truth.mjs` holds the always-on cross-file truth checks (W7-W12) so the health surface can grow without turning the main command into one monolith.
991
994
 
992
995
  5. **Reuses existing modules.** `readManifest()` and `detectModifications()` from `manifest.mjs` handle W1-W3. `isProjectInitialized()` pattern from `models.mjs` handles the pre-init guard. Truth checks stay read-only and operate on repo-local artifacts only when those framework files exist.
993
996
 
994
- 6. **Framework-source mode skips installed-project template checks.** Inside the GSDD framework repo itself, `distilled/templates/` is the source of truth and `.planning/templates/` is intentionally absent. `npx -y gsdd-cli health` therefore skips the installed-project template/manifest checks (E3-E8, W1-W3) in framework-source mode instead of producing false positives during self-health runs.
997
+ 6. **Framework-source mode skips installed-project template checks.** Inside the GSDD framework repo itself, `distilled/templates/` is the source of truth and `.planning/templates/` is intentionally absent. `npx -y gsdd-cli health` therefore skips the installed-project template/manifest checks (E3-E9, W1-W3) in framework-source mode instead of producing false positives during self-health runs.
995
998
 
996
999
  **What was removed vs GSD:**
997
1000
  - `--repair` flag and associated repair actions
998
- - Error codes E001-E005/W001-W007 (replaced with simpler E1-E8/W1-W12/I1-I3)
1001
+ - Error codes E001-E005/W001-W007 (replaced with simpler E1-E9/W1-W12/I1-I3)
999
1002
  - STATE.md checks (GSDD has no STATE.md per D7)
1000
1003
  - PROJECT.md checks (GSDD uses SPEC.md, not checked by health — it's workflow-authored)
1001
1004
  - Phase directory naming format checks (GSDD uses flat numbered files, not NN-name directories)
@@ -1365,6 +1368,7 @@ Both paths produce identical output: `{padded_phase}-APPROACH.md` in the phase d
1365
1368
  | 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 |
1366
1369
  | 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 |
1367
1370
  | 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 |
1371
+ | 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 |
1368
1372
  | Intermediate persistence | No persistence until final output | Confirmed decisions written to disk incrementally | Protects against context limits in long conversations |
1369
1373
  | Context loading | "Read everything" | JIT extraction guidance (e.g., "From SPEC.md read ONLY locked decisions") | Prevents context pollution with irrelevant content |
1370
1374
  | Plan-checker integration | None | New `approach_alignment` dimension in plan-checker | Verifies plans honor approach decisions, not just requirements |
@@ -1398,11 +1402,11 @@ Isolating research in subagents and returning compressed summaries follows the C
1398
1402
 
1399
1403
  **Trade-offs:**
1400
1404
 
1401
- - Benefit: planner receives locked user decisions instead of guessing approaches; plan-checker can verify approach alignment; context stays lean via research isolation
1405
+ - 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
1402
1406
  - 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
1403
1407
  - 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
1404
1408
 
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)
1409
+ **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)
1406
1410
 
1407
1411
  ---
1408
1412
 
@@ -2157,7 +2161,8 @@ Sub-gap (b) was closed by D28's `<persistence>` mandate and guarded by G30. Sub-
2157
2161
  - it reports blockers, owned writes, mutation expectations, and lifecycle posture
2158
2162
  - it does not mutate ROADMAP or milestone state itself
2159
2163
  - Keep `gsdd phase-status` as the only explicit ROADMAP mutator for phase-state transitions.
2160
- - Require transition-sensitive workflow contracts to call the shared preflight seam instead of narrating their own lifecycle inference.
2164
+ - Require transition-sensitive workflow contracts, including plan creation, to call the shared preflight seam instead of narrating their own lifecycle inference.
2165
+ - Treat planning-state drift as warning-only for read-only surfaces and blocking for owned-write surfaces, with file-level drift details from the session fingerprint helper.
2161
2166
  - Preserve `progress` as read-only and make it explicitly defer any recommended transition back to the downstream workflow's own preflight gate.
2162
2167
 
2163
2168
  **Why this fits the codebase:**
@@ -2170,7 +2175,9 @@ Sub-gap (b) was closed by D28's `<persistence>` mandate and guarded by G30. Sub-
2170
2175
  - `.planning/ROADMAP.md` (Phase 30 success criteria)
2171
2176
  - `bin/lib/lifecycle-preflight.mjs`
2172
2177
  - `bin/lib/lifecycle-state.mjs`
2178
+ - `bin/lib/session-fingerprint.mjs`
2173
2179
  - `bin/gsdd.mjs`
2180
+ - `distilled/workflows/plan.md`
2174
2181
  - `distilled/workflows/execute.md`
2175
2182
  - `distilled/workflows/verify.md`
2176
2183
  - `distilled/workflows/audit-milestone.md`
@@ -2179,6 +2186,7 @@ Sub-gap (b) was closed by D28's `<persistence>` mandate and guarded by G30. Sub-
2179
2186
  - `distilled/workflows/resume.md`
2180
2187
  - `distilled/workflows/progress.md`
2181
2188
  - `tests/phase.test.cjs`
2189
+ - `tests/session-fingerprint.test.cjs`
2182
2190
  - `tests/gsdd.guards.test.cjs`
2183
2191
  - `tests/gsdd.scenarios.test.cjs`
2184
2192
  - GSD comparison source: `get-shit-done/workflows/progress.md` still keeps lifecycle routing inside the workflow surface rather than through a shared helper seam, so this is an intentional GSDD tightening.
@@ -2188,7 +2196,7 @@ Sub-gap (b) was closed by D28's `<persistence>` mandate and guarded by G30. Sub-
2188
2196
  - `progress` can continue reporting lifecycle posture without inheriting write authority or becoming a hidden transition surface.
2189
2197
  - Phase 31 can build evidence-gated closure on top of a stable deterministic preflight contract instead of competing lifecycle entry logic.
2190
2198
 
2191
- **GSDD implementation:** `bin/lib/lifecycle-preflight.mjs`, `bin/lib/lifecycle-state.mjs`, `bin/gsdd.mjs`, `bin/lib/init.mjs`, `distilled/workflows/execute.md`, `distilled/workflows/verify.md`, `distilled/workflows/audit-milestone.md`, `distilled/workflows/complete-milestone.md`, `distilled/workflows/new-milestone.md`, `distilled/workflows/resume.md`, `distilled/workflows/progress.md`, `tests/phase.test.cjs`, `tests/gsdd.guards.test.cjs`, `tests/gsdd.scenarios.test.cjs`
2199
+ **GSDD implementation:** `bin/lib/lifecycle-preflight.mjs`, `bin/lib/lifecycle-state.mjs`, `bin/lib/session-fingerprint.mjs`, `bin/gsdd.mjs`, `bin/lib/init.mjs`, `distilled/workflows/plan.md`, `distilled/workflows/execute.md`, `distilled/workflows/verify.md`, `distilled/workflows/audit-milestone.md`, `distilled/workflows/complete-milestone.md`, `distilled/workflows/new-milestone.md`, `distilled/workflows/resume.md`, `distilled/workflows/progress.md`, `tests/phase.test.cjs`, `tests/session-fingerprint.test.cjs`, `tests/gsdd.guards.test.cjs`, `tests/gsdd.scenarios.test.cjs`
2192
2200
 
2193
2201
  ---
2194
2202
 
@@ -2646,6 +2654,126 @@ Sub-gap (b) was closed by D28's `<persistence>` mandate and guarded by G30. Sub-
2646
2654
  - Generated governance remains compact and routing-focused because helper-surface instructions stay out of `AGENTS.md`.
2647
2655
  - Cross-platform proof is stronger for the local-helper seam itself, but direct live validation still needs to stay conservative by environment: the repo now has focused tests plus Windows fixture proof; Linux/WSL live consumer validation remains a separate evidence question.
2648
2656
 
2657
+ ## D59 - Continuity Authority And Planning-State Drift
2658
+
2659
+ **Decision (2026-04-27):** Workspine continuity authority is split by surface. Git/worktree truth owns integration visibility and overwrite risk, `.planning/` owns local workflow contracts, phase artifacts own phase-local scope and proof, generated runtime surfaces own consumed helper/adapter freshness, and compressed judgment remains advisory context. Planning-state drift must stay warning-only for read-only/reporting surfaces, but mutating lifecycle surfaces must not silently proceed through material drift.
2660
+
2661
+ **Context:**
2662
+ - `.planning/` remains local-only by default in this framework repo. That preserves privacy and avoids noisy framework-internal planning commits, but it also means planning state can drift across sessions without git history protecting it.
2663
+ - Gap `I46` showed the concrete failure: one session wrote milestone state under ignored `.planning/`, another session read stale planning state and nearly routed execution as if the milestone did not exist.
2664
+ - Gap `S6` showed the related judgment failure: fresh sessions can recover artifact structure while losing the active constraints, unresolved uncertainty, decision posture, and anti-regression rules that explain how to continue safely.
2665
+ - Existing helper seams already detect part of the risk: `session-fingerprint.mjs` fingerprints `.planning/ROADMAP.md`, `.planning/SPEC.md`, and `.planning/config.json`; `lifecycle-preflight.mjs` exposes drift as `planning_state_drift`; `health` reports the same condition as `W12`.
2666
+
2667
+ **Authority matrix:**
2668
+
2669
+ | Surface | Owns | Does not own | Provenance check | Drift signal | Stop condition | Proof needed |
2670
+ | --- | --- | --- | --- | --- | --- | --- |
2671
+ | Git branch/HEAD | Integration surface identity, commit baseline, branch-local work context | Planning truth, phase status, judgment | `git rev-parse --abbrev-ref HEAD`; `git rev-parse --short HEAD` | Unexpected branch or HEAD relative to the active plan/change | Mutating workflow targets a different branch or HEAD than the active plan/change declares | Captured branch/HEAD before mutation; explicit acknowledgement if mismatched |
2672
+ | Staged changes | Pending commit contents and delivery visibility risk | Final repo truth until committed; planning authority | `git diff --name-only --cached` | Staged paths outside declared write set | Staged work overlaps unrelated scope or would be accidentally included | Staged path list reviewed against plan write set |
2673
+ | Unstaged changes | Local uncommitted edits and overwrite/conflict risk | Approved implementation state; phase closure | `git diff --name-only` | Dirty tracked files outside declared write set | Mutating workflow would overwrite or reinterpret unrelated edits | Dirty path list reviewed; user decision if conflict or overlap exists |
2674
+ | Untracked files | Local-only artifacts and possible proof gaps | Durable repo truth; public/delivery evidence | `git status --porcelain=v1` | Untracked required artifacts, generated dirs, or scope-expanding files | Required proof/output exists only untracked when closure claims tracked truth | Required artifacts are tracked intentionally or explicitly classified local-only |
2675
+ | `.planning/SPEC.md` | Local product/workflow requirements and active milestone requirement truth | Git-tracked public truth in the framework repo; branch delivery state | Read active requirements/current state; compare to roadmap and trackers | `W12`; mismatch with ROADMAP/TODO/gaps; stale active milestone | Mutating lifecycle action depends on stale or contradictory requirements | Fresh read plus drift acknowledgement/blocking behavior before mutation |
2676
+ | `.planning/ROADMAP.md` | Active milestone/phase ordering, status, success criteria, stop/replan contract | Artifact existence proof; implementation completion by itself | Read active phase section; lifecycle evaluator/preflight | `W12`; overview/detail mismatch; phase artifact mismatch | Execute/verify/audit/complete would act on stale or contradictory roadmap state | Preflight passes or blocks; phase status agrees with artifacts |
2677
+ | Phase PLAN/SUMMARY/VERIFICATION | Phase-local scope, execution result, verification result, compressed judgment handoff | Milestone-wide truth alone; git integration truth; generated runtime freshness | Check phase directory and required artifact sequence | PLAN without SUMMARY; SUMMARY missing for verify; VERIFICATION missing for completed phase | Execute without valid pending plan; verify without summary; close phase without verification | Required artifact exists, is substantive, and matches roadmap status |
2678
+ | Checkpoint files | Session-local resume context and mid-session compressed judgment | Durable status; routing authority over fresh roadmap/git truth | `.planning/.continue-here.md` and `.planning/.continue-here.bak` presence/classification | Checkpoint narrative conflicts with branch/worktree/planning truth; stale generic checkpoint | Resume would route from materially misleading checkpoint without acknowledgement | Resume surfaces checkpoint/planning/git split; material mismatch requires acknowledgement |
2679
+ | Brownfield CHANGE/HANDOFF/VERIFICATION | Medium-scope brownfield operational anchor, judgment handoff, closeout proof | Milestone phase state; roadmap-owned lifecycle; generic scratchpad | `.planning/brownfield-change/*` presence and lifecycle-state classification | Artifact branch/write-scope mismatch; missing sibling file; stale next action | Resume/progress would treat stale brownfield artifact as current without warning/acknowledgement | CHANGE primary, HANDOFF judgment-only, VERIFICATION proof; mismatch handled by progress/resume split |
2680
+ | Milestone audit | Milestone closure evidence and pass/fail posture | Phase execution; public release/delivery unless evidence says so | `.planning/<version>-MILESTONE-AUDIT.md`, `status: passed`, evidence contract | Missing audit for completion; audit not passed; evidence gaps | `complete-milestone` without passed audit or required evidence | Audit artifact exists, passed, and required evidence kinds are present |
2681
+ | Generated runtime surfaces | Consumed local runtime/helper surfaces generated from authored source | Authored workflow truth; planning status; branch truth | `gsdd health --json` runtime freshness and manifest comparison | `W11` drift from current render output | Phase behavior depends on generated-surface parity, or closure claims runtime freshness | Run the normal update path only when needed; health/checks prove freshness |
2682
+
2683
+ **Decision rules:**
2684
+ - Read-only/reporting surfaces may warn on planning-state drift and continue. They must not refresh or mutate the planning fingerprint as a side effect.
2685
+ - Owned-write lifecycle surfaces must treat material planning-state drift as a stop or explicit acknowledgement boundary before writing summary, verification, milestone, roadmap, or checkpoint-cleanup artifacts.
2686
+ - No-baseline fingerprint state is not itself proof of drift. It should be classified explicitly, but it must not strand first-session users unless another contradiction exists.
2687
+ - Compressed judgment remains the four-section `<judgment>` shape (`active_constraints`, `unresolved_uncertainty`, `decision_posture`, `anti_regression`) and remains subordinate to operational state.
2688
+ - A tracked coordination artifact is not justified by Phase 44 evidence alone. It becomes necessary only if deterministic local checks cannot prevent stale-read/overwrite behavior or if a future release claim requires fresh-clone/public evidence.
2689
+
2690
+ **Evidence:**
2691
+ - `.planning/phases/44-continuity-authority-and-persistence/44-APPROACH.md`
2692
+ - `.planning/phases/44-continuity-authority-and-persistence/44-PLAN.md`
2693
+ - `.planning/SPEC.md` (`REL-01`)
2694
+ - `.planning/ROADMAP.md` (Phase 44)
2695
+ - `.internal-research/gaps.md` (`I46`, `S6`)
2696
+ - `bin/lib/session-fingerprint.mjs`
2697
+ - `bin/lib/lifecycle-preflight.mjs`
2698
+ - `bin/lib/runtime-freshness.mjs`
2699
+ - `distilled/workflows/progress.md`
2700
+ - `distilled/workflows/resume.md`
2701
+ - `distilled/workflows/execute.md`
2702
+ - `distilled/workflows/verify.md`
2703
+ - `distilled/workflows/audit-milestone.md`
2704
+ - `distilled/workflows/complete-milestone.md`
2705
+ - `distilled/workflows/new-milestone.md`
2706
+ - `distilled/templates/brownfield-change/CHANGE.md`
2707
+ - `distilled/templates/brownfield-change/HANDOFF.md`
2708
+ - `distilled/templates/brownfield-change/VERIFICATION.md`
2709
+ - `tests/session-fingerprint.test.cjs`
2710
+ - `tests/phase.test.cjs`
2711
+
2712
+ **Consequences:**
2713
+ - Phase execution can remain local-first without pretending ignored `.planning/` files are unconditional authority.
2714
+ - Planning drift becomes a concrete lifecycle safety signal rather than a generic health warning that agents can ignore.
2715
+ - The design avoids adding a scratchpad or second state system while preserving enough compressed judgment to guide cold-start continuation.
2716
+ - The remaining implementation question is narrow: make helper output and targeted tests reflect this authority split without widening Phase 44 into generated-surface or release-closeout work.
2717
+
2718
+ ---
2719
+
2720
+ ## D60 - Release Closeout Contract
2721
+
2722
+ **Decision (2026-04-27, enforced 2026-04-27):** Release-quality milestone closeout uses a release claim posture layered over the existing evidence posture matrix. The allowed postures are `repo_closeout`, `runtime_validated_closeout`, and `delivery_supported_closeout`; each posture must stay within the fixed evidence kinds `code`, `test`, `runtime`, `delivery`, and `human`.
2723
+
2724
+ **Context:**
2725
+ - D50 already defined the closure evidence matrix for `verify`, `audit-milestone`, and `complete-milestone`, but `repo_only` and `delivery_sensitive` are evidence bars rather than wording boundaries.
2726
+ - D59 clarified that `.planning/` remains local-only by default, generated runtime surfaces own their own freshness, and public/delivery claims need git/worktree or tracked repo-visible proof.
2727
+ - Phase 45 needed a way to close repo-local milestone work honestly without implying GitHub Releases, package publishes, runtime parity, generated-surface freshness, or external availability.
2728
+ - GitHub Releases remain explicitly deferred under `LSC-05`, so release closeout cannot depend on public release objects unless a later milestone approves them.
2729
+
2730
+ **Decision:**
2731
+ - Add release claim posture semantics to `bin/lib/evidence-contract.mjs` without adding evidence kinds or replacing delivery postures.
2732
+ - Define the three postures as claim boundaries:
2733
+ - `repo_closeout`: default; permits repo-local closeout only and must not imply public support, runtime validation, delivery, publication, or generated-surface freshness.
2734
+ - `runtime_validated_closeout`: permits claims about a named runtime behavior or runtime surface only when `runtime` evidence exists for that exact runtime or surface.
2735
+ - `delivery_supported_closeout`: permits externally consumed release, install, support, or delivery claims only when the `delivery_sensitive` evidence bar is satisfied.
2736
+ - Thread the posture through `audit-milestone` as audit-owned release closeout metadata: unsupported claims, waivers, deferrals, and contradiction checks are recorded with the audit evidence contract.
2737
+ - Make `complete-milestone` inherit the audit posture and stop when unsupported claims, invalid waivers, missing evidence, incompatible posture metadata, or failed claim-scoped contradiction checks remain.
2738
+ - Keep `verify` out of the main release-claim decision path; phase verification still records evidence, while milestone audit and completion own release closeout.
2739
+ - Enforce the inherited contract in `lifecycle-preflight complete-milestone` so milestone completion cannot proceed from a passed audit that lacks release-claim metadata or still contains unsupported stronger claims, invalid waivers, missing required evidence, incompatible posture metadata, or failed claim-scoped contradiction checks.
2740
+
2741
+ **Why this fits the codebase:**
2742
+ - It preserves the compact D50 evidence matrix and avoids a new `release` evidence kind.
2743
+ - It avoids a new workflow lane or `gsdd-release` command by using the existing closeout surfaces.
2744
+ - It lets repo-local milestones close without fabricated delivery proof while preventing stronger public/runtime/delivery language from outrunning evidence.
2745
+ - It respects D59: local-only planning artifacts can support internal closeout, but public release/support claims need tracked public or repo-visible evidence.
2746
+
2747
+ **Waiver and deferral rule:**
2748
+ Waivers may narrow a claim posture or defer an unsupported claim, but they never satisfy missing required evidence for the stronger claim. Deferrals must name the unsupported claim, missing evidence kind(s), and later workflow or milestone candidate when known.
2749
+
2750
+ **Contradiction checks:**
2751
+ Closeout must check evidence, public-surface, runtime, delivery, planning-drift, and generated-surface contradictions. Generated-surface drift blocks only claims that depend on generated runtime/helper freshness; it does not fail unrelated `repo_closeout` claims.
2752
+
2753
+ Posture compatibility is part of that closeout contract: `repo_closeout` and `runtime_validated_closeout` are repo-local wording boundaries over `repo_only`, while `delivery_supported_closeout` requires the `delivery_sensitive` evidence bar.
2754
+
2755
+ **Evidence:**
2756
+ - `.planning/phases/45-release-closeout-contract/45-APPROACH.md`
2757
+ - `.planning/phases/45-release-closeout-contract/45-PLAN.md`
2758
+ - `.planning/phases/48-generated-helper-and-closeout-contract-parity/48-PLAN.md`
2759
+ - `.planning/research/45-RESEARCH.md`
2760
+ - `.planning/SPEC.md` (`REL-02`, deferred `LSC-05`)
2761
+ - `.planning/ROADMAP.md` (Phase 45)
2762
+ - `bin/lib/evidence-contract.mjs`
2763
+ - `bin/lib/lifecycle-preflight.mjs`
2764
+ - `distilled/workflows/audit-milestone.md`
2765
+ - `distilled/workflows/complete-milestone.md`
2766
+ - `distilled/DESIGN.md` D50 and D59
2767
+ - `tests/phase.test.cjs`
2768
+ - `tests/gsdd.guards.test.cjs`
2769
+ - `tests/gsdd.scenarios.test.cjs`
2770
+
2771
+ **Consequences:**
2772
+ - A milestone audit can now distinguish internal repo closeout, runtime-validated closeout, and delivery-supported closeout without changing evidence kinds.
2773
+ - Missing delivery or runtime evidence must produce a downgrade or deferral; it cannot be hidden behind human waiver prose.
2774
+ - `complete-milestone` now fails closed before archive writes when the passed audit omits or contradicts the release claim contract.
2775
+ - Public claims are scoped to tracked public or repo-visible proof, while GitHub Releases, tags, package publication, and release automation remain deferred until explicitly planned.
2776
+
2649
2777
  ## Maintenance
2650
2778
 
2651
2779
  This document is updated when:
@@ -101,7 +101,7 @@
101
101
  - `.internal-research/gsd-distilled-audit-13th-march-2026.md` — Highest-ROI recommendation #3
102
102
 
103
103
  ## D13 — Mechanical Invariant Enforcement
104
- - `tests/gsdd.invariants.test.cjs` lines 1015+ (6 suites, ~106 assertions)
104
+ - `tests/gsdd.invariants.test.cjs` and `tests/gsdd.guards.test.cjs` enforce structural drift checks with actionable `FIX:` messages
105
105
  - OpenAI Harness Engineering blog (Feb 2026): "error messages as enforcement mechanism"
106
106
  - External audit (2026-03-13): recommendation #4 "Mechanize the framework's invariants"
107
107
  - PRs #20-23: orphan `</output>` tags survived 4 manual review cycles before G4 caught them
@@ -212,7 +212,8 @@
212
212
  - `get-shit-done/workflows/discuss-phase.md` (gray area identification, GSD source)
213
213
  - `get-shit-done/workflows/list-phase-assumptions.md` (5-dimension assumption surfacing)
214
214
  - `get-shit-done/workflows/discovery-phase.md` (3-level research workflow)
215
- - `agents/approach-explorer.md`, `distilled/templates/delegates/approach-explorer.md`
215
+ - `agents/approach-explorer.md`, `distilled/templates/approach.md`, `distilled/templates/delegates/approach-explorer.md`, `distilled/templates/delegates/plan-checker.md`
216
+ - `distilled/workflows/plan.md`, `bin/adapters/opencode.mjs`, `tests/gsdd.guards.test.cjs`, `tests/gsdd.plan.adapters.test.cjs`, `tests/gsdd.scenarios.test.cjs`
216
217
 
217
218
  ## D30 — Hardening Propagation
218
219
  - D28 consumer audit (2026-03-21): persistence failures at every workflow boundary
@@ -357,12 +358,12 @@
357
358
  ## D49 — Deterministic Lifecycle Preflight Gates
358
359
  - `.planning/SPEC.md` (`ENGINE-01`, `ENGINE-02`, `ENGINE-03`)
359
360
  - `.planning/ROADMAP.md` (Phase 30)
360
- - `bin/lib/lifecycle-preflight.mjs`, `bin/lib/lifecycle-state.mjs`
361
+ - `bin/lib/lifecycle-preflight.mjs`, `bin/lib/lifecycle-state.mjs`, `bin/lib/session-fingerprint.mjs`
361
362
  - `bin/gsdd.mjs`, `bin/lib/init.mjs`
362
- - `distilled/workflows/execute.md`, `distilled/workflows/verify.md`
363
+ - `distilled/workflows/plan.md`, `distilled/workflows/execute.md`, `distilled/workflows/verify.md`
363
364
  - `distilled/workflows/audit-milestone.md`, `distilled/workflows/complete-milestone.md`
364
365
  - `distilled/workflows/new-milestone.md`, `distilled/workflows/resume.md`, `distilled/workflows/progress.md`
365
- - `tests/phase.test.cjs`, `tests/gsdd.guards.test.cjs`, `tests/gsdd.scenarios.test.cjs`
366
+ - `tests/phase.test.cjs`, `tests/session-fingerprint.test.cjs`, `tests/gsdd.guards.test.cjs`, `tests/gsdd.scenarios.test.cjs`
366
367
  - `get-shit-done/workflows/progress.md`
367
368
 
368
369
  ## D50 — Evidence-Gated Closure Matrix
@@ -454,6 +455,29 @@
454
455
  - `distilled/workflows/execute.md`, `distilled/workflows/verify.md`, `distilled/workflows/resume.md`, `distilled/workflows/progress.md`
455
456
  - `tests/gsdd.init.test.cjs`, `tests/gsdd.health.test.cjs`, `tests/gsdd.manifest.test.cjs`, `tests/phase.test.cjs`, `tests/gsdd.scenarios.test.cjs`
456
457
 
458
+ ## D59 — Continuity Authority And Planning-State Drift
459
+ - `.planning/phases/44-continuity-authority-and-persistence/44-APPROACH.md`
460
+ - `.planning/phases/44-continuity-authority-and-persistence/44-PLAN.md`
461
+ - `.planning/SPEC.md` (`REL-01`)
462
+ - `.planning/ROADMAP.md` (Phase 44)
463
+ - `.internal-research/gaps.md` (`I46`, `S6`)
464
+ - `bin/lib/session-fingerprint.mjs`, `bin/lib/lifecycle-preflight.mjs`, `bin/lib/runtime-freshness.mjs`
465
+ - `distilled/workflows/progress.md`, `distilled/workflows/resume.md`, `distilled/workflows/plan.md`, `distilled/workflows/execute.md`, `distilled/workflows/verify.md`, `distilled/workflows/audit-milestone.md`, `distilled/workflows/complete-milestone.md`, `distilled/workflows/new-milestone.md`
466
+ - `distilled/templates/brownfield-change/CHANGE.md`, `distilled/templates/brownfield-change/HANDOFF.md`, `distilled/templates/brownfield-change/VERIFICATION.md`
467
+ - `tests/session-fingerprint.test.cjs`, `tests/phase.test.cjs`
468
+
469
+ ## D60 — Release Closeout Contract
470
+ - `.planning/phases/45-release-closeout-contract/45-APPROACH.md`
471
+ - `.planning/phases/45-release-closeout-contract/45-PLAN.md`
472
+ - `.planning/phases/48-generated-helper-and-closeout-contract-parity/48-PLAN.md`
473
+ - `.planning/research/45-RESEARCH.md`
474
+ - `.planning/SPEC.md` (`REL-02`, deferred `LSC-05`)
475
+ - `.planning/ROADMAP.md` (Phase 45)
476
+ - `bin/lib/evidence-contract.mjs`, `bin/lib/lifecycle-preflight.mjs`
477
+ - `distilled/workflows/audit-milestone.md`, `distilled/workflows/complete-milestone.md`
478
+ - `distilled/DESIGN.md` D50 and D59
479
+ - `tests/phase.test.cjs`, `tests/gsdd.guards.test.cjs`, `tests/gsdd.scenarios.test.cjs`
480
+
457
481
  ---
458
482
 
459
483
  ## Maintenance
@@ -6,6 +6,8 @@ Template for `.planning/phases/XX-name/{phase_num}-APPROACH.md` — captures imp
6
6
 
7
7
  **Key principle:** The top-level structure (`<domain>`, `<decisions>`, `<assumptions>`, `<deferred>`) is fixed. Section names WITHIN `<decisions>` emerge from what was actually discussed for THIS phase — a CLI phase has CLI-relevant sections, a UI phase has UI-relevant sections.
8
8
 
9
+ **Alignment proof:** When `.planning/config.json` has `workflow.discuss: true`, every APPROACH artifact must include an `## Alignment Proof` section before `<domain>`. It must record the canonical fields `alignment_status`, `alignment_method`, `user_confirmed_at`, `explicit_skip_approved`, `skip_scope`, `skip_rationale`, and `confirmed_decisions`. `Agent's Discretion` and agent-only "No questions needed" are not valid proof.
10
+
9
11
  **Downstream consumers:**
10
12
  - `planner` — Reads decisions to constrain implementation choices. Locked decisions must be implemented. Agent's Discretion items allow planner flexibility.
11
13
  - `plan-checker` — Reads decisions to verify plans implement chosen approaches (approach_alignment dimension). Flags plans that contradict explicit user choices.
@@ -20,6 +22,18 @@ Template for `.planning/phases/XX-name/{phase_num}-APPROACH.md` — captures imp
20
22
  **Explored:** [date]
21
23
  **Status:** Ready for planning
22
24
 
25
+ ## Alignment Proof
26
+
27
+ - `workflow.discuss`: [true | false]
28
+ - `alignment_status`: [user_confirmed | approved_skip | not_required]
29
+ - `alignment_method`: [conversation source, e.g. runtime command or user message]
30
+ - `user_confirmed_at`: [date or N/A]
31
+ - `explicit_skip_approved`: [true | false]
32
+ - `skip_scope`: [phase-wide / named gray area / N/A]
33
+ - `skip_rationale`: [why the user approved skipping discussion, or N/A]
34
+ - `confirmed_decisions`:
35
+ - [User-confirmed decision, or "N/A - approved skip"]
36
+
23
37
  <domain>
24
38
  ## Phase Boundary
25
39
 
@@ -87,6 +101,19 @@ Template for `.planning/phases/XX-name/{phase_num}-APPROACH.md` — captures imp
87
101
  **Explored:** 2026-03-22
88
102
  **Status:** Ready for planning
89
103
 
104
+ ## Alignment Proof
105
+
106
+ - `workflow.discuss`: true
107
+ - `alignment_status`: user_confirmed
108
+ - `alignment_method`: planning conversation
109
+ - `user_confirmed_at`: 2026-03-22
110
+ - `explicit_skip_approved`: false
111
+ - `skip_scope`: N/A
112
+ - `skip_rationale`: N/A
113
+ - `confirmed_decisions`:
114
+ - Use Recharts for chart rendering
115
+ - Use react-grid-layout for dashboard widgets
116
+
90
117
  <domain>
91
118
  ## Phase Boundary
92
119
 
@@ -158,6 +185,19 @@ Build an interactive dashboard with configurable widgets. Users can view metrics
158
185
  **Explored:** 2026-03-22
159
186
  **Status:** Ready for planning
160
187
 
188
+ ## Alignment Proof
189
+
190
+ - `workflow.discuss`: true
191
+ - `alignment_status`: user_confirmed
192
+ - `alignment_method`: planning conversation
193
+ - `user_confirmed_at`: 2026-03-22
194
+ - `explicit_skip_approved`: false
195
+ - `skip_scope`: N/A
196
+ - `skip_rationale`: N/A
197
+ - `confirmed_decisions`:
198
+ - Use HTTP-only cookies with JWT
199
+ - Use structured JSON errors
200
+
161
201
  <domain>
162
202
  ## Phase Boundary
163
203
 
@@ -4,8 +4,11 @@ You are the approach explorer delegate for the plan workflow.
4
4
 
5
5
  **Your job:** Identify gray areas in the target phase, research viable approaches for technical decisions, conduct an adaptive conversation with the user to capture locked decisions, and write APPROACH.md to the phase directory.
6
6
 
7
+ When `workflow.discuss: true`, APPROACH.md must prove user alignment before planning: use `alignment_status: user_confirmed` for real user-confirmed decisions or `alignment_status: approved_skip` only when the user explicitly approves skipping discussion. Record the canonical fields `alignment_method`, `user_confirmed_at`, `explicit_skip_approved`, `skip_scope`, `skip_rationale`, and `confirmed_decisions`. `Agent's Discretion` and agent-only "No questions needed" are not valid alignment proof.
8
+
7
9
  Read only the explicit inputs provided by the orchestrator:
8
10
  - target phase goal and requirement IDs from `.planning/ROADMAP.md`
11
+ - project config from `.planning/config.json`, especially `workflow.discuss`
9
12
  - locked decisions and deferred items from `.planning/SPEC.md`
10
13
  - phase research file (if exists)
11
14
  - relevant codebase files (existing patterns and conventions)