Background
PR #641 Cycle-3 surfaced a recurring failure mode: when an agent prepares a stage-ready paste describing what's been edited and staged, the prose can drift from disk reality. Concrete instances during #641:
- Cycle-3: backend-coder claimed 3 files / 940 lines / sanitize_slug helper / NEW test_session_state.py — disk showed 5 files / 133 lines / inline regex. Prose-output substituted for tool-call-belief.
- Cycle-3: architect claimed
git add ran but disk showed no modifications. On retry: "I prepared diffs in my plan + composed the stage-ready paste, but never actually invoked Edit."
- Cycle-3: lost ~5 minutes per drift to investigation + correction + recompose.
PR #641 Cycle-4 validated a mitigation: split-Bash-call discipline + M+space vs space+M cross-check. The architect applied it consistently and the verify-only round flagged zero drift. Backend's HANDOFF retired the open issue as "known recipe."
Recipe
For any stage-ready paste:
1. Edit the file (separate Bash call — Edit tool, not Bash)
2. Run `git diff <file>` (separate Bash call) — capture pre-add state
3. Run `git add <file>` (separate Bash call) — never compound `&& git add`
4. Run `git status --short` (separate Bash call) — capture post-add state
5. Run `git diff --cached --stat -- <file>` (separate Bash call) — capture index-state
6. Compose stage-ready prose AGAINST the captured Bash outputs (paste byte-equal from step 5)
Cross-check: in step 4 output, your file should show "M " (M followed by space — left-side M).
If it shows " M" (space followed by M — right-side M), the file is in working-tree only,
NOT in the index. Investigate before composing the paste.
Why each step matters
- Step 1 separate from 2: Compound
Edit && git diff would fail if Edit fails, but the bigger issue is that Edit's output isn't captured. Diff against disk after Edit is the verification.
- Step 2 separate from 3:
git diff shows working-tree changes. If empty, Edit didn't actually run (architect's case).
- Step 3 separate from 4: Compound
git add && git status collapses two facts (add succeeded, post-add state) into one observation. Separating gives audit-grain.
- Step 4 separate from 5:
git status --short shows index vs working-tree state per file (M+space vs space+M). --cached --stat shows what's staged. Both are needed for index-state confidence.
- Step 6 against captured outputs: prose-vs-disk drift happens because the LLM is writing prose from its mental model, not from the substrate's actual state. Pasting from captured outputs forces the prose to match reality.
Proposal — pin to CLAUDE.md as stable recipe
Per pinned project rule structure, add a new pinned context entry to project CLAUDE.md:
### Split-Bash-call stage-ready discipline (PR #641 retired-mitigation)
For any stage-ready paste in a peer-review remediation cycle, follow the 5-step
Bash-call sequence: Edit → diff → add → status → stat — each in a separate
Bash invocation. Compose prose against captured outputs.
Cross-check: `git status --short` left-side M (M+space) = staged; right-side M
(space+M) = working-tree only. Drift surfaces here, not at commit-time.
Prevents prose↔tool-call-belief drift in stage-ready announcements (recurring
#642 instance class).
Acceptance criteria
Cross-references
Background
PR #641 Cycle-3 surfaced a recurring failure mode: when an agent prepares a stage-ready paste describing what's been edited and staged, the prose can drift from disk reality. Concrete instances during #641:
git addran but disk showed no modifications. On retry: "I prepared diffs in my plan + composed the stage-ready paste, but never actually invoked Edit."PR #641 Cycle-4 validated a mitigation: split-Bash-call discipline + M+space vs space+M cross-check. The architect applied it consistently and the verify-only round flagged zero drift. Backend's HANDOFF retired the open issue as "known recipe."
Recipe
Why each step matters
Edit && git diffwould fail if Edit fails, but the bigger issue is that Edit's output isn't captured. Diff against disk after Edit is the verification.git diffshows working-tree changes. If empty, Edit didn't actually run (architect's case).git add && git statuscollapses two facts (add succeeded, post-add state) into one observation. Separating gives audit-grain.git status --shortshows index vs working-tree state per file (M+space vs space+M).--cached --statshows what's staged. Both are needed for index-state confidence.Proposal — pin to CLAUDE.md as stable recipe
Per pinned project rule structure, add a new pinned context entry to project CLAUDE.md:
Acceptance criteria
agent-teamsor wherever stage-ready dispatches are described mentions the discipline.Cross-references