From 71bb19d25086af427d02971dca846c16656172ae Mon Sep 17 00:00:00 2001 From: wshallwshall Date: Thu, 13 Aug 2026 11:16:15 -0500 Subject: [PATCH] docs: the 29% and the 44% are two numerators over one denominator, and every copy now says so The table at docs/WORKTREE-GATE.md:26-30 is this repo's authoritative record of the 30-day write-collision measurement: 166 sessions ran with their cwd in the shared primary, 6,075 of THEIR Edit/Write calls (44%) landed in that primary's tree, and 4,010 (29%) landed in a sibling worktree by absolute path. Both data rows open with "Their", so the two percentages are shares of ONE denominator -- roughly 13,800 calls -- and roughly 27% of that population landed outside the repository entirely. Fourteen other sites stated a share of writes without naming that population. A bare "29% of writes" does not read as ambiguous: the reader supplies the wider denominator and is never corrected. Four of the fourteen are the ones that matter most -- the gate's own docstring, this suite's own test_worktree_gate.py, and prune-merged.ps1 twice, once in a string printed to an operator at the moment they are authorising a destructive worktree deletion. TWO SITES ASSERTED A WRONG POPULATION RATHER THAN OMITTING ONE. scripts/hooks/worktree_gate.ps1:23 and tests/test_worktree_gate.py:5 both said "29% of THIS REPO'S Edit/Write calls". That is not vague, it is false, and it is the sentence that justified the target-path design. Both were invisible to the regex that found the other twelve, because its noise allowlist held only "the" and "all" -- the blind spot is recorded in the new gate's docstring so the next reader does not have to rediscover it. THE FALSE ATTRIBUTION IS RETIRED. docs/SESSION-DRIFT-CONTROLS.md:640 named the gate's docstring as the source of the whole cluster. That is false for the 44% and the 166: `git log -S '44%'` and `git log -S '166'` over scripts/hooks/worktree_gate.ps1 each return ZERO commits across all history, so the docstring never carried either and only ever carried the 29%. The table is the only artifact holding both numerators, which is the only context in which their shared denominator had to be made explicit -- and the false attribution is what made the loose reading look authoritative. Corrected in place with a dated CORRECTION block rather than struck, because the figures stand; only the denominator and the source were wrong. "Cited, not re-measured" still holds and is kept: the DENOMINATOR is known, the COUNTS are what nobody can re-derive. Stating those together as one blanket hedge is weaker than the truth and invites relaxing the scope on the grounds that it was hedged anyway. THE ARCHIVE IS CORRECTED, NOT REWRITTEN. docs/archive/backlog/BACKLOG-CLOSED.md:6709 QUOTES what occupancy.ps1 disclosed. Rewording the script would have turned that quotation into a misquote, so the sentence stands and a dated CORRECTION blockquote follows it, modelled on the #1099 correction already in that file. It also fixes the paraphrase in the same sentence: "false about one write in three" is true only of primary-seated writes. No ledger number was allocated -- a prose correction has no fix and no closing condition, so it is not an item, and CLAUDE.md forbids filing something that would sit open describing something true. The deviation from #1099's numbered form is deliberate and stated in the block itself. ONE SITE WAS DELIBERATELY NOT TOUCHED. docs/WORKTREES.md:695 already reads "166 sessions ran with their cwd in the shared primary, and 44% of all their file writes landed in the primary's tree". It was the only correctly scoped statement in the repo, and a mechanical sweep would have damaged it invisibly. It is now the new gate's positive control. THE GATE. tests/test_write_share_denominator.py, added to the DOC_GUARDS list in ci.yml in this same commit so a docs-only pull request still runs it. It bans the loose form rather than requiring one spelling, because the scope can be carried by an attribution after the figure, a lead-in before it, or a possessive, and pinning one wording would go red on a harmless rewrite. Three properties are load-bearing and each is documented next to the knob it constrains: it matches WHOLE-FILE text because two live sites wrapped between "of" and its noun; it rejects a repo-naming possessive outright; and its window is 200 characters and looks both ways, because both orders occur here and a window wide enough to reach WORKTREE-GATE.md's own table from 794 characters below would let any file containing that table say anything. An archived quotation is discharged only by a CORRECTION block that itself names the population. PROVED IT CAN FAIL. Mutating each of the 13 sites the gate can see, one at a time, with both windows blanked: caught 13 of 13, no blind spot. An earlier mutation that blanked only the FORWARD context reported 5 misses -- that was the instrument, not the gate, and it is why the check blanks both. Stated limits, in the source: the noun list is an allowlist, so "44% of edits" or a spelled-out percentage passes, and no percentage-keyed scan can ever see a paraphrase like "one write in three". Verification: 192 passed, 1 skipped over the doc guards and both edited test modules. The skip is test_gate_installed_parity, which declares itself -- the installed gate is SUPPOSED to differ while worktree_gate.ps1 has uncommitted changes; re-run after this commit. Backlog banners unchanged: 513 items parsed by scripts/docs/backlog_status_check.py, 203 open, before and after. ruff check and ruff format clean over 1109 files; all three edited PowerShell scripts parse. mypy reports the same 21 pre-existing errors as HEAD, in files this commit does not touch -- they are the worktree venv's missing optional extras, not a regression. The sibling repo claude-multisession shipped this correction first; this is the source repo catching up, and the source was the less accurate of the two until now. AMENDED. Two defects found by an adversarial pass over the first version of this commit, both in the new gate rather than in the prose: * THE PATTERN WAS STILL BLIND, to the same class it was written for. Its modifier run was an allowlist of determiners, and ONE ADJECTIVE defeated it: "~29% of this repo's REAL Edit/Write calls" -- the exact wording that stood in tests/test_worktree_gate.py until this commit -- did not match at all, so the single wrongest sentence in the repository was the one sentence the guard could not see. The run is now open and capped at three tokens, with `durable`, `body` and `bytes` barred so the store- transaction family ("63% of the hub's durable writes", a different subject) and "77% of the body bytes this message writes" (a verb) stay out, plus a lookbehind so the benchmark corpus's "49.44%" is not read as a bare "44%". Four false-positive controls pin those. The gate now sees 14 sites, all scoped, and mutating each with both windows blanked is caught 14 of 14. * $GateVersion WAS NOT BUMPED, and the variable's own comment at :60-67 records that exact omission happening once before: rules were added without a bump, so `-Status` printed the same version on both sides directly above a *** STALE *** verdict. This commit changes the file's bytes, so the label moves to 2026.08.13.1. Nothing enforces the bump -- test_install_gate_wiring only checks the format -- which is why it is worth doing by hand rather than assuming a gate will catch it. The installed gate on the developing machine is now STALE against this commit, which tests/test_gate_installed_parity.py reports rather than hides. It skipped while the source was uncommitted and reds from here until a human runs install-gate.ps1 from a PLAIN terminal; the installer refuses under $env:CLAUDECODE by design. CI is unaffected: no gate is installed there and the module skips. --- .github/workflows/ci.yml | 2 +- docs/BACKLOG.md | 2 +- docs/SESSION-DRIFT-CONTROLS.md | 25 ++- docs/WORKTREE-GATE.md | 8 +- docs/WORKTREES.md | 14 +- docs/archive/backlog/BACKLOG-CLOSED.md | 3 + scripts/coord/occupancy.ps1 | 5 +- scripts/hooks/worktree_gate.ps1 | 10 +- scripts/worktree/prune-merged.ps1 | 5 +- tests/test_script_root_anchoring.py | 3 +- tests/test_worktree_gate.py | 6 +- tests/test_write_share_denominator.py | 259 +++++++++++++++++++++++++ 12 files changed, 314 insertions(+), 28 deletions(-) create mode 100644 tests/test_write_share_denominator.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92d07ed7..fae43d46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -215,7 +215,7 @@ jobs: tests/test_security_doc_rate_limits.py tests/test_threat_model_doc_drift.py tests/test_backlog_status_check.py tests/test_sds_rule_ids_are_stable.py tests/test_link_resolution.py tests/test_dast_claims.py - tests/test_claude_section_citations.py" + tests/test_claude_section_citations.py tests/test_write_share_denominator.py" # Every named module must EXIST. A path typo would otherwise make pytest error on an unknown # file, or — worse under a future -k/--ignore form — silently scan nothing and read as a pass. for m in $DOC_GUARDS; do diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index f6bccb1b..831dab1c 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -4873,7 +4873,7 @@ and `enforce_admins` governs **protected branches**. Re-enabling it would refuse **A signal exists, but NOT the one this item first claimed — read this before designing anything.** `scripts/coord/occupancy.ps1` provides `Get-WorktreeOccupancy`, `Get-WorktreeOccupants` (with `-IncludeNested`), `Get-NestedWorktrees` and `Get-ContainingWorktrees`, and `scripts/worktree/prune-merged.ps1` uses them as a *fence* before removing worktrees, re-reading immediately before acting. The first version of this item concluded from that: *"the project already accepts this signal as sufficient to gate a deletion"*. **That is true of the COMBINATION and false of the occupancy lookup alone, and the difference is the whole design.** -Measured on a live `-Apply` run, 2026-08-05: of 24 candidates, **signal 1 (occupancy) vetoed 0**. All 16 skips came from signal 2, the git-metadata age rule — 14 *"recently active"*, 2 *"not merged"*. Measured independently from the session that filed this item, at the same time: the fence reported `Available = True`, reported 5 of 42 worktrees occupied, and placed **0** occupants in `MessageFoundry-gate-deferrals` — the worktree that session was demonstrably live in, having committed to it a minute earlier. That is the script's own disclosed blind spot: *a session writing into a worktree by absolute path from elsewhere*, which it puts at 29% of writes on this repo. +Measured on a live `-Apply` run, 2026-08-05: of 24 candidates, **signal 1 (occupancy) vetoed 0**. All 16 skips came from signal 2, the git-metadata age rule — 14 *"recently active"*, 2 *"not merged"*. Measured independently from the session that filed this item, at the same time: the fence reported `Available = True`, reported 5 of 42 worktrees occupied, and placed **0** occupants in `MessageFoundry-gate-deferrals` — the worktree that session was demonstrably live in, having committed to it a minute earlier. That is the script's own disclosed blind spot: *a session writing into a worktree by absolute path from elsewhere*, which it puts at 29% of the writes made by sessions sitting in the primary. **So the load-bearing half is the 36-hour age rule, not the occupancy lookup.** A design that vendors only `Get-WorktreeOccupancy` inherits the half that measured 0 of 24, and under the fail-closed constraint below that is the worse half to choose: it returns a confident *"unoccupied"* for a tree that was being written to a minute ago. Whatever is built must carry the age rule too, or the fail-closed requirement is carried by nothing. Rule 3d remains the one place making this decision with neither. diff --git a/docs/SESSION-DRIFT-CONTROLS.md b/docs/SESSION-DRIFT-CONTROLS.md index 2b759586..7ccfcd3c 100644 --- a/docs/SESSION-DRIFT-CONTROLS.md +++ b/docs/SESSION-DRIFT-CONTROLS.md @@ -62,8 +62,8 @@ there is no defence in depth between them. | 4 | `EnterWorktree` (relocating a live session) | tool name only | The single most important design decision is that **rules 1/3/3b key on the target, never on the cwd**. -The gate's own docstring records that 29% of Edit/Write calls came from a session *sitting* in the primary -that wrote *correctly* into a worktree by absolute path; a cwd-keyed gate would have denied all of them. +The gate's own docstring records that 29% of the Edit/Write calls made by sessions *sitting* in the primary +wrote *correctly* into a worktree by absolute path; a cwd-keyed gate would have denied all of them. Rule 2 is the sole exception, and that exception is the source of the ultracode friction in §4. **[`scripts/hooks/block-blanket-git-stage.ps1`](../scripts/hooks/block-blanket-git-stage.ps1)** refuses @@ -637,9 +637,24 @@ worktrees, which the gate explicitly permits writing into. **Cited, not re-measured — treat with care:** -- **"29% of Edit/Write calls landed in a worktree; 44% in the primary; 166 sessions over 30 days."** From - the gate's own docstring. This is the *sole* quantitative justification for the target-keyed design. - Nothing in the repo lets it be recomputed, and nobody has asked whether it still holds. +- **"Over 30 days, 166 sessions ran with their cwd in the shared primary; 6,075 of *their* Edit/Write + calls (44%) landed in the primary's tree and 4,010 (29%) landed in a worktree by absolute path."** + From the table in [`WORKTREE-GATE.md`](WORKTREE-GATE.md). This is the *sole* quantitative + justification for the target-keyed design. Nothing in the repo lets it be recomputed, and nobody has + asked whether it still holds. + + > **CORRECTION 2026-08-13 — this entry stated the denominator wrongly and named the wrong source.** + > It originally read *"29% of Edit/Write calls landed in a worktree; 44% in the primary; 166 sessions + > over 30 days."* **From the gate's own docstring.** Both halves were wrong. The percentages are + > shares of the Edit/Write calls made by those 166 primary-seated sessions — roughly 13,800 — not of + > every call in the repo; stated bare, a reader supplies the wider denominator and is not corrected. + > And the docstring is not the source: `git log -S '44%'` and `git log -S '166'` over + > [`scripts/hooks/worktree_gate.ps1`](../scripts/hooks/worktree_gate.ps1) each return **zero commits + > across all history**, so it has never carried either figure and only ever carried the 29%. The + > table is the only artifact holding both numerators, which is the only context in which their shared + > denominator had to be made explicit. Corrected rather than rewritten silently, because the false + > attribution is what made the loose reading look authoritative and a later reader will otherwise + > re-derive it. ~~**"A subagent's denied edits came back with an empty `permission_denials` list."**~~ **Superseded** — re-measured above. The denial surfaces clearly to the subagent, the write never lands, and the receipt now records it against the subagent's pid. diff --git a/docs/WORKTREE-GATE.md b/docs/WORKTREE-GATE.md index 74eea37b..7a0c1509 100644 --- a/docs/WORKTREE-GATE.md +++ b/docs/WORKTREE-GATE.md @@ -37,9 +37,11 @@ session — accumulated 12 stale worktrees. Advisory text has no measurable effe human or on the model. **Second — and this is the part that is easy to get wrong — the gate must key on the write's TARGET PATH, -never on the session's cwd.** 29% of writes already come from a session sitting in the primary that -correctly writes *into a worktree* by absolute path. A cwd-keyed gate would have denied all 4,010 of them. -Where a session *sits* is irrelevant; only where it *writes* matters. +never on the session's cwd.** The worktree row of the table above is the 29%: those sessions already +write *correctly* into a worktree by absolute path, and a cwd-keyed gate would have denied all 4,010 of +them. Both percentages are shares of the same 166 sessions' Edit/Write calls, so the 29% and the 44% +are two numerators over one denominator rather than two measurements. Where a session *sits* is +irrelevant; only where it *writes* matters. ## What it blocks diff --git a/docs/WORKTREES.md b/docs/WORKTREES.md index 5356f9f4..45a3352d 100644 --- a/docs/WORKTREES.md +++ b/docs/WORKTREES.md @@ -169,8 +169,9 @@ segment, is now excluded outright and listed as a non-candidate; `-Name` cannot ### Why signal 2 is not a nicety -Signal 1 only sees where a session was **launched**. Measured on this repo: 29% of writes come from a -session sitting in the primary and landing in a sibling by absolute path — and on 2026-07-30, with 5 +Signal 1 only sees where a session was **launched**. Measured on this repo: 29% of the writes made by +sessions sitting in the primary land in a sibling by absolute path — a share of those sessions' own +writes, not of every write here — and on 2026-07-30, with 5 live sessions across 9 worktrees, signal 1 vetoed **none** of the four `-` siblings, including one a session was demonstrably building in. Signal 2 was the only thing standing between that session and this script. The run therefore prints how many candidates signal 1 actually vetoed, @@ -418,9 +419,10 @@ own them). **WHERE A COMMAND RUNS IS NOT WHERE THE CALLER IS, and tooling here keeps assuming it is.** Much of this repo's coordination machinery resolves "which worktree is this about?" from the **current directory** — `git rev-parse --show-toplevel`, `getcwd`, an unqualified relative path — even when it -was handed an explicit path. That assumption is false about **one write in three**: `occupancy.ps1` -measures a session acting on a worktree by absolute path from elsewhere at **29% of writes on this -repo**. So `pwsh -File /scripts/coord/alloc.ps1` run from worktree A while you intend to commit +was handed an explicit path. That assumption is false about **one primary-seated write in three**: +`occupancy.ps1` measures a session acting on a worktree by absolute path from elsewhere at **29% of the +writes made by sessions sitting in the primary**. So `pwsh -File /scripts/coord/alloc.ps1` run +from worktree A while you intend to commit from worktree B records A, and `cd "$D" && git ...` is resolved against your session's cwd rather than `$D`, because a hook cannot expand a shell variable. @@ -754,7 +756,7 @@ it never moves anything — and `-Rehome` refuses on a session that still looks `-MinIdleMinutes`, default 10; override with `-Force`) and honours `-WhatIf` for a no-op preview. **It keys on the write's target path, never on the session's cwd.** In that same 30-day window, **29% of -writes came from a session sitting in the primary but landed inside a sibling worktree by absolute +the writes made by those same 166 primary-seated sessions landed inside a sibling worktree by absolute path** — already correct. A cwd-keyed gate would have denied every one of them. So a session may stay where it is and simply write into its worktree; there is no need to `cd`, relocate, or restart. diff --git a/docs/archive/backlog/BACKLOG-CLOSED.md b/docs/archive/backlog/BACKLOG-CLOSED.md index c900f436..17511314 100644 --- a/docs/archive/backlog/BACKLOG-CLOSED.md +++ b/docs/archive/backlog/BACKLOG-CLOSED.md @@ -6708,6 +6708,9 @@ A slash satisfies git as a refname but makes `Join-Path` build a nested director `occupancy.ps1` already discloses the rate: **a session acting on a worktree by absolute path from elsewhere is 29% of writes on this repo**, by the project's own measurement. So the premise is not merely unstated, it is false about one write in three. +> **CORRECTION 2026-08-13 — the rate above is quoted with the wrong denominator, and the script it quotes no longer says that.** +> The 29% is a share of the Edit/Write calls made by the **166 sessions whose cwd was the shared primary** — roughly 13,800 calls — not of every write in the repo. So *"false about one write in three"* overstates it: the premise is false about one **primary-seated** write in three. The authoritative record is the table in [`WORKTREE-GATE.md`](../../WORKTREE-GATE.md), whose two data rows both read *"Their"* against those 166 sessions; it is the only artifact holding both numerators, which is the only context in which their shared denominator had to be made explicit. `occupancy.ps1` has been reworded to state the population, so the sentence above is now a quotation of what that script said on 2026-08-06, not of what it says today. Left standing rather than rewritten, because this is closed record and the quotation is accurate as history — the same treatment as the #1099 correction in this file. No ledger number was allocated: this is a prose correction with no fix and no closing condition, so it is not an item. + **All three fail silently, and all three fail in the benign-looking direction** — a deny naming the wrong worktree, an owner recorded as the wrong worktree, an occupancy of zero for a worktree in active use. None raises. Each looks like a working answer. **All three were found by accident, none by looking**, which is the part that should not be trusted. Three instances is a coincidence-sized sample, and the honest next step is a targeted sweep for the shape — anything resolving a target from `--show-toplevel`, `getcwd`, or an unqualified relative path *when it was handed an explicit one* — which either produces a fourth concrete instance or shows three was the whole set. That is deliberately **not** filed as a theme item: "three mechanisms share a premise" has no fix and no closing condition, and would sit open describing something true. The premise is also recorded in [`docs/WORKTREES.md`](../../WORKTREES.md), so it outlives this item's closure. diff --git a/scripts/coord/occupancy.ps1 b/scripts/coord/occupancy.ps1 index e3394f95..3a06c296 100644 --- a/scripts/coord/occupancy.ps1 +++ b/scripts/coord/occupancy.ps1 @@ -42,8 +42,9 @@ WHAT IT CANNOT SEE -- state this wherever it is consumed: * A session that writes into a worktree BY ABSOLUTE PATH from somewhere else. Records carry the - cwd a session was launched in, and measurement on this repo says 29% of writes come from a - session sitting in the primary and land in a sibling worktree. Those are invisible here, so a + cwd a session was launched in, and measurement on this repo says 29% of the writes made by + sessions sitting in the primary land in a sibling worktree -- a share of THOSE sessions' + writes, not of every write in the repo. Those are invisible here, so a cwd-keyed fence alone is not sufficient protection for a destructive action. Measured 2026-07-30 on this repo: 5 live sessions, 9 worktrees, and ZERO of the four `-` siblings drew a veto -- including the one a session was demonstrably building in. A caller that diff --git a/scripts/hooks/worktree_gate.ps1 b/scripts/hooks/worktree_gate.ps1 index 5464681e..d67e7bbd 100644 --- a/scripts/hooks/worktree_gate.ps1 +++ b/scripts/hooks/worktree_gate.ps1 @@ -20,9 +20,11 @@ parent (measured: the parent's result came back with an EMPTY permission_denials list). Blocking the fan-out costs one second; letting it run costs the whole workflow. - KEYED ON THE TARGET PATH, NEVER ON THE SESSION'S cwd. Over 30 days, 29% of this repo's Edit/Write - calls came from a session sitting in the primary but wrote into a sibling worktree by absolute path -- - i.e. already correct. A cwd-keyed gate would have denied all of them. Only the DESTINATION matters. + KEYED ON THE TARGET PATH, NEVER ON THE SESSION'S cwd. Over 30 days, 29% of the Edit/Write calls + made by sessions sitting in the primary wrote into a sibling worktree by absolute path -- i.e. + already correct. A cwd-keyed gate would have denied all 4,010 of them. Only the DESTINATION + matters. That 29% is a share of those primary-seated sessions' own calls, NOT of every call in + the repo; the counts and the population are in docs/WORKTREE-GATE.md. FAILS OPEN on every error path (bad JSON, missing fields, unreadable allowlist). A guardrail that wedges all work gets uninstalled, and then it protects nothing. @@ -63,7 +65,7 @@ param( # the drift, but a stamp that disagrees with the verdict beside it is the exact ambiguity this machinery # exists to remove. -Status now prints the SHA prefix on both lines, so agreement is visible rather than # asserted, and this label can never again be the only thing a reader compares. -$GateVersion = "2026.08.12.3" +$GateVersion = "2026.08.13.1" # Fail OPEN: any unhandled error must let the tool call through, never block it. $ErrorActionPreference = "SilentlyContinue" diff --git a/scripts/worktree/prune-merged.ps1 b/scripts/worktree/prune-merged.ps1 index b3e69831..e2e0e5dd 100644 --- a/scripts/worktree/prune-merged.ps1 +++ b/scripts/worktree/prune-merged.ps1 @@ -55,7 +55,8 @@ WHAT THE FENCE CANNOT SEE (printed on every run, because a fence believed to be wider than it is is worse than no fence): * a session that writes into this worktree BY ABSOLUTE PATH from somewhere else -- measured on - this repo, 29% of writes come from a session sitting in the primary and land in a sibling. + this repo, 29% of the writes made by sessions sitting in the primary land in a sibling. That + is a share of those sessions' own writes, not of every write in the repo. Measured again 2026-07-30: 5 live sessions, 9 worktrees, and signal 1 vetoed NONE of the four `-` siblings, including one a session was demonstrably building in. Signal 2 is what stood between that session and this script; @@ -676,7 +677,7 @@ $liveInRepo = @($occ.Sessions | Where-Object { Test-OccupancyVeto $_.State }).Co $fenceVetoedAtDecision = @($decisions | Where-Object { $_.Occupants.Count -gt 0 }).Count $fenceVetoed = $fenceVetoedAtDecision $blindSpots = @( - 'a session writing into a worktree by absolute path from elsewhere (29% of writes on this repo)', + 'a session writing into a worktree by absolute path from elsewhere (29% of the writes by primary-seated sessions, measured on this repo)', 'a cwd recorded as a UNC or 8.3 short path', 'a session that never registered', 'a session that only edits files and runs no git command (invisible to signal 2 as well)' diff --git a/tests/test_script_root_anchoring.py b/tests/test_script_root_anchoring.py index 5d51f4c6..8b3867e5 100644 --- a/tests/test_script_root_anchoring.py +++ b/tests/test_script_root_anchoring.py @@ -9,7 +9,8 @@ checkout passes with the bug still in: cwd and script root are the same directory, so the two candidate answers are indistinguishable. The case that can tell them apart is an absolute ``-File`` invocation whose cwd is a DIFFERENT checkout that also carries the file the script writes -- which is the ordinary shape on -a clone carrying dozens of worktrees, and is measured at 29% of writes on this repo. Per BACKLOG #1000 a +a clone carrying dozens of worktrees, and is measured at 29% of the writes made by sessions sitting in +the primary. Per BACKLOG #1000 a control needs the case that can distinguish; a test run from inside the target proves nothing. The static spelling guards below are deliberately paired with a behavioural test each. On their own they diff --git a/tests/test_worktree_gate.py b/tests/test_worktree_gate.py index 07dd3487..afc11625 100644 --- a/tests/test_worktree_gate.py +++ b/tests/test_worktree_gate.py @@ -2,9 +2,9 @@ The gate keeps concurrent Claude Code sessions from BUILDING in the shared primary checkout. It is keyed on the write's TARGET PATH, never on the session's cwd -- the distinction these tests exist to pin down, -because ~29% of this repo's real Edit/Write calls come from a session sitting in the primary but write -into a sibling worktree by absolute path, and those are already correct. A cwd-keyed gate would deny them -all. +because ~29% of the real Edit/Write calls made by sessions sitting in the primary write into a sibling +worktree by absolute path, and those are already correct. A cwd-keyed gate would deny them all. That +share is of those sessions' own calls, not of every call in the repo. Each test drives the real hook script as a subprocess with a real PreToolUse payload on stdin and asserts on the deny/allow decision, so the contract under test is the one Claude Code actually invokes. diff --git a/tests/test_write_share_denominator.py b/tests/test_write_share_denominator.py new file mode 100644 index 00000000..a0b145cd --- /dev/null +++ b/tests/test_write_share_denominator.py @@ -0,0 +1,259 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (C) 2026 MessageFoundry Organization and contributors +"""Every statement of the write-collision share must name the population it is a share OF. + +THE FAILURE THIS EXISTS FOR, and it is measured rather than imagined. One 30-day measurement is +recorded in the table at ``docs/WORKTREE-GATE.md``: 166 sessions ran with their cwd in the shared +primary, 6,075 of *their* Edit/Write calls (44%) landed in that primary's tree, and 4,010 (29%) +landed in a sibling worktree by absolute path. Both data rows are scoped to those sessions, so the +two percentages are TWO NUMERATORS OVER ONE DENOMINATOR -- roughly 13,800 calls -- with the +remaining ~27% landing outside the repository altogether. + +On 2026-08-13 that denominator was stated correctly in exactly ONE place in this repository +(``docs/WORKTREES.md``, the 44% sentence) and loosely in fourteen others, including the gate's own +docstring, a string printed to an operator mid-deletion, and this suite. A bare "29% of writes" +does not read as ambiguous -- the reader supplies the wider denominator and is never corrected. + +WHY A BAN ON THE LOOSE FORM, not a required spelling. The scope can be carried by an attribution +clause after the figure, by a lead-in sentence before it, or by a possessive. Pinning one wording +would go red on a rewrite that harms no reader. What must never return is the unscoped form. + +THREE PROPERTIES ARE LOAD-BEARING, each with the measurement that fixed it: + +* WHOLE-FILE, never line-by-line. Two live sites wrapped between ``of`` and its noun, one of them + ``scripts/hooks/worktree_gate.ps1`` -- the sentence that justified the target-path design. A + line-oriented scan cannot see either. +* A POSSESSIVE NAMING THE REPO IS REJECTED OUTRIGHT. "29% of *this repo's* Edit/Write calls" does + not omit a population, it asserts the WRONG one, so no amount of nearby context redeems it. This + is also the shape that defeated the first version of this pattern, which allowed only "the" and + "all" as noise and so could not see the single most consequential site. +* THE WINDOW IS SMALL AND LOOKS BOTH WAYS. Both orders occur in this corpus: the population follows + the figure in the scripts and precedes it in ``docs/WORKTREES.md``. 200 characters covers the + correctly-scoped site, whose marker sits ~90 characters back. It deliberately does NOT reach the + table in ``docs/WORKTREE-GATE.md`` from that file's own restatement 794 characters below it -- a + window wide enough to cover that distance would let any file with the table in it say anything. + +WHAT IT CANNOT CATCH, stated because an unstated limit reads as coverage. The noun list is an +allowlist: "44% of edits", "44% of tool calls" and a spelled-out "forty-four percent" are invisible. +So is a PARAPHRASE carrying no digits -- "one write in three" was a real site here and no +percentage-keyed scan will ever see it. Widen the list when a new spelling appears; do not read a +green run as proof that none exists. +""" + +from __future__ import annotations + +import re +import subprocess +from pathlib import Path + +import pytest + +_REPO = Path(__file__).resolve().parents[1] + +# "N% of ". \s+ spans the newline a wrapped line puts +# mid-phrase. +# +# THE MODIFIER RUN IS OPEN, NOT AN ALLOWLIST, and that is the whole point. The first version of this +# pattern listed the determiners it expected -- all, the, their, its, this repo's -- and ONE ADJECTIVE +# defeated it: "~29% of this repo's REAL Edit/Write calls", the wording that stood in this suite's own +# sibling until it was corrected, did not match at all. The single wrongest sentence in the repository +# was the one sentence the guard could not see. An allowlist decides in advance which words a defect +# is allowed to contain, which is not a thing anyone can know. +# +# TWO BARS KEEP IT HONEST. `durable` excludes the store-transaction family (ADR 0084 and the cost-model +# tests say "63% of the hub's durable writes" about SQLite transactions, a different subject). `body` +# and `bytes` exclude "77% of the body bytes this message writes", where `writes` is a verb. The +# three-token cap does the rest: five words of noun phrase cannot reach the noun. +# +# The lookbehind stops "49.44%" in the benchmark corpus from being read as a bare "44%". +_SHARE = re.compile( + r"(?(?:(?!durable\b|body\b|bytes\b)[\w'’-]+\s+){0,3})" + r"(?:file\s+writes|Edit/Write\s+calls|write\s+calls|writes)\b", + re.IGNORECASE, +) + +# A qualifier that names the repository as the denominator. Affirmatively wrong, not merely vague. +_WRONG_POPULATION = re.compile(r"\b(?:this|the)\s+repo's\b", re.IGNORECASE) + +# The population marker: a session word AND an anchor tying it to the primary checkout. Both are +# required, so "by other sessions" and a stray mention of the primary each fail on their own. +_SESSIONS = re.compile(r"\bsessions?\b", re.IGNORECASE) +_PRIMARY = re.compile(r"primary|shared\s+checkout|\b166\b", re.IGNORECASE) + +_WINDOW = 200 + +# A closed-record QUOTATION may keep its original wrong denominator -- rewriting archived text +# falsifies it as history -- but only when a correction stands with it. So a `> **CORRECTION` +# blockquote that itself names the population discharges the site, and nothing else does. The +# window is generous because the correction follows the quoted paragraph rather than the figure, +# and the correction must carry the population marker itself, so this cannot be satisfied by an +# unrelated correction that happens to sit nearby. +_CORRECTION = re.compile(r">\s*\*\*CORRECTION\b", re.IGNORECASE) +_CORRECTION_WINDOW = 1500 + +# Unrelated measurements that merely happen to be a share of something. Benchmarks quote CPU +# percentages in the same shape; they are a different subject and are not in scope here. +_EXEMPT_PREFIXES = ("docs/benchmarks/",) + +# This module plants the defective sentences on purpose, in the negative controls below. Named +# explicitly rather than pattern-excluded, so the exemption is one file and cannot quietly grow. +_SELF = "tests/test_write_share_denominator.py" + + +def _tracked_text_files() -> list[str]: + out = subprocess.run( + ["git", "ls-files"], cwd=_REPO, capture_output=True, check=True + ).stdout.decode("utf-8", errors="replace") + return [ + p + for p in out.split() + if p != _SELF + and not p.startswith(_EXEMPT_PREFIXES) + and not p.lower().endswith((".png", ".jpg", ".gif", ".ico", ".pdf", ".db", ".zip")) + ] + + +def _is_scoped(text: str, match: re.Match[str]) -> bool: + """Does the figure name the population it is a share of?""" + if match.group("qualifier") and _WRONG_POPULATION.search(match.group("qualifier")): + return False + lo = max(0, match.start() - _WINDOW) + window = " ".join(text[lo : match.end() + _WINDOW].split()) + if _SESSIONS.search(window) and _PRIMARY.search(window): + return True + return _has_correction(text, match) + + +def _has_correction(text: str, match: re.Match[str]) -> bool: + """Is this an archived quotation whose wrong denominator is corrected in place?""" + tail = text[match.end() : match.end() + _CORRECTION_WINDOW] + hit = _CORRECTION.search(tail) + if hit is None: + return False + block = " ".join(tail[hit.start() :].split()) + return bool(_SESSIONS.search(block) and _PRIMARY.search(block)) + + +def _unscoped_sites() -> tuple[list[str], int, int]: + """Return (offending 'path:line: quote' strings, files scanned, figure sites found).""" + offenders: list[str] = [] + scanned = 0 + sites = 0 + for rel in _tracked_text_files(): + try: + text = (_REPO / rel).read_text(encoding="utf-8") + except (OSError, UnicodeDecodeError): + continue + scanned += 1 + for m in _SHARE.finditer(text): + sites += 1 + if not _is_scoped(text, m): + line = text.count("\n", 0, m.start()) + 1 + offenders.append(f"{rel}:{line}: {' '.join(m.group(0).split())!r}") + return offenders, scanned, sites + + +def test_no_copy_states_the_share_without_naming_its_population() -> None: + offenders, scanned, sites = _unscoped_sites() + assert not offenders, ( + f"scanned {scanned} tracked files and found {sites} share-of-writes claims; " + "these do not name the population the share is OF:\n " + "\n ".join(offenders) + "\n" + "The 44% and the 29% are shares of the Edit/Write calls made by the 166 sessions whose cwd " + "was the shared primary, NOT of every write in the repo. Name whose writes, or the next " + "reader supplies a denominator and supplies the wrong one. Counts: docs/WORKTREE-GATE.md." + ) + + +def test_the_scan_actually_reaches_the_corpus() -> None: + """A pattern that matches nothing passes everything. Pin that it still finds the real sites.""" + _, scanned, sites = _unscoped_sites() + assert scanned > 500, f"only {scanned} tracked files scanned; the corpus walk is broken" + assert sites >= 10, ( + f"only {sites} share-of-writes claims found across the repo. This figure is stated in the " + "gate docstring, both worktree scripts, this suite's sibling and four docs, so a count in " + "single digits means the pattern stopped matching rather than that the corpus got cleaner." + ) + + +def test_the_authoritative_table_is_reachable_and_still_scopes_both_rows() -> None: + """The whole ban rests on this table. If it moves, the deny text points at nothing.""" + gate_doc = (_REPO / "docs" / "WORKTREE-GATE.md").read_text(encoding="utf-8") + for needle in ("166", "6,075", "4,010"): + assert needle in gate_doc, f"docs/WORKTREE-GATE.md no longer states {needle}" + assert gate_doc.count("| Their Edit/Write calls") == 2, ( + "the two data rows no longer both open with 'Their'. That possessive is the entire " + "evidence that the 44% and the 29% share one denominator; without it the table stops " + "settling the question this gate enforces." + ) + + +@pytest.mark.parametrize( + "sentence", + [ + # The store-transaction family: a different subject that shares the surface shape. + "63% of the hub's durable writes buy no delivered message", + "`wasted == 32` for the hub -- 63% of its durable writes", + # `writes` as a VERB, not a noun. + "the routed rows alone are 20 of the 26 copies: 77% of the body bytes this message writes.", + # A decimal percentage in the benchmark corpus, which must not read as a bare "44%". + "delivered 49.44% and slope +115.1", + ], +) +def test_the_pattern_does_not_fire_on_a_different_subject(sentence: str) -> None: + """False positives are the expensive failure: a guard that cries wolf gets deleted. + + Widening the modifier run to catch an adjective also widened the reach toward these, so each is + pinned. If one of them starts matching, the fix is a narrower bar, never an exemption for the + file it happens to live in. + """ + assert _SHARE.search(sentence) is None, ( + f"the pattern now fires on {sentence!r}, which is not the write-collision measurement. " + "Tighten the bars in _SHARE rather than exempting the path." + ) + + +@pytest.mark.parametrize( + ("sentence", "scoped"), + [ + # The historical defects, verbatim in shape. + ("29% of writes on this repo come from a session elsewhere", False), + ("Over 30 days, 29% of this repo's Edit/Write calls came from a session", False), + ("44% of all file writes still landed in the primary's tree", False), + # An ADJECTIVE inside the modifier run. This exact wording stood in + # tests/test_worktree_gate.py and the first version of _SHARE could not see it at all. + ("~29% of this repo's real Edit/Write calls come from a session in the primary", False), + ("44% of the repo's total file writes landed there", False), + # Attribution present but naming a DIFFERENT population. + ("29% of writes by other sessions landed in a sibling", False), + # A bare CORRECTION marker does not discharge a site; it must state the population. + ("29% of writes on this repo\n\n> **CORRECTION** the wording above was loose.", False), + # An archived quotation kept verbatim, with a correction that names the denominator. + ( + "is 29% of writes on this repo, by the project's own measurement.\n\n" + "> **CORRECTION 2026-08-13 -- wrong denominator.**\n" + "> It is a share of the calls made by the 166 sessions whose cwd was the shared primary.", + True, + ), + # The corrected forms actually used in this repository, both orders. + ( + "29% of the Edit/Write calls made by sessions sitting in the primary wrote elsewhere", + True, + ), + ("29% of the writes made by sessions sitting in the primary land in a sibling", True), + ( + "166 sessions ran with their cwd in the shared primary, and 44% of all their file " + "writes landed in the primary's tree", + True, + ), + ], +) +def test_the_pattern_rejects_what_it_exists_to_reject(sentence: str, scoped: bool) -> None: + """Negative controls. Without these the ban above is a claim about a regex nobody exercised.""" + m = _SHARE.search(sentence) + assert m is not None, f"the pattern no longer recognises a share-of-writes claim: {sentence!r}" + assert _is_scoped(sentence, m) is scoped, ( + f"expected scoped={scoped} for {sentence!r}. A pattern broadened until it stops " + "discriminating is a green that means nothing; one narrowed until it rejects the " + "corpus's own corrected wording fails the repository it guards." + )