From 27b7b38f35fc5664d92f089eec4a50e269af1ecc Mon Sep 17 00:00:00 2001 From: wshallwshall Date: Wed, 5 Aug 2026 22:16:48 -0500 Subject: [PATCH] docs(gate): record the ledger-gate coupling where someone can BREAK it, 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 (341e650d) widened rule 1 to the whole of .git/mefor-coord/ and thereby exposed alloc//.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. --- scripts/hooks/worktree_gate.ps1 | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/scripts/hooks/worktree_gate.ps1 b/scripts/hooks/worktree_gate.ps1 index e5cf815f..bf240cb7 100644 --- a/scripts/hooks/worktree_gate.ps1 +++ b/scripts/hooks/worktree_gate.ps1 @@ -786,6 +786,24 @@ worktree gate blocked it." The primary's HEAD belongs to the user, not to a sess # --------------------------------------------------------------------------------------------------- # Rule 1 -- writing INTO the primary's working tree, from anywhere. +# +# ANOTHER GATE DEPENDS ON THIS ONE, and not for the reason the rest of this file talks about. Elsewhere the +# relationship is that this hook PROTECTS the ledger gate's inputs -- rule 3c refuses a core.hooksPath +# repoint, rule 1b refuses a write to alloc/. This is different and it runs the other way: the ledger gate's +# ownership check keys on the WORKTREE that allocated a number (scripts/hooks/ledger_check.py owns()), and +# that key is only meaningful because rule 1 makes each session build somewhere of its own. Before this gate +# existed the key was MEASURED broken -- co-tenant sessions in the shared primary all mapped to one worktree, +# so the check was a no-op between exactly the sessions it was meant to separate. See +# docs/LEDGER-GATE.md, "Ownership keying -- and why it works now": the two gates are a pair. +# +# WHY IT IS WRITTEN HERE rather than only there. That document states the dependency from the DEPENDENT's +# side, which is invisible from the side that can break it -- and breaking it does not look like breaking a +# gate. Widening what rule 1 governs disarms no hook and fails no test; it quietly turns owns() back into a +# no-op for the newly-ungoverned paths, and the ledger then merges clean and corrupts silently, which is the +# defect that registry exists to prevent (measured 3x: d1d0a5a, 5b7d046, 9f3483d). This is not hypothetical: +# the first cut of rule 1b's exemption widened rule 1 to the whole of .git/mefor-coord/ and exposed +# alloc//.json, so a Write could forge an allocation owns() would then authorise. It was caught by +# an adversarial review, not by any gate. So if you are about to widen this rule, that is the cost to price. # --------------------------------------------------------------------------------------------------- if ($tool -notin @("Write", "Edit", "MultiEdit", "NotebookEdit")) { exit 0 }