`committed()` built the directory set from `range(4, len(parts))`. Index 3 is
`docs/re/captures` itself, so every SUB-directory was registered and the root
never was. Eight pages cite the directory as a whole -- PROTOCOL's evidence
table, CONSOLIDATION, CONTAINERS-AND-AGENTS, decoder-loop, both HANDOFFs,
BLOCKED, verify-screen-blend-divergence -- and each of those looked like a
citation of a file that does not exist. `check-capture-citations` exited 1 on a
correct checkout, which is the failure mode its own comments warn about: "a
gate that is red on every clean checkout" teaches people to ignore it.
The selftest could not see this. It takes `next(iter(dirs))`, and an arbitrary
member of that set is always a sub-directory -- the one case that works. It now
asserts the root explicitly, with and without its trailing slash. Both new cases
were confirmed to FAIL against the unfixed function before the fix went in; a
selftest case that passes either way is decoration.
Measured: full check 203 citations, 212 captures, 0 dangling, 0 tracked assets,
exit 0. Before: exit 1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Issue #49 removed game assets from git. It also, silently, removed the only
transport agents had for showing each other evidence: each agent works in its
OWN clone, so "commit the screenshot, the other one pulls it" was the mechanism,
and PROTOCOL.md's file table said so in as many words -- "evidence cited by a
finding -> git". That row sat directly above "🔴 Never commit game content",
which is how 76 MB accumulated: the two contradicted each other and the table
won, because it was the one that told you what to do.
WHAT REPLACES IT
* one host directory, `Sylpheed/docs/re/captures/`, bind-mounted read-write
into BOTH agents at /work/docs/re/captures. All three -- host, decoder,
port -- see the same files live, every citation resolves, and nothing can
reach git history. Read-write on purpose: showing each other a screenshot
is the point.
* PROTOCOL.md's table rewritten. Cited evidence -> present but never
committed; derived measurements (csv/tsv/txt/log/json) -> still git, they
are our numbers not game content; evidence that must cross MACHINES ->
attached to the issue or PR, because a bare clone has no captures.
Verified, not assumed: container A wrote a .png there, a SEPARATE container B
read it back, the host saw it, `git status` reported 0 changes, and
`git check-ignore` named the rule.
THE CHECKER WAS RED ON EVERY CLEAN CHECKOUT
A fresh clone/worktree/CI has no captures, so it called all 134 citations
dangling and exited 1. A gate that is red before anyone changes anything is one
people learn to ignore -- the exact failure this file already carries a comment
about. It now distinguishes "no captures here" (expected, explains itself,
exit 0) from "these are missing" (real, exit 1, unchanged when assets ARE
present). Both paths tested.
ALSO
* `sylph-decoder` no longer mounts `xenia-rs` -- retired repo, gone from disk,
the mount pointed at nothing.
* CONSOLIDATION.md closed: it still described captures as committed and the
history fork as undecided. Both are settled.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Issue #49: the repos carry code, tooling and docs only.
Untracks 143 screenshots, 3 savegame blobs and `tools/re-capture/ob_digits.png`
(a digit-template sheet cut from game frames) -- 146 files, 76.4 MB. They stay
in the working tree and are gitignored, so the pages' relative links still
resolve where the captures exist and nothing ships.
Derived measurements (csv/tsv/txt/log/json/jsonl/npy) are our own numbers, not
game content, and stay tracked -- they are what most claims rest on.
`check-capture-citations` had its contract inverted, and it is the half worth
reading:
* presence now comes from the WORKING TREE, not `git ls-files`. The assets are
deliberately untracked, so asking the index would report every screenshot as
missing and fail all 203 citations.
* a NEW failure: a game asset that IS tracked. A screenshot that sneaks back
in is invisible in review -- a binary shows as "Bin 0 -> 1234567 bytes" --
and is permanent once merged, since removing it later needs a history
rewrite. So that half has to be loud.
Verified:
* selftest 8/8, including the new rule
* scan: 212 present, 212 cited, 0 dangling, 0 tracked -> exit 0
* force-add one PNG -> "game assets TRACKED: 1", exit 1, selftest red
⚠️ This does NOT remove the blobs from history; a clone still fetches them.
That needs a filter-repo rewrite and a force-push, which is a separate,
human-run step.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`check-capture-citations` exits 1 on a clean checkout of this branch, and would
have kept doing so for ever:
🔴 cited but NOT committed: 1
docs/re/captures/no-such-file-anywhere.png
`SEARCH` includes `tools`, so the scan reads this file -- and `selftest()`'s
planted fixture is a literal capture path. The checker cited its own test data,
to a file that will never exist by construction. A gate that is red before
anyone changes anything teaches people to ignore it, which is the opposite of
what Phase 4 built it for.
Excluding only this one file (`SELF`) keeps every other tool in scope. A real
citation belongs in a page, or in a tool that opens the capture -- never in the
checker itself.
Added a selftest case for it, because this is exactly the class of bug the rest
of this file already documents surviving: the ERE that matched nothing while
five ticks stayed green. Verified the guard can fail, rather than assuming it:
exclusion neutralised -> "own fixtures not counted 🔴 FAILED",
selftest rc=2, real check rc=1 reproducing the bug
exclusion restored -> selftest ok (7 cases), check rc=0
After the fix, on this branch:
captures committed : 212
cited by a page or a tool : 212
cited by nothing : 0
🔴 cited but NOT committed: 0 rc=0
which is also the first independent confirmation of Phase 4's "212 captures,
all cited" -- the checker now agrees with the page.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CONSOLIDATION.md Phase 4. `tools/port/check-citations` has checked
`docs/port/*.md` since it was written; `docs/re/` never had one, and
`docs/re/captures/` is the largest thing in the repository -- the one place a
file can be added, never cited, and never noticed.
captures committed : 212
cited by a page or a tool : 212
cited but NOT committed : 0
🔴 THE PREMISE I STARTED FROM WAS WRONG FOUR TIMES, AND EACH CORRECTION IS IN
THE TOOL RATHER THAN JUST IN MY HEAD:
* "10 dangling citations" -- the real number was ONE. Eight were DIRECTORY
references, which resolve and are simply absent from `git ls-tree`; one was
a path at the end of a sentence with the full stop pulled into the match.
A checker that cries wolf nine times in ten teaches you to ignore it.
* The one real dangler, `live-submenu-unidentified.png`, was COMMITTED and
then deleted on 2026-08-30 while the page kept citing it and kept making
the claim it backs. Restored from 77e54e95 rather than dropping the link:
deleting evidence while keeping the conclusion is the thing this corpus
exists to prevent.
* Two "orphans" are opened BY FILENAME from `screen_match.py`, which builds
the directory separately. A path-only scan called them unreferenced and
deleting them would have broken the tool. The check now counts any
basename named anywhere.
* Pruning then EMPTIED two directories that pages cite as directories, and
the check went red on the very citations that made them evidence. It
caught its own damage. A file inside a cited directory is cited.
The selftest covers all of it, including the failure that actually happened:
an earlier version passed five green ticks while the scan silently returned
NOTHING, because `git grep -E` is POSIX ERE and cannot compile `(?:`. A
selftest that cannot see the failure that occurred is decoration.
46 orphaned captures dropped, 30.7 MB from the checkout. ⚠️ That reclaims no
repository space -- the blobs stay in history -- and it is not meant to. It
means every capture here is now evidence some page or tool actually uses.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>