fix(worktree): a write to the machine-global gate now leaves a record (BACKLOG #1247) - #607
Open
wshallwshall wants to merge 14 commits into
Open
fix(worktree): a write to the machine-global gate now leaves a record (BACKLOG #1247)#607wshallwshall wants to merge 14 commits into
wshallwshall wants to merge 14 commits into
Conversation
… (BACKLOG #1247)
The gate install was a bare Copy-Item. When the installed gate's content
changed on this box while three sessions ran against it, nobody could say
who wrote it -- and four separate mechanisms could each have recorded it.
None existed. The change itself moved the gate forward, so this is a
governance defect rather than an incident; an unattributable write to a
shared safety control is the same class of event whether it upgrades or
downgrades.
All four are now present, and each has a named test so removing one reds
that test rather than quietly restoring the gap:
BACKUP the bytes being overwritten are copied to .bak first. On an
unattributed write those are the only copy of what was there.
RECEIPT a JSON sidecar carrying content_hash, hash_replaced,
replaced_ours, written_at_utc, source_repo, source_commit,
source_blob.
ATTRIBUTION replaced_ours answers the question nobody could answer when
this was filed: were the bytes I just overwrote ones THIS
installer put there? It is false exactly when a previous
write was unattributed.
REAL MTIME Copy-Item carries the SOURCE mtime across, so the installed
file reported a checkout's timestamp as though it were the
install's. That is worse than no timestamp because it reads
as one, and this row records an inherited mtime carrying a
true finding into retraction.
THE RECEIPT HASHES WITH Get-GateHash, NOT Get-FileHash, AND THAT IS THE
DETAIL MOST LIKELY TO BE UNDONE. This file already learned it once: a
byte-exact digest made every Windows checkout read as STALE while git status
called the file clean, because git stores LF and checks out CRLF. The remedy
that false STALE printed was a re-install -- which DOWNGRADES a machine-global
control when the checkout is older than the installed gate. -Status and
tests/test_gate_installed_parity.py already share that function; a third
basis in the receipt would reintroduce the same defect one instrument over.
A test pins it.
-RefuseOnMismatch DEFAULTS OFF, deliberately. A mismatch against the receipt
is not proof of tampering -- an older installer, a hand copy or a legitimate
out-of-band fix all look identical -- and refusing by default would break
first installs and ordinary upgrades. Off, it warns and records the replaced
hash; on, it refuses and preserves the bytes for inspection rather than
destroying the evidence.
THE TESTS ARE STRUCTURAL AND THAT IS FORCED, NOT CHOSEN. install-gate.ps1
refuses to run when CLAUDECODE is set -- "a session that can install its own
gate can uninstall it" -- so the write path cannot be executed from a test
session at all, sandboxed HOME or otherwise. Unsetting that variable to reach
the code would be defeating the control the file exists to be. The existing
-Status tests work only because -Status sits above that refusal. Each new
test was mutation-checked against the shipped file: removing the mtime stamp,
the backup, or the refuse branch reds exactly one test each, restored by
byte-copy with the hash verified.
ONE OF THOSE TESTS WAS WRONG FIRST, IN THE WAY IT WAS TESTING FOR. It searched
the raw installer text for "Get-FileHash" and matched its own comment saying
"Get-GateHash, NOT Get-FileHash" -- failing on a file that was correct. Both
occurrences in this installer are in comments. It now reads code lines only:
a string search cannot see whether a name is being CALLED or RULED OUT, and
the mention most likely to exist is the one ruling it out.
tests/test_gate_installed_parity.py is untouched: the receipt does not change
what installed-versus-source parity means, and it already shares the hash
function.
Verified: 104 passed across the five gate, wiring, parity and repo-wide
inventory test files. ruff clean. install-gate.ps1 parses clean under the
PowerShell parser.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
wshallwshall
enabled auto-merge (squash)
August 26, 2026 00:12
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 gate install was a bare
Copy-Item. When the installed gate's content changed on this boxwhile three sessions ran against it, nobody could say who wrote it -- and four separate mechanisms
could each have recorded it. None existed.
All four are now present, each with a named test so removing one reds that test:
.bakfirst -- the only copy of what was thereon an unattributed write.
content_hash,hash_replaced,replaced_ours,written_at_utc,source_repo,source_commit,source_blob).replaced_oursanswers whether the bytes just overwritten were ones thisinstaller put there -- false exactly when a previous write was unattributed.
Copy-Itemcarries the source mtime across, so the installed file reported acheckout's timestamp as though it were the install's -- worse than no timestamp because it reads
as one.
Hashes with
Get-GateHash, notGet-FileHash-- deliberate, since a byte-exact digest made everyWindows checkout read STALE against a clean
git status(LF-vs-CRLF), and the false-STALE remedywas a re-install that could downgrade the control.
-Statusandtests/test_gate_installed_parity.pyalready share that function; a test pins the receipt to ittoo.
-RefuseOnMismatchdefaults off: a mismatch isn't proof of tampering (an older installer, a handcopy, a legitimate out-of-band fix all look identical), so the default records and warns rather
than breaking ordinary installs; on, it refuses and preserves the bytes for inspection.
Tests are structural by necessity:
install-gate.ps1refuses to run whenCLAUDECODEis set (asession that can install its own gate could uninstall it), so the write path cannot execute from an
agent session. Each new test was mutation-checked against the shipped file instead -- removing the
mtime stamp, the backup, or the refuse branch reds exactly one named test each, restored by
byte-copy with the hash verified.
Verified: 104 passed across the gate, wiring, parity and repo-wide inventory test files; ruff
clean; PowerShell parser clean (re-confirmed independently before opening this PR).
Built by Builder1, opened by Lander.
🤖 Generated with Claude Code