Conversation
Pure move, no content change: `git diff domform-submittable-category --
.claude/` is empty. PR-A0 bundled a general-purpose enforcement tool, a
shared-map refactor, and a plan-review gate change into a WHATWG-HTML
citation sweep. CLAUDE.md "Edge-dense work = multi-PR program" makes the
split a rule, not a judgment, and the base case that would exempt it
requires a passed plan-review the sweep memo still lists as pending.
The dependency is one-directional — the sweep needs a detector; the
detector, `spec_labels.py`, `coverage_map.py`, `webref_data.py` and the
`preflight.py` change do not need the sweep — so this half stands alone:
36 tests green, `cite-audit` runs against unswept `crates/` (412 sections
/ 2535 cites / 64 unresolved), `preflight.py` exits 0.
`preflight.py` is in scope here by construction; in the sweep it sat
outside that memo's own declared code exception ("the tool + its tests").
The detector's known under-report paths and the gate's fail-open are NOT
fixed by this commit — it is deliberately a provenance-preserving move so
the fixes are reviewable as a delta against what PR-A0 actually shipped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Covers the implementation that remains after the carve in bf580047: the nine confirmed under-report paths in the detector, making preflight.py's citation gate fail closed, retiring the "≥4 grep pattern" discovery method the detector supersedes, and wiring the _webref suites into CI. Every quantity ships the command that derives it, measured against this branch's clean base rather than carried over — the source PR's memo carried 13 / 26 / 36 / 38 for one test count and was wrong three ways. Notable findings while authoring, all against the code rather than recalled: - The proposed `(?=[^\w.-]|$)` fix for the section-token grammar is wrong: it also rejects sentence-final `§4.10.5.`, of which crates/ has 344. Only the atomic-group form is admissible. - `.github/workflows/ci.yml` lists `.claude/**` in neither path filter and never invokes mise, so a tooling-only PR — this one — currently triggers no CI job at all on a PR. A mise task alone would not close that. - Fixing attribution moves the number a sweep's exit criterion reads: UNATTRIBUTED 6832 → 5733, distinct attributed specs 10 → 65. That is a coordination obligation on the sweep, recorded in §13. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two carves in one session, both forced by the edge-dense rule, both found by a gate rather than at authoring time: PR-A0 bundled a general-purpose detector, a shared spec-label refactor, and a plan-review hard-gate change into a WHATWG-HTML citation sweep; the carve then produced a plan-memo whose own §9 conceded the trigger fires and the base case does not apply, and proceeded as a single PR anyway. CLAUDE.md's base case terminates that recursion, but only under an approved umbrella — which did not exist. This is it. Slice order is forced rather than preferred. Enforcement plumbing goes first because `.claude/**` is in neither ci.yml path filter and ci.yml never invokes mise, so a tooling-only PR triggers zero jobs today. Policy retirement goes last because it rests on a supersession claim that is only admissible once the detector's reach is measured — and today that claim is false: cite-audit needs the literal § glyph, leaving 62 AO-name cites, 79 `per <spec>` prose lines and 24 spec-URL cites unreachable. The 785-line slice memo committed in 45bd11bc is re-sliced under this before any implementation starts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The 785-line single-PR memo is partitioned under the umbrella's slice
table. Nothing is summarised across memos — each concern is stated once,
in one slice's memo, and the others link to it.
A (new) enforcement plumbing: preflight fail-closed, the derivation
assertion relocation, the mise task + CI filter/job.
Review-ready; preflight EXIT 0.
B (mv) the detector, so the 785-line memo's provenance survives.
§4.0-§4.1 / §4.6 / §5 verbatim; framing rewritten to the
slice boundary. Draft.
C (new) policy retirement, blocked on B's reach measurement. Draft;
preflight EXIT 1 by design (no §3 table until kickoff).
Two corrections the re-slice produced, both by execution, not reading:
* The fail-closed tri-state does not work where the pre-slice memo
sited it. Applied verbatim in a sandbox, it fails closed for a memo
whose §3 rows carry spec labels (EXIT 1) and still fails OPEN for one
whose rows open with `§` (EXIT 0) — `shortname_from_label`'s
`if not label: return None` short-circuits before the availability
check, so the gate's fail-closed property becomes a function of the
reviewed memo's cell formatting. Re-sited to a process-level
precondition in `main()`, which is also where the per-citation
`WEBREF.is_file()` re-check collapses to.
* Wiring the suites into CI takes a live-network dependency the
pre-slice memo never surfaced. The 48-test `_webref` suite fetches
exactly 2 URLs from raw.githubusercontent.com, and `cache.py` issues
a conditional GET even on a warm cache and `sys.exit`s on URLError —
so a network-blocked run is 15 failures + 3 errors regardless of the
101 MB local cache. Accepted with the measurement stated; the
offline-mode fix belongs to B's `_catalog()` availability contract.
Also re-derived rather than carried: `mise.toml` is 136 lines post-#488
(not 131), and `main` has no branch protection, so the new job makes a
regression visible at review time rather than blocking a merge.
Both branches rebased onto 96a8e47 first; the carve is still
provenance-preserving (`git diff domform-submittable-category -- .claude/`
= 0 lines).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t-1 errors /elidex-plan-review on draft 1 returned 2 CRIT. Verifying them showed the memo had measured its entire evidence base on the branch instead of on origin/main, and the consequences were structural, not cosmetic. The slice boundary was wrong (F1). `origin/main`'s preflight.py carries a local SPEC_LABEL_REVERSE dict and imports nothing from `_webref`, so the fail-open the memo existed to fix is *introduced by the carve*, not pre-existing. The detector carve sits inside origin/main..HEAD, so the PR draft 1 described would have opened with ~945 lines of Slice B — the third recurrence of the bundling this umbrella exists to undo. Fix: re-carve `26721cfa` on the seam the umbrella already draws, verified file by file. The dependency is one-directional (cite_audit imports spec_labels, never the reverse), and TestSharedSpecLabelMap subclasses unittest.TestCase rather than the detector's _TreeCase — the same fact in the test tree. A takes the shared spec-label map and lands it fail-closed so the defect is never introduced; B takes the detector. Landing the map fail-open and repairing it two slices later was never the ideal option. The row-loop contradiction (F2): draft 1 deleted shortname_from_label's capability branch as "unreachable from main" while main's row loop calls it at :353 on every path including --no-verify — the J3 must-survive path, which would have become a TypeError. Resolved by skipping the mapping call when the capability is absent, so "uncertified" and "unmapped" stay distinct without a second site answering the capability question. Nine further corrections, each re-derived rather than taken on the agents' word (§14): branch protection is an active *ruleset*, not absent — the legacy endpoint's 404 misled draft 1; §13 used two-dot ranges and fabricated a mise.toml overlap with PR #489; the offline obligation was routed to a Slice B section that makes offline *more* fatal, leaving it unowned; the Python 3.11 floor was Slice B's need carried by A; the "six-row complete edge matrix" was six of nine cells; the CI facts were headed for the externalizable generic core; the trip-wire non-discharge rationale inverted the Layout lane's own record; §12's load-bearing red-check read a patch committed nowhere; and the slot obstacle text lives in project_inline-mod-split-owed.md, not the defer ledger. Also now correct and derivable: the origin/main baseline is 47 tests across 4 files (not 83 across 5), A's own suite fetches 1 URL (not 2 — the second leaves with the detector), and every count ships its command. Preflight: EXIT 0, 0 hard / 0 soft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Round 2 of /elidex-plan-review returned 2 CRIT, both introduced by draft 2's own fix. Re-derived by hand before acting on either. CRIT-1 — A introduces a THIRD capability failure and its precondition covered two. A's new import reaches spec_labels.shortname_for -> _catalog() -> webref_data._data_index() -> cache.py:131 sys.exit, and SystemExit is a BaseException, so _catalog()'s `except Exception` never sees it — its docstring's "an offline run degrades to the pinned set rather than dying" is false. Reproduced: offline + any label outside the 24 pinned keys (the catalog has 948; the umbrella records 10 in-flight memos citing such labels) gives a bare exit from inside the row loop, no diagnostic, no --no-verify escape. origin/main exits 0 on the same input. That is J3 broken by the slice written to protect it. CRIT-2 — §13 rested on an incomplete `gh pr list`. Four PRs are open, not the two tabulated; #381 (actions/checkout 6->7, open since June) touches ci.yml, so "no branch introduces a .github/workflows change" was false, A's ci.yml edit has actual contention, and the trip-wire slot's trigger had already fired independently of A. Root fix subsumes both plus four Axis-2 findings: don't skip the row loop. Draft 2 skipped the per-row mapping call when the capability was absent, but both writers of `unique_specs` are downstream of it — measured, a 7-spec fixture went SPLIT-DEFAULT -> `ok (single PR scope)` with --strict-breadth 1 -> 0, silently disabling a different gate than the one being fixed. Instead: _catalog() returns a discriminated result (catching SystemExit), resolve_label is three-valued (MAPPED/UNKNOWN/UNCERTAIN), the loop keeps its shape and gains a third arm, and the capability verdict is the union of two static causes and one dynamic one. Breadth survives in every configuration; P3 now pins K rather than the exit code alone. The discriminated _catalog() moves from Slice B to A — the slice that introduces a failure owns it — and B's §4.1.7 is rewritten to consume the type rather than introduce it. 17 further corrections in §14, including three the memo made about itself: draft 2 silently reversed draft 1's Q5 recommendation, moved the deferral count 1->2, and deleted draft 1's "slots this slice does not register" paragraph, none recorded in the section whose preamble forbids exactly that. Also: the SPECS bound §3.1 relied on is the one A deletes; §5's "complete 3x2 matrix" was stated three inconsistent ways and its rows were measured under a non-default flag; two `cleanup-*` slots were counted against a cap the registry treats them as exempt from; and §12(3) could see neither the six prose sites naming cite_audit.py nor the 799 lines of B's and C's memos the branch carries. Preflight: EXIT 0, 0 hard / 0 soft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Round 3 of /elidex-plan-review: 0 CRIT on Axis 1/3/4/5, 2 CRIT on Axis 2. Every finding acted on below was re-derived by hand first. E1, the sharpest and found by three of five agents: §4.6 still asserted "the row loop is skipped" — the design draft 3 replaced — while §14 D3 recorded that spelling as removed. A self-falsifying claim inside the section whose stated thesis is that a silent correction is the defect being removed. D3 now records the miss instead of the fix. E2: §5's "breadth is preserved in every row" was draft 2's bug inverted. MAPPED rows key unique_specs by shortname, UNKNOWN/UNCERTAIN by label spelling — measured on one memo whose 9 rows alias 3 specs, K goes 3 -> 9 and --strict-breadth 0 -> 1 when the capability drops. Claim withdrawn; the semantic choice is now the one open question in §10, because it changes what --strict-breadth means for every lane. E3: §5 row 11 was two rows. With all labels pinned the catalog is never consulted, but under default mode the MAPPED rows reach verify_citation, whose subprocess has its own network path — measured exit 1, not the claimed 0. P9's in-process urlopen spy structurally could not have caught it, so P9 is scoped to --no-verify and row 11b gets its own pin. E8: the no-spec-surface gap is now fixed in A (§4.2.5) rather than deferred. Draft 2 routed it to B, draft 3 to C; Axis 4 verified the §3 contract lives in SKILL.md Pre-condition #1, which §4.1 already assigns to A, and C's charter excludes preflight.py. Two successive owners who could not perform the fix is the signal that the deferral, not the owner, was the error. E9/E10/E11, all corrections to claims about state outside the diff: the trip-wire trigger did NOT fire via #381 (it predates the slot by five weeks — A itself is the trigger); three of the four stale-memory strings the landing checklist named no longer exist, because this session had already rewritten that file; and #491 merged mid-review, so the base moved to db96f23 and the allowlist collateral is now permanent rather than one PR's. Also: the uncertified_* accumulators were read by three sections and written by none; the test-isolation contract was one module too shallow (webref_data._INDEX and the try_fetch_data cache); row 12's carve value was 0 not 1; the "exit code never moves 1 -> 0" invariant is falsified by the memo's own rows 9/10; and count fixes at §4.0, §4.3.1, §4.2.4, §8, §12. §14 is collapsed from a restatement to an index. Round 3's findings were dominated by section-contradicts-section, which is the duplicated-decision- surface defect rather than eleven separate ones. Preflight: EXIT 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Round 4's conclusion was that the slice boundary was still wrong three drafts in, not that draft 4 needed another patch. So this is a scope change: spec_labels.py lands pinned-map-only and the 948-entry catalog fall-through moves to Slice B, which already owns the lookup semantics that make it correct (B §4.1.2 / §4.1.7 / §4.1.8 — B's memo needs no edit). The ground is the boundary, not danger. A's own §4.1 already assigned lookup semantics to B while draft 4 shipped the fall-through — which *is* lookup semantics. Re-derived, round 4's stated consequence does not survive: every catalog level-collision pair (cssom/cssom-1, selectors/selectors-4, pointerevents3/4, wai-aria, webaudio) returns byte-identical heading data, because webref's ed/ extracts are keyed to the series' current spec. 195 of the 203 non-round-trips are same-document aliases; the 8 that are not are cross-series or fork cases no elidex memo cites. §0 records the falsification rather than inheriting the claim, and §13 hands it to B. What the change deletes, because the widening was their sole cause: the dynamic third capability cause, the aggregated verdict, the tri-state resolver and its two accumulators, the fifth remedy string, the _INDEX/cache_clear isolation contract (whose cited API does not exist on origin/main), the network dependency in `mise run ci`, the cleanup-webref-suites-offline deferral, and the umbrella offline obligation. Both remaining causes are static, so the verdict is computed once before the loop — which is what §1's own corollary prescribed. Also: §4.2.5 fully specified (marker shape, mutual exclusion with a table, n/a not ok, capability interaction, residual stated) after round 4 found it declared but undefined; §5/§6/§4.6/§12(2) collapsed into one table with a Pin column, which makes the section-contradicts-section class structurally impossible; ~59 draft-number mentions and 12 draft-N correction blocks deleted. 1024 → 907 lines, preflight 0 hard / 0 soft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ing coordinates Round 5: 1 CRIT / 25 IMP / 22 MIN / 5 FP, six root clusters. G1 (CRIT) draft 5's §4.2.3 item 6 made shortname_from_label raise when the map is absent, while item 5 and §5 row 8 both require the row loop to classify and exit 0 under --no-verify. J1 forbids one *return value* carrying both questions; it does not forbid two *sites*. The branch keeps returning None; the verdict is answered once in main. G2 "A changes no resolution outcome" was false. The pinned map is a strict superset — 9 spellings newly resolve, and four landed memos carry such cells (WebIDL §3.2.15/§3.2.25, XHR §3.2, Fetch §2.2.5; all green today). The honest fact is that A's *spec set* is unchanged and 9 *spellings* of those same 12 specs now resolve. P12b pins it. G3 "B's memo needs no edit" was false at seven sites: B's §4.1.2/§4.1.7/ §4.1.8 measure the catalog as extant at B's base, with line anchors that this re-slice removes. §13 enumerates the edits A makes to B in the re-carve commit. G4 four pins could not check what they claimed. P9 patched urlopen in the parent while verify_citation's fetch is in a child; rows 1/2 were pinned to a unit assertion that never enters main; _spec_label's last-resort lost its only exerciser to B; §12(2) was a second list. P1b stubs verify_citation so J5 and the happy path stop competing. G5 the no-spec-surface marker had no recognition rule — now line-anchored, fence-aware and §3-scoped, the three properties both existing §3 scanners already thread. Re-measured on a real origin/main worktree, §5 row 13 is 0, not 1: the marker is inert prose there, so the table verifies. G6 the staleness class, fourth round running. The rebase this draft required moved the carve sha a third time, which is the proof: draft 6 cites origin/main by symbol, the carve by subject, and puts every quantity in a new §15 re-derivation block. Eight line cites were branch-relative — four found by review, four more by re-derivation. Also: §1 gains a third instance of its own class, live on origin/main and missed by four drafts — an all-unmapped memo prints no `citation verify:` line at all and exits 0. §7 stops claiming A avoids externalization debt it in fact adds. §9 stops conflating capability causes with invariant axes. §10-Q3 cites Control C, not D. §11 gains Resolved-by + confidence. 907 -> 984 lines, preflight 0 hard / 0 soft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Draft 6's §15 was a *description* of commands. Round 6 found the consequence across four axes: three of its blocks were prose placeholders (§5's whole origin/main column, the J5 fetch count, the §11 timings), two hard-coded the answer they claimed to derive, and one re-introduced a stored coordinate — while §15's preamble reads "Nothing here is a stored value". Axis 4's verdict was that every measured value was correct and the defects were "numbers whose stated derivation does not derive them". So the derivation becomes an executable. Each function prints one quantity the memo relies on; the memo cites the function name and carries no digits of its own except where a decision turns on the value. The fixture bodies live here too, so the six memos a reviewer measures are byte-identical to the ones the test plan ships — draft 6 named the fixtures in prose, which let two reviewers build different files. Two fixtures are new and both close a hole review found: - dedup.md — two rows resolving to ONE (shortname, section) pair. Draft 6 justified its second labelled row as exercising seen_pairs, but both rows were distinct keys, so the dedup `continue` was taken zero times and the 21->15 figure it underwrites was unpinned. Measured now: 2 rows -> "1 unique citation(s) checked". - alias.md — `| Fetch §2.2.5 |`, the spelling §5 row 10 is about. No draft-6 fixture could reach that row. Running `column` reproduces §5's origin/main column mechanically and confirms three values draft 6 asserted: allunmapped and alias both print NO `citation verify:` line at exit 0 (§1 item 3), nospec-and-table exits 0, nospec-and-header exits 1 on the 0-data-rows path. `keysets` also settles a round-6 layering finding: deleting every one of the 8 parse aliases leaves LABEL_TO_SHORTNAME byte-identical at 24 keys, because each alias lowercases to its own shortname. The aliases are inert; the 9 newly-resolving spellings come from the shortname-as-parse- key rule instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…orced Round 6: 1 CRIT / 46 IMP / 43 MIN / 10 FP across five axes. 984 -> 771 lines, because the surface that generated findings was prose describing executable things. G1 (CRIT, found independently by two axes and by hand) draft 6 routed the new `citation verify: n/a` line through §4.2.3 item 4's loop predicate. In the one row it exists for -- map present, every row unmapped -- that predicate is False (`citations` empty, `unavailable` False), so the line would never print and its pin would be red. The reporting arm now has its own condition and N is defined. G2 "A changes no resolution outcome" was false in draft 5; draft 6's replacement blamed a widened alias list, which is ALSO false. Measured: deleting all 8 parse aliases leaves LABEL_TO_SHORTNAME byte-identical at 24 keys, because each lowercases to its own shortname. A deletes them. The 9 new spellings come from shortname-as-own-parse-key. G3 the B-memo edit list was written from reading; four of seven items were wrong or incomplete. It is now stated as classes to grep, and it is owed at Step 0 rather than claimed as done. G4 four pins could not check what they claimed. Row 10's "detects the carve" was false -- the carve already resolves `| Fetch §2.2.5 |`, measured -- and no fixture could reach that row. P5's "and no other" was falsified: with the map absent the per-row soft-warn still prints "add the spec to ...::SPECS", so the founding wrong-cause defect survived A's own fix. §4.2.3 gains item 7 to suppress it. Remedy 3 promised an import error that `except Exception` discards, so A must capture it. G5 the marker's recognition rule is now line-anchored, fence-aware and §3-scoped, with a fenced-quotation fixture pinning the second. G6 §5's Pin column, §6's prose and §12(2)'s list were three views of one thing across three rounds. §6 is now the single pin table and §12(2) reads its column. Also: §7's coupling census was built on a string grep and is corrected -- origin/main's generic tree already carries 7 plan-memo/plan-review references across 2 files, so A adds instances to a saturated class, not a new class; §9 now argues both conjuncts of the base case; §11 converts its last own deferral into an umbrella constraint (0 own deferrals); §10-Q3 picks promote-to-PR instead of inventing a sixth disposition; §12(4) states the sequence that made draft 6's §13 unsatisfiable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ility instrument Two problems, one root: §4.2.3 specifies the control flow of code that does not exist yet, in prose, so a review round was the only thing executing it. Round 6 found the reporting arm False in the one row it exists for; draft 7's fix made it True in six rows where it must be False. Two inversions in a row is a method failure. - `armmatrix` grafts §4.2.3 + §4.2.5 onto a copy of preflight.py in a scratch worktree and runs all 17 §5 rows plus 7 untabulated states with THREE candidate reporting predicates instrumented side by side, and a spy counting webref subprocesses per row. - `instruments` measures the three candidate capability instruments on all three signals. Draft 7's `mv .claude/tools/_webref` flips neither §5 axis: `.claude/tools/webref` is a separate 16-line shim, so `WEBREF.is_file()` stays True while the CLI dies rc 1 at invocation. The map axis is an in-process `sys.meta_path` block (tree intact => the child CLI still rc 0); the CLI axis is renaming the shim. `remedies` now uses the former. - The runner also pins `shortname_for` to the pinned map, which is what A ships: measured against the BRANCH resolver, `allunmapped.md` resolves `CSSOM VIEW` -> `cssom-view-1` via the catalog and fully verifies, so the fixture named for the all-unmapped state does not produce it. - `column` now varies the CLI axis, which §5 rows 3/4/5 need and draft 6's version never did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Round 7 found the round-6 CRIT fix INVERTED: draft 7's reporting arm is True in six rows where it must be False, one of them printing "0 of 2 rows resolvable" about a memo whose 2 of 2 rows resolved. Two inversions in a row on the same clause is a method failure — §4.2.3 governs code that does not exist yet, so prose was the only medium and a review round was the only interpreter. Draft 8 measures it. `rederive armmatrix` grafts §4.2.3 + §4.2.5 onto a copy of preflight.py and runs 24 states with three candidate predicates side by side. Results: - draft 7's arm: True in 10 states, must be True in 2. - the obvious repair (a `verify_ran` flag set where the loop is entered): True in ZERO states, including the two it exists for — any flag set inside the verification stage inherits item 4's entry predicate, which is False in exactly the row the reporting arm exists for. - `not no_verify and data_rows and not unavailable and not seen_pairs`: True in exactly rows 11 and 11b. Shipped. Three edits no review round proposed, all surfaced by running it: - item 7b: the row loop must partition unmapped rows into labelled-unknown vs label-less, or remedies 1 and 2 both fire off one list and §4.2.4's table is unimplementable. - item 7c: J1 binds the reporting layer — with the capability absent the summary still asserts `unmapped-label rows: N`, a datum the mapper never established. It states its basis instead. - §4.2.5: the marker suppresses citation verification, not grep-pass, so the grep-pass stage moves to a function both paths call. Also from round 7, measured: - the capability instrument was wrong in drafts 1-7 (§4.2.1) — see the preceding commit. - C2: exactly 5 webref subprocesses across 4 rows => pins P1b/P1c/P4/P10/P11d need the stub, so it is a suite-level fixture, not a P1b clause. T-net(a) asserts on the WEBREF path, not a "webref" substring. - P11d's "fails at the carve = yes" was false: the carve exits 0 on the fenced fixture too. P11d and P11e now assert on the mechanism. - remedy 3's captured import error must be initialised before the `try`, or it survives a SUCCEEDING importlib.reload. - §5 gains row 11b (label-less, capabilities present) — the second state the new line must print in, and the only one P4 can compare at the available end. - §8's "~500 → ~540" was invented; `budget` now reports statement count and A is roughly statement-neutral. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Round 8 returned 0 CRIT / 30 IMP, and ELEVEN of the IMPs were defects in the
harness draft 8 introduced. Building the executable and checking that the
executable covers the memo's claims are two different things; draft 8 did the
first and asserted the second.
- `_proto` now models `displayed_specs`, so item 8 ("K and the spec list cannot
disagree") is measurable. It is FALSE as drafted: item 7b moves label-less
rows out of `unrecognized_labels`, and the summary prints `K: 1 (-)`.
`PROTO-DISPLAY` reports item8_routed / item8_unrouted per state.
- new `malformed.md` fixture. No fixture had a row without a section mark, so
item 5's denominator clause -- "N = len(data_rows), malformed rows included"
-- was the one clause of the item nothing measured. Row 16 now shows
`n/a (0 of 2 rows resolvable)` co-printing with the malformed hard fail.
- `armmatrix` prints its own state totals. Draft 8 hand-counted "24 states / 17
§5 rows / 20 other states"; measured 27 / 19 / 8 after the additions, and
25 / 18 / 7 before them. It also no longer greps away the `remedy*` lines two
sections cite it for.
- items 7/7c re-keyed from `unavailable` onto `map_missing`. With only the CLI
absent the mapper ran and declined, so the rows ARE classified and remedy 1 is
the correct diagnosis; suppressing it reported a capability problem the run
did not have. Same conflation item 7c exists to fix, one level up.
- item 7b's partition reaches the summary: `unknown-label rows` / `label-less
rows` replace the merged counter, which said "label" for rows that have none.
- `couplings` computes the verdict §12(3) attributes to it: file paths only,
restricted to A's half, as a DELTA against origin/main. "Must be 0" was the
wrong criterion -- `cli.py` already carries one -- and the real answer is that
A adds exactly one, `spec_labels.py:7`.
- `lanes` ranges over the files A contends on. Its docs/plans/ filter plus
`gh pr list` could not see the Layout lane's unpushed CI branch, which commits
an opposite answer on all three files A edits.
- `staleclaims` greps the concept, not `10 in-flight|10 memos`, which missed
MEMORY.md's Japanese `10 memo`; and its sha check no longer `head -20`s 571
repo-wide results past the three shas §13 acts on.
- `bmemo` covers all 11 classes §13 names, not 7, and the two blocks whose grep
returned something other than their own label are replaced.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ven roots
R8 = 0 CRIT / 30 IMP / 21 MIN / 5 FP across five axes. Three memo-internal
roots plus one that was not memo-internal at all.
ROOT 1 — the harness's coverage of its own claims was never checked (11 IMPs).
Handled in the preceding commit; the memo now cites totals it does not carry.
The sharpest consequence lands here: item 8 ("K and the spec list cannot
disagree") is measurably FALSE once item 7b partitions the unmapped bucket —
`unique specs (K): 1 (-)`. A routes label-less rows into the display.
ROOT 2 — three discipline questions answered by re-labelling.
- §11 registers `#11-webref-preflight-inprocess-resolution` as A's ONE own
deferral. origin/main's preflight.py has no `_webref` import, so the
in-process reach is A-created; "pre-existing" was false and "zero own
deferrals" was reached by conversion, not discharge. Cap is <=3.
- §10-Q2 / §11 no longer contradict each other, and neither `cleanup-*` id is
described as recorded — measured, neither exists in any ledger. §13 item 7
registers both.
- §9 drops the "the harness is evidence FOR the conjunct" argument rather than
repairing it: bounded is not narrow, and the coverage figure it rested on was
hand-counted and wrong. The base case is now claimed as a judgement with its
weakest point named, and A no longer self-ratifies its own umbrella Scope
cell — the amendment becomes a step that PRECEDES A's plan-review.
- §12(4) gives the harness a lifecycle: `_proto` is deleted by the
implementation PR, and the author-local blocks are marked and excluded.
ROOT 3 — §4.0 partitioned spec_labels.py / DESIGN.md by code branch while §7
and §12(3) make claims about their prose. Measured, §12(3)'s 4th check could
not pass: A's half carries `.claude/skills/.../preflight.py` at spec_labels.py:7
inside a docstring assigned to A with no rewrite instructed. §4.0 gains prose
rows; DESIGN.md's A text is stated verbatim because "minus its catalog
sentence" is not separable (the clause shares a sentence with one that is FALSE
under A); §12(3) reads a path-only delta.
NOT MEMO-INTERNAL — a live CI-topology collision. The Layout lane's unpushed
`layout-trip-wire-ci` ships an ungated trip-wire job whose in-file rationale
refutes A's allowlist filter directly, and rewrites the mise key A extends.
§4.3.2 ADOPTS the ungated shape: the filter is the very "someone must remember"
failure §1 is about, the toolchain cost argument does not apply to the Python
suites, and one-issue-one-way forbids two answers. Entirely inside A — no file
of that branch is touched. §12(5) restated so it does not depend on landing
order.
Also: §0's partition clause split into the narrow claim (true) and the general
one (measured FALSE — 5 of 8 same-series, all forkOf None, so a same-series
level collision DOES resolve to a different document; B's own memo carries the
sound version); §0.5 fixes a self-refuting fixture attribution and tables all
four label-§ pairs incl. the load-bearing `Fetch §2.2.5`; the fabricated title
`CSSOM VIEW §4.2 Foo` corrected; items 7/7c re-keyed onto map_missing; §4.1
routes the Flags bullet and states SKILL.md's coverage as grep-classes; §13
corrects the four-site claim to two and adds the two missing checklist items.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…scharges round 9 found in prose only Nine plan-review rounds on one Slice-A memo, and round 9 came back WORSE than round 8: 3 CRIT / 33 IMP vs 0 CRIT / 30 IMP. Four consecutive rounds produced one root at ascending levels — executable-described-in-prose (R6), the fix inverting the predicate (R7), the harness not covering its own claims (R8), the discharge written in the memo but not executed in the artifact (R9). A loop whose severity rises is not approaching real-gap exhaustion. UMBRELLA (user-approved). Slice A splits three ways, on the seam round 9's findings actually fall along: every Axis 1 finding is in the map extraction, every Axis 2 finding — including both CRITs — is in the gate's failure semantics. Those two shared a memo because one ENABLES the other, which is an ordering relation, not a cohesion one. A-i the shared spec-label map (pinned-only). Pure refactor. A-ii the gate's failure semantics. Stacked on A-i. A-iii the suite scheduler, ungated. Stacked on A-ii. An earlier candidate seam (J1-J3 vs J4/J5) was tested and rejected for the wrong reason: it measured where findings landed, not whether the slices separate. Also corrected in the umbrella, all re-derived rather than read: - the cross-lane worktree list named `elidex-wt-c4fix`, which does not exist, and omitted two that do. It is now derived, not listed. - "10 in-flight memos in elidex-wt-c3-plan" — measured, 1. - "wiring the suites into CI takes a LIVE-NETWORK dependency" was itself wrong: measured 0 urlopen across the origin/main suites. The figure came from a branch-measured run, and the fetching thing — the catalog fall-through — is Slice B's. B owns the offline contract, as a constraint. - CI topology is now a two-lane decision: PR #496 lands an ungated trip-wire job, A-iii adopts that shape rather than adding a competing filter. - new constraint: a check must derive its own COVERAGE, not only its values. HARNESS. Round 9 found four discharges that existed only as prose in the memo while the artifact carried the old behaviour. All four now execute: - `lanes`/`staleclaims` are genuinely excluded from `all` and named as author-local; the memo claimed this in two places and it was false. - `_proto`'s header said "nothing here is shipped" — the claim the memo had already retracted. It now states the deletion obligation. - `marker` claimed three recognition properties and implemented one. It now implements line-anchored AND fence-aware AND §3-scoped, and prints what a bare grep would have over-reported. - `citations` tabled four pairs and derived two — and the two it skipped were the two draft 9 had just changed, one of them a title corrected FROM a fabrication. It now derives all four and enumerates the fixture bodies, so a new pair cannot be added without showing up. - `regions` grepped `SPECS is a fallback`, which matches 0 lines; the docstring A/B seam two §4.0 rows depend on was invisible. Fixed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
First of the three memos the 2026-08-01 re-slice calls for. A-i is the pure refactor half: collapse the three hand-maintained label enumerations onto one pinned-map-only `spec_labels.py`, and move the prose that describes them. It is 394 lines against the merged memo's 1196, and it carries none of the gate-semantics content — which is the point. Round 9's findings separated by axis almost perfectly, and every Axis 1 finding is here. Three things this memo does that the merged one could not: - §0.5/§3 cite only labels A-i's OWN resolver maps. The merged memo's §3 carried `CSSOM View §4.2`, which resolves only via the branch's catalog — machinery this program routes to Slice B — so its coverage map was certified by something its own slice removes and would have soft-warned against itself after landing. New rule, stated: a slice's §3 may only cite labels that slice's own resolver maps. - §4.2/§4.2.1 partition by NAMED ARTIFACT, not by file and not by code branch. That is round 9's Axis 1 root: an edit set that assigns files cannot be verified by a check that reads file assignments. So the `--help` epilog line advertising `webref cite-audit` (shipped user-facing text for a subcommand absent at A-i's head), the second load-time consumer list, both function docstrings, the alias rationale, and all four copy-count sites each get an instruction. - §12(2)/(3) are greps over prose occurrences, and K2 is a DELTA because `origin/main`'s generic core already carries one elidex file path. Writing §12(2) then running it immediately falsified its own claim: I widened the pattern to `cite.?audit|webref_data|_catalog` and asserted origin/main had zero hits. Measured, `cite.?audit` and `_catalog` are indeed 0, but `webref_data` has 8 — in css/dfn/element/heading/idl/specs/inventory/resolver, where it is a legitimate shared data source. Three tokens, three scopes, now stated as three commands with their baselines. Gate: preflight EXIT 0, K=2 (fetch, html), 2 citations verified, 0 hard / 0 soft grep-pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Completes the 2026-08-01 re-slice. 1196 lines become 404 + 561 + 307, and the
merged memo is deleted rather than kept — keeping it would be a second
statement of every decision the three now own, which is the duplication this
program exists to remove. Each carved memo's §14 carries its provenance; the
nine-round history lives in the program's memory file.
A-ii — the gate's failure semantics. The densest of the three, and it opens
with round 9's two CRITs stated as OPEN DEFECTS rather than as history, since
both survive into it:
- item 6: the basis qualifier reads the un-partitioned `unmapped_rows`, so a
memo whose only row is label-less prints "1 of 1 counted by label
spelling". A-ii's rule: the basis names the classes it counted, and is
emitted only when the mapper ran.
- item 8: `K` counts `unique_specs` keys added inside the row loop that item
7c declares never ran, so every map-absent state prints `K: 1 (…) (-)` —
K=1 against an empty list, the exact disagreement the merged memo's item 8
called impossible. A-ii's rule: when `map_missing`, K is `n/a (label map
unavailable)`. And the instrumentation must reach the branch where the
claim can be false — the merged version's `PROTO-DISPLAY` sat inside the
mapper-ran branch and was structurally blind to all seven failing states.
A-ii also adds J1b to §2 (J1 at the reporting layer) as an invariant in its own
right, because the merged memo satisfied J1 and violated its reporting
consequence in seven measured states, and §2 now states each PAIR's
intersection rather than two aggregate sentences.
A-iii — the suite scheduler. Two decisions the merged memo got wrong:
- ungated, no path filter. The Layout lane's PR #496 argues in-file that
gating `.claude/tools/**` makes the tamper path of an allowlist gate itself
an allowlist entry. A-iii adopts that shape; the change is entirely inside
A-iii and touches no file of that branch.
- `scripts/`, not `.claude/tools/`. Measured, origin/main already sites
CI-invoked DRIVERS in `scripts/` (ci-sweep.sh, doc-changed.sh) while
`.claude/tools/*.sh` holds the trip-WIRES; the merged memo's siting ground
conflated the two.
A-iii declares **no spec surface** and therefore preflight-fails today by
design — it is the first real consumer of A-ii's §4.2.5, and demonstrates the
feature by needing it. Under the merged shape it would have had to invent two
citations and then receive `citation verify: ok` as its headline, which is §1's
own failure mode in the memo whose subject is a gate.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A-i's round 1 came back 1 CRIT / 28 IMP / 18 MIN, and Axis 2 named the root as
"a read whose write-path A-i changes, without reconciling the other readers of
that state". That is the same root as R7, R8 and R9. Four rounds, one cause,
and it was never a command — it was an intention.
`rederive readers <symbol> [ref]` is that census. It ranges over a ref
(defaulting to origin/main, the baseline the memos declare — run at HEAD it
reports zero readers of a symbol the branch already deleted, which is the
reassuring and useless answer), and it separates CODE readers from PROSE
readers, because every edit set that failed did so by assigning code and
leaving prose, or by assigning one prose site out of three.
Writing it took four corrections, each of which is the same class of defect it
exists to catch:
- the dispatcher `"${1:-all}"` swallowed every argument, so the symbol could
never arrive;
- `\b` is not supported by git grep's ERE, so the census silently matched
NOTHING and printed a clean bill of health;
- it defaulted to HEAD, where the interesting symbols are already gone;
- the docstring walker read the worktree instead of the ref.
First real run, `readers SPEC_LABEL_REVERSE @ origin/main`, found what five
review axes did not: besides preflight's 7 sites, the symbol is named in FIVE
other plan-memos, one of which registers `#11-preflight-css-module-labels` —
a defer slot whose subject is the very map A-i deletes.
Also fixed, both being this memo's own verification machinery failing:
- `budget` wc -l'd the merged memo deleted in the same commit that carries
A-i, so §8's sole cited derivation errored. It now lists all six slice
memos plus the harness.
- `couplings`' AHALF was a hardcoded 4-file inclusion list, so it could not
see `test_spec_labels.py` — the generic-tree file A-i CREATES. It is now
derived as the generic tree minus B's files (31 files).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…a false pointer I wrote, record the hard import A-i round 1 = 1 CRIT / 28 IMP. This applies the three Fix decisions whose concrete action is outside the A-i memo. R4 — the "a slice may only cite labels its own resolver maps" rule existed at two sites, both delete-on-completion slice memos. It moves to the umbrella, which A-i lands and which is the approval boundary, and its scope widens from §3 to EVERY citation surface: the defect it came from appeared at two, and A-i own §0.5 was outside a §3-only reading. R5 — the umbrella claimed the nine-round history lives in the program memory file. Measured, that file stopped at round 7 and mentioned neither round 8, round 9, nor the split. I wrote that pointer without checking it, one constraint below the one that forbids exactly that. Corrected, and the memory file and MEMORY.md are brought current in the same change rather than at landing, which is what the umbrella already required. R1 — the Scope cell now records that A-i lands the import HARD. Draft 1 kept the carve except-guard, which would have put a fail-open plan-review gate on main for the duration of A-ii, the state the same table calls disqualifying for Slice B. The cell also now covers A-i two invariant axes, not one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…oot needed Round 1 = 1 CRIT / 28 IMP / 18 MIN, resolved into seven Step-3.5 roots. This applies the four whose action is inside the A-i memo. R1 (CRIT + 4 IMP, one fix) — A-i lands the import HARD, no `except`. Draft 1 said "A-i changes no failure semantics" and kept the carve's guard; measured, origin/main's `shortname_from_label` reads a module-local dict and is TOTAL, so A-i is precisely what makes it failable — and the guard routes that process failure into the per-row unmapped bucket, i.e. every row soft-warned, nothing verified, exit 0. That would have put a fail-open plan-review gate on main for the whole duration of A-ii, the state the umbrella calls disqualifying for B. A hard import dies loudly instead, so the window does not exist and A-i opens no deferral for one. The agent proposals were all "manage the window"; the polish-domination smell fired and the root option was "remove it". Same fix's other half: the preflight assertion STAYS in A-i. Draft 1 sent it to A-ii, so nothing asserted the preflight consumer resolved at all between the slices — on the very read A-i makes failable. The deleted test's own docstring says why that matters: "preflight is the copy that empirically drifted, and no test imported it at all." R2 (12 IMP, one fix) — §4.2's rows are now DERIVED. Before writing a row for a piece of state, run `rederive readers <symbol> [ref]` and assign every line it prints. The census for the three symbols A-i removes is in the memo, and it surfaces two sites draft 1 shipped: preflight's stdout summary and stderr remedy both name `SPEC_LABEL_REVERSE`, so after A-i the gate tells a developer to extend a symbol that no longer exists — instructing exactly the hand-added local copy K1 abolishes. Draft 1 routed "the remedy strings" to A-ii. They are A-i's: they read state A-i deletes. The census also found the open slot `#11-preflight-css-module-labels`, whose subject is that map. R6 — §2 gains the pairwise table; draft 1 asserted a non-intersection while §4.4 four paragraphs later enumerated five. R7 — K2 becomes an absolute. A-i discharges cli.py's pre-existing elidex path rather than parking it at C, which has no cli.py mandate. That removes the set-difference apparatus from §2, §7, §12(3) and S8. Also: the `Fetch §2.2.5` row's stated reason was false (it is the canonical label, resolving identically at baseline; `Fetch`/`fetch` are what newly resolve), §5 row 3 filed five deleted aliases in the wrong class, §5 gains row 7 for the tools-tree-absent case, K4 is scoped to label resolution rather than left false, S3b pins the third consumer nothing ever covered, S9 pins the dangling-symbol class, and "10 tests" was 9. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…nd on Round 1, Axis 2 MIN: the block cited as the derivation for §4.2 region table grepped for docstring braces and definitions, and printed NEITHER the alias rationale comment nor the in-comprehension comment — the two regions the alias-deletion rows turn on. Widened to those plus the tuple shape line and its variadic annotation, which are the other two readers of the alias mechanism the census flagged as unassigned. Also fixes the header, which still cited §4.0 — a section of the deleted merged memo. A-i has no §4.0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… a record A-i round 2 returned 1 CRIT / 38 IMP — worse than round 1's 1 / 28. Of the 38, exactly ONE was a defect in the change; the rest were defects in its description. Both changes below are user-approved. SCOPE — A-i no longer touches `preflight.py`. Drafts 1 and 2 both migrated the gate's copy and both regressed the gate, in opposite directions. Measured on origin/main with the tools tree absent: default mode : exit 1 --no-verify: exit 0, correct guarded import : exit 0 (!) --no-verify: exit 0 hard import : traceback --no-verify: traceback (!) origin/main is not fail-open in either mode — my draft-1 premise was wrong, and draft 2's hard import fixed one cell by breaking the other, which is also A-ii's J3 and A-ii's P2b mutant. Preserving both cells requires a capability check at the verification stage suppressed by --no-verify, i.e. A-ii's act-site 1. The gate's copy is not separable from the gate's failure semantics, so it moves to A-ii and lands with them. A-i is now entirely inside the generic tree: two of the three copies, no adapter file, no gate semantics. K1 completes across the pair. FORM — the memo is a record, not a specification, per the umbrella's new "review cost tracks blast radius" constraint. 462 -> 297 lines. The delta table restating what a diff shows is gone; §12's checks are four greps; K2 is stated once as an absolute rather than at six sites in two forms. A-i does not trip CLAUDE.md's edge-dense trigger on its own terms (one invariant, canonical algorithm, zero crates/**) — the MERGED Slice A did, and A-i inherited its apparatus without earning it. Also fixed, all measured: the "five other plan-memos" census digit is four (a branch-era figure inside an origin/main-headed table); the copy-count enumeration named a site carrying no count and omitted two that do — it is five sites; the `Fetch` row's retracted justification survived at its sibling in §3; §15 omitted `readers`, the block §4.1's whole table derives from. And the umbrella's recovery pointer for the deleted 1196-line memo named `ee2d0dc0`, which THIS SESSION's rebase destroyed. The content is intact at `707b69cc^` (verified, §14 index included). A SHA pointer in a branch that rebases has a half-life; `<commit-that-deleted-it>^` survives rewriting. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
901 lines, ~29 blocks, four slices, routed to none — and the umbrella records that whichever slice next touches it splits it first. That slice is A-i, so this is A-i's prereq (CLAUDE.md "1000-line debt = touch-time split"; the authoring band is 700-800 lines). The seam is slice OWNERSHIP, measured rather than guessed: each memo's §15 block list plus `grep -nE 'rederive [a-z ]*<block>'`. Blocks cited by more than one memo (`citations`, `couplings`, `budget`, `lanes`) and the plumbing (`$MAIN`, `say`, `$AUTHOR_LOCAL`, the §6 fixture bodies, and `_proto`, which `budget` and `armmatrix` both call) go to `-common.sh`; blocks cited by exactly one memo go to that slice's file. The five uncited blocks are routed by the quantity they derive, not by guess: `partition` and `offline` to B (B §4.1.2/§4.1.8 embed exactly those two scripts inline — these blocks are their executable twin), `anchors` and `timing` to A-ii (its 7 preflight symbols measure 26 hits in A-ii vs 1 in A-i; `timing` measures the §4.2.1 CLI-subprocess axis), `bmemo` and `staleclaims` to B (they derive the classes of edit B's memo needs). The shape is a thin dispatcher because the invocation surface is fixed: six memos cite block names by the path `…-A-rederive.sh`, so `bash …-A-rederive.sh <block>` and `… all` must keep resolving every name. The dispatcher sources all five parts before dispatching, so ownership decides only where a block LIVES, never how it is called. 55 …-A-rederive.sh (dispatcher) 422 …-common.sh 85 …-Ai.sh 272 …-Aii.sh 37 …-Aiii.sh 103 …-B.sh Verified behaviourally, not by inspection: every block captured before and after the split (each block by name, `readers` in three argument shapes, and `all`), then diffed. The two non-deterministic blocks were identified FIRST, by capturing the unsplit file twice — `suites` (test elapsed seconds) and `timing` (perf ratio) — so their differences are not attributed to the split. Besides those, the only pre/post differences are `staleclaims`, whose docs/plans/ grep reports the harness's own moved file:line (self-reference), and `budget`, changed on purpose: one line-count is no longer a statement about a six-file harness, so it now prints every part and the total. Every exit code identical. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The block's terminal check was a DELTA — `comm -13 <(base) <(head)`,
"ADDED BY A must be empty" — with an in-block comment arguing that "must
be 0" would be the wrong criterion because `cli.py` already carries one
elidex path on origin/main and discharging it is not A's scope. That
decision is superseded: A-i's K2 was changed to an ABSOLUTE at round 1,
because A-i already edits `cli.py` and Slice C, the earlier routing
target, has no `cli.py` mandate. §2, §6 pin S8 and §12(3) of
`…-Ai-spec-label-map.md` all state the absolute, and §12(3) names this
block as its check — so the block was implementing a criterion its own
memo had retracted. The comment is replaced by a one-line record of the
supersession; the gate is now the plain grep §7 says it is, over the
whole generic tree, with the A-half count kept as attribution only.
Also writes down the predicate, which was implicit in the regex and
stated nowhere else: `.claude/(skills|tools)/<seg>/<seg>` requires TWO
segments, so `.claude/tools/webref` — the tool's own invocation path, 22
occurrences in `cli.py` on origin/main — never matches. Measured on a
scratch worktree: 35 occurrences of that path present, 0 matched. The
exclusion is correct (an install path is not a path into elidex's tree)
but a reader could not have known it was deliberate.
Verified by deliberately failing it, in a throwaway worktree of HEAD so
no `.claude/` file was touched:
- at HEAD unmodified the absolute reports 2 — `cli.py:77` (the
pre-existing one, which the delta version did NOT report) and
`spec_labels.py:7` — VERDICT: RED.
- with a constructed elidex path appended to `resolver.py`, 3, RED, and
the constructed path is listed; the superseded delta version run
verbatim on the same state reported only the 2 additions and stayed
silent about `cli.py`.
- rewriting all three by role takes it to 0, VERDICT: GREEN.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The block says it "prints CODE readers and PROSE readers separately,
because the edit sets that failed did so by assigning code and leaving
prose". Measured, it did not: the code pass was
`git grep -nwE "$sym" "$ref" -- .claude | grep -vE ':[0-9]+: *#'` and
the prose pass was `git grep -nwE "$sym" "$ref" -- .claude docs`, the
UNFILTERED SUPERSET. For any symbol without a leading-`#` comment reader
the two sections printed byte-identical output —
`readers SHORTNAME_TO_LABEL HEAD` printed the same 5 lines twice. It only
looked separable for `SPEC_LABEL_REVERSE`, which happens to have exactly
one comment reader. The block that exists to catch "a write-path changed
and its other readers were not reconciled" was not computing the
distinction the reconciliation needs.
Now one census, partitioned: prose is the genuine complement of code.
Classification is syntactic — a markdown/prose file is prose, a
`#`/`//` comment line is prose, a line inside a docstring is prose, and
the docstring ranges come from the AST section that already existed and
only reported beside the partition; it now decides it, so a docstring hit
lands in prose and never in code. The `docs/` widening the prose pass
needs is kept, and each prose line carries the reason it is prose.
Adds the trip-wire the block needed and lacked: an empty census, or code
and prose coming out identical, now prints `!! ` lines and exits 1. A
block that silently reports nothing issues a clean bill of health it did
not earn — the failure mode that let four review rounds through.
Verified by deliberately failing it:
- code-only (`SHORTNAME_TO_LABEL` @ HEAD): 5 code / 0 prose, rc 0.
- prose-only (`MAX_LABEL_WORDS` @ HEAD): 0 code / 3 prose, rc 0.
- both, with docstrings (`shortname_for` @ HEAD): 12 code / 27 prose,
the two `[docstring]` lines in prose and named by the AST section;
(`SPEC_LABEL_REVERSE` @ origin/main): 6 code / 7 prose.
- nonexistent symbol: the loud-empty path fires, rc 1.
- the superseded superset rule restored in a throwaway worktree: the
identical-sections trip-wire fires on `SHORTNAME_TO_LABEL`, rc 1 —
i.e. it catches exactly the defect that shipped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Round 3 returned 3 CRIT / 8 IMP / 7 MIN. The three CRITs share one root: the memo never said which tree its edit set is relative to, so it was written against `origin/main` and against this branch at once. Measured: `git ls-tree origin/main -- .claude/tools/_webref/spec_labels.py` is empty and `git show origin/main:.claude/tools/_webref/cli.py | grep -c cite-audit` is 0, so §0.1's "creates" was origin/main-relative while §4.2's deletion rows and its five-site copy-count were branch-relative — contradicting §3.1's own rule. §4 now opens with the decision: A-i is authored from `origin/main`, and `b3a7d469` — measured to be the sole `.claude/` commit on this branch — is dropped from A-i's lineage, B and A-ii re-introducing their own halves. The recovery pointer is recorded as content-plus-location (branch `domform-submittable-category` carries a byte-identical `_webref` tree) rather than a bare SHA, per §14's lesson. Branch-revert rows are gone; the copy-count becomes five statements A-i *authors*. Also measured and corrected: the gate subprocesses `.claude/tools/webref` on every citation it verifies, so §5's "no gate behaviour, because it touches no gate file" was a non-sequitur with a false premise — rewritten as reachability citing S3b and T-net, with the `@lru_cache` on `try_fetch_data` routed to B rather than dropped. `preflight.py:48`'s dangling "keep in sync" comment is taken by A-i (A-ii's memo has no hits for it). §8's harness claim was false — A-i grew it 840 -> 901 in two post-carve commits — and the split is now discharged in three prereq commits, which makes §11's zero-own-deferrals true. K2's predicate, K3's module count, §9-vs-§2's invariant senses, §12's refless diff checks, and §13's slot/PR/frozen-literal claims are all re-measured. preflight: EXIT 0, K=2, 0 hard / 0 soft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four review rounds turned the ⚠ convention into a ratchet: each round's fix added a note narrating what an earlier draft got wrong, until the retrospective ledger was the memo's largest re-review surface. Every "Drafts 1-3 said X" is a claim about deleted text a reviewer cannot verify from the file in front of them, and the same correction history was stated at three sites — this memo, the commit bodies, and memory/project_citation-hygiene-program.md. Per one-issue-one-way and the umbrella's review-cost-tracks-blast-radius constraint, it collapses to one canonical site: the commit messages, which carry it in full. Rule applied: a ⚠ note stays iff it constrains a FUTURE action — what A-ii / A-iii / B / C or the implementer must do, a standing authoring rule, or a caveat about the current state of something outside this memo. Everything else goes. Where a retrospective clause trailed a live paragraph, only the clause was deleted; where a measurement was stated only inside a deleted sentence, the measurement was kept and re-stated in the present tense (webref_data's 8 files / 6 command modules, the 22 install-path occurrences, the origin/main base measurements, verify_citation's subprocess, #496's file list). Dangling connectives — "Simpler:", "What holds instead", "The real basis is" — repaired to plain present-tense statements. No decision, measurement, pin, invariant, exit criterion, coordination row or hand-off was altered; draft 4's eighteen fixes all stand. 394 -> 367 lines, 24 -> 10 ⚠ notes. preflight: EXIT 0, K=2, 0 hard / 0 soft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The CRIT is not a defect the lineage decision created; it is a recorded debt the decision surfaced. §4 dropped `b3a7d469` from A-i's lineage and justified it with "Nothing is lost; Slice B and A-ii each re-introduce their own half from their own memos." Measured, that is false for B: its memo is written as repairs to a tree that exists at its base, and that tree is `b3a7d469`'s. `cite_audit.py` and `spec_labels.py` are absent from `origin/main` (`git cat-file -e` fails for both), yet B carries 17 line-anchored edits into them, baselines their sizes at 289 and 410, and says at :11/:13/:18-21 that it rebases onto a landed Slice A. A-ii has the same problem at :148, :174 and :504-505, all premised on A-i moving the map — which §12(1) now forbids. The program memo already records the cause verbatim: B's re-slice edits were delegated once, the agent died on an account spend limit, and B's memo is untouched. So A-i stops claiming the reconciliation is done and states it as owed, with §13.1 naming the sites; it does not re-derive B's 696 lines or A-ii's 578, which is the decision-surface duplication this program exists to remove. The debt is also independent of §4: K3 forbids `cite_audit.py` at A-i's head under any lineage route. What measurement forced the rest: - K2's check missed a byte-identical twin. Over `.claude/tools/`, not `.claude/tools/_webref/`, the path regex prints two lines — `cli.py:78` and `.claude/tools/webref:5`, the entry point, same string. K2 widens to `.claude/tools/` and takes both; the harness filter is now narrower than the invariant, recorded as an owed edit rather than made here. - The Web IDL hand-off named a spelling that occurs 0 times. `WHATWG Web IDL` → 0 files, `WHATWG WebIDL` → 5. The `Web ?IDL` regex matched both, so the count was right and the string was wrong; a remedy keyed to the spaced form would close none of the five. - `@lru_cache`'s routing cited B :618, which reasons from the decorator being already present, and B :637, which files the consequence as pre-existing — both invert at the new base. Restated as "B adds it", with the payoff from the decorator's own docstring. - Three of §13's four hand-offs have no receiving site (`web ?idl` → 0 in A-ii, `frozen|refresh|S3b` → 0 in A-ii, `lru_cache` → 0 in the umbrella). Restated as owed, not owned. - `b3a7d469`'s third `coverage_map.py` hunk is a behaviour fix, not a move: it took `_spec_label`'s last resort out of `.upper()` and into `label_for() or shortname` to restore round-trip. A-i reverts it (K4), so it is named and given to Slice B rather than vanishing. - §11's "nothing is owed at landing" contradicted §13; scoped to defer slots, which is what it is about. - The umbrella is falsified at six points (the discharged harness split still open at :112, and four A-i-row statements that assume artifacts absent on `origin/main`, plus the blast-radius bullet's premise). §9 forbids amending it mid-review, so landing enumerates them. - §9's design/edit-hygiene partition is not in CLAUDE.md's text and is falsified inside the memo (K4 has five pins and a measured delta; K2 is a layering invariant from DESIGN.md). Restated on the real grounds: the trigger fires, and the prescribed remedy — umbrella + per-slice split, each plan-reviewed — has been applied twice, which is the base case. - Recovery pointer widened to name `preflight.py`, the eighth file. Widening to `-- .claude/` instead does NOT work: six unrelated files. - MINs: §12(1)'s live 89-line reading restored; the #496 filter stated (8 paths, 2 in scope); DESIGN.md's cite-audit paragraph assigned to B; the `preflight.py` exception stated as the comment (:47-49 in :47-50); "four plan-memo readers" resolved to four files / six lines plus :342; a `label_for`/`shortname_for` row added; `readers`' absence from both `all` and AUTHOR_LOCAL declared; §5's "observable" reworded; §12(2)'s webref_data count given its ref (8 at origin/main, 10 at HEAD); the `suites` misplacement recorded as a second owed harness edit. Gate: preflight EXIT 0, 0 hard / 0 soft. 475 lines, 21 ⚠. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Slice A-i of the 2026-07 citation-hygiene program. `origin/main` carried
one spec-label enumeration three times -- `coverage_map._SPEC_LABEL_MAP`,
`cli.COMMON_SHORTNAMES`, and the plan-review gate's `SPEC_LABEL_REVERSE`.
This collapses the two in the generic tree onto a new `spec_labels.py`,
pinned map only. The gate's copy is untouched: it is not separable from
the gate's failure semantics, so it migrates in A-ii and K1 completes
there.
Lineage: authored from `origin/main`, not from this branch's head.
`b3a7d469` (the cite-audit carve) is dropped from it -- the detector, the
catalog fall-through, `coverage_map`'s round-trip change and
`webref_data.py`'s `@lru_cache` are Slice B's, and the gate's
`spec_labels` import is A-ii's. The content is recoverable: branch
`domform-submittable-category` carries a byte-identical copy.
`_spec_label`'s last resort `shortname.upper().replace("-", " ")` is kept
verbatim. A-i is a pure refactor; replacing it is a behaviour change
whose correctness runs through the fall-through Slice B owns.
`.claude/skills/elidex-review/axes.md.` is rewritten by role at both of
its sites under `.claude/tools/` -- `_webref/cli.py` and the `webref`
entry point -- so the generic core names no elidex file path. The single
adapter-file touch is the gate comment naming a symbol this slice
deletes.
14 new tests pin S1-S8 and T-net: the derived help blurb is byte-identical
to the literal it replaces, and the label map is byte-identical with the 8
parse aliases omitted.
Plan: docs/plans/2026-07-citation-hygiene-Ai-spec-label-map.md
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 669f692e03
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…fail is not a control
Two findings on `669f692e`, both in the harness rather than the scanner.
**1. The routed control's environment was word-split.** `env ${8:-}` splits on
whitespace, so a `TMPDIR` holding a space broke it with
`env: 'dir/.../.git': No such file or directory` and the whole gate exited 1 for
a contributor whose temp path has a space. Passed as an ARRAY now
(`${_ctl_env[@]+"${_ctl_env[@]}"}`, which is also `set -u`-safe when empty).
⚠ Not reproducible on macOS — `/usr/bin/mktemp` ignores `TMPDIR` without a
template — so the mechanism was measured in isolation instead: the string form
gives exactly the reported error and rc 127, the array form passes both values
through intact.
**2. Two fixtures passed their controls in their FALLBACK state.** Both are
built with `|| true`, and for these two the state left behind when construction
fails still satisfies the control's own assertion — so a failed `git replace`
(or a failed `info/exclude` write) left the control green while testing nothing,
and the mutation it exists to catch would have survived it.
I swept the other seven fixtures rather than fixing only the reported one: every
other falls back to a state its control REJECTS (a missing `mkfifo` leaves a
regular file, a failed `git add` leaves the path untracked, an empty fixture
trips the zero-read guard). These two were the exceptions, and each now asserts
the precondition that makes it meaningful, reporting CONTROL NOT EXERCISED
rather than passing.
⚠ The first precondition I wrote for the replace fixture was itself vacuous —
it read the blob, and this run exports `GIT_NO_REPLACE_OBJECTS=1`, so it would
have returned the violating bytes whether or not the replacement took. It fired
on a correctly-built fixture, which is how I found it; it asks `replace -l` now.
Both preconditions verified by breaking the construction they guard.
Verified: `scripts/trip-wires.sh` exit 0, wire clean → 0, 102 reads.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA
… its seam, and stop the memo restating it
Codex flagged an exit criterion in §8 reading green while the wire stood at 994
lines and this memo at 959. The criterion was wrong, and so was the thing it
failed to catch.
**The wire is split, in its own commit**, per CLAUDE.md's touch-time discipline
("split は単独 PR / 単独 commit", and don't defer it). The seam was visible well
before the line count: the wire ANSWERS about a tree; everything now in
`webref-generic-core-trip-wire.controls.sh` exists to prove it can reach every
answer it claims. 1027 → 630 + 431.
⚠ A missing controls file is not a skipped self-test: sourcing it is the only
way this wire earns the word PASSED, so its absence ends the run at exit 2,
"decided nothing" (verified: removing the file takes the wire and the driver to
2, restoring it to 0). The driver's glob is `*-trip-wire.sh`, so the controls
file is not discovered as a wire and the retention check does not drift.
**The criterion said "no file is *near*" the threshold** — a judgement word
doing quantitative work with a band nobody defined, which is how it read green
at 994. It is keyed on CLAUDE.md's fixed 1000 now, which does not move with a
commit; "near" did.
**And the memo stopped restating the wire.** §12(3) carried a ⚠ block per review
round — population, content sources, stored-path predicate, locale, matcher
statuses, threat model, one per defect the loop found — every one of them a
duplicate of the wire's own canonical account, which R93 made the single site
for exactly this reason. That duplicate was the growth mechanism: tens of lines
a round describing something one file away. 120 lines → 21, and the four sites
pointing into the removed text now point at the wire. Two limits stay, because
they are not the wire's to state: the permission controls cannot run as root,
and the byte-locale fixture is environment-sensitive.
Memo 959 → 865. Verified: 13 tests OK, `scripts/trip-wires.sh` exit 0, A-i
preflight exit 0 (0 hard / 1 soft, unchanged), 102 reads, clean → 0.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b3de0421d1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…is not routing-only One finding on `b3de0421`, and it is R94's defect reaching the same place by another route — worth stating plainly, because the comment I wrote one round earlier asserted the opposite. `git rev-parse --local-env-vars` also names `GIT_CONFIG`, `GIT_CONFIG_PARAMETERS` and `GIT_CONFIG_COUNT`, which are CONFIGURATION inputs, not repository routing. So unsetting the list wholesale stripped the caller's configuration: a foreign-owned checkout authorised through `GIT_CONFIG_COUNT=1` / `GIT_CONFIG_KEY_0=safe.directory` / `GIT_CONFIG_VALUE_0=*` works under a direct `git -C <repo> ls-files` and exited 2 here, after reading nothing. ⚠ I had that list in front of me when I wrote "routing only" — the R95 verification printed it in full, `GIT_CONFIG*` included, and I read past it. The `GIT_CONFIG*` family is held back now, as a family rather than three named variables. ⚠ And the comment says why the exemption is that narrow, because the risk directions are not symmetric: clearing too much costs configuration and the wire then REFUSES to run — loud; clearing too little leaves git routed at another tree and the wire ANSWERS about it — silent and wrong. The default is to clear, and this is the one retreat, taken against a reproduced setup. Control `cfgkept`: a `git` shim that answers `ls-files` with nothing unless `GIT_CONFIG_COUNT` reached it, over a fixture holding a violation — so keeping the configuration reds on K2 and stripping it reads zero and exits 2, differing in status AND message. ⚠ Shimmed because the real case needs a checkout owned by another UID, which the harness cannot build; the variable's SURVIVAL is the property under test and that is constructible. The mutation that removes the exemption is caught. Verified: 13 tests OK, `scripts/trip-wires.sh` exit 0, A-i preflight exit 0 (0 hard / 1 soft, unchanged), 102 reads, clean → 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA
|
@codex review |
|
Codex Review: Didn't find any major issues. Keep them coming! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review |
|
Codex Review: Didn't find any major issues. 🎉 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
…stacked PR Design re-gate 5 (`/elidex-review`, 5 agents) returned 0 CRIT / 19 IMP / 15 MIN. Three axes reached the same root independently, and this commit is that root's fix: the K2 trip-wire does not belong in this slice. It entered A-i at review round 68 — **after** A-i's own plan-review — and grew into 1089 lines carrying its own `REQUIRED_WIRES` registration and edits to `.github/workflows/ci.yml` and `CLAUDE.md`. Measured at re-gate 5: 59 % of the repository's trip-wire corpus and ~83 % of the driver's runtime, for one fixed predicate over 34 files with 0 live hits, and **34 of this branch's 148 commits** spent stabilising it — while A-i's own thesis (K1/K4, the suite) is enforced by nothing until A-iii. CLAUDE.md makes `/elidex-plan-review` a rule rather than a judgment for work of that shape, and the base-case clause that lets an approved slice be a single PR covers what the plan-review approved; it does not reach an instrument added afterwards. So the wire, its controls, the registration and the two policy edits move to a stacked PR with its own plan-review. What this commit removes: - `.claude/tools/webref-generic-core-trip-wire.sh` + `…controls.sh` - the `REQUIRED_WIRES` line and the two comment corrections it made necessary - `.github/workflows/ci.yml` and `CLAUDE.md` back to `origin/main` ⚠ **K2's closed part is therefore NOT closed at this head, and §12(3) says so.** A-i discharges K2 the way it already discharges K2's open part — by diff review, finite and reviewed, but not a gate. That is a narrowing, not a discharge, and it is why the wire is stacked rather than deferred. The memos follow the carve rather than describing it from outside: - §0.1 returns to **one stated exception** (the `preflight.py` comment) and carries the record of why the other two left. Its own derivation command now returns exactly that one file — the shape the sentence was written for seven weeks before the wire arrived. - §4.2 drops the wire's artifact row; S8, §7, §8, §12(3), §13 and §15's gate table state the carve instead of restating the instrument. - §13's contention row is **withdrawn and re-derived**. It said a second lander "takes a textual merge, not a decision"; open PR #510 registers a wire that requires `python3` and raises the job's `timeout-minutes` from 2 to 10, while this wire's rationale rests on the set needing no toolchain. That is a design decision, and it belongs to the carved slice's plan-review. The row was a hand list; the derivation over every local branch returns a third branch, and it is the one with the open PR. - The umbrella gains slice **A-i-wire** and withdraws the same false sentence at its own site. Verified: 13 tests OK, `scripts/trip-wires.sh` exit 0 (back to four registered wires), A-i preflight exit 0 (0 hard / 1 soft, unchanged). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA
…th A-i The carve (previous commit) closed F1/F2/F3/F26/F34's root. These are the re-gate's remaining findings whose subject is A-i itself. **The divergence list undercounted, and its re-derivation recipe could not discriminate** (Axis 4). `spec_labels.py`'s ⚠ block said five rows diverge from upstream; the criterion it states — a label that is not the upstream `title` — is met by **seven**. `ecma262` and `ecma402` are shortnames this project coined (`sources/tc39.py`'s `TC39_FAMILY`) and are absent from the w3c/webref index as spec AND series, i.e. they meet the same test as `webcrypto` more strongly. Verified independently: `webref specs ecma262` prints nothing — and so does `webref specs zzznotaspec`, so the documented recipe returns the same answer whether the row is right, wrong or nonexistent. The block now names the predicate rather than a count, lists all seven, and routes the tc39 pair to `webref heading ecma262 1`, which does discriminate (`heading zzznotaspec 1` errors). This block is the only in-tree record of label correctness, so a row missing from it is a row nothing states anything about. **"Two modules inside the approximation do adapter work" was an enumeration** (Axis 1). Measured with a predicate instead: at least five — `agent_brief.py`, `cli.py`'s `--paths` default *and* its `# plan-memo §3 skeleton` example, `agent_policy.py`, `coverage_map.py`, `refresh.py:52`. An exemption list leaves every site outside it authoritative as "generic", which is what a maintainer reads off a green wire. The row now derives rather than counts, and the adjacent warning says plainly that those five are what the wire cannot see. **§0's gate tally was 119 commits and four re-gates stale** (Axis 5) and claimed its dispositions landed "in the same commit set as this revision". It now states no tally and names where the gate history is owned. **§12(2)'s K3 command still used `--exclude-standard`** — the flag #501 R92 measured as machine-dependent and replaced everywhere else. A memo that tells a maintainer to run a command should not hand them the one that was rejected. Also: `DESIGN.md`'s bullet said `spec_labels.py` replaced two copies of a *label map*; `cli.py`'s was shortname → blurb and 10 of 12 blurbs differ from the label, so the shared thing is the **enumeration** — and "single source in this package" now carries the caveat the module itself states (the suite holds two deliberate frozen pins; the adapter keeps its reverse map until A-ii). `shortname_for`'s empty-string guard is deleted (dead: `.get()` already answers `None`, the annotation forbids `None`, and it was the only one of six mutations that survived). The CLI description no longer reads as a closed list over half the tool. `coverage_map.py`'s declared defect now cites the slot that owns it (`#11-preflight-css-module-labels`) instead of naming a broken consumer with no route to where it is tracked. Verified: 13 tests OK, `scripts/trip-wires.sh` exit 0, A-i preflight exit 0 (0 hard / 1 soft, unchanged), `webref --help` renders. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA
|
@codex review |
…r had The wire entered #501 at review round 68, after that slice's `/elidex-plan-review` had closed, so nothing has ever reviewed it as a design. This memo is that review's subject. It is deliberately short and carries no figure that moves with a commit — every quantity is the command that derives it. Slice A-i is the reason: it wrote figures into its memo and spent four review rounds on figures its own later edits falsified. The program's ratified rule (a plan memo holds no measurements and no self-measuring apparatus) is applied here from the first draft rather than scoped to start at the next slice. §5 lists the six questions design re-gate 5 left for this slice, and they are deliberately NOT fixed in the carried implementation — fixing them before the review would repeat the mistake that produced this slice. §6 states the #510 contention as a decision this memo owes rather than a merge someone inherits. ⚠ §3 has no spec row, and says why: the predicate is over repository paths and its authorities are `DESIGN.md` and CLAUDE.md, not a web specification. The Step 0 preflight's citation arm is not the review that matters here, and §3 carries the command that derives how many landed plan memos are in the same position rather than asserting it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA
|
Codex Review: Didn't find any major issues. Hooray! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review |
|
Codex Review: Didn't find any major issues. Hooray! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
`/elidex-plan-review` on draft 1 returned 2 CRIT, 25 IMP, 19 MIN and 14 FP across five axes, on a 183-line memo. This revision is the disposition for every block whose lens converged; the one genuine fork is now §1.1 and is NOT decided here. **The CRIT, found independently by four of the five axes**: §1 said "Five files" and §7 made an exit criterion of it. The memo is itself a tracked file in the diff it counted, so the count was false when written and the criterion could never pass — the exact failure the memo's own opening ⚠ names, two sections below it. The boundary is a predicate now (nothing under `_webref/`), the artifact set is §4's table, and §4 lists this memo. **§1.1 is new and is the review's most consequential finding.** A third option nobody had considered: slice A-iii already plans an **ungated `tools` job with an interpreter floor**, and putting K2 there makes §6's contention *not arise* — the question "may the required, ungated wire set require an interpreter?" exists because this wire chose the `trip-wires` job. The fork (here / A-iii / withdraw the carve) is tabled with its costs and left open. **§0 now starts from the lane SSoT's own record.** It declined this carve once, on two grounds — the edge-dense trigger's "no canonical algorithm" limb was falsified by measurement, and carving separates A-i's invariant from its mechanism. The same block set the re-evaluation trigger that has since fired ~24 times, so the carve is what the SSoT scheduled; but the second ground was never answered and §1.1 is where it is answered or the carve is withdrawn. **And the proportionality argument was wrong in its internals.** "1089 lines" hid the split: the scanner's own code is smaller than the largest existing wire, and the disproportion — code, fixtures and runtime — is in the controls. §0 now derives the two halves separately and says to run it before arguing about size. §2 gains the coupled-invariant enumeration (six invariants, the intersections that matter) the edge-dense rule requires, and states the finding that the predicate **forbids what `DESIGN.md` permits**: that file's closing rule allows elidex policy in adapter *documentation*, and `DESIGN.md` is inside the scanned population — reproduced in review. §5's agenda is restated because four of its six items rested on false premises: three of the four blind spots are already disposed of by #501 §12(3); "three controls" was two; item 4's claim lives at four sites and this slice already answered half of it on a repo-wide surface while calling the question open; and item 5 offered an option CLAUDE.md names as the wrong basis. §6 records three claimants rather than two, the textual half of the #510 conflict, and that the carried commit already wrote one answer. §7's mutation criterion no longer points at a population that #501's squash merge erases, and no longer freezes the artifact set the review may need to change. Also clerical: `REQUIRED_WIRES` was sorted before this slice and the insertion broke it, while both concurrent branches insert alphabetically — restored. Verified: `scripts/trip-wires.sh` → 0, preflight → 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA
#501's tip `fed9876b` changes five files INSIDE K2's scanned scope (`_webref/DESIGN.md`, `cli.py`, `coverage_map.py`, `spec_labels.py` and the `webref` entry script), so this branch's wire was measuring against a base that had moved — found by the pre-push design review, which noted that §7's exit criterion resolves through the merge-base and would not have said so. Merged rather than rebased: the branch is already pushed as #519, and this repo forbids force-pushing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA
…s, a false CI rationale, and a mutation set The plan-review's §5 asked eight questions about this instrument. Six of them change it; this commit is that change, and the memo commit that follows records every answer with its measurement. **Two controls passed without testing what they name.** `cachedir` shared the fixture loop that runs `git add -A` BEFORE the fixture's `.gitignore` exists, so its probe was tracked already and the force-add it exists to exercise changed nothing — measured, deleting `_fgit add -f __pycache__/probe.txt` outright left the wire at exit 0. It is built outside that loop now, in the only order that makes the force-add load-bearing, with a precondition asserting the probe is ignored AND tracked (`check-ignore --no-index`, because with the index consulted an ignored path reads "not ignored" the moment it is tracked — the flag is off exactly in the state the control requires). And the `odd`/`fifotracked` pair each built its FIFO under `|| true`: on a filesystem without them, `odd` printed "every other control ran" in precisely the runs where `fifotracked` had just failed for the same missing capability, and `fifotracked` reported a WIRE defect for a MACHINE limit. One probe, one report line, built beside the decision. **A mutation set, machine-readable, in the controls file.** Every control proves a verdict is REACHABLE; none proved it is produced by the code it is about. The population used to be prose scattered across #501's review commits, which that PR's squash erases. 18 entries now ship beside the controls — `WEBREF_WIRE_MUTANTS=1 bash …trip-wire.sh` — each required to change the copy, red it, and red it naming its own control. It found three things: * its own probe had the wrong subject: `sed` writes mode 644 and `_control` invokes `"$SELF"` directly, so every mutant exited 126 for every control, satisfying "did the right control fire?" vacuously. All 18 "passed" that way until a deliberately inert entry exposed it. * `-a` on `_content`'s grep was not asserted: without it the grep prints "Binary file … matches" and exits 0, so the run still reds — with a record naming a temp blob path instead of the entry and line. The needle is the record now, not the headline. * one value stated at two levels, load-bearing at a different level each time: `GIT_NO_REPLACE_OBJECTS` IS in `git rev-parse --local-env-vars`, so `_git`'s purge clears it and only the re-export inside survives, while `GIT_NO_LAZY_FETCH` is not. The mutation aimed at the outer one survived because the line it changed decided nothing. Both live in one place now. **The CI rationale was false at four sites and this PR had answered half of one.** "The wires are grep-only" stopped being true when this wire took its population and its bytes from git. The property the ungated job actually rests on is the ABSENCE OF A SETUP STEP — the shell, git and grep a bare checkout already has — and it is spelled that way now at `ci.yml`'s rationale block, `ci.yml`'s step comment, `CLAUDE.md` and the wire's header, including the line this slice had touched the file of but not the line. **The controls' interface is asserted, not narrated.** It claimed `$ROOT` and `_phys`, which it never mentions, and attributed `_fgit` to the wire, which does not define it. The real list is checked at entry, so running the file directly says what it is (exit 2) instead of failing inside `mktemp` — which is also the pin for "is this a wire?", alongside the driver's unregistered-direction check. **And what the wire does not decide is stated once.** The four classes were at four sites; they are one block that #501 §12(3) delegates to. None is a defer slot: they are the reach of a predicate, not work owed — and for two of them "closable here" is answerable only as no, so a re-evaluation trigger could never fire. Verified under bash 5.3 and bash 3.2 (the stock macOS shell this file commits to, where a quoted here-document nested in a command substitution is still parsed for expansions — the mutation table is a function for that reason): wire 0, `scripts/trip-wires.sh` 0, mutation set 18/18 killed as named. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA
…viewers, applied `/code-review high` plus `/elidex-review`'s five axes on the two commits above. 0 CRIT, but three of the findings reverse answers those commits had just written, and every premise below was re-measured here before being acted on. **The §2 answer was built on a quotation with its subject replaced.** `DESIGN.md` opens: *"`webref` is maintained inside elidex for now, but ITS DRIFT-DETECTION CORE should stay generic enough to move to a standalone repository later. ELIDEX SPECIFIC BEHAVIOR BELONGS IN THIN ADAPTER COMMANDS."* The previous revision quoted the first half with "the package" substituted for "its drift-detection core", and never quoted the second sentence at all — `grep -rn "thin adapter\|drift-detection core"` over the memo and both shell files returned 0. That substitution is exactly what made "clause one is unqualified over the package, adapter commands included" appear to follow from the authority. It does not. So review round 1's finding — *the predicate forbids something its own authority permits* — stands, and its withdrawal is withdrawn. What resolves it is the honest statement: **K2 is a deliberate widening of `DESIGN.md`'s rule**, chosen by this program because such a string does not move whoever wrote it, with the cost (a thin adapter command may not spell a two-segment host path) stated rather than argued away. Two more quotations did not survive checking: §2 rendered #501 §12(3) as *"no other host path OR HOST POLICY is named here"* — the phrase occurs on no ref — and §0 claimed the carve trigger *"fired in every round from R74 to R97"*, which the SSoT's own R82/R83/R84 headers falsify. **"THE WHOLE LIST" was missing a class, and it is the decidable one.** A `.claude/(skills|tools)/` path with ONE further segment: 31 live instances inside the scanned scope (`cli.py` 22, `DESIGN.md` 7, `__init__.py` 1, `commands/refresh.py` 1), all of them this package's own entry script. Unlike interpolation and bare names it IS grep-decidable, so "not closable by any wire" does not cover it; it is listed with the honest statement that the predicate never looked. **The base memo is swept, not "raised".** The declining ground — §1's boundary predicate — is scoped to `-- .claude/tools/_webref` and does not reach `docs/plans/`. #501's memo was booking four defer slots ON THIS PR (§12(4)) while §8 refuses to file any, and restating two blind classes §12(3) claims to delegate. Both swept here, because this is the PR that decided them. **The replacement for "grep-only" was false in the same shape.** "the shell, `git` and `grep`" — written by the edit retiring "grep-only" — misses `sed`, `tr`, `cmp`, `readlink`, `mktemp`, `mkfifo`, `chmod`, `env`, `cut`, `ln`, `cp`, and the sibling wires' `awk`/`sort`/`comm`/`wc`. The residue command could not see it because it grepped the retired PHRASE. All four sites now state the property (nothing to install) with a derivation over the job's shape, and the wire's closing "belongs in a test, not here" is scoped to this wire rather than reading as an answer to §6. **The mutation harness's own defects, three of them reproduced:** * fixed paths (`${SELF%.sh}.mutant.sh`) in a working tree CLAUDE.md says is shared — two concurrent runs deleted each other's files and the harness reported the collision as `killed for the WRONG REASON`, i.e. it blamed the mutation set. Measured at 16 / 11 / 10 "not killed" on a head that measures 0 alone. Per-run names now, and a leftover is reported rather than removed. * `WEBREF_WIRE_MUTANTS` merely PRESENT in the environment made the required gate `exit 0` without scanning `_webref/` at all, with the driver recording it as a wire that ran. The block no longer ends the run. * the set was a floor that asserted nothing. It now carries a ratchet (`_MUT_FLOOR`), a correspondence check (a record naming no control reds), and a STANDING negative control (`!survive`) — the inert entry that caught the 126/vacuous-pass defect was run once and thrown away, and a control that is not standing cannot catch it twice. All five guards verified by breaking them. **Two more controls that passed without testing what they name**, found by measuring the complement rather than the five sites this branch edited: `empty` (a non-repository fixture produces a byte-identical verdict, because the `SCANNED -eq 0` guard short-circuits before `ERR_HITS`) and the HEAD inventory arm, which `fakegit` never reached — it fails `ls-files` only, so `ls-tree`'s status check could be deleted with every control green. New `fakegitls` shim, new control, its own mutation record. The sentence claiming there were "two exceptions" is retired: there are five, and the population is not closed. Also: `_ctl_env` is cleared by `_control` instead of by a positional convention; a post-probe `mkfifo` failure says so instead of aborting the file silently; the FIFO not-exercised line names both properties it lacks; `$_lh` joins the cleanup list it was left out of; `timeout-minutes` is re-derived 2 → 5 with the rule that a wire adding fixtures re-derives it; and the umbrella gains the A-i-wire memo row its own repo-wide preflight command needs. Verified at this head, both shells: wire 0, `scripts/trip-wires.sh` 0, controls run directly 2, mutation set 20/20 killed as named under bash 5.3 and 3.2, `preflight` 1 by design. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA
…d two false-positive predicates Ten unresolved Codex threads were already on #519, written against the carve commit, and this slice's own pre-push gate never saw them. Eight were real; four survived to this head. **Two more ways to put this wire in a mode nobody asked for.** `WEBREF_WIRE_SELFTEST` exported in a shell — left over from debugging a control — is inherited by the ordinary `scripts/trip-wires.sh` run, which then points `ROOT` at that directory AND skips every control. Reproduced by the reviewer: exit 0 while the real `_webref` tree held a forbidden untracked file. Self-test mode now needs a companion token the controls pass, so a leftover makes the gate refuse loudly instead of answering about the wrong tree. This is the third instance of one shape (after `WEBREF_WIRE_MUTANTS` and the HEAD probe below): a mode reachable from outside must be unreachable or loud, never silent. And the HEAD probe treated ANY non-zero `rev-parse --verify --quiet` as an unborn repository, so an operational failure silently disabled the entire HEAD pass — a committed forbidden path cleaned in the index and worktree read green. Measured: unborn is 1, "git cannot answer" is 128. Anything above 1 is an `err` record now. **Two false-positive predicates, which in a REQUIRED gate is the direction that gets gates switched off.** Closing punctuation counted as a path segment, so the harmless prose `See (.claude/tools/foo/) for details` reddened the job over a ONE-segment reference outside K2 entirely; `)]}>,;` joined the running-text terminators. And neither predicate required a boundary before `.claude`, so `https://example.claude/skills/team/rule.md` — and an entry named `…/fixtures/example.claude/skills/team/rule.md` — matched on the suffix of another segment. ⚠ The punctuation fix was wrong the first time in a way worth recording: `]` placed mid-bracket CLOSES the bracket expression, so the predicate silently matched nothing. The `routed` control caught it on the next run. **Two reads whose status was being discarded.** The staged-symlink blob's trailing-newline sentinel preserved the value but not the status, so a failed `cat` became a successfully-read empty target; `R%d` now carries both. `_match_path`'s pipeline reported a pre-processing failure as `grep`'s 1 — an ordinary "no match" — so it is no longer a pipeline. **And a control that could pass from the wrong arm.** `cachedir` had the violation both staged and in the worktree, so it passed from the index arm alone and a worktree-arm regression stayed green. The staged blob is clean now and the violation is worktree-only — verified by disabling the worktree content arm, which the control catches and previously did not. **The one finding that changes a design claim rather than code**: Codex cited `DESIGN.md` §Architecture, which is a stronger text than the closing rule this memo had been arguing with. It draws a two-column boundary and NAMES the modules — and `commands/agent_brief.py`, listed there as the module that "scans elidex paths", is inside K2's scope. So `DESIGN.md`'s "generic core" and K2's are different sets: five named modules versus the whole package plus the entry script. §2 says so now, the memo's earlier reconciliation is withdrawn, and both resolutions (narrow K2 in #501 §2, or amend `DESIGN.md`) are raised as a cross-slice question rather than settled here. The remaining two threads are answered, not waved: the plan-review one predates this memo's existence, and the defer-ledger one is §8, whose argument the reviewer's head could not see. Five new controls (two of them green-direction — the wire must NOT fire) and five new mutation records; the bare-control ratchet is unchanged at 21. Verified: wire 0 and driver 0 under bash 5.3 and 3.2, controls run directly 2, mutation set 25/25 killed as named on both shells, `preflight` 1 by design. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA
…res; one shim covered two inventories Five findings. Two were made by R6's split, one by the edit that retired a stale figure, and two were coverage holes fresh probing found. **A caller's git configuration reached the fixtures (reproduced, 10 failures).** `_git` deliberately preserves `GIT_CONFIG*` — #501 R97, a checkout readable only through a caller's `safe.directory` — which is right for the REAL SCAN and wrong for the FIXTURES, which must be built from a known configuration whatever the caller carries. Invoking the gate with `GIT_CONFIG_COUNT=1 core.excludesFile=*.py` made the fixtures' `git add` skip their own `.py` inputs and produced ten `CONTROL NOT EXERCISED` on a clean checkout. `GIT_CONFIG_GLOBAL`/`_SYSTEM` alone do not reach that channel. `_fgit` is a subshell that unsets `GIT_CONFIG`/`_PARAMETERS`/`_COUNT`; re-measured 10 -> 0. The asymmetry — preserve for the repository, scrub for the fixtures — is why there are two helpers, and it is stated at the one that scrubs. **One shim was failing both `ls-files` inventories.** `" ls-files "` is in the tracked (`--stage`) call and the worktree (`--cached --others`) one, so removing either arm's status check left the other's error to mask it: the reviewer deleted the worktree emission and the whole run stayed green. And mutation record 17 rewrote all three `_ls_rc` checks at once, so it only ever proved that AT LEAST ONE remained. `_ls_rc` is now `_rc_tracked` / `_rc_worktree` / `_rc_head` — one name per arm is what makes each individually provable — the shim is narrowed to `--stage`, and a `--others` shim, fixture, control and record are new. The collapsed record becomes three. ⚠ Fixing that exposed one of my own: excluding `lsfail` from the fixture repository loop had been justified by "its shim fails `ls-files` whatever the directory is", which stopped being true the moment the shim was narrowed. Its worktree inventory then ran for real against a non-repository and the control got `read 0 stored objects` instead of the inventory error it names. AN EXCLUSION JUSTIFIED BY ANOTHER MECHANISM'S BREADTH EXPIRES WHEN THAT MECHANISM IS NARROWED, and nothing links the two but a note — so the note is at the exclusion now. **The split fragment wrote the caller's variable.** `_mut_correspondence` set `ctl_ok`, owned by the controls file, so a rename there would have left this file assigning an unused global while the caller stayed green — the exact cross-file drift the entry guard exists to prevent, reintroduced by the split that added the guard. It returns a status now and the caller decides; `$_MUTATIONS` joins the checked contract. Also: `CLAUDE.md`'s `実測は一桁秒台` is removed rather than replaced — a new figure introduced by the edit that retired a stale one, in a paragraph that says not to record elapsed time, and already false. Third time this session; the rule is derive it or omit it. And §7 criterion 3 still said the records live "in the controls file itself" after R6 moved them, while §4's table already named the new file — the acceptance criterion and the artifact table giving competing accounts of the same seam. Verified: wire 0 and driver 0 under bash 5.3 and 3.2, controls and mutations run directly 2, mutation set 36/36 killed as named on both shells, the caller-config reproduction now exits 0, no leftover files, `preflight` 1 by design. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA
…are three The enumeration was a second copy of the one at `_stored` twenty lines below, and it had gone stale against it: #501 R92 added the staged-blob arm, so three subjects reach the matcher — entry name, worktree symlink target, staged blob (`grep -c '_stored "' .claude/tools/webref-generic-core-trip-wire.sh` -> 3). The copy is deleted rather than recounted; `_stored`'s comment stays the one list. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
§5 item 4's derivation of "nothing to install" ends in a grep naming five language runtimes. A sixth passes it in silence, and silence is that line's green — the false-negative side, in a job that is required and ungated. That is the third enumeration to stand in for this property in one section, after the two the same section records as retired. Not widened. This wire's own header carries the rule that a predicate which cannot return its population is a seed and that lengthening its regex is the wrong repair, so the line is labelled a seed, kept for the regression it actually caught (#501 R69), and the authority is moved to the two things that do not depend on a vocabulary: the `uses:` derivation above it, and §6. Also removes the "~25% faster" comparison beside `_shq`'s expansions — no baseline, no command, and the same class as the spawn counts deleted from that comment one commit ago. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ven-round range "Eight review rounds (#501 R69-R79)": R69–R79 is eleven rounds, and which eight is recorded in the lane SSoT, outside this repository — so the figure cannot be checked from here and the range contradicts it. The count is deleted; "ten ways" stays, because the sentence enumerates ten. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…carved from #501) (#519) * feat(trip-wires): the K2 generic-core layering wire, carved out of A-i (#501) This is the instrument #501 carried from review round 68 to design re-gate 5, moved here so it gets the plan-review CLAUDE.md requires for work of its shape. The content is unchanged from `611758ff` — 99 external review rounds and four design re-gates are in its history — and this branch is stacked on A-i's head so its diff is exactly the surface that left A-i: - `.claude/tools/webref-generic-core-trip-wire.sh` (642) + `…controls.sh` (447) - the `REQUIRED_WIRES` line, and the two driver comments its arrival falsified - the `trip-wires` rationale in `.github/workflows/ci.yml`, and the paragraph restating it in `CLAUDE.md` ⚠ **This commit is the starting point for a plan-review, not the end of one.** Design re-gate 5 left findings that are this slice's rather than A-i's, and they are not fixed here — they are what the plan memo has to answer: - The wire declares four classes it cannot see (the policy half of `DESIGN.md`'s closing rule; bare top-level names; interpolation; a segment containing whitespace) and registers none of them as a slot, while a required gate that names a blind spot is supposed to close it or file it. - Its "the threat model is accident, not adversary — and saying so bounds this file" paragraph is falsified by measurement: 886 lines when it was written, 1089 now, and the NUL arm it was written to justify IS a new mechanism. - Three controls can pass without testing what they name (`cachedir`'s fallback satisfies its own control; two Python-side pins iterate a literal that may be empty; the `odd` note asserts "every other control ran" in a run where `fifotracked` has already failed). - `ci.yml`'s "the wires are grep-only" is false of this wire (38 `git` calls), and the paragraph headed "DELIBERATELY NO RUNTIME FIGURE" carries three. - The split at R96 is a real cohesion seam but a `source`d fragment: the controls file cannot run or be tested standalone. - The live contention with open PR #510 — it registers a wire requiring `python3` and raises this job's `timeout-minutes` from 2 to 10, while this wire's rationale rests on the set needing no toolchain. Verified at this head: wire → PASSED (102 reads over 34 paths), `scripts/trip-wires.sh` → 0 with five registered wires. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA * docs(plans): the A-i-wire plan memo — the review this instrument never had The wire entered #501 at review round 68, after that slice's `/elidex-plan-review` had closed, so nothing has ever reviewed it as a design. This memo is that review's subject. It is deliberately short and carries no figure that moves with a commit — every quantity is the command that derives it. Slice A-i is the reason: it wrote figures into its memo and spent four review rounds on figures its own later edits falsified. The program's ratified rule (a plan memo holds no measurements and no self-measuring apparatus) is applied here from the first draft rather than scoped to start at the next slice. §5 lists the six questions design re-gate 5 left for this slice, and they are deliberately NOT fixed in the carried implementation — fixing them before the review would repeat the mistake that produced this slice. §6 states the #510 contention as a decision this memo owes rather than a merge someone inherits. ⚠ §3 has no spec row, and says why: the predicate is over repository paths and its authorities are `DESIGN.md` and CLAUDE.md, not a web specification. The Step 0 preflight's citation arm is not the review that matters here, and §3 carries the command that derives how many landed plan memos are in the same position rather than asserting it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA * docs(plans): correct §3's preflight prediction — it exits 0, not hard-fail Written from the shape of the rule rather than from running it, which is the failure mode this program exists to remove. Recorded at the site rather than quietly corrected, and replaced with the command instead of a prediction. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA * docs(plans): plan-review round 1 disposition — 2 CRIT / 25 IMP / 19 MIN `/elidex-plan-review` on draft 1 returned 2 CRIT, 25 IMP, 19 MIN and 14 FP across five axes, on a 183-line memo. This revision is the disposition for every block whose lens converged; the one genuine fork is now §1.1 and is NOT decided here. **The CRIT, found independently by four of the five axes**: §1 said "Five files" and §7 made an exit criterion of it. The memo is itself a tracked file in the diff it counted, so the count was false when written and the criterion could never pass — the exact failure the memo's own opening ⚠ names, two sections below it. The boundary is a predicate now (nothing under `_webref/`), the artifact set is §4's table, and §4 lists this memo. **§1.1 is new and is the review's most consequential finding.** A third option nobody had considered: slice A-iii already plans an **ungated `tools` job with an interpreter floor**, and putting K2 there makes §6's contention *not arise* — the question "may the required, ungated wire set require an interpreter?" exists because this wire chose the `trip-wires` job. The fork (here / A-iii / withdraw the carve) is tabled with its costs and left open. **§0 now starts from the lane SSoT's own record.** It declined this carve once, on two grounds — the edge-dense trigger's "no canonical algorithm" limb was falsified by measurement, and carving separates A-i's invariant from its mechanism. The same block set the re-evaluation trigger that has since fired ~24 times, so the carve is what the SSoT scheduled; but the second ground was never answered and §1.1 is where it is answered or the carve is withdrawn. **And the proportionality argument was wrong in its internals.** "1089 lines" hid the split: the scanner's own code is smaller than the largest existing wire, and the disproportion — code, fixtures and runtime — is in the controls. §0 now derives the two halves separately and says to run it before arguing about size. §2 gains the coupled-invariant enumeration (six invariants, the intersections that matter) the edge-dense rule requires, and states the finding that the predicate **forbids what `DESIGN.md` permits**: that file's closing rule allows elidex policy in adapter *documentation*, and `DESIGN.md` is inside the scanned population — reproduced in review. §5's agenda is restated because four of its six items rested on false premises: three of the four blind spots are already disposed of by #501 §12(3); "three controls" was two; item 4's claim lives at four sites and this slice already answered half of it on a repo-wide surface while calling the question open; and item 5 offered an option CLAUDE.md names as the wrong basis. §6 records three claimants rather than two, the textual half of the #510 conflict, and that the carried commit already wrote one answer. §7's mutation criterion no longer points at a population that #501's squash merge erases, and no longer freezes the artifact set the review may need to change. Also clerical: `REQUIRED_WIRES` was sorted before this slice and the insertion broke it, while both concurrent branches insert alphabetically — restored. Verified: `scripts/trip-wires.sh` → 0, preflight → 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA * fix(trip-wires): answer the K2 wire's plan-review — two blind controls, a false CI rationale, and a mutation set The plan-review's §5 asked eight questions about this instrument. Six of them change it; this commit is that change, and the memo commit that follows records every answer with its measurement. **Two controls passed without testing what they name.** `cachedir` shared the fixture loop that runs `git add -A` BEFORE the fixture's `.gitignore` exists, so its probe was tracked already and the force-add it exists to exercise changed nothing — measured, deleting `_fgit add -f __pycache__/probe.txt` outright left the wire at exit 0. It is built outside that loop now, in the only order that makes the force-add load-bearing, with a precondition asserting the probe is ignored AND tracked (`check-ignore --no-index`, because with the index consulted an ignored path reads "not ignored" the moment it is tracked — the flag is off exactly in the state the control requires). And the `odd`/`fifotracked` pair each built its FIFO under `|| true`: on a filesystem without them, `odd` printed "every other control ran" in precisely the runs where `fifotracked` had just failed for the same missing capability, and `fifotracked` reported a WIRE defect for a MACHINE limit. One probe, one report line, built beside the decision. **A mutation set, machine-readable, in the controls file.** Every control proves a verdict is REACHABLE; none proved it is produced by the code it is about. The population used to be prose scattered across #501's review commits, which that PR's squash erases. 18 entries now ship beside the controls — `WEBREF_WIRE_MUTANTS=1 bash …trip-wire.sh` — each required to change the copy, red it, and red it naming its own control. It found three things: * its own probe had the wrong subject: `sed` writes mode 644 and `_control` invokes `"$SELF"` directly, so every mutant exited 126 for every control, satisfying "did the right control fire?" vacuously. All 18 "passed" that way until a deliberately inert entry exposed it. * `-a` on `_content`'s grep was not asserted: without it the grep prints "Binary file … matches" and exits 0, so the run still reds — with a record naming a temp blob path instead of the entry and line. The needle is the record now, not the headline. * one value stated at two levels, load-bearing at a different level each time: `GIT_NO_REPLACE_OBJECTS` IS in `git rev-parse --local-env-vars`, so `_git`'s purge clears it and only the re-export inside survives, while `GIT_NO_LAZY_FETCH` is not. The mutation aimed at the outer one survived because the line it changed decided nothing. Both live in one place now. **The CI rationale was false at four sites and this PR had answered half of one.** "The wires are grep-only" stopped being true when this wire took its population and its bytes from git. The property the ungated job actually rests on is the ABSENCE OF A SETUP STEP — the shell, git and grep a bare checkout already has — and it is spelled that way now at `ci.yml`'s rationale block, `ci.yml`'s step comment, `CLAUDE.md` and the wire's header, including the line this slice had touched the file of but not the line. **The controls' interface is asserted, not narrated.** It claimed `$ROOT` and `_phys`, which it never mentions, and attributed `_fgit` to the wire, which does not define it. The real list is checked at entry, so running the file directly says what it is (exit 2) instead of failing inside `mktemp` — which is also the pin for "is this a wire?", alongside the driver's unregistered-direction check. **And what the wire does not decide is stated once.** The four classes were at four sites; they are one block that #501 §12(3) delegates to. None is a defer slot: they are the reach of a predicate, not work owed — and for two of them "closable here" is answerable only as no, so a re-evaluation trigger could never fire. Verified under bash 5.3 and bash 3.2 (the stock macOS shell this file commits to, where a quoted here-document nested in a command substitution is still parsed for expansions — the mutation table is a function for that reason): wire 0, `scripts/trip-wires.sh` 0, mutation set 18/18 killed as named. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA * docs(plans): answer all eight of §5, §6's interpreter question, and §7's mutation criterion §1.1's fork is closed: **(a)**, chosen by the lane owner on 2026-09-21 — K2 stays a shell wire in `REQUIRED_WIRES`, carried by this stacked PR. The three-way table is kept as the record of what was weighed. The ground for rejecting (b) (move it to slice A-iii's Python job) is "one issue, one way" read the other way round: §6 has a candidate answer that costs no wire movement, and under that answer (b) is not a dissolution of §6 but the wrong side of it. §6 is answered rather than sidestepped: **no**, the required ungated wire set may not require an interpreter — the umbrella already plans an ungated `tools` job WITH an interpreter floor, so each job gets one rule instead of two jobs sharing one and `trip-wires` losing the property that makes it cheap enough to be ungated. That is a finding about #510's wire's HOME, not its content; the write path is in that PR's files, which §1's boundary forbids this diff from touching, so it is raised and agreed, not executed here. Nothing in this slice blocks on the outcome. §3 takes A-iii's declared-no-spec-surface shape, and its `preflight` exit 1 is by design. Measured both ways: the placeholder row exited 0 with the label unrecognised, breadth counted and NO webref verification attempted — the one path through the citation arm that neither verifies nor fails, sitting in the memo whose subject is a gate. §7 criterion 3 is met: 18 mutation entries, `0 not killed as named`, with the three defects the set found on its first honest run recorded — including that its own probe had the wrong subject (mode 644 + direct `"$SELF"` invocation = exit 126 for every control, satisfying the right-reason test vacuously), and one the set introduced that only bash 3.2 shows. §8 registers no slots and says why it is "none" rather than "none yet": a slot records work owed; a declared blind spot records the reach of a predicate. The cap arithmetic dissolves — own deferrals 0, not 4 over a cap of 3. Two claims from review round 1 are withdrawn against measurement: "the predicate forbids something its own authority permits" (DESIGN.md's two clauses are about paths and about policy, and neither permits a path in the package that must be able to move), and "this memo's own §0 command and the driver's disagree" (they return the same five files; §0 names the artifact pair explicitly on purpose). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA * fix(trip-wires): pre-push design gate — 21 IMP / 20 MIN across six reviewers, applied `/code-review high` plus `/elidex-review`'s five axes on the two commits above. 0 CRIT, but three of the findings reverse answers those commits had just written, and every premise below was re-measured here before being acted on. **The §2 answer was built on a quotation with its subject replaced.** `DESIGN.md` opens: *"`webref` is maintained inside elidex for now, but ITS DRIFT-DETECTION CORE should stay generic enough to move to a standalone repository later. ELIDEX SPECIFIC BEHAVIOR BELONGS IN THIN ADAPTER COMMANDS."* The previous revision quoted the first half with "the package" substituted for "its drift-detection core", and never quoted the second sentence at all — `grep -rn "thin adapter\|drift-detection core"` over the memo and both shell files returned 0. That substitution is exactly what made "clause one is unqualified over the package, adapter commands included" appear to follow from the authority. It does not. So review round 1's finding — *the predicate forbids something its own authority permits* — stands, and its withdrawal is withdrawn. What resolves it is the honest statement: **K2 is a deliberate widening of `DESIGN.md`'s rule**, chosen by this program because such a string does not move whoever wrote it, with the cost (a thin adapter command may not spell a two-segment host path) stated rather than argued away. Two more quotations did not survive checking: §2 rendered #501 §12(3) as *"no other host path OR HOST POLICY is named here"* — the phrase occurs on no ref — and §0 claimed the carve trigger *"fired in every round from R74 to R97"*, which the SSoT's own R82/R83/R84 headers falsify. **"THE WHOLE LIST" was missing a class, and it is the decidable one.** A `.claude/(skills|tools)/` path with ONE further segment: 31 live instances inside the scanned scope (`cli.py` 22, `DESIGN.md` 7, `__init__.py` 1, `commands/refresh.py` 1), all of them this package's own entry script. Unlike interpolation and bare names it IS grep-decidable, so "not closable by any wire" does not cover it; it is listed with the honest statement that the predicate never looked. **The base memo is swept, not "raised".** The declining ground — §1's boundary predicate — is scoped to `-- .claude/tools/_webref` and does not reach `docs/plans/`. #501's memo was booking four defer slots ON THIS PR (§12(4)) while §8 refuses to file any, and restating two blind classes §12(3) claims to delegate. Both swept here, because this is the PR that decided them. **The replacement for "grep-only" was false in the same shape.** "the shell, `git` and `grep`" — written by the edit retiring "grep-only" — misses `sed`, `tr`, `cmp`, `readlink`, `mktemp`, `mkfifo`, `chmod`, `env`, `cut`, `ln`, `cp`, and the sibling wires' `awk`/`sort`/`comm`/`wc`. The residue command could not see it because it grepped the retired PHRASE. All four sites now state the property (nothing to install) with a derivation over the job's shape, and the wire's closing "belongs in a test, not here" is scoped to this wire rather than reading as an answer to §6. **The mutation harness's own defects, three of them reproduced:** * fixed paths (`${SELF%.sh}.mutant.sh`) in a working tree CLAUDE.md says is shared — two concurrent runs deleted each other's files and the harness reported the collision as `killed for the WRONG REASON`, i.e. it blamed the mutation set. Measured at 16 / 11 / 10 "not killed" on a head that measures 0 alone. Per-run names now, and a leftover is reported rather than removed. * `WEBREF_WIRE_MUTANTS` merely PRESENT in the environment made the required gate `exit 0` without scanning `_webref/` at all, with the driver recording it as a wire that ran. The block no longer ends the run. * the set was a floor that asserted nothing. It now carries a ratchet (`_MUT_FLOOR`), a correspondence check (a record naming no control reds), and a STANDING negative control (`!survive`) — the inert entry that caught the 126/vacuous-pass defect was run once and thrown away, and a control that is not standing cannot catch it twice. All five guards verified by breaking them. **Two more controls that passed without testing what they name**, found by measuring the complement rather than the five sites this branch edited: `empty` (a non-repository fixture produces a byte-identical verdict, because the `SCANNED -eq 0` guard short-circuits before `ERR_HITS`) and the HEAD inventory arm, which `fakegit` never reached — it fails `ls-files` only, so `ls-tree`'s status check could be deleted with every control green. New `fakegitls` shim, new control, its own mutation record. The sentence claiming there were "two exceptions" is retired: there are five, and the population is not closed. Also: `_ctl_env` is cleared by `_control` instead of by a positional convention; a post-probe `mkfifo` failure says so instead of aborting the file silently; the FIFO not-exercised line names both properties it lacks; `$_lh` joins the cleanup list it was left out of; `timeout-minutes` is re-derived 2 → 5 with the rule that a wire adding fixtures re-derives it; and the umbrella gains the A-i-wire memo row its own repo-wide preflight command needs. Verified at this head, both shells: wire 0, `scripts/trip-wires.sh` 0, controls run directly 2, mutation set 20/20 killed as named under bash 5.3 and 3.2, `preflight` 1 by design. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA * refactor(trip-wires): /simplify — one fixture-build record replaces five hand-written preconditions `/simplify`'s four angles on the gate-disposition commit. The altitude angle found the root the other three were circling, and it is the same shape this slice has now hit four times: a fact that was free at one point was reconstructed, separately, at five later ones. **Five controls had grown a bespoke PRECONDITION** — a probe re-deriving from a fixture's end state that its build had failed (was the blob tracked? is there a replace ref? did `info/exclude` get written? is it a repository at all?). Each was added after a control was caught passing over a tree that never posed its question, and the comment introducing the first two declared the class closed at two. It was not: `cachedir`, `empty` and `lstreefail` followed, TWO OF THEM ADDED BY THE COMMIT THAT WROTE THE SENTENCE. Every fixture is now `( … ) || _fixture_failed <name>` and `_control` refuses to report on a fixture whose chain did not succeed, so the population is every control rather than the five somebody noticed. Verified by breaking four builds — including `staged`, which never had a probe and is now covered. Five probes and their guard blocks are gone; net −18 lines. ⚠ One of those probes had to be subtle, which is the second argument against hand-writing them: this run exports `GIT_NO_REPLACE_OBJECTS=1`, so the obvious probe for `replaced` would have read the violating bytes whether or not the replacement took — passing vacuously for the very reason its control exists. **The mutation set's bookkeeping was in the wrong place and the wrong shape.** The ratchet and the needle↔label correspondence are static properties of the shipped file costing milliseconds, sitting inside an opt-in harness costing minutes — so deleting a record or renaming a control stayed green until someone ran it by hand. Both are always-on now. And the ratchet is no longer a floor on the record COUNT (which cannot tell "one deleted, one added" from "unchanged", and names nothing): it is a ratchet on THE NUMBER OF CONTROLS WITH NO RECORD, so both directions red and the bare control is named. The direction that had been checked has never had a violation; the direction that had not is where both real gaps lived. ⚠ The standing negative control now edits COMMENT TEXT. Its first version appended a space to an `rm -f` list — inert, but accidentally so, and that `rm` is itself dead. A negative control whose inertness depends on the behaviour of the code it edits stops being one the moment that code changes. (The harness caught the re-anchoring of two other records when the helpers below moved, which is what it is for.) **Taken on cost, because this job runs on every PR:** `_esc` and `_onerec` were `printf | sed | tr` pipelines called per entry per source — 306 of the scan's 592 process spawns. They are parameter expansion now, output proven byte-identical on bash 3.2 and 5.x over backslashes, embedded newlines, tabs, `~`-leading strings and empty input. ⚠ The spelling is load-bearing: a literal `~` replacement is tilde-expanded, and quoting the variable emits literal quote characters under bash 3.2 — `_T=$'~'` UNQUOTED is correct on both. `_scan`'s five `mktemp` calls are gone ($SCRATCH is already per-process and `_scan` runs once per process), and `_verdict`'s three copies of the grep-status rule are one `_classify` helper called three times. **Declined, with grounds, in §9** — concurrent controls (3.5–4.4×, but it restructures the instrument this PR exists to stabilise), skipping the HEAD pass on SHA equality (−37%, but every reproduced defect in this walk came from reading one source and inferring another), the entry-NAME dedup, merging `_verdict`'s passes, a shared shell library for `_control`/`st_probe`, and `git grep` for the content half. `ci.yml`'s `timeout-minutes` comment also loses the before/after and the runner ratio it had just introduced twenty lines below the rule retiring such figures — three reviewers measured this checkout and got materially different numbers. Verified: wire 0 and driver 0 under bash 5.3 and 3.2, controls run directly 2, mutation set 20/20 killed as named on both shells, `preflight` 1 by design, and the five guards (fixture status, both correspondence directions, the negative control, the ratchet) each shown to fire by breaking them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA * fix(trip-wires): PR519 Codex R1 — 10 findings; two fail-open modes and two false-positive predicates Ten unresolved Codex threads were already on #519, written against the carve commit, and this slice's own pre-push gate never saw them. Eight were real; four survived to this head. **Two more ways to put this wire in a mode nobody asked for.** `WEBREF_WIRE_SELFTEST` exported in a shell — left over from debugging a control — is inherited by the ordinary `scripts/trip-wires.sh` run, which then points `ROOT` at that directory AND skips every control. Reproduced by the reviewer: exit 0 while the real `_webref` tree held a forbidden untracked file. Self-test mode now needs a companion token the controls pass, so a leftover makes the gate refuse loudly instead of answering about the wrong tree. This is the third instance of one shape (after `WEBREF_WIRE_MUTANTS` and the HEAD probe below): a mode reachable from outside must be unreachable or loud, never silent. And the HEAD probe treated ANY non-zero `rev-parse --verify --quiet` as an unborn repository, so an operational failure silently disabled the entire HEAD pass — a committed forbidden path cleaned in the index and worktree read green. Measured: unborn is 1, "git cannot answer" is 128. Anything above 1 is an `err` record now. **Two false-positive predicates, which in a REQUIRED gate is the direction that gets gates switched off.** Closing punctuation counted as a path segment, so the harmless prose `See (.claude/tools/foo/) for details` reddened the job over a ONE-segment reference outside K2 entirely; `)]}>,;` joined the running-text terminators. And neither predicate required a boundary before `.claude`, so `https://example.claude/skills/team/rule.md` — and an entry named `…/fixtures/example.claude/skills/team/rule.md` — matched on the suffix of another segment. ⚠ The punctuation fix was wrong the first time in a way worth recording: `]` placed mid-bracket CLOSES the bracket expression, so the predicate silently matched nothing. The `routed` control caught it on the next run. **Two reads whose status was being discarded.** The staged-symlink blob's trailing-newline sentinel preserved the value but not the status, so a failed `cat` became a successfully-read empty target; `R%d` now carries both. `_match_path`'s pipeline reported a pre-processing failure as `grep`'s 1 — an ordinary "no match" — so it is no longer a pipeline. **And a control that could pass from the wrong arm.** `cachedir` had the violation both staged and in the worktree, so it passed from the index arm alone and a worktree-arm regression stayed green. The staged blob is clean now and the violation is worktree-only — verified by disabling the worktree content arm, which the control catches and previously did not. **The one finding that changes a design claim rather than code**: Codex cited `DESIGN.md` §Architecture, which is a stronger text than the closing rule this memo had been arguing with. It draws a two-column boundary and NAMES the modules — and `commands/agent_brief.py`, listed there as the module that "scans elidex paths", is inside K2's scope. So `DESIGN.md`'s "generic core" and K2's are different sets: five named modules versus the whole package plus the entry script. §2 says so now, the memo's earlier reconciliation is withdrawn, and both resolutions (narrow K2 in #501 §2, or amend `DESIGN.md`) are raised as a cross-slice question rather than settled here. The remaining two threads are answered, not waved: the plan-review one predates this memo's existence, and the defer-ledger one is §8, whose argument the reviewer's head could not see. Five new controls (two of them green-direction — the wire must NOT fire) and five new mutation records; the bare-control ratchet is unchanged at 21. Verified: wire 0 and driver 0 under bash 5.3 and 3.2, controls run directly 2, mutation set 25/25 killed as named on both shells, `preflight` 1 by design. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA * fix(trip-wires): PR519 Codex R2 — 5 findings, two of them made by R1's own fixes **R1 traded one direction of wrongness for the other, twice.** Both are the same mistake — fixing the site a finding named rather than the property it was about. The punctuation terminators (`)]}>,;`) were excluded from path segments ENTIRELY, so the false positive came back as a FALSE NEGATIVE: a real path `.claude/tools/team,inc/rule.md` stopped at the comma and read K2 zero. A segment is now "any run of path characters that does not END in punctuation", which admits `team,inc` and still refuses a bare `)`. The green control pins one direction and a red control the other; neither alone could have caught this. And `_match_path` still ignored `_onerec`'s status after R1 removed the pipeline: it is called beneath `||` in `_stored`, where `errexit` is suspended, so a failing assignment fell through to `grep`, which returned 1 for the empty value — the same misclassification by another route. Codex reproduced it by replacing `_onerec` with `return 2`: an entry named `.claude/skills/team/rule.md` reported `K2: 0` and exited 0. ⚠ No control pins the repair and the wire says so: `_onerec` is parameter expansion now, so nothing external is left for a shim to break. Kept for the shape one refactor away, on the same footing as the `-a` on `_verdict`'s arms. **An inventoried path that vanishes was skipped in silence.** A worktree entry removed between `ls-files` and the read matches none of `_entry`'s arms — no `ok`, no `err`, no record — and the final guard only requires the AGGREGATE `SCANNED` to be non-zero, so its siblings carried the run to green (reproduced). An absent tree entry that git does not report as tracked is an `err` now; the membership question is asked of git rather than inferred from absence, because a TRACKED path deleted from the worktree is the legitimate case the index pass has already answered for. Control: a `git` shim whose `--others` inventory names a path that is not there. **The watchdog killed a process, not a process group.** A command substitution or `grep` blocked beneath the wire — precisely the FIFO hang the watchdog exists to catch — was reparented and stayed blocked, so repeated local pre-push runs accumulated permanent orphans. The child is started under `set -m` and the group is killed. Measured on bash 5.3 and 3.2: group kill reaps the descendant, top-PID kill does not. **And the green boundary control pinned only half of what it claimed.** It exercises the entry NAME, hence `$K2RE_PATH`; the independently-changed arm in the running-text `$K2RE` could be reverted with every control still green. A second fixture carries the URL as file content, and the mutation record has a sibling for the running-text regex. Two new controls, two new records, one re-anchored (the punctuation record's target changed shape with the fix). Verified: wire 0 and driver 0 under bash 5.3 and 3.2, controls run directly 2, mutation set 27/27 killed as named on both shells, no orphaned processes after a full run, `preflight` 1 by design. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA * fix(trip-wires): PR519 Codex R3 — name the invariant three rounds kept finding violations of All four findings were "fresh evidence after the claimed fix", which is the loop's recurrence trigger, so the root-check ran before any of them was patched. **The root, and it has a name now:** A NON-ZERO STATUS IS NOT A SPECIFIC NEGATIVE. A command's failure may be read as a PARTICULAR negative ("there is no HEAD", "this path is untracked") only when a separate, POSITIVE test establishes that negative. Otherwise it is an ERROR. It kept biting because the wrong reading is always the convenient one: it turns "I could not find out" into "there is nothing to find", which is the direction that makes a gate green. The audit is written out in the header, so "is there another site?" has an answer rather than a guess. Two sites inferred a specific negative — the HEAD probe and the tracked-membership question, i.e. exactly this round's findings — and every other status this file reads concludes only "error", either from a documented contract (grep's 1-vs->=2) or from nothing at all. A new git call joins that list or it is a defect. Own-ideal test: the header says "ONE CHECK, ABSOLUTE … no un-asserted report" and "one authority answers all of it, and it is git". The walk is not the anti-pattern; the scattered INTERPRETATION of git's answers was — the opposite of one authority. Hence the named invariant plus an audit rather than a fourth site-patch. **The four sites:** * `rev-parse --verify --quiet HEAD` exits 1 for a MALFORMED branch ref too, so R2's "only >1 is an error" still skipped the HEAD inventory and exited 0 while HEAD lookup had failed. Unborn is now established positively (`rev-list -n 1 --all` exits 0 with empty output). Measured: unborn 0/empty, malformed 128. * the membership check read `$rel` as a PATHSPEC — a vanished untracked `foo[1].py` matched a tracked `foo1.py` and was reported tracked, so the entry nothing had answered for was passed over. `--literal-pathspecs`. Measured: rc 0 without, 1 with. Third instance in this file of "a path is data, not a pattern". * the self-test companion token was a fixed literal IN THIS FILE, so exporting both variables — what copying the two lines out of the controls produces — still redirected a normal run. It is the parent's live PID now; the child's own `$PPID` must equal it, which copying cannot satisfy. The reviewer's exact reproduction refuses. * R2's punctuation rule over-reached onto BOTH segments, so `.claude/tools/team,/rule.md` went undetected. The restriction belongs only on the FINAL segment — the only place the end of a reference is ambiguous. ⚠ The punctuation predicate was wrong three times in three DIFFERENT directions, each repair aimed at the example in the finding. What settled it was stating the property ("ambiguity exists only where the reference ends"), with a control on each side — neither direction alone could have caught the other. ⚠ And one R2 control had to be rewritten rather than kept: `headprobe` encoded R2's rule on a fixture that was genuinely unborn, so under the corrected rule its green is right and it could no longer discriminate. It has a commit now. A control written against a rule outlives the rule. Four new controls, four new records, two re-anchored (my own edits moved their targets — caught by the harness). Verified: wire 0 and driver 0 under bash 5.3 and 3.2, controls run directly 2, mutation set 30/30 killed as named on both shells, no leftover processes or files, `preflight` 1 by design. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA * fix(trip-wires): PR519 Codex R4 — PAUSE; the predicate was a heuristic wearing the word ABSOLUTE Four consecutive rounds with a finding in this file = the loop's scope-creep PAUSE, so this is option A (step back and collapse), not a fifth boundary patch. **The root-check moved this time.** §10.2's invariant held — R4's HEAD finding is a violation of it that MY OWN R3 fix introduced: I established the negative positively, as the invariant demands, but for the WRONG SUBJECT, asking whether the repository had commits rather than whether THIS HEAD did. Nothing further is missing there. What moved is the own-ideal test. The header said "ONE CHECK, ABSOLUTE. It is closed and decidable; it is not a heuristic." Against four rounds of evidence that is FALSE OF HALF OF IT: * `$K2RE_PATH`, over a stored path, is genuinely closed — git hands the value over whole, `/` is the only delimiter. One finding, in R1, stable since. * `$K2RE`, over running text, is a BOUNDED HEURISTIC. Every boundary finding in R1, R2, R3 and R4 was here. "Does a path reference start and end here?" cannot be decided without knowing whether the bytes are prose, code, Markdown, a URL or a `.pyc`. **The claim was the defect, not the regex**: it made each counter-example read as "a bug to repair", so each repair was aimed at the example and the next round found the opposite direction — too loose (prose in parentheses reddened the gate), too tight (a comma inside a segment), too tight again (a comma before a slash), then wrong in kind (`@` treated as a boundary, because the rule was written as "not these few path characters" instead of "one of these prose delimiters"). The header states the two halves' status now, and the requirement that follows: EVERY BOUNDARY RULE CARRIES A CONTROL IN BOTH DIRECTIONS, because each of those four was invisible to a control that tested only the other way. What the wire DOES is unchanged; what it CLAIMS is now true. **The four findings:** * unborn is a property of THIS HEAD: `symbolic-ref -q HEAD` + `show-ref --verify` on the named ref. Measured — orphan branch = symbolic-ref 0 / ref absent, empty repo = same, malformed ref = symbolic-ref 128. * the leading boundary admitted PATH characters, so `foo@.claude/…` matched on a component suffix. The list is positive now. ⚠ `[:cntrl:]` is load-bearing and the BINARY control caught its absence in the same run that introduced it. * `-f` followed an ancestor symlink, so a tracked `dir/a.py` with `dir` replaced by a link to an external directory reddened the gate over bytes `git add -A` would never stage. An ancestor symlink is an `err`, not a skip. * `grep -c .` on an EMPTY `.bare` prints 0 and exits 1, aborting the gate under `set -e` — and it fires exactly when the ratchet reaches the state it exists to permit. `wc -l`. No control (reaching that state needs every control to have a record); recorded rather than implied. ⚠ And two of my own fixtures were wrong in ways a PASSING control hid. The `headprobe` shim matched `--verify` anywhere, so it also broke the `show-ref --verify` that now decides unbornness — it had silently become a control for a different arm. Narrowing it to `rev-parse --verify` exposed a second defect: `*" rev-parse "*" --verify "*` can NEVER match, because the first half consumes the space the second needs, so the shim matched nothing and the control exercised an unshimmed git. Three new controls (two green-direction), four records re-anchored. Verified: wire 0 and driver 0 under bash 5.3 and 3.2, controls run directly 2, mutation set 33/33 killed as named on both shells, `preflight` 1 by design. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA * fix(trip-wires): PR519 Codex R5 + design re-gate — R4 made the gate fail open R4 declared "option A — step back and collapse, not a fifth boundary patch". Codex's R5 and the mandated cumulative design re-gate (two axes, fired because PAUSE tripped and a diverging loop never reaches TERMINAL) agree it was BOTH, and that the patch half is the worst change in this PR. **CRIT — R4's leading-boundary rewrite made a REQUIRED gate FAIL OPEN.** Replacing the exclusion class with a positive delimiter list closed one contrived false positive (`foo@.claude/…`) and opened five false negatives. Measured, R3's predicate vs R4's: `DEFAULT=.claude/…`, `--paths=.claude/…`, `k:.claude/…`, `` `.claude/…` `` and `**.claude/…**` all went HIT -> MISS. Two of those shapes are LIVE IN THE SCANNED TREE — `--opt=<path>` is how `cli.py` spells its `--help` examples, and a backtick is how `DESIGN.md`, which is Markdown, spells a path. The gate silently stopped covering its own most likely violation, and no control could see it because every red fixture writes its path after a space or a quote. What was missing was not a better list but a stated failure DIRECTION. Neither form can enumerate its complement; the question is where an unknown character lands. An exclusion class makes it a boundary -> over-match -> false positive -> the gate reds and somebody fixes it. A positive list makes it not a boundary -> under-match -> false negative -> the gate is green and nobody finds out. In a required gate those are not symmetric. The class is an exclusion again, `@` is handled inside it beside `+`/`%`/`-`, and the reasoning is in the wire so the next round cannot re-derive it wrong. Six red-direction fixtures pin the spellings above — the direction that had no control at all. **And the retraction had reached the reader, not the gate.** Three reviewers independently found the line CI prints still said `K2: 0 … -- ABSOLUTE`, over a count that is the UNION of the closed stored-path predicate and the half R4 had just called a heuristic. It reports the two separately now. This is the sweep-three-faces rule: R4 swept the statement and neither the obligation (a control in both directions — unmet for the rule R4 itself wrote) nor the consequence (the verdict line). Also fixed: the status audit named `rev-list -n1 --all` as the positive test for unbornness AFTER R4 removed that mechanism, and omitted `symbolic-ref`, `show-ref`, `cat-file`, `tr|cmp` and `_ancestor_link` — re-derived at HEAD with a derivation command and the rule "re-derive when a mechanism changes, do not amend around it". `_ancestor_link` was ordered after `[ -L "$f" ]`, so an external leaf symlink won and the gate reported a K2 hit on bytes outside the tree; the ancestor question is asked first now. "THE WHOLE LIST … THE ONE PLACE IT IS STATED" was stale in three ways and has items 6 and 7. "Every other control here proves the wire can RED" was false (10 of 53 are green-direction, two added three lines above the claim) and is a derivation now — which itself had to be run before being written down, because the first spelling printed the wrong awk field. **§8 said zero slots** while the loop had added obligations it was never reopened to see. Three slots now, each with a fireable trigger and a date; own deferrals 3, at the cap. Slot 1 is the touch-time split: both files crossed 1000 lines during this loop, and CLAUDE.md requires that split to be ITS OWN PR — so doing it here is what the rule forbids, not what it asks. `CLAUDE.md`'s "~1s" justification for the ungated job is retired: the decision rests on the absence of a setup step, not on a figure that is now an order of magnitude stale. ⚠ The lesson is about the loop, not the wire. I ran the root-check, wrote both mandated questions, reached a correct diagnosis — "the claim is the defect" — and then shipped a patch of exactly the kind the diagnosis forbade, in the same commit, under a heading saying I had not. A correct root-check does not immunise the round it is written in, and what caught it was the design re-gate firing BECAUSE the loop was still diverging: the one guard that does not depend on my own judgement of my own work. Verified: wire 0 and driver 0 under bash 5.3 and 3.2, controls run directly 2, mutation set 34/34 killed as named on both shells, `preflight` 1 by design. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA * refactor(trip-wires): split the mutation set out of the controls (touch-time, its own commit) Standalone split commit, doing nothing else. Codex R6 (P1) is right that R5's §8 inverted the rule it cited: CLAUDE.md's heading is "1000-line debt = touch-time split (defer しない)" and *prereq* means BEFORE, but the slot used the other half of the same sentence — "split は単独 PR / 単独 commit" — as permission to merge the oversized files first and schedule the split afterwards. Reading a rule's constraint as a licence for the thing it constrains. The sentence admits 単独 commit, so this is that commit. The seam is the one the reviewer named, and it is two subjects: controls — can the wire REACH every verdict it claims? (fixtures, each asserting the wire's exit status over a fixture tree) mutations — is each control ABOUT THE ARM IT NAMES? (the record table, the correspondence between the two lists, the opt-in runner) `.claude/tools/webref-generic-core-trip-wire.controls.sh` 1031 -> 810. ⚠ The memo's own counter-argument is answered rather than dropped. §9 argued against this seam because "the two lists must be edited together, so splitting them puts the two halves of one assertion in two files". They must — and the correspondence check is what ENFORCES that instead of hoping for it. Being cross-file is the point: it reads the controls for labels and this file for records, and reds when they drift. The argument was against a split that moved the table and left the check behind; that is not this split. ⚠ Two things the split had to get right, and the standing negative control caught the second: the correspondence moves WITH the mutation set, and the runner — which copies the controls beside each mutant — now copies this file too. Without that every mutant exited 2 ("decided nothing") for a reason unrelated to its mutation, and the harness reported it as the entry failing. The `!survive` entry died and said so: a broken harness reporting itself, in the run that broke it. The WIRE is not split, and that is a cohesion judgement with its measurement attached: 1089 lines is 249 code / 817 comment, and what remains is one predicate, one walk, one verdict — CLAUDE.md's 一枚岩の cohesive unit exemption, which is a cohesion test and not a line count. If that is wrong the seam to propose is predicate-vs-walk, and §8 names it so the next reviewer argues against a position rather than a silence. §8 goes to two slots (own deferrals 2 of 3); §4's artifact table gains the new file; the absence of the mutation file is exit 2 "decided nothing", like the controls' own. Verified: wire 0 and driver 0 under bash 5.3 and 3.2, controls run directly 2, mutations run directly 2, mutation set 34/34 killed as named on both shells, no leftover files, `preflight` 1 by design. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA * fix(trip-wires): PR519 Codex R7 — caller git config reached the fixtures; one shim covered two inventories Five findings. Two were made by R6's split, one by the edit that retired a stale figure, and two were coverage holes fresh probing found. **A caller's git configuration reached the fixtures (reproduced, 10 failures).** `_git` deliberately preserves `GIT_CONFIG*` — #501 R97, a checkout readable only through a caller's `safe.directory` — which is right for the REAL SCAN and wrong for the FIXTURES, which must be built from a known configuration whatever the caller carries. Invoking the gate with `GIT_CONFIG_COUNT=1 core.excludesFile=*.py` made the fixtures' `git add` skip their own `.py` inputs and produced ten `CONTROL NOT EXERCISED` on a clean checkout. `GIT_CONFIG_GLOBAL`/`_SYSTEM` alone do not reach that channel. `_fgit` is a subshell that unsets `GIT_CONFIG`/`_PARAMETERS`/`_COUNT`; re-measured 10 -> 0. The asymmetry — preserve for the repository, scrub for the fixtures — is why there are two helpers, and it is stated at the one that scrubs. **One shim was failing both `ls-files` inventories.** `" ls-files "` is in the tracked (`--stage`) call and the worktree (`--cached --others`) one, so removing either arm's status check left the other's error to mask it: the reviewer deleted the worktree emission and the whole run stayed green. And mutation record 17 rewrote all three `_ls_rc` checks at once, so it only ever proved that AT LEAST ONE remained. `_ls_rc` is now `_rc_tracked` / `_rc_worktree` / `_rc_head` — one name per arm is what makes each individually provable — the shim is narrowed to `--stage`, and a `--others` shim, fixture, control and record are new. The collapsed record becomes three. ⚠ Fixing that exposed one of my own: excluding `lsfail` from the fixture repository loop had been justified by "its shim fails `ls-files` whatever the directory is", which stopped being true the moment the shim was narrowed. Its worktree inventory then ran for real against a non-repository and the control got `read 0 stored objects` instead of the inventory error it names. AN EXCLUSION JUSTIFIED BY ANOTHER MECHANISM'S BREADTH EXPIRES WHEN THAT MECHANISM IS NARROWED, and nothing links the two but a note — so the note is at the exclusion now. **The split fragment wrote the caller's variable.** `_mut_correspondence` set `ctl_ok`, owned by the controls file, so a rename there would have left this file assigning an unused global while the caller stayed green — the exact cross-file drift the entry guard exists to prevent, reintroduced by the split that added the guard. It returns a status now and the caller decides; `$_MUTATIONS` joins the checked contract. Also: `CLAUDE.md`'s `実測は一桁秒台` is removed rather than replaced — a new figure introduced by the edit that retired a stale one, in a paragraph that says not to record elapsed time, and already false. Third time this session; the rule is derive it or omit it. And §7 criterion 3 still said the records live "in the controls file itself" after R6 moved them, while §4's table already named the new file — the acceptance criterion and the artifact table giving competing accounts of the same seam. Verified: wire 0 and driver 0 under bash 5.3 and 3.2, controls and mutations run directly 2, mutation set 36/36 killed as named on both shells, the caller-config reproduction now exits 0, no leftover files, `preflight` 1 by design. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9GdJXeFrgZWqkr5ygkEdA * fix(trip-wires): PR519 Codex R8 — self-test mode moves off the environment; the umbrella stops copying the memo R8 P2: a shell that exports WEBREF_WIRE_SELFTEST and WEBREF_WIRE_SELFTEST_PPID=$$ is the parent of every wire it later launches, so the PID check passed and an ordinary run skipped every control and scanned the fixture (reproduced in a clone --local sandbox: PASSED over the fixture at 0ba1ed2c, with a violation planted in the real _webref/). This was the third value asked to prove "the controls started this" — a literal token, then the parent's PID — and the environment is inherited by definition, so no value in it can. Self-test mode is now `--selftest <root> [dir] [extra]`: arguments are not inherited, the driver passes none, and the old names are no longer read. The control is R8's reproduction verbatim; a second pins the missing-root refusal; one mutation record each (37/37 killed as named, bash 5.3 and 3.2). R8 P2: the umbrella's A-i-wire row copied the slice memo's artifact list, slot verdict and blind-spot count, and all three had moved on. The row now points at the memo's §4 and §8 instead of restating them. Also: the wire now states the rule the memo said was recorded at the mode entry and was not (unreachable or loud, never silent), and memo §9 records why pre-push Stage 5 /review did not run as its own stage (/review is an alias of /code-review since Claude Code v2.1.223). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(trip-wires): PR519 Codex R9 — relative TMPDIR leak, unquoted shim paths, stale figures; the loop stops Five findings on 0c0187b4 (three from a review Codex ran on the R8 push by itself, unread for six hours because the landing probe only counted items newer than the next trigger): - relative TMPDIR: GNU `mktemp -d` returns a relative path, the trap's `/*/*` guard matched nothing, and every run left its scratch behind. The path is now resolved to its physical absolute form before the trap is installed. Control via a shim answering the GNU way (macOS's mktemp ignores a relative TMPDIR); one mutation record. - shim paths were spliced unquoted into /bin/sh source. One helper, `_shq`, now quotes every one; as the harness's own part it is asserted by a round-trip through /bin/sh rather than given a mutation record (the set edits the wire). - stale figures: "single-digit seconds" (a survivor of R7's own fix), "40 controls", "41 invocations", "the other thirty-nine", "all 18 entries below" — removed, not refreshed. - two declined §9 items worded as follow-ups are now stated as not owed. 38/38 mutation entries killed as named, bash 5.3 and 3.2. The first finding is a sweep miss of R7's fix, which fires the stop condition set before R8: the Codex loop is not re-triggered; a fresh enumeration over the populations these findings came from stands in for its remaining rounds (memo §10.8). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(plans): A-i-wire §11 — design revision after the enumeration attestation (for plan-review) The Codex loop stopped at R9; a fresh enumeration at d5dcad1c returned 3 CRIT / 7 IMP / ~30 MIN. §11 proposes: re-exec under an env allowlist (the ambient-environment class, which every earlier fix handled with a denylist), point fixes D2/D3/D4/D5/D9/D10, and collapsing the comment layer to invariants. Edge-dense, so plan-review precedes implementation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(plans): A-i-wire §11 rev 2 — #519 keeps its own fixes; the launch contract becomes slice A-i-launch Rev 1's plan-review (5 axes) found the in-wire env allowlist wrong at its boundary: bash consumes BASH_ENV/SHELLOPTS/BASHOPTS/BASH_FUNC_* before a script's first line, the allowlisted GIT_CONFIG* channel carries any config key (core.fsmonitor), and the class covers every required wire. User decision 2026-09-23: a new umbrella slice for the launch contract, #519 lands first with its own fixes (D2, D3 widened not declared, D4 completion record, D5, D10, and the false current-state claims). The enumeration's populations and its MIN list are now recorded in §11.4 so the terminator can be re-run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(plans): A-i-wire §11 rev 3 — environment findings sorted by failure direction; silent ones closed here Rev 2's plan-review found its carve premise false for D1 (grep reads its environment per exec, so the wire can close GREP_OPTIONS for its own calls) and its ledger wrong (the carved items were mostly this PR's own). User decision 2026-09-23: rev 3. Silent failures (D1, D4's causes) are closed in #519; loud ones satisfy the wire's own rule and are stated; only the pre-existing, launcher-only part is carved, as a ledger slot (#11-trip-wire-launch-environment), not an umbrella slice — the A-i-launch row is retracted. The point fixes take the holes rev 2's review measured: D2 via the nearest existing ancestor, D3 widened for every segment followed by '/', D4's fixture geometry and ordering, D5 at both sites. MIN findings are deleted by default. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(plans): A-i-wire §11.6 — rev 3's focused review (0 CRIT); plan-review closes on implementation detail Three focused passes (disposal check, new-claims audit, prototype on bash 5.3/3.2 with the mutation set) found no CRIT: every §11.2 mechanism works, the real tree stays K2: 0, each new red control fails pre-fix. Remaining findings are implementation detail, most caught by the mutation harness itself; §11.6 disposes each. Also: fsmonitor is own and closed in #519; §8 reads 3 of 3; the ledger slot drops POSIXLY_CORRECT and BASHOPTS (closable in-script; D4 owns their effect). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor(tools): split the K2 wire's control harness out of its controls file Touch-time split ahead of the rev-3 point fixes, which take the controls file past the line threshold. The seam is HOW a control runs (scratch root, fixture git helper, shim quoting, FIFO probe, `_control`) versus WHICH controls exist (each fixture and its assertion). Move only: the controls file sources the harness after asserting the wire's interface, refuses to run without it, and the mutation harness copies it beside each mutant. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(tools): K2 wire — close the silent-green environment and boundary holes The plan memo's §11.2 point fixes, each with its control and mutation record (`docs/plans/2026-09-citation-hygiene-Ai-wire-k2-trip-wire.md`): * D1 `unset GREP_OPTIONS` — BSD grep places it at the front of every argument list, so `--exclude=*` made a named file read as "no match". * D2 absence is established positively (`_absent`): `[ -L/-f/-e ]` all fail with EACCES, so their joint failure was read as tracked-and-gone. A non-directory nearest ancestor is an absence (ENOTDIR); a directory must be searchable. * D3 a segment followed by `/` is bounded only by `/` and whitespace; only the segment that ends the match keeps the running-text terminators. `K2: 0` on the real tree under the widened class. * D4 `_scan` emits a terminal record after its last source and at its early return; `_verdict` refuses a stream without exactly one, in last position, before the zero-read guard. * D5 `x=$(…) || x=""` at both sites, so the guard that follows can say why. * D10 one control per boundary-rule direction that had none, each shown missing by a mutant that survived the control set as it stood. * `_git` passes `-c core.fsmonitor=false -c core.untrackedCache=false`: the kept `GIT_CONFIG*` can carry a hook that git RUNS inside this wire's own reads. The mutation set gains a floor on its own size and a check that the standing negative control is present — deleting a paired record, or that one, was silent. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(tools): delete the K2 wire's false current-state claims The §11.4 MIN list, deleted by default and corrected only where deletion would leave a reader believing something false — never with a new count. Wire: the status audit is re-derived (the `[ -L/-f/-e ]` tests, `_absent`, `cat`'s sentinel, `_phys`, `: >`, the discarded `$(_scan)`, and the two overclaims); "every git call goes through `_git`" becomes every call that reads the tree; the claimed live spellings become a derivation; the not-decided list drops its "one place"/count claims and item 7 names what no control pins. Controls/harness/mutations: the `_fgit`, shim-path, verb-and-flag, live-spelling, `cachedir` and "three ways" claims; the consumes list; what the correspondence check actually greps. Memo: §8 slot 2's trigger is re-derived — nothing makes `_MUT_UNRECORDED_MAX` reach 0 on its own, and the ratchet is hand-edited in both directions; §8's cohesion judgement now says two predicates over one walk, without line counts; the harness split is recorded in §4 and §8; and the superseded `check-ignore`, "not taken", `bash "$_CONTROLS"`, tool-enumeration and "nothing is open" claims go. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(tools): say where the vanished-path arm's "gone" comes from The arm reads a non-zero `ls-files --error-unmatch` as "untracked", and its neighbours' joint failure as "gone" — which since D2 is `_absent`'s answer, not theirs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * ci(trip-wires): re-derive the job's timeout for the K2 wire's new controls The line's own rule: a wire that adds fixture self-tests re-derives it in the same PR. Measured on this branch and on its base, three runs each — the spread on one machine was wider than the difference between them, and both are far under the budget, so the number is unchanged and the derivation (not a figure) is recorded at the line. The same block's tool enumeration goes the way of the two before it: the list was narrower than the truth again, and this PR would have had to extend it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(plans): record what the §11 implementation decided where the memo did not §11.7: `_absent`'s remaining shapes fail safe; how the two re-aimed mutation records are re-aimed; why the fsmonitor control is not a `_control` and how it refuses to pass vacuously; the untracked-cache half nothing pins; what "counts records per needle" became (a `!survive` presence check and a record floor, with the residue stated); D10's post-D3 survivors; and the harness split. Plus the one wording fix the wire's own `_git` block needed: the `rev-parse --local-env-vars` call has to run before the function works, not before it can exist. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(plans): §11.7 item 1 said _absent errs on a dangling-symlink ancestor; it returns absence Measured: a dangling-symlink ancestor takes the non-directory arm, so the path reads as absent. That is the right answer — the worktree path is unreachable and its content is still read by the index and HEAD passes — so the row is corrected to the code rather than the code to the row. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(k2-wire): pin the three boundary rules a surviving mutant found unpinned Each of these was a rule `$K2RE` enforces with no control in either direction: a mutant editing it exited 0 PASSED over the whole control set. * the leading boundary's `/` — `$K2RE_PATH` spells the same rule as `(^|/)` and `slashname` pins it there, but nothing pinned the running-text half, so adding `/` to the exclusion class survived. Fixture `slashtext`, alone in its own tree: `bnd` bundles six spellings and stays red when one stops matching. * the final segment's minimum length of one — raising `[…]*[…]` to `[…]+[…]` survived, because every red fixture's last segment was longer than one character. Fixture `finalone`. * `A-Z`, the one member group of the leading exclusion class with no line in `atclaude` — removing it made an upper-case letter a prose boundary and no control noticed. Measured, each mutant before and after: exit 0 with nothing failing -> exit 1 with its own control's label in the output. Also: the scope preflight said "does not exist" where `[ -e ]`/`[ -L ]` fail on EACCES too. The run refuses either way, so it says that instead of asserting a negative it did not establish. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(k2-wire): retire the prose claims the terminator attestation falsified Per the memo's §11.2 MIN rule: delete by default, correct only where deletion would leave a reader believing something false, never with a new count. Wire — the status audit said "every status this file reads" while its own derive command returns `_match_path`'s `|| return 4`, which the table omitted; the claim is dropped and the two omissions (`|| return 4` and `[ -s "$_e" ]`) are listed where they belong. The `[-L]/[-f]/[-e]` row said their joint failure is never read as absence, but the scope preflight read exactly that — the diagnostic stopped asserting it in the previous commit, and the row now says so. Item 3's "two instances pre-exist" is deleted (measured: more than two, in three files). Item 7 gains the `$_last` half of `_verdict`'s terminal test, which no input can reach. Controls — the grep offered for "the wire reads NONE of them" tested six of the seven names; `_control` is added, with the `\b` its one collision needs. Mutations — `_MUT_RECORDS_MIN` was missing from WHAT IT DEFINES. Memo — §4 said the controls are one fixture per verdict the scanner can reach, which contradicts §8's own slot for the verdict sites that have none; §2's parenthetical measurement counted the shell files as two and §11.4's P1 population as three, and there are four; §11.1 gains the row for `PATH`, the channel every external tool arrives through, bounded in practice by the controls and closable only where bash is started. Co-Authored-By: Claude Opus 5 (1M context) <noreply…
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e8f7889665
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| _fgit() ( unset GIT_CONFIG GIT_CONFIG_PARAMETERS GIT_CONFIG_COUNT | ||
| GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null _git "$@" ) |
There was a problem hiding this comment.
Neutralize the environment template for fixtures
When the caller exports GIT_TEMPLATE_DIR, every _fgit init still copies that template because this wrapper only scrubs configuration variables and _git does not clear GIT_TEMPLATE_DIR. With a template whose info/exclude contains *.py, I reproduced an otherwise clean wire run reporting numerous CONTROL NOT EXERCISED failures because the staged/HEAD fixtures were not built; git init -h describes the template as the “directory from which templates will be used.” Unset this environment variable for fixture Git calls as well.
Useful? React with 👍 / 👎.
Slice A-i of the 8-slice citation-hygiene program (umbrella:
docs/plans/2026-07-citation-hygiene-umbrella.md).origin/maincarries one spec-label enumeration three times —coverage_map._SPEC_LABEL_MAP,cli.COMMON_SHORTNAMES, andpreflight.SPEC_LABEL_REVERSE. A-i creates.claude/tools/_webref/spec_labels.py, pinned map only, and collapses the two in the generic tree onto it. The gate's copy migrates in A-ii: it is not separable from the gate's failure semantics.Implementation is 434 lines under
.claude/; the rest is the plan memos and the re-derivation harness underdocs/plans/.Behaviour
The only observable change is which spellings resolve: 9 shortname spellings begin to resolve, over the same 12 specs, 0 changed and 0 lost — from the shortname-as-own-parse-key rule, not a widened alias list. The 8 parse aliases are omitted, measured inert (the map is byte-identical without them).
coverage_map's last resort staysorigin/main's.upper().replace("-", " ")verbatim — K4 requires identical resolution, and the round-trip fix that belongs there is routed to Slice B.Invariants (memo §2)
origin/mainhas two instances (_webref/cli.py:78and.claude/tools/webref:5, byte-identical strings), both discharged by by-role rewriteorigin/main's 15 pairs vendored and frozenReview history
Four
/elidex-plan-reviewrounds. Round 3 (3 CRIT) found defects a diff gate cannot see: the memo never stated which tree its edit set starts from;§12(1)'s check had no ref, so it returned 0 on any clean tree while a 50-line migration sat at HEAD; and§12(2)demanded ~730 lines of removal no edit-set row assigned. The response was the lineage decision — A-i is authored fromorigin/main, dropping the one commit that carried the whole.claude/implementation.The harness was split as a prereq (901 → 6 files, invocation surface preserved), and two of its blocks were repaired:
couplingshad computed a delta while carrying a comment arguing the memo's absolute was wrong, andreaders' "code/prose partition" was a superset/subset pair that printed byte-identical halves./elidex-reviewthen returned 0 CRIT / 7 IMP / 15 MIN, and its Step 4.5 pass a further 5 IMP — all applied. The sharpest: the new suite was the first generic-tree file ever to compute a repo root and walk.claude/skills/, inverting the layering rule the slice exists to enforce; and after moving those checks into the harness,couplingswas blind to untracked files, exited 0 on RED, could not distinguish "no violations" from "the scanner never ran", and resolved its roots against cwd. Each was confirmed by planting a violation and observing GREEN.Verification
_webrefsuite 27 tests OK ·elidex-plan-reviewsuite 35 OK · plan-review gate on the memo exit 0, 0 hard / 0 soft · all four §12 exit criteria green ·coverage-mapoutput byte-identical toorigin/mainacross 12 pinned + 3 unpinned specs · every check verified by deliberate failure, with exit codes.Owed, and deliberately not taken here
rederive partition(a Slice-B block) is broken by A-i's K3 and was failing silently;allnow propagates, so it exits 1 on this branch until B restores_catalog..claude/tools/whileDESIGN.mddefines it over_webref/. Measured, the widening buys zero evidence while importing five other-lane trip-wire artifacts into A-i's exit criterion. Redrawing it re-states a plan-ratified invariant and the canonical-site choice is shared with A-ii/A-iii — routed to plan-review at umbrella altitude.🤖 Generated with Claude Code