Skip to content

docs(gate): record the ledger-gate coupling where someone can BREAK it, not only where it is relied on - #228

Merged
wshallwshall merged 3 commits into
mainfrom
claude/gate-ledger-coupling-note
Aug 6, 2026
Merged

docs(gate): record the ledger-gate coupling where someone can BREAK it, not only where it is relied on#228
wshallwshall merged 3 commits into
mainfrom
claude/gate-ledger-coupling-note

Conversation

@wshallwshall

Copy link
Copy Markdown
Collaborator

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's owns() 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:185 documents 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 a core.hooksPath repoint, rule 1b refusing a write to alloc/, 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 exposed alloc/<kind>/<n>.json, so a Write could have forged an allocation that owns() would then authorise. --ci skips 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-WorktreeSlug and Get-SafeForMessage still present as FunctionDefinitionAst; 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.

…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
wshallwshall enabled auto-merge (squash) August 6, 2026 03:18
@wshallwshall
wshallwshall merged commit 132dc68 into main Aug 6, 2026
33 checks passed
@wshallwshall
wshallwshall deleted the claude/gate-ledger-coupling-note branch August 6, 2026 13:49
wshallwshall added a commit that referenced this pull request Aug 7, 2026
…G #325) (#240)

The leak gate's home-path / worktree-slug case-fold (#325) landed folded into
#177 (commit 88703a3), an ancestor of main -- not on a branch of this item's
name -- so there is no code to write in this lane. It only flips the #325 banner
to closed and reconciles the item text with the shipped code.

Verified against the shipped code and its git history:
  - scan_forbidden.py:114-121 folds the _HOME_PATH drive-letter arm inline,
    scoped so the POSIX /users/ REST route stays unmatched (a whole-pattern
    re.I would have measured 47 false positives). _WORKTREE_SLUG folds whole
    at :96.
  - Falsified against the pre-fix code (88703a3^): the old _HOME_PATH fired on
    the canonical spelling but missed all three wrong-case spellings; the
    shipped pattern fires on all four and still skips the benign /users/ routes.
    The old slug pattern missed an upper-cased slug; the shipped one catches it.
  - Regression fixtures at tests/test_scan_tokens_source.py:701,731 pass.

Added an AMENDED 2026-08-05 blockquote under the closed banner reframing the
What / Why / Proposed / Source body -- still voiced as the open finding, with
the pre-fix regex and a "Verified open at HEAD" line -- as the historical
filing record, not current state, mirroring the same-day #228 close. Without it
a reader meets a closed banner over a body that reads as a live gap and could
reopen or re-implement it.

Banner flipped WITHOUT recomputing the census. The ranked-table row, the census
distribution lines, and the cross-references to #325 under other items remain
coordinator work for the close-and-archive reconcile sweep.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant