# Phase 20.4: Implement all RETRO-AGENT-FAILURE-PATTERNS mitigations — Research

**Researched:** 2026-04-16
**Domain:** Agent workflow hardening (docs + templates + hooks + workflow edits) — no runtime Rust changes
**Confidence:** HIGH (all artifacts verified against filesystem; hook schema cited from hooks reference)

## Summary

Phase 20.4 implements M-1..M-10 from `.planning/RETRO-AGENT-FAILURE-PATTERNS.md`. The phase is a **process/workflow hardening pass** — it edits markdown documents, templates, GSD workflow files, and adds two soft-warning Claude Code hooks. Zero production Rust changes. A majority of the work is in two scope regions: (a) the project repo (`.planning/`, `code_tips/`, `CLAUDE.md`, `.claude/settings.json`) and (b) the user-home GSD install (`~/.ccs/instances/bigscreen/get-shit-done/workflows/` and `templates/` and `references/`).

The dominant scoping decision that must be made explicit in PLAN.md: **edits to `~/.ccs/instances/bigscreen/get-shit-done/` are outside the project git repo.** M-1, M-3, M-9, and M-10 all require such edits. The planner must either (a) make those edits and note them, (b) propose a sibling project-level override, or (c) document the change requests as follow-ups for the GSD instance owner. Recommended: make the edits in place (the user IS the GSD instance owner — `bigscreen` is a personal instance).

**Primary recommendation:** Ten single-mitigation plans, each with a clear "files modified" list and grep-verifiable proof. Group dependencies: M-2 soft-blocks reference the M-1 checklist; M-9 UAT checklist generator references M-3 BUGSWEEPER gate. Doc home: keep all new artifacts at `.planning/` root (matches existing DATA-FLOW.md / RETRO-AGENT-FAILURE-PATTERNS.md / ROADMAP.md pattern; no `architecture/` subdir exists or is needed). CLAUDE.md edits: inline (file is 44 lines — easily read by every agent).

---

## User Constraints (from phase description — no CONTEXT.md exists)

### Locked Decisions
- **Scope:** All 10 mitigations (M-1 through M-10) are in scope per phase title "Implement all …".
- **Hooks (M-2, M-6):** Soft warnings, not hard blocks (retro §6 recommendation accepted).
- **Depends on:** Phase 20 (which is complete — per STATE.md line 614 of ROADMAP.md).

### Claude's Discretion (this research resolves)
- M-4 Modal State Audit timeline — recommendation below.
- Doc home (`.planning/` root vs `.planning/architecture/`) — recommendation below.
- CLAUDE.md edits direct vs AGENT-RULES.md — recommendation below.
- Sequencing / wave packing of the 10 mitigations.

### Deferred Ideas (OUT OF SCOPE)
- Performing the actual Modal State Audit content (M-4 itself): this phase only inserts a follow-on phase for it.
- Rewriting the retrospective document.
- Building M-7 regex into a linter binary (`code_tips` + grep is sufficient).

---

## Phase Requirements

This phase has no formally-mapped REQ-IDs in `.planning/REQUIREMENTS.md`. The retro file IS the requirements spec. For traceability in VERIFICATION.md, use identifiers **M-1 … M-10** with the retro-doc `Concrete artifact` lines as acceptance criteria.

| ID | Description | Research Support |
|----|-------------|------------------|
| M-1 | Parallel-Sites checklist in PLAN.md template | Callsite inventory below proves the checklist is needed; planner prompt file located |
| M-2 | Pre-fix "find-all-sites" rule in CLAUDE.md + soft PreToolUse hook | CLAUDE.md structure verified; hook schema cited |
| M-3 | BUGSWEEPER gate before UAT-claim (gsd-verifier prompt + VERIFICATION.md template) | verifier workflow + template files located |
| M-4 | Modal-state architectural review — produces `.planning/MODAL-STATE.md` | Current phase is only the **phase-insertion wrapper**; audit itself deferred |
| M-5 | `.planning/SYNC-MERGE.md` contract doc + DATA-FLOW.md cross-link | DATA-FLOW.md RULE numbering verified; merge code sites located |
| M-6 | Commit-size + parallel-path verification soft-block (PreToolUse hook) | Hook event and `git diff --stat` shell pattern validated |
| M-7 | `code_tips/CALLBACK_PIPELINE.md` codifying apply_filters / invoke_sync_cards_updated invariants | Full callsite inventory gathered; existing `code_tips/` layout confirmed |
| M-8 | `.planning/REOPENED.md` ledger + one-line policy in CLAUDE.md | Current reopened docs verified (2 items) |
| M-9 | UAT checklist generator in gsd-verifier — outputs `UAT-CHECKLIST.md` | verifier workflow + BUGSWEEPER endpoints inventoried |
| M-10 | Replace-vs-refactor decision gate — PLAN.md template + gsd-planner prompt | planner-subagent template + plan-phase workflow located |

---

## Architectural Responsibility Map

| Capability | Primary Tier | Secondary Tier | Rationale |
|------------|--------------|----------------|-----------|
| Docs produced (`SYNC-MERGE.md`, `REOPENED.md`, `MODAL-STATE.md` wrapper, `CALLBACK_PIPELINE.md`, `PARALLEL-SITES-CHECKLIST.md`) | Project repo `.planning/` + `code_tips/` | — | Matches existing layout (DATA-FLOW.md, RETRO-*.md, code_tips/*_TIPS.md all live there) |
| CLAUDE.md directives (M-2 sibling-search rule, M-8 reopened-bug policy, M-10 replace-vs-refactor) | Project repo root | — | CLAUDE.md is short (44L) and already hosts rules of this shape |
| GSD workflow edits (planner, plan-checker, verifier) | User home `~/.ccs/instances/bigscreen/get-shit-done/` | — | That is the authoritative source for this GSD instance — no project override mechanism exists |
| PLAN.md template updates (M-1 parallel-sites block, M-10 requirements-preserved block) | `~/.ccs/instances/bigscreen/get-shit-done/templates/` + planner workflow | Project-level checklist `.planning/templates/` | Both paths; template in GSD home is the generator, project template is the fillable checklist |
| Hooks (M-2, M-6) | Project `.claude/settings.json` (shareable) | Cross-platform shell scripts in `.claude/hooks/` | Project-scoped so any contributor gets them; must be Windows-compatible (Git Bash) |
| Verification templates | `~/.ccs/instances/bigscreen/get-shit-done/templates/verification-report.md` | `.planning/phases/<id>/UAT-CHECKLIST.md` per-phase output | Template in GSD home; per-phase output in project |

---

## Project Constraints (from CLAUDE.md)

CLAUDE.md (44 lines, verified at `CLAUDE.md`) imposes these existing directives this phase must not violate:

1. **Windows environment** — scripts must not use `jq`; use `python` or Git-Bash `grep`/`awk`. (Applies to M-2 and M-6 hooks.)
2. **code_tips discipline** — if the phase touches tech covered by `code_tips/*`, read them first. M-7 extends this directory; the new `CALLBACK_PIPELINE.md` must be listed the same way as `SQLITE_TIPS.md` / `SLINT_TIPS.md`.
3. **DATA-FLOW.md is authoritative for data architecture** — M-5's `SYNC-MERGE.md` must be cross-linked from DATA-FLOW.md and use the same RULE-XX numbering convention (RULE-01..RULE-09 exist today; SYNC-MERGE.md can introduce SYNC-01..SYNC-NN, local to that file).
4. **Owl messaging** — any subagents spawned by an orchestrating phase must get an owl ID. This phase is doc/template work so subagent-spawning is minimal; the planner should note Owl IDs only if it fans out to independent agents.
5. **BUGSWEEPER session rule** — mutations during a debug session must be reverted. M-3 text must preserve this language exactly when elevating BUGSWEEPER to mandatory.
6. **Self-healing rule** — M-3's mandatory BUGSWEEPER gate must preserve the `/gsd:quick` self-healing clause.

No CLAUDE.md directive blocks any of M-1..M-10.

---

## Standard Stack

This is a documentation / workflow-wiring phase. There are no new libraries. The "stack" here is the tooling we lean on:

| Tool | Version | Purpose | Why Standard |
|------|---------|---------|--------------|
| Claude Code hooks | Current (2026-04) | PreToolUse soft warnings for M-2 and M-6 | Only mechanism for triggering on Edit/Write/Bash before the action [CITED: ~/.claude/reference_docs/claude-code-hooks.md] |
| Git Bash (MSYS) on Windows | project-standard | Hook shell | CLAUDE.md mandates Windows-Unix-shell syntax |
| python3 | user-verified | JSON parsing in hooks (replaces jq) | CLAUDE.md explicitly bans `jq` |
| BUGSWEEPER HTTP debug server | feature-gated in `crates/bugsweeper/` | M-3 gate + M-9 UAT assertions | Already the project standard (CLAUDE.md BUGSWEEPER section) [VERIFIED: `crates/bugsweeper/GUIDE.md` exists, 478 lines] |

**No installation required.** All tools are already available in the project environment.

---

## Architecture Patterns

### System Flow — How the Mitigations Wire Together

```
                  user runs /gsd-plan-phase N
                            |
                            v
   +-----------------------------------------------------+
   |  research-phase.md workflow  (no change)            |
   +-----------------------------------------------------+
                            |
                            v
   +-----------------------------------------------------+
   |  plan-phase.md workflow                             |
   |                                                     |
   |   +--[M-1]--> planner reads PARALLEL-SITES-         |
   |   |          CHECKLIST.md + CALLBACK_PIPELINE.md    |
   |   |                                                 |
   |   +--[M-10]-> planner reads Replace-vs-Refactor     |
   |              rule; if replace, produces             |
   |              "Requirements Preserved" doc           |
   |                                                     |
   |   --> PLAN.md emitted with Parallel-Sites section   |
   +-----------------------------------------------------+
                            |
                            v
   +-----------------------------------------------------+
   |  plan-checker (few-shot example + inline rules)     |
   |   --> BLOCKS if PLAN.md touches sync/modal/callback |
   |       and Parallel-Sites section is empty (M-1)     |
   +-----------------------------------------------------+
                            |
                            v
   +-----------------------------------------------------+
   |  /gsd-execute-phase                                 |
   |   --> agent writes code                             |
   |                                                     |
   |   on Edit/Write  --[M-2 HOOK]--> warn if function   |
   |                                  name not grep'd    |
   |                                  this session       |
   |   on `git commit` -[M-6 HOOK]--> warn if >200 LOC   |
   |                                  and no "parallel   |
   |                                  sites checked"     |
   +-----------------------------------------------------+
                            |
                            v
   +-----------------------------------------------------+
   |  verify-phase workflow                              |
   |   --[M-3]--> run BUGSWEEPER smoke test              |
   |              emit VERIFICATION.md with              |
   |              "BUGSWEEPER Coverage" subsection       |
   |                                                     |
   |   --[M-9]--> emit UAT-CHECKLIST.md from modified    |
   |              callbacks + sync sites                 |
   +-----------------------------------------------------+
                            |
                            v
                 user runs /gsd-verify-work
                            |
                            v
        Bug reopens  --[M-8]-->  append to REOPENED.md
```

**Components referenced by the diagram (file mapping):**

| Component | File | Status |
|-----------|------|--------|
| PARALLEL-SITES-CHECKLIST.md | `.planning/templates/PARALLEL-SITES-CHECKLIST.md` | CREATE (M-1) |
| CALLBACK_PIPELINE.md | `code_tips/CALLBACK_PIPELINE.md` | CREATE (M-7) |
| SYNC-MERGE.md | `.planning/SYNC-MERGE.md` | CREATE (M-5) |
| MODAL-STATE.md | `.planning/MODAL-STATE.md` | DEFERRED (M-4 produces later) |
| REOPENED.md | `.planning/REOPENED.md` | CREATE (M-8) |
| Planner workflow | `~/.ccs/instances/bigscreen/get-shit-done/workflows/plan-phase.md` | EDIT (M-1, M-10) |
| Planner template | `~/.ccs/instances/bigscreen/get-shit-done/templates/planner-subagent-prompt.md` | EDIT (M-1, M-10) |
| Plan-checker calibration | `~/.ccs/instances/bigscreen/get-shit-done/references/few-shot-examples/plan-checker.md` | EDIT (M-1) |
| Verifier workflow | `~/.ccs/instances/bigscreen/get-shit-done/workflows/verify-phase.md` | EDIT (M-3, M-9) |
| VERIFICATION.md template | `~/.ccs/instances/bigscreen/get-shit-done/templates/verification-report.md` | EDIT (M-3) |
| Project hooks config | `.claude/settings.json` | CREATE (M-2, M-6) |
| Hook scripts | `.claude/hooks/sibling-search-warn.sh`, `.claude/hooks/commit-size-warn.sh` | CREATE (M-2, M-6) |
| CLAUDE.md | `CLAUDE.md` | EDIT (M-2, M-7 link, M-8, M-10) |
| ROADMAP.md | `.planning/ROADMAP.md` | EDIT (M-4: insert placeholder phase 20.5 for Modal Audit) |

### Recommended Project Structure (after this phase)

```
.planning/
├── DATA-FLOW.md                       (existing — cross-link added by M-5)
├── MODAL-STATE.md                     (NEW — empty placeholder created in M-4)
├── SYNC-MERGE.md                      (NEW — M-5)
├── REOPENED.md                        (NEW — M-8)
├── RETRO-AGENT-FAILURE-PATTERNS.md    (existing)
├── ROADMAP.md                         (existing — edited by M-4 to insert 20.5)
├── STATE.md                           (existing)
├── templates/                         (NEW directory)
│   └── PARALLEL-SITES-CHECKLIST.md    (NEW — M-1)
└── phases/
    └── 20.4-.../
        ├── 20.4-RESEARCH.md
        └── 20.4-NN-PLAN.md            (one per mitigation)

code_tips/
├── SLINT_TIPS.md       (existing)
├── SQLITE_TIPS.md      (existing)
└── CALLBACK_PIPELINE.md (NEW — M-7)

.claude/
├── settings.json                      (NEW — M-2, M-6 hook config)
└── hooks/
    ├── sibling-search-warn.sh         (NEW — M-2)
    └── commit-size-warn.sh            (NEW — M-6)
```

### Per-Mitigation Patterns

**M-1 Parallel-Sites Checklist** — one-page template in `.planning/templates/` that the planner's PLAN.md preamble links to. Make it grep-friendly: the planner writes `## Parallel Sites` section with H3 subheadings for each of: `### Code sites doing the same operation`, `### Local-only fields at risk`, `### Callbacks assumed pre-wired`. Plan-checker greps for the `## Parallel Sites` header and errors BLOCKER if plan touches sync/modal/callback files and section is empty.

**M-2 Pre-fix sibling search (hook)** — `PreToolUse` hook matched on `Edit|Write`. The hook reads `tool_input.file_path` and `tool_input.new_string` (or `content`) — if either mentions a function-name-like token (regex `\bfn [a-z_]+\(` or Slint callback `\.on_[a-z_]+\(`), it scans the current session's transcript (`$CLAUDE_TRANSCRIPT_PATH` from hook input) for a prior Grep call with that token. If not found, it emits `additionalContext: "Reminder: before editing 'fn X', run Grep for 'X' across the codebase to find sibling sites."` with permissionDecision `allow` (soft). Shell: Git-Bash compatible, uses `grep` + `python` (no jq).

**M-3 BUGSWEEPER gate** — verify-phase.md gets a new step `<step name="bugsweeper_smoke">` that (a) runs `cargo build --features bugsweeper`, (b) launches the app, (c) polls `/api/debug/health`, (d) runs the smoke script from GUIDE.md §Typical workflows, (e) appends a `### BUGSWEEPER Coverage` section to VERIFICATION.md listing which endpoints were hit. Phase that touches sync/modal/callback CANNOT reach `status: passed` without that section present.

**M-4 Modal audit wrapper** — this phase's plan only: (a) creates `.planning/MODAL-STATE.md` with a template skeleton and a TODO preamble, (b) inserts a new phase `20.5: Modal State Architectural Audit` into ROADMAP.md, (c) adds CLAUDE.md line: "Before modifying modal state machines, read `.planning/MODAL-STATE.md`; after, update it in the same commit." The actual audit content is produced by the 20.5 phase.

**M-5 Sync-merge contract** — `.planning/SYNC-MERGE.md` with these sections:
  - `## AGENT RULES` — mirrors DATA-FLOW.md style; new rules SYNC-01 "Every struct field declares `local_only: true|false`", SYNC-02 "Every sync entry point documents which fields it merges".
  - `## Local-only Fields Inventory` — table keyed by struct + field.
  - `## Sync Entry Points` — table keyed by function (`run_sync_cycle`, `save_note`, `sync_products`, `sync_card_issues`, `detect_card_changes`, `upsert_*` family) with what they overwrite vs. merge.
  - DATA-FLOW.md gets a new paragraph under existing RULE-09 pointing to SYNC-MERGE.md.

**M-6 Commit size hook** — `PreToolUse` matcher `Bash`, inspects `tool_input.command` for `git commit`. If detected, shell script runs `git diff --cached --shortstat` to compute net lines. If > 200, emits `additionalContext` reminding agent of Parallel-Sites link OR explicit statement in commit body. `permissionDecision: "allow"` always (soft).

**M-7 Callback pipeline invariants** — `code_tips/CALLBACK_PIPELINE.md`:
  - Two invariants stated as `INV-1` and `INV-2`.
  - Concrete regex: `apply_optimistic_[a-z_]+\(` must be followed within 30 lines by `apply_filters\(` — confirmed via code scan (see Runtime State Inventory below, only one live site today but the pattern is preventive).
  - List of every current callsite so future agents grep this doc, not `main.rs`.
  - CLAUDE.md "Code Tips" section gets this file added to its list.

**M-8 Reopened-bug ledger** — single file `.planning/REOPENED.md`. CLAUDE.md gets a one-line policy: "If a debug doc is moved out of `/debug/resolved/` a second time, add an entry to `.planning/REOPENED.md` with the reopen date and a one-sentence root cause."

**M-9 UAT checklist generator** — verify-phase.md emits `.planning/phases/<id>/UAT-CHECKLIST.md` by reading the phase's touched callbacks (`grep -E '^\s*window\.on_'` over modified files listed in plan frontmatter `files_modified`). Each callback = one checklist item with an expected BUGSWEEPER `/api/ui/callback` POST to trigger it.

**M-10 Replace-vs-refactor gate** — PLAN.md template gains a conditional `## Requirements Preserved (Replacement Plans Only)` section. The planner-subagent-prompt.md and plan-phase.md workflow add a decision rule: "If the plan replaces a Slint component or a Rust module with more than 100 lines, emit the Requirements Preserved section listing each behavior of the original that the replacement must keep." CLAUDE.md gets a pointer rule.

### Anti-Patterns to Avoid
- **Treating GSD workflow edits as out-of-repo write-offs.** They must be listed in plan `files_modified` using absolute paths to `$HOME/.ccs/instances/bigscreen/get-shit-done/...` so VERIFICATION.md can grep them.
- **Making hooks blocking.** Retro §6 explicitly recommended soft. Hard blocks would stall every `git commit` during normal iteration.
- **Embedding the M-4 audit content in this phase.** That's the 20.5 phase's work; this phase only scaffolds.
- **Writing new `.planning/architecture/` subdir.** None exists today — adding one fragments navigation. Keep flat.
- **AGENT-RULES.md split.** CLAUDE.md is 44 lines — keep directives inline.

## Don't Hand-Roll

| Problem | Don't Build | Use Instead | Why |
|---------|-------------|-------------|-----|
| Soft-warn on edit without prior sibling search | Custom session-history tracker | Claude Code `PreToolUse` hook with `$CLAUDE_TRANSCRIPT_PATH` input | Hooks natively receive transcript path; rolling our own session store duplicates state [CITED: claude-code-hooks.md §PreToolUse] |
| JSON parsing in hooks on Windows | Inline `sed`/`awk` pipeline | `python -c` (already in PATH per CLAUDE.md) | CLAUDE.md bans jq; python is the stock substitute |
| "Are we in a git commit?" detection in a Bash hook | String matching `tool_input.command` with regex permutations | `echo "$COMMAND" \| grep -Eq '^\s*git\s+commit(\s\|$)'` | Simple and robust; Claude Code passes command verbatim in input JSON |
| Modal state diagram format | Hand-drawn ASCII art | Mermaid fenced block inside `.planning/MODAL-STATE.md` | Renders in GitHub; machine-greppable for node names |
| Parallel-sites enumeration regex for callbacks | Custom AST parser | `grep -E 'window\.on_[a-z_]+'` on the diff files | BUGSWEEPER registry already lists every callback for validation |

**Key insight:** Every mitigation in this phase has a "don't-hand-roll" substitute either in Claude Code primitives (hooks, transcript path) or in existing project tools (BUGSWEEPER, code_tips convention). Writing custom shell frameworks is the anti-pattern.

## Runtime State Inventory

> Included because this phase refactors the planning/verification **process** and the in-code invariants it codifies (M-7). Zero runtime-data state is touched.

| Category | Items Found | Action Required |
|----------|-------------|------------------|
| Stored data | **None** — no database schema or stored content is changed. | none |
| Live service config | **None** — no external service config is touched. | none |
| OS-registered state | **None** — no Task Scheduler / pm2 / service registrations. | none |
| Secrets/env vars | **None** — hooks use only `$CLAUDE_TRANSCRIPT_PATH` and `$CLAUDE_PROJECT_DIR` which Claude Code sets. | none |
| Build artifacts | BUGSWEEPER binary `target/debug/app.exe` with `--features bugsweeper` is required at runtime by M-3 verifier step. Already built for this project. No migration. | ensure `cargo build --features bugsweeper` is runnable; no cleanup needed |

### Callback / Sync Pipeline Invariants Inventory (for M-7 content)

All sites verified via `Grep` at research time:

**`apply_optimistic_*` callsites (source of M-7 INV-1):**
| File:Line | Context |
|-----------|---------|
| `crates/app/src/main.rs:450` | `fn apply_optimistic_item_remove` — definition |
| `crates/app/src/main.rs:4045` | Call site in `on_card_confirm_remove_item` — **followed** by `apply_filters(&w, ...)` at 4061 (compliant) |
| `crates/app/src/main.rs:6911,6917,6923` | Test references |

Only one live call site today. `apply_optimistic_note_update` removed in plan 20.1.1-08 per comment at main.rs:6917. Pattern is preventive — future adds must comply.

**`invoke_sync_cards_updated` callsites (source of M-7 INV-2):**
| File:Line | Context |
|-----------|---------|
| `crates/app/src/main.rs:1920` | — |
| `crates/app/src/main.rs:2674` | — |
| `crates/app/src/main.rs:2997` | In `on_settings_shopify_clear_clicked` (the cascade-bug path, commit dc622640) |
| `crates/app/src/main.rs:3100` | In `on_settings_save_clicked` |

**`all_cards_ref.borrow_mut()` sites:** `main.rs:2815, 2841` (only two — both inside `save_note` optimistic path, both followed by `apply_filters(&window, ...)` at 2855).

**Settings save/clear pair (the historical cascade):** `on_settings_save_clicked` at line 3012 and `on_settings_shopify_clear_clicked` at line 2961. Both currently call `invoke_sync_cards_updated` (patched in dc622640). M-7 codifies this invariant.

**`apply_filters(...)` callsites:** 37 sites across `main.rs` (verified via Grep — lines listed in full in M-7 doc). This is the invariant sink: every local mutation of `all_cards` must be followed by one of these.

**Sync entry points for M-5 SYNC-MERGE.md:**
| File:Line | Function | Writes |
|-----------|----------|--------|
| `crates/app/src/live_client.rs:1051` | `run_sync_cycle` | Primary sync — `upsert_recipient` x2, `upsert_card`, `upsert_product`, `upsert_product_unit` |
| `crates/app/src/live_client.rs:396` | `save_note` | Local-originated — calls `upsert_notes_for_card` then posts to GH |
| `crates/app/src/live_client.rs:948..1035` | `cascade_shipment_state_to_units` call paths | Calls `store.update_unit_state` — local-only `assigned_card_id` preservation via `.as_deref()` |
| `crates/app/src/live_client.rs:1230-1231` | Merge step in `run_sync_cycle` | Keeps existing `product_refs` with `serial_id` — the local-only field pattern |
| `crates/app/src/live_client.rs:1449-1451` | Product issue body read-back | Sets `assigned_card_id` from ww-unit body |

The explicit comment at live_client.rs:1230 — "Shopify sync data does not carry unit assignments — those are local-only" — is exactly what M-5 SYNC-MERGE.md must catalog in machine-readable form.

## Common Pitfalls

### Pitfall 1: Editing GSD workflow files and losing them on GSD upgrade
**What goes wrong:** User's GSD instance in `~/.ccs/instances/bigscreen/get-shit-done/` is a git-tracked install. A future `ccs upgrade` could overwrite M-1/M-3/M-9/M-10 edits.
**Why it happens:** The retro assumes project-scoped changes, but planner/verifier live in GSD home.
**How to avoid:** Plans that edit GSD files must (a) commit the change in the GSD instance repo (separate from project repo), AND (b) note the change in `.planning/REOPENED.md`-style backup so it can be re-applied after an upgrade. Alternative: PLAN.md lists these edits under a "GSD-instance edits" subsection so the execution agent knows to commit them separately.
**Warning signs:** Agent edits plan-phase.md but doesn't mention the GSD commit. Verifier later shows the rule is present; weeks later, upgrade wipes it.

### Pitfall 2: Hook scripts not executable on Windows
**What goes wrong:** `.sh` scripts in `.claude/hooks/` fail to execute because Windows doesn't honor Unix executable bits.
**Why it happens:** Git Bash can run `.sh` files but only if invoked as `bash script.sh` or if shebang is honored (hook `"shell": "bash"` config).
**How to avoid:** In hook config, use `"shell": "bash"` explicitly AND shebang `#!/usr/bin/env bash` at top. Verified-shell pattern: `"command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/sibling-search-warn.sh\""`.
**Warning signs:** Hook registered but never fires, no stderr in Claude Code verbose mode.

### Pitfall 3: Soft-warn hooks that always warn
**What goes wrong:** A hook that emits `additionalContext` on every Edit becomes noise; agents learn to ignore it.
**Why it happens:** Overly broad matcher (e.g., triggers on doc edits too).
**How to avoid:** Narrow match — only when `tool_input.file_path` ends in `.rs` or `.slint` AND the new content contains a function-signature or callback pattern. Same for M-6: only on `git commit` with large diff, not small ones.
**Warning signs:** Hook fires in every session within minutes of install.

### Pitfall 4: M-1 Parallel-Sites section enforced on plans that don't need it
**What goes wrong:** Plans for pure doc updates or config-only changes get blocked for missing the Parallel-Sites section.
**Why it happens:** Plan-checker enforcement too broad.
**How to avoid:** Gate enforcement on trigger files — only require if `files_modified` lists anything under `crates/app/src/` matching `main.rs|live_client.rs|dashboard.rs|*.slint`.
**Warning signs:** Every plan review bounces with BLOCKER on Parallel-Sites.

### Pitfall 5: BUGSWEEPER gate failing for phases that don't touch UI/data
**What goes wrong:** M-3 mandates BUGSWEEPER for phases touching sync/modal/callback — but Phase 20.4 itself (this one!) touches none of those, so verification can't prove M-3 works.
**Why it happens:** Circular: the mitigation phase has to verify the mitigation.
**How to avoid:** M-3 verify step is GATED by file scope — if `files_modified` intersects `{*.rs, *.slint}` under `crates/app/`, BUGSWEEPER runs; otherwise recorded as "N/A — no runtime changes". This phase's own verification uses grep-based presence checks instead.
**Warning signs:** This phase's verifier tries to run BUGSWEEPER smoke test and finds nothing to test.

### Pitfall 6: DATA-FLOW.md update obligation not honored for M-5
**What goes wrong:** SYNC-MERGE.md is created but DATA-FLOW.md is not cross-linked in the same commit, violating CLAUDE.md "update obligation."
**Why it happens:** Agent treats them as separate plans.
**How to avoid:** M-5 plan lists both `.planning/SYNC-MERGE.md` AND `.planning/DATA-FLOW.md` under `files_modified` and single atomic commit.
**Warning signs:** M-5 commit only shows one file; DATA-FLOW.md still reads "No cross-reference to SYNC-MERGE.md exists" on next grep.

## Code Examples

### M-2 Sibling Search Hook (shell)
```bash
#!/usr/bin/env bash
# Source: patterned on claude-code-hooks.md §PreToolUse
# .claude/hooks/sibling-search-warn.sh
set -uo pipefail
INPUT=$(cat)
TOOL=$(echo "$INPUT" | python -c 'import sys,json; print(json.load(sys.stdin).get("tool_name",""))')
[[ "$TOOL" != "Edit" && "$TOOL" != "Write" ]] && { echo '{}'; exit 0; }

FILE=$(echo "$INPUT" | python -c 'import sys,json; t=json.load(sys.stdin).get("tool_input",{}); print(t.get("file_path","") or t.get("path",""))')
case "$FILE" in *.rs|*.slint) ;; *) echo '{}'; exit 0 ;; esac

CONTENT=$(echo "$INPUT" | python -c 'import sys,json; t=json.load(sys.stdin).get("tool_input",{}); print(t.get("new_string","") or t.get("content",""))')
FN=$(echo "$CONTENT" | grep -oE '\bfn [a-z_][a-z0-9_]*\b' | awk '{print $2}' | head -1)
[[ -z "$FN" ]] && { echo '{}'; exit 0; }

TRANSCRIPT="${CLAUDE_TRANSCRIPT_PATH:-}"
if [[ -n "$TRANSCRIPT" && -f "$TRANSCRIPT" ]] && grep -q "\"pattern\".*$FN" "$TRANSCRIPT"; then
  echo '{}'; exit 0
fi
cat <<EOF
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","additionalContext":"Pre-fix sibling-search reminder: editing fn $FN — have you grepped for '$FN' across crates/app/src and crates/app/ui this session? (see CLAUDE.md M-2 rule)"}}
EOF
```

### M-6 Commit Size Hook (shell)
```bash
#!/usr/bin/env bash
# .claude/hooks/commit-size-warn.sh
INPUT=$(cat)
CMD=$(echo "$INPUT" | python -c 'import sys,json; print(json.load(sys.stdin).get("tool_input",{}).get("command",""))')
echo "$CMD" | grep -Eq '^\s*git\s+commit(\s|$)' || { echo '{}'; exit 0; }
NET=$(cd "$CLAUDE_PROJECT_DIR" && git diff --cached --shortstat 2>/dev/null | grep -oE '[0-9]+ insertion' | head -1 | grep -oE '[0-9]+' || echo 0)
[[ "$NET" -lt 200 ]] && { echo '{}'; exit 0; }
cat <<EOF
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","additionalContext":"Commit size >200 lines ($NET insertions). RETRO-AGENT-FAILURE-PATTERNS §M-6: include 'parallel sites checked' list in commit body or link to PLAN.md parallel-sites section."}}
EOF
```

### `.claude/settings.json` (hook registration)
```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/sibling-search-warn.sh\"", "shell": "bash", "timeout": 10 }
        ]
      },
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/commit-size-warn.sh\"", "shell": "bash", "timeout": 10 }
        ]
      }
    ]
  }
}
```

### M-7 CALLBACK_PIPELINE.md skeleton (code_tips style)
```markdown
# Callback Pipeline Invariants

## INV-1: every local mutation of all_cards_ref is followed by apply_filters
Pattern: `all_cards_ref.borrow_mut()` ... `apply_filters(&window, &all_cards_ref.borrow(), &runtime)`.
Current compliant sites: main.rs:2815+2855, main.rs:2841+2855.

## INV-2: every secondary sync path ends with invoke_sync_cards_updated
Pattern: `{settings,save,clear}_clicked` ... `w.invoke_sync_cards_updated()`.
Current compliant sites: main.rs:1920, 2674, 2997 (settings clear), 3100 (settings save).
Historical violation: dc622640 (fixed — on_settings_shopify_clear_clicked).

## Reviewer grep
`rg 'apply_optimistic_[a-z_]+\(' -A 30 crates/app/src/ | rg -e apply_filters -e '^--$'`
Any block lacking `apply_filters` within 30 lines is a violation.
```

### M-1 PARALLEL-SITES-CHECKLIST.md skeleton
```markdown
# Parallel-Sites Checklist

Required in every PLAN.md whose files_modified touches:
crates/app/src/{main.rs,live_client.rs,dashboard/**,assignment.rs} or crates/app/ui/**.

## Parallel Sites
### Code sites doing the same operation
- file:line — description

### Local-only fields at risk
- struct::field — why this sync pass could destroy it

### Callbacks assumed pre-wired
- callback name — where it is declared
```

## State of the Art

| Old Approach | Current Approach | Impact |
|--------------|------------------|--------|
| "Read code_tips if relevant" (soft) | Hooks actively remind (M-2) | Cheap enforcement, no hard block |
| Plans as post-UAT gap lists | Plans enumerate parallel sites up front (M-1) | Inverts reactive → proactive planning |
| BUGSWEEPER "should run" | BUGSWEEPER "must run" before verified (M-3) | Catches class F4 (verification-skipped) |
| Static code review only | Runtime assertion + static (M-3 + existing plan-checker) | Catches class F5 |
| Silent reopens | Ledger-enforced (M-8) | Makes reopen cost visible to process |

No deprecated/outdated patterns — this phase adds, doesn't subtract.

## Assumptions Log

| # | Claim | Section | Risk if Wrong |
|---|-------|---------|---------------|
| A1 | `~/.ccs/instances/bigscreen/` is user-owned and edits survive `ccs upgrade` if committed locally | Architectural Responsibility Map; Pitfall 1 | [ASSUMED] — if upgrade overwrites, M-1/M-3/M-9/M-10 edits may regress. Mitigation: Pitfall 1 mandates a ledger entry. User must confirm they control the GSD instance repo. |
| A2 | `$CLAUDE_TRANSCRIPT_PATH` is set as env var for hooks (vs only in stdin JSON) | M-2 hook code example | [ASSUMED from hooks ref §Common Input Fields lists `transcript_path` in stdin]. Actual env exposure not directly cited. If env var missing, read from stdin JSON instead (trivial script change). |
| A3 | `git diff --cached --shortstat` reliably gives insertion count in Git Bash on Windows | M-6 hook code example | [VERIFIED — standard git command, cross-platform]. No risk. |
| A4 | Plan-checker BLOCKER enforcement can be added via the few-shot examples file alone | M-1 implementation | [ASSUMED] — the plan-checker is driven by `plan-checker.md` example + the checker workflow's dimensions table. If enforcement requires a new dimension to be formally added to the schema, the plan must also edit the dimensions list. |
| A5 | `workflow.nyquist_validation` is absent from config.json → section included by default per research agent rules | Validation Architecture | [VERIFIED by cat of `.planning/config.json`] — key absent, section included. |
| A6 | Phase 20 is complete so this phase can depend on it | Summary | [VERIFIED — ROADMAP.md line 614: "Phase 20 ... Complete 2026-04-11"]. |
| A7 | `.claude/settings.json` project-level hook config is honored on Windows and will not clash with user `~/.claude/settings.json` existing hooks | Architecture Patterns | [CITED: claude-code-hooks.md §Hook Locations] — merge order: user → project → local → managed → plugins. Project-level additions merge additively. No clash risk for new matchers. |

## Open Questions (RESOLVED)

1. **M-1 dimension wiring in plan-checker.** The few-shot examples file is a calibration reference, not the dimension definitions. If formal dimension registration is needed for `parallel_sites`, the plan must include editing whatever schema defines the 10-dimension list.
   - What we know: `plan-checker.md` few-shot file verified; mentions dimensions like `task_completeness`, `dependency_correctness`, `verification_derivation`, `scope_sanity`.
   - What's unclear: Is there a `references/plan-checker-dimensions.md` or similar?
   - Recommendation: Planner should grep `~/.ccs/instances/bigscreen/get-shit-done/references/` for the dimension registry; if present, edit it; if absent, rely on few-shot examples.

2. **M-4 timeline.** Run as Phase 20.5 immediately, defer to v1.2, or skip?
   - Recommendation: **Insert as Phase 20.5 placeholder** in ROADMAP.md but do not execute in 20.4. The modal layer accounts for 71% of recent gap-closures — the audit pays for itself but needs its own planning pass. Inserting as a placeholder makes the commitment visible without bloating 20.4.

3. **Doc home.** `.planning/` root vs `.planning/architecture/` subdir?
   - Recommendation: **Flat, at `.planning/` root.** No `architecture/` exists today; all prescriptive docs (DATA-FLOW, ROADMAP, RETRO-*) live flat. Adding a subdir fragments navigation and breaks the pattern every agent learns.

4. **CLAUDE.md direct vs AGENT-RULES.md split.**
   - Recommendation: **Direct edits to CLAUDE.md.** File is 44 lines; adding M-2/M-7/M-8/M-10 pointers keeps it under 80 lines. AGENT-RULES.md split adds indirection without size benefit.

5. **Commit granularity.** One commit per mitigation, or grouped?
   - Recommendation: **One commit per mitigation** (10 commits). M-5 is the single exception — SYNC-MERGE.md + DATA-FLOW.md edit in one commit (CLAUDE.md update obligation). Per-mitigation commits keep `git log` scannable for future retros.

## Environment Availability

| Dependency | Required By | Available | Version | Fallback |
|------------|------------|-----------|---------|----------|
| Git Bash (bash 4.x+) | M-2, M-6 hooks | ✓ | present per CLAUDE.md | — |
| python (3.x) | M-2, M-6 hooks (JSON parsing; jq-ban) | ✓ | present per existing project scripts in GUIDE.md | — |
| BUGSWEEPER feature build | M-3 verify step | ✓ | `crates/bugsweeper/` confirmed, GUIDE.md 478L | — |
| Claude Code hooks runtime | M-2, M-6 | ✓ | current version used by user | — |
| `~/.ccs/instances/bigscreen/get-shit-done/` | M-1, M-3, M-9, M-10 | ✓ | verified via `$HOME/.ccs/...` listing | — |
| `ripgrep` or `rg` | M-7 reviewer grep hint | — | not verified | Use `grep -rn` as documented alternative |

**Missing dependencies with no fallback:** None.
**Missing dependencies with fallback:** None critical — `rg` recommendation has `grep` fallback.

## Validation Architecture

`workflow.nyquist_validation` is absent from `.planning/config.json` (verified). Section included per research agent rules.

### Test Framework
| Property | Value |
|----------|-------|
| Framework | Grep-based presence + hook invocation test (no new test harness). For BUGSWEEPER gate: `cargo test --features bugsweeper` exists in project |
| Config file | `.planning/config.json` (verified) |
| Quick run command | `./target/debug/app.exe` + `curl http://127.0.0.1:9876/api/debug/health` for M-3 |
| Full suite command | `cargo test --workspace` (no new tests added by this phase) |

### Phase Requirements → Test Map

| Req ID | Behavior | Test Type | Automated Command | Evidence Exists? |
|--------|----------|-----------|-------------------|-------------------|
| M-1 | Parallel-Sites checklist file exists; planner + plan-checker reference it | grep presence | `test -f .planning/templates/PARALLEL-SITES-CHECKLIST.md && grep -l "Parallel Sites" $HOME/.ccs/instances/bigscreen/get-shit-done/templates/planner-subagent-prompt.md $HOME/.ccs/instances/bigscreen/get-shit-done/references/few-shot-examples/plan-checker.md` | Wave 0 |
| M-2 | CLAUDE.md has Pre-fix sibling search section; hook file exists; settings.json registers it | grep + shell test | `grep -q "Pre-fix sibling search" CLAUDE.md && test -x .claude/hooks/sibling-search-warn.sh && python -c "import json; assert 'sibling-search-warn' in json.load(open('.claude/settings.json'))['hooks']['PreToolUse'][0]['hooks'][0]['command']"` | Wave 0 |
| M-3 | verify-phase.md has bugsweeper_smoke step; verification-report.md has BUGSWEEPER Coverage subsection | grep | `grep -q bugsweeper_smoke $HOME/.ccs/instances/bigscreen/get-shit-done/workflows/verify-phase.md && grep -q "BUGSWEEPER Coverage" $HOME/.ccs/instances/bigscreen/get-shit-done/templates/verification-report.md` | Wave 0 |
| M-4 | MODAL-STATE.md skeleton exists; ROADMAP.md has 20.5 phase; CLAUDE.md has the rule | grep | `test -f .planning/MODAL-STATE.md && grep -q "Phase 20.5" .planning/ROADMAP.md && grep -q "MODAL-STATE.md" CLAUDE.md` | Wave 0 |
| M-5 | SYNC-MERGE.md exists; DATA-FLOW.md cross-links it | grep | `test -f .planning/SYNC-MERGE.md && grep -q "SYNC-MERGE.md" .planning/DATA-FLOW.md` | Wave 0 |
| M-6 | commit-size-warn.sh exists; settings.json registers Bash matcher | grep + shell | `test -x .claude/hooks/commit-size-warn.sh && python -c "import json; ... assert 'commit-size-warn' in ..."` | Wave 0 |
| M-7 | code_tips/CALLBACK_PIPELINE.md exists; CLAUDE.md code_tips list references it | grep | `test -f code_tips/CALLBACK_PIPELINE.md && grep -q "CALLBACK_PIPELINE" CLAUDE.md` | Wave 0 |
| M-8 | REOPENED.md exists; CLAUDE.md policy line present | grep | `test -f .planning/REOPENED.md && grep -q "REOPENED.md" CLAUDE.md` | Wave 0 |
| M-9 | verify-phase.md has uat_checklist step emitting UAT-CHECKLIST.md | grep | `grep -q "UAT-CHECKLIST" $HOME/.ccs/instances/bigscreen/get-shit-done/workflows/verify-phase.md` | Wave 0 |
| M-10 | planner-subagent-prompt.md and plan-phase.md have Replace-vs-refactor rule; CLAUDE.md pointer | grep | `grep -l "Replace-vs-refactor\|Requirements Preserved" $HOME/.ccs/instances/bigscreen/get-shit-done/workflows/plan-phase.md $HOME/.ccs/instances/bigscreen/get-shit-done/templates/planner-subagent-prompt.md && grep -q "Requirements Preserved" CLAUDE.md` | Wave 0 |

### Hook Smoke Test (M-2 and M-6)
```bash
# Dry-run M-2 hook with synthetic Edit payload
echo '{"tool_name":"Edit","tool_input":{"file_path":"crates/app/src/main.rs","new_string":"fn new_func() {}"},"tool_use_id":"t"}' | bash .claude/hooks/sibling-search-warn.sh | python -c "import sys,json; d=json.load(sys.stdin); assert 'additionalContext' in d['hookSpecificOutput']; print('M-2 OK')"

# Dry-run M-6 hook with large commit payload
echo '{"tool_name":"Bash","tool_input":{"command":"git commit -m test"}}' | CLAUDE_PROJECT_DIR=. bash .claude/hooks/commit-size-warn.sh
```

### Sampling Rate
- **Per task commit:** grep-based presence checks (sub-second, run inline)
- **Per wave merge:** hook smoke tests (M-2, M-6 dry-run with fixtures)
- **Phase gate:** all 10 M-NN presence checks must pass before `/gsd-verify-work`

### Wave 0 Gaps
- No existing test harness to reuse — grep-based checks are native to bash. No framework install.
- `UAT-CHECKLIST.md` fixture for M-9 — planner should create one canonical example in this phase's own directory as reference.

## Security Domain

`security_enforcement` is not explicitly set in config.json. Default = enabled. This phase introduces two PreToolUse hooks that execute shell commands, so a minimal threat model is required.

### Applicable ASVS Categories

| ASVS Category | Applies | Standard Control |
|---------------|---------|-----------------|
| V2 Authentication | no | N/A — hooks run locally as the user |
| V3 Session Management | no | N/A |
| V4 Access Control | no | N/A |
| V5 Input Validation | yes | Hook input is untrusted — any tool_input string reaches the shell. Mitigate with `python -c 'print(json.load(sys.stdin).get(...))'` — no shell interpolation of untrusted strings |
| V6 Cryptography | no | N/A |

### Known Threat Patterns for these hooks

| Pattern | STRIDE | Standard Mitigation |
|---------|--------|---------------------|
| Command injection via tool_input content (e.g., agent writes a file containing `$(rm -rf /)` — hook reads the content into a variable) | Tampering | Never `eval` the content. Only use it inside `grep -oE`/`awk` — pattern-scan, never execute. Example in M-2 hook: `echo "$CONTENT" \| grep -oE '\bfn ...'` — `$CONTENT` is safely quoted and only used for pattern matching |
| Path traversal via `tool_input.file_path` (e.g., `../../../etc/passwd`) | Tampering | Only used in `case "$FILE" in *.rs\|*.slint)` — pattern match, no filesystem read |
| Transcript path exposure — hook receives `CLAUDE_TRANSCRIPT_PATH` which may contain prior messages with secrets | Info Disclosure | Hook only greps for a function name in the transcript — no full dump. If the transcript happens to contain secrets, the `grep -q` returns silently |
| Hook itself compromised (malicious edit) | Tampering | Scripts are checked into git; PR review catches edits. CLAUDE.md already prohibits destructive git ops without explicit user ask |
| Hook hangs and blocks tool execution | DoS | `"timeout": 10` in settings.json — hook auto-terminates |

No new credentials, tokens, or external services introduced. Both hooks are local-only and read-only except for stdout (hook response).

## Sources

### Primary (HIGH confidence)
- `[VERIFIED: filesystem 2026-04-16]` `.planning/RETRO-AGENT-FAILURE-PATTERNS.md` — the spec itself
- `[VERIFIED: filesystem]` `CLAUDE.md` (44 lines) — rules and existing patterns
- `[VERIFIED: filesystem]` `.planning/DATA-FLOW.md` (912 lines, RULE-01..RULE-09+)
- `[VERIFIED: filesystem]` `.planning/ROADMAP.md` — Phase 20.4 entry confirmed at line 372
- `[VERIFIED: filesystem]` `.planning/config.json` — `nyquist_validation` and `security_enforcement` not set (defaults apply)
- `[VERIFIED: filesystem]` `crates/bugsweeper/GUIDE.md` (478 lines) — M-3 and M-9 endpoint inventory
- `[VERIFIED: filesystem]` `~/.ccs/instances/bigscreen/get-shit-done/workflows/plan-phase.md` — planner orchestrator
- `[VERIFIED: filesystem]` `~/.ccs/instances/bigscreen/get-shit-done/templates/planner-subagent-prompt.md`
- `[VERIFIED: filesystem]` `~/.ccs/instances/bigscreen/get-shit-done/workflows/verify-phase.md`
- `[VERIFIED: filesystem]` `~/.ccs/instances/bigscreen/get-shit-done/templates/verification-report.md`
- `[VERIFIED: filesystem]` `~/.ccs/instances/bigscreen/get-shit-done/references/few-shot-examples/plan-checker.md`
- `[VERIFIED: Grep]` `apply_optimistic_*` callsites (6 matches in `crates/app/src/main.rs`)
- `[VERIFIED: Grep]` `invoke_sync_cards_updated` callsites (4 matches)
- `[VERIFIED: Grep]` `all_cards_ref.borrow_mut()` callsites (2 matches)
- `[VERIFIED: Grep]` `apply_filters(` callsites (37 matches, all in `main.rs`)
- `[VERIFIED: filesystem]` `.planning/debug/{byproduct-multi-item-grouping.md,item-modal-focus-and-esc.md}` exist in both `debug/` and `debug/resolved/` — confirming retro §7 "2 reopened" count

### Secondary (MEDIUM confidence — cited from authoritative reference docs)
- `[CITED: ~/.claude/reference_docs/claude-code-hooks.md]` — PreToolUse event schema, `permissionDecision: allow|deny|ask|defer`, hook locations/merge order, stdin JSON shape
- `[CITED: ~/.claude/reference_docs/claude-code-hooks.md §Common Input Fields]` — `transcript_path` is a stdin field (env-var version is the A2 assumption)

### Tertiary (LOW confidence — flagged for validation)
- None. All claims in this research either grep-verified or cited from reference docs.

## Metadata

**Confidence breakdown:**
- Standard stack: HIGH — all tools already present in environment
- Architecture: HIGH — all file paths verified on filesystem
- Callsite inventory (M-7 basis): HIGH — direct Grep evidence
- Hook schema: HIGH — cited from reference doc
- GSD instance edit durability: MEDIUM — assumption A1 flagged, mitigation provided
- Plan-checker dimension wiring: MEDIUM — assumption A4 flagged, Open Question #1

**Research date:** 2026-04-16
**Valid until:** 2026-05-16 (docs and process artifacts are stable; hook schema may evolve with Claude Code releases)

## RESEARCH COMPLETE

Phase: 20.4 - Implement all RETRO-AGENT-FAILURE-PATTERNS mitigations (M-1 through M-10)
Confidence: HIGH

Key findings:
- All ten mitigations map to verified files — no blockers.
- Dominant scoping choice: ~5 of the 10 mitigations edit files outside the project repo (in `~/.ccs/instances/bigscreen/get-shit-done/`). Planner must list these explicitly in `files_modified` per plan.
- Recommended structure: 10 plans, one per mitigation; M-5 commit bundles DATA-FLOW.md cross-link per CLAUDE.md update obligation; M-4 is scaffolding-only (inserts Phase 20.5 placeholder).
- Hook threat model is tiny and mitigable with `python -c` JSON parsing (no shell interpolation of untrusted content).
- The apply_optimistic / apply_filters / invoke_sync_cards_updated callsite inventory is small enough (6 + 4 + 2 sites) that M-7 doc can enumerate every site explicitly — future agents grep this doc instead of the 6400-line main.rs.

File created: `.planning/phases/20.4-implement-all-retro-agent-failure-patterns-mitigations-m-1-t/20.4-RESEARCH.md`

Ready for planning. The planner should produce 10 single-mitigation PLAN.md files with the file-map in the Architectural Responsibility Map as the ground truth for `files_modified` fields.
