Repository navigation
Description
Summary
Decision archival can move entries from a tracked file into an untracked, non-ignored destination. The data survives on disk, but at the git level the entries are deleted with no corresponding addition — so committing the source file alone silently drops them from history.
This is the same failure class as #1774 / #1783. nap.ts's archiveDecisions already guards it via isCommittableDestination. The Scribe archival path has no equivalent guard.
Observed live
During PR #1987, Scribe ran the decisions 7-day archive gate. Reported parity was clean (55 / 55), and on-disk integrity is genuinely fine:
.squad/decisions/archive/decisions-archive.md 120,614 bytes, 55 "### " entries ✅
But the tracking status is asymmetric:
$ git ls-files --error-unmatch .squad/decisions.md
TRACKED
$ git ls-files --error-unmatch .squad/decisions/archive/*.md
UNTRACKED ⚠️
$ git check-ignore -v .squad/decisions/archive/decisions-archive.md
(no match — NOT ignored, merely untracked)
$ git diff --numstat .squad/decisions.md
289 1438 .squad/decisions.md1,438 lines removed from a tracked file; 55 entries added to a file git will not commit.
Root cause
.gitignore enumerates squad state paths individually:
13:.squad/orchestration-log/
14:.squad/orchestration-log/dispatchguard/
15:.squad/log/
16:.squad/decisions/inbox/ ← inbox IS ignored
17:.squad/sessions/
18:.squad/config.json
.squad/decisions/inbox/ is ignored, but .squad/decisions/archive/ is not listed at all. It was created fresh by the archival step, so it is neither tracked nor ignored — the one state that looks fine locally and loses data on commit.
Archival Safety Rule A ("destination must be tracked") is stated in the Scribe spawn prompt, but nothing enforces it — unlike the code path, where isCommittableDestination does.
Why it didn't cause loss here
Nothing under .squad/ was staged or committed. PR #1987 contains exactly 11 files, none of them squad state — verified with git show --name-only. The archive file is intact in the working tree. This is a latent hazard, not an incident.
Suggested fix
Two candidates, not mutually exclusive:
- Decide the intent for
.squad/decisions/archive/. If archives are meant to be committed, ensure the archival stepgit adds the destination. If they're local-only likelog/andinbox/, add it to.gitignoreso the asymmetry is explicit rather than accidental. - Give the Scribe path the same guard the code path has. Rule A is currently prose in a prompt;
isCommittableDestinationis an executable check. Prose guidance is not a guard — an agent can report55 / 55parity and still have moved content somewhere git won't carry.
Option 2 generalizes: any prompt-stated safety invariant that has a code-level equivalent should reuse the code-level one.
Repro
# after a Scribe run that trips the decisions archive gate
git ls-files --error-unmatch .squad/decisions.md # TRACKED
git ls-files --error-unmatch .squad/decisions/archive/*.md # fails
git check-ignore -v .squad/decisions/archive/*.md # no match
git diff --numstat .squad/decisions.md # large deletionFound while delivering #1987. Filed separately rather than expanding that PR's scope.
Activity