You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Scribe's Archival Safety Rules (A–E) live only in the spawn prompt. They are declared, not enforced — nothing observes whether they were followed. As a result the same data-loss failure has now occurred twice, one day apart, with a repair PR in between that did not prevent the recurrence.
This is the same structural class as #1824/#1812/#1801/#1822/#1825/#1827: a gate that cannot observe its own failure is not a gate.
Evidence — measured, this session
Occurrence 1 (2026-08-19) — repaired by #1782. Scribe reported "no archival required" while having archived 25 decision records + 3 history entries to new, untracked files under .squad/. Caught manually before commit (752 deletions vs 265 insertions).
Occurrence 2 (2026-08-20) — never caught until today. A Scribe run trimmed .squad/agents/eecom/history.md from ~15,119 → ~5,249 chars and wrote this provenance line:
Full pre-summary history archived at .squad/agents/eecom/history-archive-2026-08-20T11-59-44-0700.md
The pointer has been dangling for two days. git status read clean the entire time.
Occurrence 2 compounded (today). A fresh Scribe run reported History summarization: SKIPPED — no moves performed, then rewrote the same file (67 added / 50 removed) and stripped the dangling pointer itself — erasing the only on-disk evidence that content had gone missing. No work content was lost (verified by heading-level comparison against HEAD), but the provenance trail was destroyed.
Same run also reported decisions.md as 31 + 3 = 34 total. Measured actual: 48 → 56. The count was asserted, not counted (Rule C).
No enforcement. Rules A–E instruct Scribe to verify the destination is tracked (git ls-files --error-unmatch) and to append-verify-then-delete. Nothing checks that it did. A run that skips verification and a run that performs it produce identical-looking reports — which is precisely the defect class this repo has spent the week eliminating elsewhere.
Rule D already says "never report a gate outcome you did not measure." Occurrence 2 violated Rule D while Rule D was in the prompt. That is the proof that prose is not the fix.
Proposed fix (structural, not prose)
A check whose output survives the run and can be asserted — following the pattern at workflows/squad.md:287:
Dangling-pointer scan. Walk .squad/**/*.md for archived at <path> / Prior archive at <path> and assert each target both exists on disk and returns exit 0 from git ls-files --error-unmatch. Any dangling pointer = fail loud, naming the file.
Prove it can fail. Per the standing bar: a fixture with a deliberately dangling pointer must turn the check red, and the assertion must name the offending file, not merely return non-zero. (#1790's *.mjs text eol=lf does not repair existing working trees — 3 suites stay dead after merge #1793's review established that a status-only assertion passes a truncating parser that reports a filename which doesn't exist.)
Non-goal: a CI gate. CI has a fresh checkout and could never observe the working-tree condition — the permanently-green anti-pattern.
Recovery status
Content is recoverable — commit 3dace32e holds the pre-summary ~15,119-char version. Repair is in progress this session: materialize the archive at the path the pointer claims, stage with git add -f, prove tracked, restore the stripped provenance lines, and enumerate any other dangling pointers across the other 15 agents.
Acceptance criteria
squad doctor fails on a dangling archive pointer and names the file
Check proven capable of failing via fixture (mutation evidence, not assertion)
Full sweep of all agent histories + decisions.md for existing dangling pointers, each enumerated with recoverability
Rules A–E remain in the prompt but are no longer the only line of defense
Summary
Scribe's Archival Safety Rules (A–E) live only in the spawn prompt. They are declared, not enforced — nothing observes whether they were followed. As a result the same data-loss failure has now occurred twice, one day apart, with a repair PR in between that did not prevent the recurrence.
This is the same structural class as #1824/#1812/#1801/#1822/#1825/#1827: a gate that cannot observe its own failure is not a gate.
Evidence — measured, this session
Occurrence 1 (2026-08-19) — repaired by #1782. Scribe reported "no archival required" while having archived 25 decision records + 3 history entries to new, untracked files under
.squad/. Caught manually before commit (752 deletions vs 265 insertions).Occurrence 2 (2026-08-20) — never caught until today. A Scribe run trimmed
.squad/agents/eecom/history.mdfrom ~15,119 → ~5,249 chars and wrote this provenance line:That file does not exist and was never committed:
The pointer has been dangling for two days.
git statusread clean the entire time.Occurrence 2 compounded (today). A fresh Scribe run reported
History summarization: SKIPPED — no moves performed, then rewrote the same file (67 added / 50 removed) and stripped the dangling pointer itself — erasing the only on-disk evidence that content had gone missing. No work content was lost (verified by heading-level comparison againstHEAD), but the provenance trail was destroyed.Same run also reported decisions.md as
31 + 3 = 34 total. Measured actual: 48 → 56. The count was asserted, not counted (Rule C).Root cause
Two independent contributors:
.git/info/excludehides untracked files only. Tracked.squad/files commit normally; new.squad/files are silently unstageable whilegit statusreads clean. An archive write appears to succeed and then evaporates. Requiresgit add -f.git ls-files --error-unmatch) and to append-verify-then-delete. Nothing checks that it did. A run that skips verification and a run that performs it produce identical-looking reports — which is precisely the defect class this repo has spent the week eliminating elsewhere.Rule D already says "never report a gate outcome you did not measure." Occurrence 2 violated Rule D while Rule D was in the prompt. That is the proof that prose is not the fix.
Proposed fix (structural, not prose)
A check whose output survives the run and can be asserted — following the pattern at
workflows/squad.md:287:.squad/**/*.mdforarchived at <path>/Prior archive at <path>and assert each target both exists on disk and returns exit 0 fromgit ls-files --error-unmatch. Any dangling pointer = fail loud, naming the file.squad doctor, alongside thecheckWorktreeEolcheck added in #1790's*.mjs text eol=lfdoes not repair existing working trees — 3 suites stay dead after merge #1793 — same shape, same reporting surface.*.mjs text eol=lfdoes not repair existing working trees — 3 suites stay dead after merge #1793's review established that a status-only assertion passes a truncating parser that reports a filename which doesn't exist.)Non-goal: a CI gate. CI has a fresh checkout and could never observe the working-tree condition — the permanently-green anti-pattern.
Recovery status
Content is recoverable — commit
3dace32eholds the pre-summary ~15,119-char version. Repair is in progress this session: materialize the archive at the path the pointer claims, stage withgit add -f, prove tracked, restore the stripped provenance lines, and enumerate any other dangling pointers across the other 15 agents.Acceptance criteria
squad doctorfails on a dangling archive pointer and names the filedecisions.mdfor existing dangling pointers, each enumerated with recoverability