Skip to content

Decision archival can move entries from a tracked file into an untracked, non-ignored destination #1988

Open

Description

@bradygaster

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.md

1,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:

  1. Decide the intent for .squad/decisions/archive/. If archives are meant to be committed, ensure the archival step git adds the destination. If they're local-only like log/ and inbox/, add it to .gitignore so the asymmetry is explicit rather than accidental.
  2. Give the Scribe path the same guard the code path has. Rule A is currently prose in a prompt; isCommittableDestination is an executable check. Prose guidance is not a guard — an agent can report 55 / 55 parity 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 deletion

Found while delivering #1987. Filed separately rather than expanding that PR's scope.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingwave1:P4Wave 1 PR group P4wave:1-nextWave 1 — immediate next sprint

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions