feat(#1963): emit blameless-postmortem Prevention block at resolution (#2410)

* test(#1963): add failing-first prevention/postmortem contract tests

Epic #1957 Phase 3B. Source-text-is-the-product contract tests: blameless
5-Whys that BRANCHES per Phase 2A RCA (not a single-cause chain; treats agent
error as 'why was that possible?'), the 'why wasn't this caught?' question,
the recurrence-guard taxonomy (regression test / assertion / lint rule / KB
pattern), the KB-entry why_not_caught + recurrence_guard fields with backward
compat, the session-manager prevention summary line, and the Zawinski
scope-boundary (a block, not a subsystem).

Failing-first: reference, archive_session edit, KB schema extension, and
session-manager summary do not yet exist.

* feat(#1963): emit blameless-postmortem Prevention block at resolution

Epic #1957 Phase 3B. At archive_session the debugger now produces a
Prevention block with three blame-free components: a branching 5-Whys causal
chain (branches per Phase 2A RCA, not a single chain; 'agent error' prompts
'why was that possible?', never blame), a 'why wasn't this caught?' answer
naming the missed gate (test/typecheck/lint/review/verify), and a concrete
recurrence guard (regression test / assertion / lint rule / KB pattern).

The knowledge-base entry gains two structured fields (why_not_caught +
recurrence_guard) so future Phase-0 recall surfaces the prior prevention, not
just the prior fix. Additive: old entries without the fields still load. The
session-manager compact summary surfaces a one-line prevention summary.

Full rules extracted to gsd-core/references/debugger-prevention.md (slim
archive_session step + 2 KB fields kept in the agent). INVENTORY + manifest +
agent-size baseline + install-parity goldens + AGENTS.md updated.

* fix(#1963): address orthogonal review (CRITICAL append-template drift + Phase-0 consumption + parity test)

- CRITICAL: the archive_session KB append template omitted Why not caught +
  Recurrence guard (only the Entry Format had them) — the feature's core
  deliverable silently did not happen. Added both fields to the append template
  the agent actually follows (nearest-instruction wins).
- HIGH: Phase 0 (KB read) only surfaced root_cause + fix; the new fields were
  dead data. Extended the Phase 0 Evidence line to consume why_not_caught +
  recurrence_guard when present (absent on old entries — backward compat holds).
- MEDIUM: added a cross-section parity test (every Entry-Format field must also
  appear in the append template — the guard that would have caught the
  Critical) + a Phase-0-consumption assertion.
- MEDIUM: the 'branches per Phase 2A' claim is now wired — reuses
  reasoning_checkpoint.candidate_causes across the four categories.
- MEDIUM: recurrence-guard taxonomy gains type refinement + config-default
  change; LOW: added 'build' gate to both surfaces for parity.
- NIT: compact-summary fallback shape ('no gate existed'); verify the guard
  artifact exists before recording it.

* test(#1963): anchor Phase-0 consumption test on the specific heading

The regex /Phase 0[\s\S]{0,1200}/ matched the first 'Phase 0' in the file
(in knowledge_base_protocol prose), not the Phase 0 block in investigation_loop.
Anchor on '**Phase 0: Check knowledge base**' and widen to 1500 chars.

* chore(#1963): backfill changeset pr number (PR #2410)
This commit is contained in:
Tom Boucher
2026-07-18 17:38:54 -04:00
committed by GitHub
parent 36a311c5bb
commit c67f301867
45 changed files with 311 additions and 41 deletions

View File

@@ -321,6 +321,7 @@ Return compact summary (terminal — investigation resolved):
**Cycles:** {N} (investigation) + {M} (fix)
**TDD:** {yes/no}
**Specialist review:** {specialist_hint used, or "none"}
**Prevention:** {one-line from the blameless postmortem — "why not caught: <gate, or 'none (no gate existed for this class)'>; guard: <artifact>"}
```
If the session was abandoned by user choice, return (terminal — user stopped):

View File

@@ -807,6 +807,8 @@ Each resolved session appends one entry:
- **Root cause(s):** {from Resolution.root_cause — one cause, or a '; '-joined list when the AND-gate fired}
- **Fix:** {from Resolution.fix}
- **Files changed:** {from Resolution.files_changed}
- **Why not caught:** {which existing gate (test/typecheck/lint/review/verify/build) should have caught it — or "no gate existed for this class"}
- **Recurrence guard:** {the concrete artifact preventing this class from returning — regression test (path:name) / assertion / lint rule / type refinement / config-default change / KB pattern}
---
```
@@ -987,7 +989,7 @@ At investigation decision points, apply structured reasoning:
- Scan knowledge base entries for 2+ keyword overlap (case-insensitive)
- If match found:
- Note in Current Focus: `known_pattern_candidate: "{matched slug} — {description}"`
- Add to Evidence: `found: Knowledge base match on [{keywords}] → Root cause was: {root_cause}. Fix was: {fix}.`
- 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)
- Test this hypothesis FIRST in Phase 2 — but treat it as one hypothesis, not a certainty
- If no match: proceed normally
@@ -1212,9 +1214,13 @@ Then commit planning docs via CLI (respects `commit_docs` config automatically):
gsd_run query commit "docs: resolve debug {slug}" --files .planning/debug/resolved/{slug}.md
```
**Append to knowledge base:**
**Append to knowledge base (with the Prevention block):**
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):
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):
@~/.claude/gsd-core/references/debugger-prevention.md
Then append to `.planning/debug/knowledge-base.md` (create file with header if it doesn't exist):
If creating for the first time, write this header first:
```markdown
@@ -1234,6 +1240,8 @@ Then append the entry:
- **Root cause(s):** {Resolution.root_cause — joined as '; ' when multiple contributing causes were confirmed}
- **Fix:** {Resolution.fix}
- **Files changed:** {Resolution.files_changed joined as comma list}
- **Why not caught:** {which existing gate (test/typecheck/lint/review/verify/build) should have caught it — or "no gate existed for this class"}
- **Recurrence guard:** {concrete artifact preventing this class from returning — regression test (path:name) / assertion / lint rule / KB pattern / type refinement / config-default change}
---
```