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 73e08741..e7f3e78d 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." + )