docs(gate): record the ledger-gate coupling where someone can BREAK it, not only where it is relied on - #228
Merged
Conversation
…t, not only where it is relied on docs/LEDGER-GATE.md already documents the pairing, in "Ownership keying -- and why it works now": the ledger gate's ownership check keys on the worktree that allocated a number, that key was measured broken before this gate existed because co-tenant sessions in the shared primary all mapped to one worktree, and "the two gates are a pair". That states the dependency from the DEPENDENT's side. This adds the reverse pointer at rule 1's own header, because the side that can break it had nothing. WHY A COMMENT IS THE RIGHT INSTRUMENT HERE. Breaking this does not look like breaking a gate. Widening what rule 1 governs disarms no hook and fails no test -- it quietly turns owns() into a no-op for the newly-ungoverned paths, and the ledger then merges clean and corrupts silently, which is the exact defect that registry exists to prevent (measured 3x: d1d0a5a, 5b7d046, 9f3483d). No test can warn about a deliberate design choice; the warning has to sit at the decision point. Not hypothetical, and the commit history shows it. The first cut of rule 1b's exemption (341e650) widened rule 1 to the whole of .git/mefor-coord/ and thereby exposed alloc/<kind>/<n>.json -- so a Write could forge an allocation that owns() would then authorise, and --ci skips that rule entirely. It was caught by an adversarial review, not by any gate, and nothing in this file would have warned the author. That is the gap this closes. Note the relationship is the OPPOSITE of the one the rest of the file discusses. Elsewhere this hook PROTECTS the ledger gate's inputs -- rule 3c refuses a core.hooksPath repoint, rule 1b refuses a write to alloc/. This dependency runs the other way: the ledger gate relies on rule 1's SCOPE, not on its protection. Seven existing mentions of "ledger" in this file are all the first kind, which is why the second was easy to miss. Comment only, 18 lines added, zero removed, no behaviour change. Verified 0 parse errors, 8 functions with both helpers still defined by AST, 0 non-ASCII bytes, and 239 passed across the 9 runnable gate files.
wshallwshall
enabled auto-merge (squash)
August 6, 2026 03:18
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.
Records a load-bearing coupling where someone can break it, not only where it is relied on. Comment only -- 18 lines added, zero non-comment lines, no behaviour change.
What was missing, which is narrower than it first appeared
ledger_check.py'sowns()authorises a ledger number by comparing the worktree that allocated it -- and that only works because the worktree gate forces each session into its own.docs/LEDGER-GATE.md:185documents that pairing from the dependent's side, ending "The two gates are a pair."The gate file itself said nothing about it. And the reason it was easy to miss is measurable: "ledger" appears seven times in
worktree_gate.ps1, and every one is the opposite relationship -- rule 3c refusing acore.hooksPathrepoint, rule 1b refusing a write toalloc/, the pre-commit protection. All of them are this hook protecting the ledger gate's inputs. The dependency runs the other way:owns()relies on rule 1's scope, not on its protection.Seven mentions of the inverse relationship is precisely why the real one went unrecorded -- including by the author of several of those seven.
Why a comment, and not an item, and not a test
Breaking this does not look like breaking a gate. Widening what rule 1 governs disarms no hook and fails no test. It simply turns
owns()into a no-op for the newly-ungoverned paths, and the ledger then merges clean and corrupts silently.No test can warn about a deliberate design choice, so the warning has to sit at the decision point -- rule 1's own header, where someone about to widen it is already reading. An item would describe the hazard somewhere nobody looks at the moment they create it.
The evidence it cites, rather than the risk it asserts
Commit
341e650d-- the author's own first cut at the rule 1 fix -- widened rule 1 to the whole of.git/mefor-coord/and thereby exposedalloc/<kind>/<n>.json, so aWritecould have forged an allocation thatowns()would then authorise.--ciskips that rule entirely.It was caught by adversarial review, not by any gate, and nothing in the file would have warned its author. That is the gap this closes, from the side that matters.
Verification
0 parse errors; 8 functions with both
ConvertTo-WorktreeSlugandGet-SafeForMessagestill present asFunctionDefinitionAst; 0 non-ASCII bytes; 239 passed across the 9 runnable gate files. Touches no BACKLOG heading, so no ledger entitlement is involved.If a conflict appears against the #1041 rule 3d work, it is additive -- this hunk is rule 1's header (
:788), that one is rule 3d (:524-570). Keep both.