feat(repo): publish CLAUDE.md, the backlog and the worktree guide; restore the backlog gate#6
Merged
Merged
Conversation
…store the backlog gate
The cutover put these in a gitignore private-only block. Three of them did not need to be there, and
keeping them out cost more than it protected.
CLAUDE.md is the important one. It is the project's persistent context, and `git worktree add` cannot
deliver an untracked file -- so EVERY worktree came up with zero project conventions loaded. Verified
on both live worktrees before this change: no HL7 parsing rules, no PHI rules, no architecture
constraints, nothing. It only appeared to work in the primary checkout because an untracked copy
happens to sit on disk there. Tracking it fixes that permanently and versions it for the first time
since the cutover.
docs/BACKLOG.md and .github/workflows/backlog-hygiene.yml go together. The workflow was never
published at all -- not gitignored, just never shipped -- so the banner/number-reuse gate ran only on
the private vault, which no longer receives the work. tests/test_backlog_status_check.py was
skipping permanently on a reason string that describes the retired mirror topology. Both now run:
229 backlog items validated, 15 previously-skipped assertions live.
docs/WORKTREES.md is a process doc with no customer content, and CLAUDE.md links to it.
REDACTIONS (2 sites, both verified):
* L592-593 enumerated the real estate/vendor tokens and the site-code pattern -- i.e. the leak
gate's own protected list. Replaced with a pointer to the private token file.
* L6837 carried a phrase a [names] detector flags as a migration artifact. Rephrased to the
hyphenated form the same document already uses in item #105; meaning unchanged.
VERIFICATION. The leak gate was run with the REAL token set, reconstructed from the retired
scripts/publish/scan_forbidden.py in the vault. It reports `names=7, estate=13, estate_file_scanned=12,
site_prefixes=1` -- identical to the counts CI logs with its own secret -- and exits 0 with no
findings. So this was checked by the project's authoritative gate, not an approximation of it. Both
redactions were found BY that gate; the token-value scan I ran first missed the second one.
LEDGER GATE FIX (scripts/hooks/ledger_check.py), forced by the import itself. The gate crashed on
`git show origin/main:docs/BACKLOG.md` (exit 128) because the base has no version of a file being
ADDED. Treating that as an empty ledger would have been worse than the crash: every heading in the
imported file then reads as a brand-new number and the gate reports ~229 items as "not allocated to
this worktree". So absence is now probed EXPLICITLY (`base_has`) instead of inferred from an error --
`git()` keeps raising on real failures, which is the property that stops a swallowed error reading as
"no numbers taken". Two tests added; the first is mutation-verified (neutralise the guard, it fails).
The second pins a system-level property only -- its docstring says so, because removing base_has's own
rev-parse guard leaves it green.
STILL PRIVATE, each for its own reason:
* docs/security/ (32 files) and docs/reviews/ -- posture and findings detail; an attacker roadmap.
* docs/CI-TOPOLOGY.md -- STALE. It documents the private-repo/public-mirror split and scripts/publish/,
which the cutover deleted. Publishing it would actively mislead; it needs a rewrite or deletion.
* docs/Secure_Development_Standards.md -- scans clean, but it was deliberately pulled from the public
PyPI sdist (#1020). Reversing that is an owner decision, not a side effect of this change.
wshallwshall
added a commit
that referenced
this pull request
Jul 27, 2026
…olation (#10) Publishing docs/BACKLOG.md (#6) broke the ledger gate on every branch cut before that merge, including PR #7 -- whose diff touched release.yml and leak-gate docs and nothing near a ledger: OSError: git show HEAD:docs/BACKLOG.md failed (128): fatal: path 'docs/BACKLOG.md' does not exist in 'HEAD' CI's change set is `diff base HEAD`. Once origin/main gained the file, a branch that predates it lists docs/BACKLOG.md as CHANGED -- as a deletion relative to base -- despite never touching it. check_backlog then read HEAD for a copy that was never there. `base_has` (added when the file was imported) covers the opposite end: absent on BASE, being added. This is the mirror case -- present on base, absent on HEAD -- and it is the one that fires repeatedly, because it hits every open branch at once rather than the single commit that publishes the file. Both probes now share `_obj_exists`, which asks `git cat-file -e` directly rather than inferring absence from an exception: `git()` must keep raising on real failures, since an error swallowed as "empty ledger" reads as "no numbers taken" -- the false-clean this gate exists to prevent. "The path is not on that ref" is the one non-failure, so it gets its own probe instead of a broad `except`. `head_has` mirrors `head_text`'s ref exactly (HEAD in CI, the INDEX locally), so the guard cannot disagree with the read it guards. Mutation-verified: neutralise the guard and the new test fails with the same exit-128 shape seen in CI. Worth noting for whoever meets this next: the failure looked like an unrelated flake on somebody else's PR, and the first re-run "fixed" nothing -- the run before it had failed for a genuinely different, genuinely random reason (a 3-char needle colliding with base64 ciphertext, fixed separately). Two different faults on consecutive attempts of the same leg is exactly the shape that gets misread as one flaky test.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The cutover put these in a gitignore private-only block. Three of them didn't need to be there, and keeping them out cost more than it protected.
Why
CLAUDE.mdis the important onegit worktree addcannot deliver an untracked file. Verified on both live worktrees before this change:So every worktree came up with zero project conventions loaded — no HL7 parsing rules, no PHI rules, no architecture constraints. Silently. It only appeared to work in the primary checkout because an untracked copy happens to sit on disk there. Tracking it fixes that permanently and versions it for the first time since the cutover.
The backlog gate was stranded, not dead
backlog-hygiene.ymlwas never published — not gitignored, just never shipped — so the banner/number-reuse gate ran only on the private vault, which no longer receives the work. Andtests/test_backlog_status_check.pywas skipping permanently on a reason string describing the retired mirror topology.Both now run: 229 backlog items validated, 15 previously-skipped assertions live.
Redactions (2 sites)
[names]detector flags as a migration artifact. Rephrased to the hyphenated form the same document already uses in item #105; meaning unchanged.How this was verified
The leak gate was run with the real token set, reconstructed from the retired
scripts/publish/scan_forbidden.pyin the vault. It reports:— identical to the counts CI logs using its own secret — and exits 0 with no findings. So this was checked by the project's authoritative gate, not an approximation of it.
Worth stating plainly: the token-value scan I ran first missed the second redaction. The real gate caught it. That's the whole argument for not trusting a partial scan before an irreversible publish.
Ledger gate fix, forced by the import
The gate crashed on
git show origin/main:docs/BACKLOG.md(exit 128) — the base has no version of a file being added. Treating that as an empty ledger would be worse than the crash: every heading then reads as a brand-new number and the gate reports ~229 items as "not allocated to this worktree".Absence is now probed explicitly (
base_has) rather than inferred from an error, sogit()keeps raising on real failures — the property that stops a swallowed error reading as "no numbers taken".Two tests added. The first is mutation-verified (neutralise the guard, it fails). The second pins a system-level property only, and its docstring says so — removing
base_has's own rev-parse guard leaves it green, so claiming otherwise would be false assurance.Still private, each for its own reason
docs/security/(32 files),docs/reviews/docs/CI-TOPOLOGY.mdscripts/publish/, which the cutover deleted. Publishing it would actively mislead. Needs a rewrite or deletion.docs/Secure_Development_Standards.md🤖 Generated with Claude Code