@opengsd/gsd-core 1.7.0 → 1.9.0

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.
Files changed (261) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +45 -1
  4. package/README.md +2 -0
  5. package/agents/gsd-code-fixer.md +1 -1
  6. package/agents/gsd-codebase-mapper.md +1 -1
  7. package/agents/gsd-debug-session-manager.md +78 -4
  8. package/agents/gsd-debugger.md +87 -29
  9. package/agents/gsd-executor.md +49 -9
  10. package/agents/gsd-intel-updater.md +3 -3
  11. package/agents/gsd-phase-researcher.md +4 -2
  12. package/agents/gsd-plan-checker.md +20 -0
  13. package/agents/gsd-planner.md +44 -59
  14. package/agents/gsd-project-researcher.md +2 -2
  15. package/agents/gsd-ui-auditor.md +0 -40
  16. package/agents/gsd-verifier.md +2 -2
  17. package/bin/install.js +1338 -135
  18. package/commands/gsd/ai-integration-phase.md +1 -1
  19. package/commands/gsd/mempalace-capture.md +9 -5
  20. package/commands/gsd/new-milestone.md +1 -1
  21. package/commands/gsd/plan-phase.md +5 -3
  22. package/commands/gsd/plan-review-convergence.md +7 -2
  23. package/gsd-core/bin/gsd-tools.cjs +2690 -2472
  24. package/gsd-core/bin/lib/adapter-imperative.cjs +8 -1
  25. package/gsd-core/bin/lib/agent-command-router.cjs +20 -5
  26. package/gsd-core/bin/lib/api-coverage.cjs +360 -53
  27. package/gsd-core/bin/lib/audit.cjs +8 -8
  28. package/gsd-core/bin/lib/broken-windows.cjs +716 -0
  29. package/gsd-core/bin/lib/capability-command-router.cjs +733 -0
  30. package/gsd-core/bin/lib/capability-consent.cjs +40 -1
  31. package/gsd-core/bin/lib/capability-lifecycle.cjs +58 -0
  32. package/gsd-core/bin/lib/capability-loader.cjs +23 -1
  33. package/gsd-core/bin/lib/capability-registry.cjs +1450 -160
  34. package/gsd-core/bin/lib/capability-trust.cjs +468 -33
  35. package/gsd-core/bin/lib/capability-validator.cjs +882 -6
  36. package/gsd-core/bin/lib/capability-writer.cjs +6 -1
  37. package/gsd-core/bin/lib/check-command-router.cjs +140 -27
  38. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +15 -0
  39. package/gsd-core/bin/lib/claude-orchestration-command-router.cjs +209 -31
  40. package/gsd-core/bin/lib/claude-orchestration.cjs +203 -25
  41. package/gsd-core/bin/lib/command-aliases.cjs +14 -0
  42. package/gsd-core/bin/lib/commands.cjs +326 -21
  43. package/gsd-core/bin/lib/config-loader.cjs +214 -30
  44. package/gsd-core/bin/lib/config.cjs +158 -22
  45. package/gsd-core/bin/lib/core-utils.cjs +6 -1
  46. package/gsd-core/bin/lib/decisions.cjs +32 -8
  47. package/gsd-core/bin/lib/docs.cjs +6 -0
  48. package/gsd-core/bin/lib/estimate-cli.cjs +336 -0
  49. package/gsd-core/bin/lib/external-descriptor-trust.cjs +14 -2
  50. package/gsd-core/bin/lib/frontmatter.cjs +125 -15
  51. package/gsd-core/bin/lib/gap-checker.cjs +17 -2
  52. package/gsd-core/bin/lib/host-integration.cjs +215 -8
  53. package/gsd-core/bin/lib/init.cjs +155 -66
  54. package/gsd-core/bin/lib/install-engine.cjs +299 -23
  55. package/gsd-core/bin/lib/install-profiles.cjs +239 -1
  56. package/gsd-core/bin/lib/installer-migrations/005-opencode-baseline-commands-dir.cjs +146 -0
  57. package/gsd-core/bin/lib/installer-migrations/006-pi-extension-cjs-to-js.cjs +91 -0
  58. package/gsd-core/bin/lib/installer-migrations.cjs +44 -5
  59. package/gsd-core/bin/lib/markdown-sectionizer.cjs +107 -0
  60. package/gsd-core/bin/lib/milestone.cjs +248 -14
  61. package/gsd-core/bin/lib/model-catalog.cjs +69 -4
  62. package/gsd-core/bin/lib/model-resolver.cjs +189 -7
  63. package/gsd-core/bin/lib/observability/logger.cjs +7 -2
  64. package/gsd-core/bin/lib/onboard-projection.cjs +11 -8
  65. package/gsd-core/bin/lib/phase-command-router.cjs +10 -1
  66. package/gsd-core/bin/lib/phase-estimation.cjs +398 -0
  67. package/gsd-core/bin/lib/phase-id.cjs +304 -9
  68. package/gsd-core/bin/lib/phase.cjs +258 -17
  69. package/gsd-core/bin/lib/plan-drift-guard.cjs +1 -1
  70. package/gsd-core/bin/lib/plan-scan.cjs +70 -2
  71. package/gsd-core/bin/lib/planning-workspace.cjs +9 -2
  72. package/gsd-core/bin/lib/profile-output.cjs +34 -8
  73. package/gsd-core/bin/lib/review-lane-descriptor.cjs +927 -0
  74. package/gsd-core/bin/lib/review-lane-invocation.cjs +348 -0
  75. package/gsd-core/bin/lib/review-lane-runner.cjs +594 -0
  76. package/gsd-core/bin/lib/review-reviewer-selection.cjs +114 -32
  77. package/gsd-core/bin/lib/roadmap-parser.cjs +61 -10
  78. package/gsd-core/bin/lib/roadmap.cjs +23 -7
  79. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +38 -5
  80. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +23 -9
  81. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +156 -0
  82. package/gsd-core/bin/lib/runtime-name-policy.cjs +15 -2
  83. package/gsd-core/bin/lib/smart-entry.cjs +70 -5
  84. package/gsd-core/bin/lib/state-document.cjs +171 -24
  85. package/gsd-core/bin/lib/state-transition.cjs +50 -11
  86. package/gsd-core/bin/lib/state.cjs +206 -32
  87. package/gsd-core/bin/lib/surface.cjs +51 -9
  88. package/gsd-core/bin/lib/uat-predicate.cjs +6 -4
  89. package/gsd-core/bin/lib/uat.cjs +428 -11
  90. package/gsd-core/bin/lib/ui-consideration-probe.cjs +2 -2
  91. package/gsd-core/bin/lib/unusable-input.cjs +216 -0
  92. package/gsd-core/bin/lib/validate.cjs +44 -8
  93. package/gsd-core/bin/lib/verification.cjs +163 -31
  94. package/gsd-core/bin/lib/verify.cjs +348 -42
  95. package/gsd-core/bin/lib/worktree-safety.cjs +360 -15
  96. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  97. package/gsd-core/bin/shared/config-schema.manifest.json +4 -15
  98. package/gsd-core/bin/shared/model-catalog.json +5 -0
  99. package/gsd-core/bin/shared/runtime-aliases.manifest.json +5 -0
  100. package/gsd-core/references/api-coverage.md +37 -7
  101. package/gsd-core/references/checkpoints.md +1 -1
  102. package/gsd-core/references/common-bug-patterns.md +13 -0
  103. package/gsd-core/references/context-budget.md +40 -0
  104. package/gsd-core/references/debugger-bug-taxonomy.md +111 -0
  105. package/gsd-core/references/debugger-fix-acceptance.md +157 -0
  106. package/gsd-core/references/debugger-philosophy.md +1 -0
  107. package/gsd-core/references/debugger-prevention.md +98 -0
  108. package/gsd-core/references/debugger-rca-branching.md +98 -0
  109. package/gsd-core/references/debugger-repro-hardening.md +130 -0
  110. package/gsd-core/references/debugger-sbfl.md +110 -0
  111. package/gsd-core/references/debugger-semantic-recall.md +81 -0
  112. package/gsd-core/references/execute-phase-quota-recovery.md +55 -0
  113. package/gsd-core/references/execute-phase-requirement-revert.md +8 -0
  114. package/gsd-core/references/execute-phase-response-language.md +7 -0
  115. package/gsd-core/references/gate-prompts.md +6 -3
  116. package/gsd-core/references/model-profile-resolution.md +64 -13
  117. package/gsd-core/references/offer-next.md +88 -0
  118. package/gsd-core/references/planner-antipatterns.md +6 -0
  119. package/gsd-core/references/planner-mvp-mode.md +12 -13
  120. package/gsd-core/references/planner-preconditions.md +156 -0
  121. package/gsd-core/references/planner-reversibility.md +132 -0
  122. package/gsd-core/references/planning-config.md +2 -1
  123. package/gsd-core/references/reviewer-instances.md +28 -19
  124. package/gsd-core/references/runtime-aware-dispatch.md +42 -0
  125. package/gsd-core/references/skeleton-template.md +1 -1
  126. package/gsd-core/references/thinking-models-planning.md +3 -1
  127. package/gsd-core/references/ui-consideration-probe.md +2 -2
  128. package/gsd-core/references/worktree-branch-check.md +4 -4
  129. package/gsd-core/templates/DEBUG.md +5 -3
  130. package/gsd-core/templates/summary-minimal.md +4 -0
  131. package/gsd-core/templates/summary-standard.md +4 -0
  132. package/gsd-core/templates/summary.md +7 -0
  133. package/gsd-core/workflows/add-phase.md +2 -0
  134. package/gsd-core/workflows/add-tests.md +3 -1
  135. package/gsd-core/workflows/add-todo.md +32 -1
  136. package/gsd-core/workflows/ai-integration-phase.md +8 -6
  137. package/gsd-core/workflows/audit-fix.md +6 -2
  138. package/gsd-core/workflows/audit-milestone.md +8 -0
  139. package/gsd-core/workflows/autonomous.md +19 -15
  140. package/gsd-core/workflows/check-todos.md +5 -3
  141. package/gsd-core/workflows/cleanup.md +7 -1
  142. package/gsd-core/workflows/code-review-fix.md +14 -6
  143. package/gsd-core/workflows/code-review.md +93 -24
  144. package/gsd-core/workflows/complete-milestone.md +3 -0
  145. package/gsd-core/workflows/debug.md +35 -7
  146. package/gsd-core/workflows/diagnose-issues.md +5 -1
  147. package/gsd-core/workflows/discovery-phase.md +7 -0
  148. package/gsd-core/workflows/discuss-phase/modes/advisor.md +2 -4
  149. package/gsd-core/workflows/discuss-phase/modes/auto.md +0 -6
  150. package/gsd-core/workflows/discuss-phase/templates/context.md +16 -2
  151. package/gsd-core/workflows/discuss-phase-assumptions.md +18 -9
  152. package/gsd-core/workflows/discuss-phase.md +2 -2
  153. package/gsd-core/workflows/do.md +7 -1
  154. package/gsd-core/workflows/docs-update.md +9 -0
  155. package/gsd-core/workflows/eval-review.md +4 -1
  156. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +4 -0
  157. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +160 -0
  158. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +4 -4
  159. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -2
  160. package/gsd-core/workflows/execute-phase.md +110 -149
  161. package/gsd-core/workflows/execute-plan.md +20 -8
  162. package/gsd-core/workflows/explore.md +4 -0
  163. package/gsd-core/workflows/extract-learnings.md +21 -0
  164. package/gsd-core/workflows/graduation.md +3 -0
  165. package/gsd-core/workflows/health.md +7 -1
  166. package/gsd-core/workflows/help/modes/full.md +9 -5
  167. package/gsd-core/workflows/import.md +11 -2
  168. package/gsd-core/workflows/inbox.md +7 -0
  169. package/gsd-core/workflows/ingest-docs.md +19 -10
  170. package/gsd-core/workflows/manager.md +3 -1
  171. package/gsd-core/workflows/map-codebase.md +17 -10
  172. package/gsd-core/workflows/mvp-phase.md +3 -0
  173. package/gsd-core/workflows/new-milestone.md +79 -23
  174. package/gsd-core/workflows/new-project.md +28 -19
  175. package/gsd-core/workflows/new-workspace.md +3 -1
  176. package/gsd-core/workflows/next.md +5 -2
  177. package/gsd-core/workflows/onboard.md +3 -0
  178. package/gsd-core/workflows/plan-phase.md +56 -51
  179. package/gsd-core/workflows/plan-review-convergence.md +61 -12
  180. package/gsd-core/workflows/plant-seed.md +3 -0
  181. package/gsd-core/workflows/profile-user.md +7 -1
  182. package/gsd-core/workflows/progress.md +31 -3
  183. package/gsd-core/workflows/quick.md +33 -10
  184. package/gsd-core/workflows/remove-workspace.md +3 -0
  185. package/gsd-core/workflows/review.md +172 -585
  186. package/gsd-core/workflows/scan.md +10 -2
  187. package/gsd-core/workflows/secure-phase.md +13 -2
  188. package/gsd-core/workflows/settings-integrations.md +3 -0
  189. package/gsd-core/workflows/settings.md +3 -0
  190. package/gsd-core/workflows/ship.md +88 -11
  191. package/gsd-core/workflows/sketch.md +3 -0
  192. package/gsd-core/workflows/smart-entry.md +4 -1
  193. package/gsd-core/workflows/spike.md +7 -1
  194. package/gsd-core/workflows/ui-phase.md +11 -2
  195. package/gsd-core/workflows/ui-review.md +11 -1
  196. package/gsd-core/workflows/undo.md +7 -0
  197. package/gsd-core/workflows/update.md +106 -5
  198. package/gsd-core/workflows/validate-phase.md +13 -2
  199. package/gsd-core/workflows/verify-phase.md +2 -2
  200. package/gsd-core/workflows/verify-work.md +15 -4
  201. package/hooks/dist/gsd-context-monitor.js +27 -9
  202. package/hooks/dist/gsd-cursor-session-start.js +6 -2
  203. package/hooks/dist/gsd-cursor-stop.js +6 -2
  204. package/hooks/dist/gsd-cursor-subagent-start.js +6 -2
  205. package/hooks/dist/gsd-graphify-update.sh +9 -0
  206. package/hooks/dist/gsd-phase-boundary.sh +14 -2
  207. package/hooks/dist/gsd-prompt-guard.js +101 -2
  208. package/hooks/dist/gsd-read-guard.js +100 -2
  209. package/hooks/dist/gsd-read-injection-scanner.js +109 -2
  210. package/hooks/dist/gsd-statusline.js +97 -9
  211. package/hooks/dist/gsd-workflow-guard.js +110 -6
  212. package/hooks/dist/gsd-worktree-path-guard.js +132 -8
  213. package/hooks/dist/lib/cursor-workspace.js +74 -0
  214. package/hooks/gsd-context-monitor.js +27 -9
  215. package/hooks/gsd-cursor-session-start.js +6 -2
  216. package/hooks/gsd-cursor-stop.js +6 -2
  217. package/hooks/gsd-cursor-subagent-start.js +6 -2
  218. package/hooks/gsd-graphify-update.sh +9 -0
  219. package/hooks/gsd-phase-boundary.sh +14 -2
  220. package/hooks/gsd-prompt-guard.js +101 -2
  221. package/hooks/gsd-read-guard.js +100 -2
  222. package/hooks/gsd-read-injection-scanner.js +109 -2
  223. package/hooks/gsd-statusline.js +97 -9
  224. package/hooks/gsd-workflow-guard.js +110 -6
  225. package/hooks/gsd-worktree-path-guard.js +132 -8
  226. package/hooks/lib/cursor-workspace.js +74 -0
  227. package/package.json +10 -8
  228. package/pi/gsd.cjs +34 -3
  229. package/scripts/changeset/lint.cjs +1 -0
  230. package/scripts/changeset/parse.cjs +26 -0
  231. package/scripts/check-coverage-gate.cjs +51 -0
  232. package/scripts/check-glossary-refs.cjs +244 -0
  233. package/scripts/ci-rebase-check.cjs +48 -4
  234. package/scripts/ci-test-scope.cjs +67 -17
  235. package/scripts/gen-adr-index.cjs +528 -0
  236. package/scripts/gen-capability-matrix.cjs +26 -2
  237. package/scripts/gen-capability-registry.cjs +132 -34
  238. package/scripts/gen-emitted-baseline.cjs +145 -0
  239. package/scripts/gen-test-timings.cjs +201 -0
  240. package/scripts/lint-compiled-artifact-sync.cjs +146 -0
  241. package/scripts/lint-emitted-drift-ack.cjs +149 -0
  242. package/scripts/lint-fix-has-regression-test.cjs +131 -0
  243. package/scripts/lint-portable-timeout.cjs +140 -0
  244. package/scripts/lint-resolution-provenance.cjs +9 -0
  245. package/scripts/lint-test-file-count.allowlist.json +1 -0
  246. package/scripts/mutation-matrix.cjs +4 -0
  247. package/scripts/prompt-injection-scan.sh +6 -0
  248. package/scripts/registry-schema.cjs +57 -8
  249. package/scripts/release-notes/conventional-title.cjs +19 -1
  250. package/scripts/release-notes/format-github-release-notes.cjs +7 -3
  251. package/scripts/release-tarball-smoke.cjs +18 -11
  252. package/scripts/run-tests.cjs +420 -58
  253. package/scripts/workflow-size.cjs +16 -8
  254. package/skills/gsd-ai-integration-phase/SKILL.md +1 -1
  255. package/skills/gsd-mempalace-capture/SKILL.md +9 -5
  256. package/skills/gsd-new-milestone/SKILL.md +1 -1
  257. package/skills/gsd-plan-phase/SKILL.md +5 -3
  258. package/skills/gsd-plan-review-convergence/SKILL.md +7 -2
  259. package/vscode/package.json +1 -1
  260. package/scripts/gen-golden-install-parity-zcode.cjs +0 -77
  261. package/scripts/update-size-baseline.cjs +0 -68
@@ -9,7 +9,7 @@
9
9
  {
10
10
  "name": "gsd-core",
11
11
  "description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
12
- "version": "1.7.0",
12
+ "version": "1.9.0",
13
13
  "source": "./",
14
14
  "author": {
15
15
  "name": "open-gsd",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gsd-core",
3
3
  "displayName": "GSD Core",
4
- "version": "1.7.0",
4
+ "version": "1.9.0",
5
5
  "description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
6
6
  "author": {
7
7
  "name": "open-gsd",
@@ -200,9 +200,23 @@ function mapToolInput(args) {
200
200
  * @param {string} [opts.cwd] working directory for the child
201
201
  * @returns {{ stdout: string, exitCode: number, timedOut: boolean }}
202
202
  */
203
+ const warnedMissingHooks = new Set();
204
+
203
205
  function runHook(hookFile, payload, opts = {}) {
204
206
  const hookPath = path.join(HOOKS_DIR, hookFile);
205
207
  if (!fs.existsSync(hookPath)) {
208
+ // A missing guard script means the guard is silently NOT enforced — the
209
+ // exact failure mode of #2305 (plugin staged, hooks bundle not). Never
210
+ // break the tool call (the adapter's design contract), but never be
211
+ // silent about it either: warn loudly, once per hook file.
212
+ if (!warnedMissingHooks.has(hookFile)) {
213
+ warnedMissingHooks.add(hookFile);
214
+ console.error(
215
+ `[gsd-core] hook script missing: ${hookPath} — ${hookFile} is NOT ` +
216
+ "enforced. The GSD install may be incomplete; reinstall (or run " +
217
+ "/gsd-update) to restage the hooks/ bundle.",
218
+ );
219
+ }
206
220
  return { stdout: "", exitCode: 0, timedOut: false };
207
221
  }
208
222
  const timeout = opts.timeout ?? 8000;
@@ -225,6 +239,32 @@ function runHook(hookFile, payload, opts = {}) {
225
239
  return { stdout, exitCode, timedOut: result.signal === "SIGTERM" };
226
240
  }
227
241
 
242
+ /**
243
+ * In-process check for whether context-usage warnings are disabled in project
244
+ * config. Mirrors the exact semantics of the same check inside
245
+ * hooks/gsd-context-monitor.js (introduced by #1073): an explicit
246
+ * `config.hooks.context_warnings === false` disables them; a missing or
247
+ * unparseable .planning/config.json keeps them enabled (the default).
248
+ *
249
+ * #2697: hoisting this check in-process lets the adapter SKIP the context-monitor
250
+ * spawn entirely when the user has opted out, instead of paying a full Node boot
251
+ * inside the child only to read the boolean and exit. Missing/unparseable config
252
+ * MUST behave identically to the hook (enabled) so the default path is unchanged.
253
+ *
254
+ * @param {string} cwd project working directory (the plugin's currentCwd)
255
+ * @returns {boolean} true when context warnings are explicitly disabled
256
+ */
257
+ function contextWarningsDisabled(cwd) {
258
+ try {
259
+ const configPath = path.join(cwd, '.planning', 'config.json');
260
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
261
+ return config.hooks?.context_warnings === false;
262
+ } catch {
263
+ // Missing or unparseable config → proceed with defaults (context warnings enabled).
264
+ return false;
265
+ }
266
+ }
267
+
228
268
  // ---------------------------------------------------------------------------
229
269
  // Hook output translation → OpenCode semantics
230
270
  // ---------------------------------------------------------------------------
@@ -573,7 +613,11 @@ const GsdCorePlugin = async ({ directory } = {}) => {
573
613
 
574
614
  // gsd-context-monitor.js — context usage warnings (Bash/Edit/Write/Task/...)
575
615
  // Only meaningful when a session_id is tracked (writes metrics sentinel).
576
- if (currentSessionId) {
616
+ // #2697: skip the subprocess spawn entirely when context warnings are
617
+ // explicitly disabled in project config — the hook would exit early anyway,
618
+ // so hoisting the check in-process avoids paying a Node boot per tool call.
619
+ // Missing/unparseable config = enabled (default), so the spawn still runs.
620
+ if (currentSessionId && !contextWarningsDisabled(cwd)) {
577
621
  const payload = {
578
622
  hook_event_name: "PostToolUse",
579
623
  tool_name: claudeTool,
package/README.md CHANGED
@@ -60,6 +60,8 @@ New here? Follow [Your first project](docs/tutorials/your-first-project.md) for
60
60
 
61
61
  ## Documentation
62
62
 
63
+ **What's new in 1.7.0** → [docs/whats-new-1.7.0.md](docs/whats-new-1.7.0.md)
64
+
63
65
  **Tutorials** — learning by doing:
64
66
  - [Your first project](docs/tutorials/your-first-project.md)
65
67
  - [Onboarding an existing codebase](docs/tutorials/onboarding-an-existing-codebase.md)
@@ -456,7 +456,7 @@ For each finding in sorted order:
456
456
 
457
457
  **If verification passed:**
458
458
 
459
- Use `gsd-tools query commit` with conventional format (message first, then every staged file path):
459
+ Use `gsd_run query commit` with conventional format (message first, then every staged file path):
460
460
  ```bash
461
461
  _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
462
462
  gsd_run query commit \
@@ -175,7 +175,7 @@ Write document(s) to `.planning/codebase/` using the templates below.
175
175
  **Document naming:** UPPERCASE.md (e.g., STACK.md, ARCHITECTURE.md)
176
176
 
177
177
  **Template filling:**
178
- 1. Replace `[YYYY-MM-DD]` with the date provided in your prompt (the `Today's date:` line). NEVER guess or infer the date — always use the exact date from the prompt.
178
+ 1. Set the `**Analysis Date:**` line, the `*... analysis: ...*` footer, and any `<!-- refreshed: ... -->` header to the date provided in your prompt (the `Today's date:` line), overwriting whatever date is already there. NEVER guess or infer the date — always use the exact date from the prompt.
179
179
  2. Replace `[Placeholder text]` with findings from exploration
180
180
  3. If something is not found, use "Not detected" or "Not applicable"
181
181
  4. Always include file paths with backticks
@@ -270,30 +270,102 @@ If user selects 1 or 2: spawn continuation agent (with any additional context pr
270
270
 
271
271
  If user selects 3: proceed to Step 4 with fix = "not applied".
272
272
 
273
+ ### 3f. FIX REJECTED BY GUARDRAIL
274
+
275
+ When agent returns `## FIX REJECTED BY GUARDRAIL`:
276
+
277
+ Present the failing signal and evidence to the user via AskUserQuestion:
278
+ ```
279
+ Fix rejected by the acceptance guardrail.
280
+
281
+ Failing signal: {failing signal}
282
+ Evidence: {why it failed}
283
+
284
+ Options:
285
+ 1. Revise fix — spawn continuation agent to revise the fix so the signal passes
286
+ 2. Accept as technical debt — record the unmet signal + justification (the fix lands without the gate passing; this is never silent)
287
+ 3. Abandon — stop; session stays unresolved
288
+ ```
289
+
290
+ If user selects 1: spawn continuation agent with `goal: find_and_fix` naming the failing signal to revise. Loop back to Step 3.
291
+
292
+ If user selects 2: spawn continuation agent instructed to record `guardrail_verdict: accepted_debt` + the justification in the debug file, then proceed to request_human_verification. Loop back to Step 3.
293
+
294
+ If user selects 3: proceed to Step 4 with fix = "not applied (guardrail rejected)".
295
+
273
296
  ## Step 4: Return Compact Summary
274
297
 
298
+ **Non-terminal early stop — check this FIRST.** Before returning any summary below, ask: is your own turn/context budget exhausted while the debugger (`gsd-debugger`) is still investigating — i.e. you have NOT reached `DEBUG COMPLETE`, a user-chosen `ABANDONED`, or exhausted the `INVESTIGATION INCONCLUSIVE` options? If so, do NOT fabricate a `DEBUG SESSION COMPLETE` or `ABANDONED` summary to fit this shape. Return the non-terminal marker instead:
299
+
300
+ ```markdown
301
+ ## CONTINUE_REQUIRED
302
+
303
+ **Session:** {debug_file_path}
304
+ **Status:** {status from frontmatter, e.g. investigating}
305
+ **Next action:** {next_action from Current Focus}
306
+ **Reason:** session-manager turn/context budget exhausted — investigation still in progress
307
+ ```
308
+
309
+ `CONTINUE_REQUIRED` is distinct from both terminal shapes below AND from `## CHECKPOINT REACHED` (Step 3d): a `CHECKPOINT REACHED` is a genuine user-input/approval checkpoint that already correctly pauses via `AskUserQuestion` before looping back to Step 3 — it is not returned to the orchestrator. `CONTINUE_REQUIRED` is emitted only when no checkpoint is pending and the loop simply cannot proceed further in this turn. The orchestrator resumes by re-spawning this agent with the SAME `slug`/`debug_file_path` — the on-disk checkpoint at `.planning/debug/{slug}.md` (its `status` and `next_action`) is the source of truth for where to pick up. Never return control to the user as if the session were complete when it is not.
310
+
275
311
  Read the resolved (or current) debug file to extract final Resolution values.
276
312
 
277
- Return compact summary:
313
+ **Commit before returning a terminal summary (#2568).** This agent owns the terminal path —
314
+ it applies fixes, archives to `resolved/`, and returns the summary — but carried no commit
315
+ step, so `commit_docs` was never consulted on the normal `/gsd:debug` flow and session docs
316
+ were left untracked. Do this for **both** terminal shapes below, and **NOT** for
317
+ `CONTINUE_REQUIRED` above: that shape is non-terminal, and committing there would strand a
318
+ half-finished session looking done, exactly as fabricating a terminal summary would.
319
+ `CHECKPOINT REACHED` (Step 3d) likewise does not commit — it pauses for user input and loops
320
+ back to Step 3.
321
+
322
+ 1. **In-session fix code.** If a fix was applied during this session and its code changes are
323
+ still uncommitted, commit them first. Stage **specific files only** — the files the fix
324
+ touched. Do this rather than `git add -A`, which would sweep unrelated working-tree
325
+ changes into a debug commit. Guard on staged content: `gsd-debugger.md`'s
326
+ `archive_session` step may already have committed this fix on the confirmed-checkpoint
327
+ path, and a bare `git commit` with nothing staged exits non-zero and would abort this
328
+ step before the summary is returned:
329
+ ```bash
330
+ git add <files the fix touched>
331
+ git diff --cached --quiet || git commit -m "fix: {brief description}"
332
+ ```
333
+ 2. **Session doc.** Commit via the CLI, which already gates on `commit_docs` and returns
334
+ `skipped_commit_docs_false` when disabled — call it unconditionally rather than
335
+ re-checking the config here, so the policy lives in one place. `query commit` treats an
336
+ empty diff as `nothing_to_commit` and exits 0, so a second call after
337
+ `archive_session` already committed the doc is a safe no-op. The canonical `gsd_run` preamble is
338
+ established once in Step 2 and is the single definition this agent carries (repo
339
+ invariant: exactly one preamble per agent file, before its first call):
340
+ ```bash
341
+ # resolved session — path spelled literally; this agent receives `slug` and
342
+ # `debug_file_path`, NOT a `debug_dir` variable (see <session_parameters>).
343
+ gsd_run query commit "docs(debug): resolve {slug} session" --files .planning/debug/resolved/{slug}.md
344
+ # abandoned session (checkpoint retained for `/gsd:debug continue {slug}`)
345
+ gsd_run query commit "docs(debug): checkpoint {slug} session" --files {debug_file_path}
346
+ ```
347
+
348
+ Return compact summary (terminal — investigation resolved):
278
349
 
279
350
  ```markdown
280
351
  ## DEBUG SESSION COMPLETE
281
352
 
282
353
  **Session:** {final path — resolved/ if archived, otherwise debug_file_path}
283
- **Root Cause:** {one sentence from Resolution.root_cause, or "not determined"}
354
+ **Root Cause:** {one sentence, or a '; '-joined list when the AND-gate identified multiple contributing causes, from Resolution.root_cause; or "not determined"}
284
355
  **Fix:** {one sentence from Resolution.fix, or "not applied"}
285
356
  **Cycles:** {N} (investigation) + {M} (fix)
286
357
  **TDD:** {yes/no}
287
358
  **Specialist review:** {specialist_hint used, or "none"}
359
+ **Prevention:** {one-line from the blameless postmortem — "why not caught: <gate, or 'none (no gate existed for this class)'>; guard: <artifact>"}
288
360
  ```
289
361
 
290
- If the session was abandoned by user choice, return:
362
+ If the session was abandoned by user choice, return (terminal — user stopped):
291
363
 
292
364
  ```markdown
293
365
  ## DEBUG SESSION COMPLETE
294
366
 
295
367
  **Session:** {debug_file_path}
296
- **Root Cause:** {one sentence if found, or "not determined"}
368
+ **Root Cause:** {one sentence if found (or a '; '-joined list if the AND-gate identified multiple contributing causes), or "not determined"}
297
369
  **Fix:** not applied
298
370
  **Cycles:** {N}
299
371
  **TDD:** {yes/no}
@@ -311,5 +383,7 @@ If the session was abandoned by user choice, return:
311
383
  - [ ] Specialist dispatch executed when specialist_dispatch_enabled and hint maps to a skill
312
384
  - [ ] TDD gate applied when tdd_mode=true and ROOT CAUSE FOUND
313
385
  - [ ] Loop continues until DEBUG COMPLETE, ABANDONED, or user stops
386
+ - [ ] Non-terminal `CONTINUE_REQUIRED` (not a fabricated terminal summary) returned when the manager's own turn/context budget is exhausted mid-investigation
387
+ - [ ] Session doc (and any uncommitted fix code from this session) committed before a terminal summary, respecting `commit_docs` — and NOT committed on the non-terminal `CONTINUE_REQUIRED` path
314
388
  - [ ] Compact summary returned (at most 2K tokens)
315
389
  </success_criteria>
@@ -253,6 +253,10 @@ reasoning_checkpoint:
253
253
  falsification_test: "[what specific observation would prove this hypothesis wrong]"
254
254
  fix_rationale: "[why the proposed fix addresses the root cause — not just the symptom]"
255
255
  blind_spots: "[what you haven't tested that could invalidate this hypothesis]"
256
+ candidate_causes:
257
+ - "[cause in category: code|config|environment|data]"
258
+ - "[cause in a DIFFERENT category — single-category is not a branch]"
259
+ and_gate: "[could this failure require >1 contributing condition simultaneously? yes/no + why — see RCA branching]"
256
260
  ```
257
261
 
258
262
  **Check before proceeding:**
@@ -260,8 +264,9 @@ reasoning_checkpoint:
260
264
  - Is the confirming evidence direct observation, not inference?
261
265
  - Does the fix address the root cause or a symptom?
262
266
  - Have you documented your blind spots honestly?
267
+ - **Did you branch across ≥2 categories and answer the AND-gate?** (Single-cause is fine when the AND-gate is no — but you must have checked.)
263
268
 
264
- If you cannot fill all five fields with specific, concrete answers — you do not have a confirmed root cause yet. Return to investigation_loop.
269
+ If you cannot fill all seven fields with specific, concrete answers — you do not have a confirmed root cause yet. Return to investigation_loop.
265
270
 
266
271
  ## Minimal Reproduction
267
272
 
@@ -274,6 +279,7 @@ If you cannot fill all five fields with specific, concrete answers — you do no
274
279
  3. Test: Does it still reproduce? YES = keep removed. NO = put back.
275
280
  4. Repeat until bare minimum
276
281
  5. Bug is now obvious in stripped-down code
282
+ 6. **Shrinking (input-space bugs)** — when the bug triggers on a class of inputs, wrap it in a property (fast-check for JS/TS, Hypothesis for Python) and let the shrinker auto-minimize the counterexample; store the **minimized** input as the regression seed. See `gsd-core/references/debugger-repro-hardening.md`.
277
283
 
278
284
  **Example:**
279
285
  ```jsx
@@ -443,18 +449,21 @@ MISMATCH: Checker looks in wrong directory → hooks "not found" → reported as
443
449
 
444
450
  **The discipline:** Never assume a constructed path is correct. Resolve it to its actual value and verify the other side agrees. When two systems share a resource (file, directory, key), trace the full path in both.
445
451
 
446
- ## Technique Selection
452
+ ## Technique Selection (routed by bug class)
447
453
 
448
- | Situation | Technique |
449
- |-----------|-----------|
450
- | Large codebase, many files | Binary search |
451
- | Confused about what's happening | Rubber duck, Observability first |
452
- | Complex system, many interactions | Minimal reproduction |
453
- | Know the desired output | Working backwards |
454
- | Used to work, now doesn't | Differential debugging, Git bisect |
455
- | Many possible causes | Comment out everything, Binary search |
456
- | Paths, URLs, keys constructed from variables | Follow the indirection |
457
- | Always | Observability first (before making changes) |
454
+ Classify the failure first (Phase 1.75), then route by class — not by ad-hoc
455
+ situation:
456
+
457
+ @~/.claude/gsd-core/references/debugger-bug-taxonomy.md
458
+
459
+ | bug_class | Route to | Revoke if already run |
460
+ |---|---|---|
461
+ | Bohrbug | deterministic reproduction → SBFL (Phase 1.25) → git bisect → binary search | — |
462
+ | Heisenbug / Mandelbug | record-replay (`rr`) → stability-stress → statistical sampling | SBFL — Phase 1.25 runs before classification; if it ran, mark its Evidence entry revoked (flaky spectrum poisons the ranking) |
463
+ | Concurrency | atomicity / order / deadlock checklist (see reference) FIRST | — |
464
+ | General (any class) | Binary search, Working backwards, Differential, Delta debugging, Comment-out-everything, Follow-the-indirection, Rubber duck, Observability first (always, before changes) | — |
465
+
466
+ The class rows pick the first move; the General lane holds situation-cued techniques that apply to any class. When the situation table and the class route disagree, the class route wins.
458
467
 
459
468
  ## Combining Techniques
460
469
 
@@ -590,6 +599,13 @@ function processUserData(user) {
590
599
  // 5. Test is now regression protection forever
591
600
  ```
592
601
 
602
+ **Harden the regression test (so the Phase 1A mutation guardrail bites):**
603
+
604
+ @~/.claude/gsd-core/references/debugger-repro-hardening.md
605
+
606
+ - **Classify the oracle** before writing the assertion — `specified` / `derived` (contract/model) / `metamorphic` / `implicit` (crash, weakest). Record it under `Resolution.oracle_type`. Never default to implicit silently.
607
+ - **Add boundary neighbors** around the fixed defect's equivalence class — off-by-one (N±1), min/max (0/length), empty/singleton — the single reported value misses the adjacent off-by-one.
608
+
593
609
  ## Verification Checklist
594
610
 
595
611
  ```markdown
@@ -788,9 +804,11 @@ Each resolved session appends one entry:
788
804
  ## {slug} — {one-line description}
789
805
  - **Date:** {ISO date}
790
806
  - **Error patterns:** {comma-separated keywords extracted from symptoms.errors and symptoms.actual}
791
- - **Root cause:** {from Resolution.root_cause}
807
+ - **Root cause(s):** {from Resolution.root_cause — one cause, or a '; '-joined list when the AND-gate fired}
792
808
  - **Fix:** {from Resolution.fix}
793
809
  - **Files changed:** {from Resolution.files_changed}
810
+ - **Why not caught:** {which existing gate (test/typecheck/lint/review/verify/build) should have caught it — or "no gate existed for this class"}
811
+ - **Recurrence guard:** {the concrete artifact preventing this class from returning — regression test (path:name) / assertion / lint rule / type refinement / config-default change / KB pattern}
794
812
  ---
795
813
  ```
796
814
 
@@ -804,9 +822,11 @@ At the **end of `archive_session`**, after the session file is moved to `resolve
804
822
 
805
823
  ## Matching Logic
806
824
 
807
- Matching is keyword overlap, not semantic similarity. Extract nouns and error substrings from `Symptoms.errors` and `Symptoms.actual`. Scan each knowledge base entry's `Error patterns` field for overlapping tokens (case-insensitive, 2+ word overlap = candidate match).
825
+ **Semantic-first, keyword-fallback.** Query MemPalace with the current symptoms and surface the top-k meaning-similar prior resolutions — this catches same-root-cause/different-wording cases keyword overlap misses. Fall back to keyword overlap on `knowledge-base.md` when MemPalace is absent. See:
826
+
827
+ @~/.claude/gsd-core/references/debugger-semantic-recall.md
808
828
 
809
- **Important:** A match is a **hypothesis candidate**, not a confirmed diagnosis. Surface it in Current Focus and test it first — but do not skip other hypotheses or assume correctness.
829
+ **Important:** A match is a **hypothesis candidate**, not a confirmed diagnosis — surface it in Current Focus and test it first; do not skip other hypotheses or assume correctness.
810
830
 
811
831
  </knowledge_base_protocol>
812
832
 
@@ -966,12 +986,10 @@ At investigation decision points, apply structured reasoning:
966
986
  **Autonomous investigation. Update file continuously.**
967
987
 
968
988
  **Phase 0: Check knowledge base**
969
- - If `.planning/debug/knowledge-base.md` exists, read it
970
- - Extract keywords from `Symptoms.errors` and `Symptoms.actual` (nouns, error substrings, identifiers)
971
- - Scan knowledge base entries for 2+ keyword overlap (case-insensitive)
989
+ - Query MemPalace semantically with the current symptoms (top-k meaning-similar prior resolutions); fall back to reading `.planning/debug/knowledge-base.md` and keyword overlap when MemPalace is absent
972
990
  - If match found:
973
991
  - Note in Current Focus: `known_pattern_candidate: "{matched slug} — {description}"`
974
- - Add to Evidence: `found: Knowledge base match on [{keywords}] → Root cause was: {root_cause}. Fix was: {fix}.`
992
+ - Add to Evidence: `found: Knowledge base match on [{keywords}] → Root cause was: {root_cause}. Fix was: {fix}. Why not caught: {why_not_caught}. Recurrence guard: {recurrence_guard}.` (the last two are absent on old entries — that's fine; consume them when present)
975
993
  - Test this hypothesis FIRST in Phase 2 — but treat it as one hypothesis, not a certainty
976
994
  - If no match: proceed normally
977
995
 
@@ -983,14 +1001,32 @@ At investigation decision points, apply structured reasoning:
983
1001
  - Run app/tests to observe behavior
984
1002
  - APPEND to Evidence after each finding
985
1003
 
1004
+ **Phase 1.25: Spectrum-based fault localization (optional, coverage-gated)**
1005
+ - When a runnable test suite with per-test coverage exists (≥1 failing AND ≥1 passing test), compute an Ochiai suspiciousness ranking and seed the top-N into Evidence before forming hypotheses — narrows the search space deterministically before LLM reasoning:
1006
+
1007
+ @~/.claude/gsd-core/references/debugger-sbfl.md
1008
+
1009
+ - Skip with a logged note when there is no test suite, no failing tests, or no per-test coverage; investigation proceeds unchanged
1010
+
986
1011
  **Phase 1.5: Check common bug patterns**
987
1012
  - Read @~/.claude/gsd-core/references/common-bug-patterns.md
988
1013
  - Match symptoms to pattern categories using the Symptom-to-Category Quick Map
989
1014
  - Any matching patterns become hypothesis candidates for Phase 2
990
1015
  - If no patterns match, proceed to open-ended hypothesis formation
991
1016
 
1017
+ **Phase 1.75: Classify the failure**
1018
+ - Assign a `bug_class` — Bohrbug (deterministic) / Heisenbug-Mandelbug (transient, non-deterministic) / Concurrency — and record it in Current Focus. The class routes which investigation technique to use:
1019
+
1020
+ @~/.claude/gsd-core/references/debugger-bug-taxonomy.md
1021
+
1022
+ - Bohrbug → reproduction + SBFL + bisect; Heisenbug/Mandelbug → record-replay/stability (skip SBFL — flaky spectra poison it); Concurrency → the atomicity/order/deadlock checklist first
1023
+
992
1024
  **Phase 2: Form hypothesis**
993
1025
  - Based on evidence AND common pattern matches, form SPECIFIC, FALSIFIABLE hypothesis
1026
+ - **Branch, don't chain** — at hypothesis formation (so it's done before the Phase 4 commit), enumerate candidate causes across ≥2 Ishikawa categories (code / config / environment / data) and answer the AND-gate check; `root_cause` may hold a set when the AND-gate fires:
1027
+
1028
+ @~/.claude/gsd-core/references/debugger-rca-branching.md
1029
+
994
1030
  - Update Current Focus with hypothesis, test, expecting, next_action
995
1031
 
996
1032
  **Phase 3: Test hypothesis**
@@ -1043,7 +1079,7 @@ Return structured diagnosis:
1043
1079
 
1044
1080
  **Debug Session:** .planning/debug/{slug}.md
1045
1081
 
1046
- **Root Cause:** {from Resolution.root_cause}
1082
+ **Root Cause:** {from Resolution.root_cause — one cause, or a '; '-joined list when the AND-gate identified multiple contributing causes}
1047
1083
 
1048
1084
  **Evidence Summary:**
1049
1085
  - {key finding 1}
@@ -1083,7 +1119,7 @@ Update status to "fixing".
1083
1119
 
1084
1120
  **0. Structured Reasoning Checkpoint (MANDATORY)**
1085
1121
  - Write the `reasoning_checkpoint` block to Current Focus (see Structured Reasoning Checkpoint in investigation_techniques)
1086
- - Verify all five fields can be filled with specific, concrete answers
1122
+ - Verify every field can be filled with specific, concrete answers — including the RCA `candidate_causes` (≥2 categories) and `and_gate` fields
1087
1123
  - If any field is vague or empty: return to investigation_loop — root cause is not confirmed
1088
1124
 
1089
1125
  **1. Implement minimal fix**
@@ -1091,11 +1127,15 @@ Update status to "fixing".
1091
1127
  - Make SMALLEST change that addresses root cause
1092
1128
  - Update Resolution.fix and Resolution.files_changed
1093
1129
 
1094
- **2. Verify**
1130
+ **2. Verify (Fix-Acceptance Guardrail)**
1095
1131
  - Update status to "verifying"
1096
- - Test against original Symptoms
1097
- - If verification FAILS: status -> "investigating", return to investigation_loop
1098
- - If verification PASSES: Update Resolution.verification, proceed to request_human_verification
1132
+ - Run the multi-signal guardrail before accepting the fix:
1133
+
1134
+ @~/.claude/gsd-core/references/debugger-fix-acceptance.md
1135
+
1136
+ - Record every signal's result under `Resolution.verification` (per-signal schema in the reference)
1137
+ - If ANY applicable signal fails (and no documented technical-debt escape applies): return `## FIX REJECTED BY GUARDRAIL` (see structured_returns) — do NOT request human verification
1138
+ - If all applicable signals pass: set `guardrail_verdict: accepted`, proceed to request_human_verification
1099
1139
  </step>
1100
1140
 
1101
1141
  <step name="request_human_verification">
@@ -1174,9 +1214,13 @@ Then commit planning docs via CLI (respects `commit_docs` config automatically):
1174
1214
  gsd_run query commit "docs: resolve debug {slug}" --files .planning/debug/resolved/{slug}.md
1175
1215
  ```
1176
1216
 
1177
- **Append to knowledge base:**
1217
+ **Append to knowledge base (with the Prevention block):**
1218
+
1219
+ Read `.planning/debug/resolved/{slug}.md` to extract final `Resolution` values. Then produce the **Prevention block** — a blameless postmortem (branching 5-Whys per RCA, "why wasn't this caught?", and a concrete recurrence guard):
1220
+
1221
+ @~/.claude/gsd-core/references/debugger-prevention.md
1178
1222
 
1179
- Read `.planning/debug/resolved/{slug}.md` to extract final `Resolution` values. Then append to `.planning/debug/knowledge-base.md` (create file with header if it doesn't exist):
1223
+ Then append to `.planning/debug/knowledge-base.md` (create file with header if it doesn't exist):
1180
1224
 
1181
1225
  If creating for the first time, write this header first:
1182
1226
  ```markdown
@@ -1193,9 +1237,11 @@ Then append the entry:
1193
1237
  ## {slug} — {one-line description of the bug}
1194
1238
  - **Date:** {ISO date}
1195
1239
  - **Error patterns:** {comma-separated keywords from Symptoms.errors + Symptoms.actual}
1196
- - **Root cause:** {Resolution.root_cause}
1240
+ - **Root cause(s):** {Resolution.root_cause — joined as '; ' when multiple contributing causes were confirmed}
1197
1241
  - **Fix:** {Resolution.fix}
1198
1242
  - **Files changed:** {Resolution.files_changed joined as comma list}
1243
+ - **Why not caught:** {which existing gate (test/typecheck/lint/review/verify/build) should have caught it — or "no gate existed for this class"}
1244
+ - **Recurrence guard:** {concrete artifact preventing this class from returning — regression test (path:name) / assertion / lint rule / KB pattern / type refinement / config-default change}
1199
1245
  ---
1200
1246
 
1201
1247
  ```
@@ -1205,6 +1251,8 @@ Commit the knowledge base update alongside the resolved session:
1205
1251
  gsd_run query commit "docs: update debug knowledge base with {slug}" --files .planning/debug/knowledge-base.md
1206
1252
  ```
1207
1253
 
1254
+ **Index into MemPalace (when available)** per the semantic-recall reference — the Resolution summary (not raw symptoms), redacted — so a future Phase-0 query surfaces it by meaning. Skip with a logged note when MemPalace is absent or the KB write failed; `knowledge-base.md` is the durable fallback.
1255
+
1208
1256
  Report completion and offer next steps.
1209
1257
  </step>
1210
1258
 
@@ -1298,7 +1346,7 @@ Orchestrator presents checkpoint to user, gets response, spawns fresh continuati
1298
1346
 
1299
1347
  **Debug Session:** .planning/debug/{slug}.md
1300
1348
 
1301
- **Root Cause:** {specific cause with evidence}
1349
+ **Root Cause:** {specific cause with evidence — one cause, or a '; '-joined list when the AND-gate identified multiple contributing causes}
1302
1350
 
1303
1351
  **Evidence Summary:**
1304
1352
  - {key finding 1}
@@ -1334,6 +1382,16 @@ Orchestrator presents checkpoint to user, gets response, spawns fresh continuati
1334
1382
 
1335
1383
  Only return this after human verification confirms the fix.
1336
1384
 
1385
+ ## FIX REJECTED BY GUARDRAIL
1386
+
1387
+ Returned when a fix-acceptance guardrail signal fails (see `@~/.claude/gsd-core/references/debugger-fix-acceptance.md`). Do **not** mark the session resolved.
1388
+
1389
+ **Debug Session:** .planning/debug/{slug}.md
1390
+ **Failing signal:** {signal 1–5 name}
1391
+ **Evidence:** {why the signal failed — e.g. "mutant at fix site survived", "deletion-only diff with no RCA justification", "bug did not return on revert"}
1392
+
1393
+ The session-manager continuation surfaces this and offers revise / accept-as-debt / abandon.
1394
+
1337
1395
  ## INVESTIGATION INCONCLUSIVE
1338
1396
 
1339
1397
  ```markdown
@@ -144,6 +144,10 @@ At execution decision points, apply structured reasoning:
144
144
 
145
145
  For each task:
146
146
 
147
+ 0. **Precondition check (before any other task work):** If the task carries a `<precondition>` element, evaluate that single prose line first — it names a runnable/checkable fact the task assumes (env var set, prior-phase artifact present, server responding to `/health`, `user_setup` step done). Verify with **read-only checks only** — file existence, env var presence (no value output), idempotent `GET /health`-style pings. Do NOT run commands with side effects (writes, network POSTs, secret emission) as the check; if a side-effecting check seems required, halt and surface via checkpoint instead.
148
+ - **Met OR absent:** continue with no visible change to execution flow. The precondition is a no-op for the rest of the task loop.
149
+ - **Unmet:** STOP — return a `checkpoint:human-verify` (use `checkpoint_return_format`) with `**Blocked by:** Precondition not met: <precondition text>`. Do NOT partial-commit the task. Unmet preconditions are NEVER auto-approved, even under `AUTO_CFG=true` — a missing prerequisite is not a verification step a human can rubber-stamp; it is a fact the executor cannot establish on its own. The human either satisfies the precondition (sets the env var, completes the `user_setup` step, regenerates the artifact) or reruns `/gsd:plan-phase` to restructure.
150
+
147
151
  1. **If `type="auto"`:**
148
152
  - Check for `tdd="true"` → follow TDD execution flow
149
153
  - Execute task, apply deviation rules as needed
@@ -152,11 +156,17 @@ For each task:
152
156
  - Commit (see task_commit_protocol)
153
157
  - Track completion + commit hash for Summary
154
158
 
155
- 2. **If `type="checkpoint:*"`:**
159
+ 2. **If `type="tracer"`:** (the leading thin end-to-end slice — production-quality, never a throwaway)
160
+ - Execute and commit exactly like `type="auto"` (real implementation, real `<verify>`, atomic commit).
161
+ - **Then run the tracer feedback gate BEFORE any expansion task** — an early integration checkpoint on the proven slice:
162
+ - **Autonomous run (auto mode active — `AUTO_CHAIN` or `AUTO_CFG` is `"true"`, per `<auto_mode_detection>`):** re-run the tracer's `<verify>` end-to-end. If it **fails**, HALT and surface it (deviation Rule 1) — do NOT proceed to expansion tasks. Pouring more layers onto a broken foundation is exactly the failure this gate prevents. If it passes, log `⚡ Tracer verified end-to-end — expanding` and continue.
163
+ - **Interactive run (auto mode not active):** immediately after committing the tracer, STOP and return a `checkpoint:human-verify` for the tracer's `<verify>` (the working slice) using checkpoint_return_format, before any expansion task.
164
+
165
+ 3. **If `type="checkpoint:*"`:**
156
166
  - STOP immediately — return structured checkpoint message
157
167
  - A fresh agent will be spawned to continue
158
168
 
159
- 3. After all tasks: run overall verification, confirm success criteria, document deviations
169
+ 4. After all tasks: run overall verification, confirm success criteria, document deviations
160
170
  </step>
161
171
 
162
172
  </execution_flow>
@@ -310,6 +320,8 @@ For full automation-first patterns, server lifecycle, CLI handling:
310
320
 
311
321
  **Quick reference:** Users NEVER run CLI commands. Users ONLY visit URLs, click UI, evaluate visuals, provide secrets. Claude does all automation.
312
322
 
323
+ **Tracer feedback gate:** a `type="tracer"` task is followed by an early integration checkpoint on the proven slice (see `<execution_flow>` → `execute_tasks`) — in autonomous runs a failing tracer `<verify>` HALTS before any expansion task; in interactive runs the executor emits a `checkpoint:human-verify` for the tracer immediately after committing it.
324
+
313
325
  ---
314
326
 
315
327
  **Auto-mode checkpoint behavior** (when `AUTO_CFG` is `"true"`):
@@ -483,11 +495,11 @@ if [ -f .git ]; then # worktree
483
495
  echo "DO NOT use 'git update-ref' to rewind the protected branch — surface as blocker (#2924)." >&2
484
496
  exit 1
485
497
  fi
486
- # Positive allow-list: HEAD must be on the canonical Claude Code worktree-agent
487
- # branch namespace (`worktree-agent-<id>`). This catches feature/* and any other
488
- # arbitrary branch that the deny-list would silently allow (#2924).
489
- if ! echo "$ACTUAL_BRANCH" | grep -Eq '^worktree-agent-[A-Za-z0-9._/-]+$'; then
490
- echo "FATAL: refusing to commit — worktree HEAD '$ACTUAL_BRANCH' is not in the worktree-agent-* namespace." >&2
498
+ # Positive allow-list: HEAD must be on a per-agent branch (`agent-<id>` or
499
+ # legacy `worktree-agent-<id>`). This catches feature/* and any other
500
+ # arbitrary branch that the deny-list would silently allow (#2924, #1995).
501
+ if ! echo "$ACTUAL_BRANCH" | grep -Eq '^(worktree-)?agent-[A-Za-z0-9._/-]+$'; then
502
+ echo "FATAL: refusing to commit — worktree HEAD '$ACTUAL_BRANCH' is not in the agent-* / worktree-agent-* namespace." >&2
491
503
  echo "Agent commits must live on per-agent branches; surface as blocker (#2924)." >&2
492
504
  exit 1
493
505
  fi
@@ -626,7 +638,16 @@ This file is the canonical output of this step. The orchestrator reads `.plannin
626
638
 
627
639
  **Use template:** @~/.claude/gsd-core/templates/summary.md
628
640
 
629
- **Frontmatter:** phase, plan, subsystem, tags, dependency graph (requires/provides/affects), tech-stack (added/patterns), key-files (created/modified), decisions, metrics (duration, completed date), status (`status: complete` — required so the audit-open scanner recognises the summary as done).
641
+ **Frontmatter:** phase, plan, subsystem, tags, dependency graph (requires/provides/affects), tech-stack (added/patterns), key-files (created/modified), decisions, metrics (duration, completed date), status (`status: complete` — required so the audit-open scanner recognises the summary as done), and `actuals` (#2632).
642
+
643
+ **`actuals` (required when the plan carried an `estimate`):** record what the phase ACTUALLY cost, on the SAME scale the estimate used — `estimateTokens` (chars/4) over the realized diff, NOT a harness token count. Mixing scales measures the measurement methods, not the miss.
644
+ ```yaml
645
+ actuals:
646
+ tokens: 74000 # chars/4 over the files you actually changed
647
+ tasks: 5 # tasks completed
648
+ commits: 7 # commits made
649
+ ```
650
+ These pair with the plan's `estimate` to calibrate future estimates (ADR-2629). Do not round to look closer to the estimate — a flattering number corrupts every later projection.
630
651
 
631
652
  **Title:** `# Phase [X] Plan [Y]: [Name] Summary`
632
653
 
@@ -660,6 +681,21 @@ Or: "None - plan executed exactly as written."
660
681
 
661
682
  If any stubs exist, add a `## Known Stubs` section to the SUMMARY listing each stub with its file, line, and reason. These are tracked for the verifier to catch. Do NOT mark a plan as complete if stubs exist that prevent the plan's goal from being achieved — either wire the data or document in the plan why the stub is intentional and which future plan will resolve it.
662
683
 
684
+ **Broken-windows ledger (issue #1950).** For each stub, skipped test, or unrun `<verify>` recorded above, ALSO append it to the cross-phase defect register at `.planning/WINDOWS.md`. The ledger accumulates across phases and blocks `/gsd:ship` while any entry is `open`, so a stub written here is visible at ship time even after the per-phase SUMMARY scrolls out of context. Append one entry per defect:
685
+
686
+ ```bash
687
+ gsd_run windows append \
688
+ --kind stub \
689
+ --phase "${PHASE_NUMBER}" \
690
+ --file "<path-relative-to-repo-root>" \
691
+ --line "<line-number-or-omit>" \
692
+ --description "<one-line description, same wording as the Known Stubs row>"
693
+ ```
694
+
695
+ Use `--kind skipped-test` for a `t.skip(...)` / `test.todo(...)` you left behind, `--kind unrun-verify` for a `<verify>` you could not run, or `--kind deviation` for a documented plan deviation. The full kind vocabulary: `stub | todo | fixme | skipped-test | lint-warning | unmet-truth | unrun-verify | deviation`.
696
+
697
+ The ledger is **optional**: if `gsd_run windows append` returns `windows_ledger_missing` or `windows_ok` without writing, continue without error — population is best-effort and never blocks execution. Recording here is what makes the defect visible to the ship gate later; forgetting to record is the failure mode this ledger exists to prevent.
698
+
663
699
  **Threat surface scan:** Before writing the SUMMARY, check if any files created/modified introduce security-relevant surface NOT in the plan's `<threat_model>` — new network endpoints, auth paths, file access patterns, or schema changes at trust boundaries. If found, add:
664
700
 
665
701
  ```markdown
@@ -753,7 +789,7 @@ gsd_run query commit "docs({phase}-{plan}): complete [plan-name] plan" --files \
753
789
  Separate from per-task commits — captures execution results only.
754
790
 
755
791
  **Handling the SDK return envelope (#3678):** `gsd-tools query commit` returns
756
- one of three shapes:
792
+ one of these shapes:
757
793
 
758
794
  - `{committed: true, hash, reason: 'committed'}` — commit succeeded; record
759
795
  the hash in the completion format.
@@ -766,6 +802,10 @@ one of three shapes:
766
802
  success path.** Record "skipped (.planning gitignored)" and move on.
767
803
  - `{committed: false, reason: 'nothing_to_commit' | 'commit_failed', ...}` —
768
804
  no-op / genuine failure; surface in the completion notes.
805
+ - `{committed: false, reason: 'staging_failed' | 'staging_timeout', file, error}` —
806
+ `git add` itself failed (#2608), e.g. an unwritable index. Nothing committed,
807
+ index rolled back. Surface `file` + `error` (git's stderr); do not retry — a
808
+ retry hits the same cause.
769
809
 
770
810
  **Do not fall back to raw `git add` / `git commit` / `git add -f`** when the
771
811
  SDK returns `skipped: true`. The SDK's skip is the user's deliberate choice