Skip to content

feat(trip-wires): the K2 generic-core layering wire (slice A-i-wire, carved from #501) - #519

Merged
send merged 61 commits into
webref-cite-audit-toolfrom
webref-generic-core-trip-wire
Sep 26, 2026
Merged

send merged 61 commits into
webref-cite-audit-toolfrom
webref-generic-core-trip-wire

Conversation

@send

@send send commented Sep 21, 2026 •

Copy link
Copy Markdown
Owner

Slice A-i-wire of the citation-hygiene program (umbrella: docs/plans/2026-07-citation-hygiene-umbrella.md). Stacked on #501 — review that one first; this PR's diff is exactly the surface that left it.

What this is

The K2 generic-core layering trip-wire — .claude/tools/webref-generic-core-trip-wire.sh and its three siblings (.controls.sh, .harness.sh, .mutations.sh), the line registering it in scripts/trip-wires.sh's REQUIRED_WIRES, and the trip-wires rationale in .github/workflows/ci.yml with the paragraph restating it in CLAUDE.md.

It asserts one predicate over the generic core (_webref/ plus the webref entry script): no .claude/(skills|tools)/<a>/<b> path is named there. origin/main had two such instances; #501 removes both, and this wire is what keeps them removed.

⚠ Until this lands, K2's closed part is not closed. #501 §12(3) says so plainly: it discharges K2 by diff review — finite and reviewed, but not a gate. That is why this is stacked rather than deferred.

Why it is a separate PR

It was not separate, and that was the defect. It entered #501 at review round 68 — after that slice's own /elidex-plan-review — and arrived carrying its own CI registration and two repo-wide policy edits. CLAUDE.md makes /elidex-plan-review a rule, not a judgment for edge-dense work; the base-case clause that lets an approved slice ship as one PR covers what its plan-review approved, and does not reach an instrument added afterwards. So the wire comes here and gets the review it never had.

D1 — a local run could go green over a violation, and now cannot

grep reads its environment on every exec. BSD grep (macOS) honours GREP_OPTIONS, so GREP_OPTIONS=--exclude=* made a named file read as "no match": a local run of this required gate went green over a real violation, silently. CI's grep is GNU, which does not honour it — so this was a local-only false green, and it was never going to show up in a CI run.

Closed here by unset GREP_OPTIONS at the wire's start, with a control (_ctl_env over a violating fixture) and a mutation record: deleting the unset line is a mutant, and it dies. ⚠ The control discriminates on BSD grep and passes trivially on GNU grep — stated at the control rather than left for a reader to discover.

⚠ This is not a denylist of a guessed population. BSD grep's manual names exactly one variable under ENVIRONMENT, and the locale is already pinned by LC_ALL=C. The general case — every other wire on main still runs grep under the caller's environment — is not closed here and is carved: #11-trip-wire-launch-environment, pre-existing on main and not introduced by this PR. Measured on main with a negative control: all four sibling wires exit 0 in a clean environment and exit 1 under GREP_OPTIONS=-v, while this wire exits 0 either way. Its trigger is this PR landing.

Carved slots

slot what it is
#11-trip-wire-launch-environment pre-existing on main: the sibling wires' grep/PATH/BASH_ENV exposure. Owner = PM lane (the driver belongs to no lane). Trigger = this PR landing.
#11-k2-wire-verdict-site-controls own: this wire has verdict sites no control reaches. The controls' claim to reach every answer is corrected here; reaching them is the slot. Trigger = the next change to any of those sites.

Own-deferral count for this PR: 3 (these two plus §8's own), at the cap.

What the review rounds left, and where it went

Re-gate 5 handed this slice an agenda rather than a clean branch — blind spots declared but unfiled, a bounding claim falsified by its own file's growth, three controls that could pass without testing what they named, ci.yml figures in a paragraph headed "DELIBERATELY NO RUNTIME FIGURE", and the live contention with #510 over whether the ungated wire set may require an interpreter.

All of it is discharged in the history rather than summarised here — §10 of docs/plans/2026-09-citation-hygiene-Ai-wire-k2-trip-wire.md is the round-by-round record, §8 the slots, §11 the instrument and its populations. Two things are worth naming because they changed how the rest was done:

  • The interpreter question is answered, not merged. §6: the required ungated trip-wires job keeps a no-interpreter floor, and Python checks belong in slice A-iii's ungated tools job — one rule per job instead of two jobs carrying the same one. Raised to tools(plan-memo): carve plan-memo-umbrella-check out of #506 — Slice 0 split + Slice 1 lexical substrate / one pipeline / one population #510 rather than imposed, since the write path is in that PR's files.
  • Four successive attestations that called themselves complete were samples. The response was to stop hand-enumerating: boundary mutants are generated from $K2RE/$K2RE_PATH rather than listed, and the header's hand-kept list says in the file that it is a floor, not an inventory. The fourth attestation then found the generator carrying the same defect one level down — it returned class members and quantifiers, and walked alternations and escapes past, while the run printed a universal over "every rule those two regexes spell". Branch-drop and unescape mutants are derived now; the one direction that would need the scanner to invent a payload (widening a branch list) is named as the hand records' and not claimed by the generated set.

Verification at this head

Judged by log text, not by an echoed $?. The mutation set runs in a git clone --local, never in the worktree — a killed run leaves mode-755 artifacts in .claude/tools/ where a git add -A stages them.

bash .claude/tools/webref-generic-core-trip-wire.sh PASSED, rc 0
bash scripts/trip-wires.sh rc 0, five registered wires, discovery ↔ REQUIRED_WIRES agree both ways
WEBREF_WIRE_MUTANTS=1, bash 5.3 and bash 3.2, separate clones 95 entr(ies), 0 not killed as named; 50 mutant(s) from $K2RE and $K2RE_PATH, 0 neither killed nor argued equivalent — every generated mutant killed by a control, not by the repository, and the equivalence table is empty
controls file removed exit 2, "decided nothing" — verified in both directions
timeout-minutes re-derived as the line requires, unchanged at 5: interleaved three rounds against the pre-controls commit put the run-to-run spread wider than the difference between the arms

Figures that move with a commit are not repeated here; wc -l, git diff --stat and the commands above are the sources.

🤖 Generated with Claude Code

#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
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-26T03:54:38.599810Z 7881cb5 Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

send and others added 2 commits September 21, 2026 14:15
…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
…-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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c22b053811

ℹ️ 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".

Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.controls.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.sh
Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
`/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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b6982136a0

ℹ️ 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".

Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
send and others added 5 commits September 21, 2026 18:01
#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
…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
…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
…ive 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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a8745f980e

ℹ️ 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".

Comment thread .claude/tools/webref-generic-core-trip-wire.sh
…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
@send

send commented Sep 21, 2026

Copy link
Copy Markdown
Owner Author

R1 disposition — all ten threads addressed and resolved; details in the plan memo's new §10 (docs/plans/2026-09-citation-hygiene-Ai-wire-k2-trip-wire.md) and in commit ee9aa973.

Fixed (8): the inherited WEBREF_WIRE_SELFTEST redirect (now requires a token the controls pass, so a leftover export makes the gate refuse loudly); the HEAD probe collapsing "unborn" (exit 1) with "git cannot answer" (128); the staged-symlink blob read whose status the sentinel discarded; _match_path's pipefail masking; closing punctuation counted as a path segment; the missing leading boundary before .claude in both predicates; and the cachedir control, which could pass from the index arm alone — its staged blob is clean now and the violation is worktree-only.

Five new controls (two of them green-direction — asserting the wire does not fire on a legitimate tree) and five new mutation records. WEBREF_WIRE_MUTANTS=1 bash .claude/tools/webref-generic-core-trip-wire.sh → 25/25 killed as named, on bash 5.3 and 3.2.

Answered rather than changed (2):

  • Complete the mandatory plan review — written against the carve commit, before the A-i-wire plan memo existed. It does now (docs/plans/2026-09-citation-hygiene-Ai-wire-k2-trip-wire.md), and has had a plan-review round plus a five-axis design gate.
  • Track or close the host-path classes — §8: no slots, because a defer slot records work owed while a declared blind spot records the reach of a predicate, and for interpolation and bare top-level names "closable here" is answerable only as no, so a re-evaluation trigger could never fire. §5 item 1 also adds a fifth class your list did not have (a one-segment .claude/tools/webref, live inside the scope).

On "Restrict K2 to the generic layer" — you are right and the memo's previous answer is withdrawn. §Architecture is a stronger citation than the closing rule I had been arguing with: it names the generic modules and assigns path heuristics to the adapter, and commands/agent_brief.py is inside K2's scope. So DESIGN.md's "generic core" and K2's (#501 §2: _webref/ plus the entry script) are genuinely different sets. §2 now states K2 as a deliberate widening with that cost named, and raises both resolutions — narrow K2 in #501 §2, or amend DESIGN.md — as a cross-slice question rather than settling it in this slice.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ee9aa973d9

ℹ️ 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".

Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.controls.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.controls.sh
…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
@send

send commented Sep 21, 2026

Copy link
Copy Markdown
Owner Author

R2 disposition — all five addressed (e2de8dd0; memo §10.1).

Two of the five were made by R1's own fixes, and they 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 — .claude/tools/team,inc/rule.md stopped at the comma. A segment is now "any run of path characters that does not END in punctuation", which admits team,inc and still refuses a bare ). Your point that the green control cannot catch this direction is exactly right; it is pinned by a red control now, and the memo records that neither direction alone would have caught it.
  • _match_path — you are right that removing the pipeline was not the fix. Under || in _stored errexit is suspended, so the failing assignment fell through to grep. || return 4 now reaches _stored's > 1 arm. ⚠ I could not pin it: _onerec is parameter expansion now, so nothing external is left for a shim to break and the only way in is to edit the function, as your reproduction did. The wire says so rather than implying coverage.

The vanished-entry finding was the sharpest — no ok, no err, no record, and the aggregate SCANNED guard carried the run to green on the siblings. Fixed; an absent tree entry that git does not report as tracked is an err. 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 already answered for. Control: a git shim whose --others inventory names a path that is not there — the deterministic form of the race.

Watchdog: the child now starts under set -m and the process group is killed. Measured on bash 5.3 and 3.2 — group kill reaps the blocked descendant, top-PID kill does not; no orphans after a full run.

Boundary control: correct, it exercised K2RE_PATH only. A second fixture carries the URL as file content, and the mutation record now has a sibling targeting the running-text regex.

Mutation set 27/27 killed as named on both shells.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e2de8dd00d

ℹ️ 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".

Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
…t 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
@send

send commented Sep 21, 2026

Copy link
Copy Markdown
Owner Author

R3 disposition (33d69582; memo §10.2). All four were "fresh evidence after the claimed fix", which is this loop's recurrence trigger — so the root-check ran before any of them was patched, and the result is a named invariant rather than a fourth site-patch:

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 wire's header so "is there another site?" has an answer: exactly two sites inferred a specific negative — the HEAD probe and the membership question, i.e. your two findings — and every other status concludes only error, from a documented contract (grep's 1-vs-≥2) or from nothing at all.

  • HEAD — right, exit 1 is not unique to unborn. Unborn is established positively now (rev-list -n 1 --all exits 0 with empty output). Measured: truly unborn = rc 0/empty, malformed ref = rc 128. New fixture with a garbage branch ref.
  • Membership — right, and this is the third instance in this file of a path is data, not a pattern. --literal-pathspecs. Measured: rc 0 without it, 1 with it. Control: a shim whose --others inventory names foo[1].py while foo1.py is tracked.
  • Self-test token — right, and the comment claiming the accident model was wrong about its own threat. The companion value is the parent's live PID now; the child's $PPID must equal it, which copying the two lines cannot satisfy. Your exact reproduction (both variables exported) refuses.
  • Punctuation before a slash — right. ⚠ This predicate has now been wrong three times in three different directions — too loose, too tight, too tight again — each repair aimed at the example in the finding. What settled it was stating the property: ambiguity exists only where the reference ends, so the restriction belongs on the final segment alone. There is a control on each side now, because neither direction alone could have caught the other.

⚠ One of R2's controls had to be rewritten, not kept: headprobe encoded R2's rule on a fixture that was genuinely unborn, so under the corrected rule its green is right and it no longer discriminated. It has a commit now. A control written against a rule outlives the rule.

Mutation set 30/30 killed as named on bash 5.3 and 3.2 — two records needed re-anchoring because my own edits moved their targets, which the harness reported.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 33d69582d6

ℹ️ 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".

Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.sh
Comment thread .claude/tools/webref-generic-core-trip-wire.controls.sh Outdated
…c 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
@send

send commented Sep 21, 2026

Copy link
Copy Markdown
Owner Author

R4 disposition (ffb09109; memo §10.3). This file has now carried a finding in four consecutive rounds, which is this loop's scope-creep PAUSE — so this round is step back and collapse, not a fifth boundary patch.

The root-check moved. R3'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 (whether the repository had commits, not whether this HEAD did). What moved is the own-ideal test. The header claimed "ONE CHECK, ABSOLUTE … it is not a heuristic", and 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–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 → too tight → too tight again → wrong in kind. The header states both halves' status now, and the requirement that follows: every boundary rule carries a control in both directions, since each of those four was invisible to a control testing only the other way.

The four:

  • Unborn HEAD — right, and thank you for the orphan-branch construction. symbolic-ref -q HEAD + show-ref --verify. Measured: orphan = symbolic-ref 0 / ref absent, empty repo = same, malformed ref = symbolic-ref 128. Green-direction control added.
  • @ as a boundary — right; the rule was written as "not these few path characters" instead of "one of these prose delimiters". Positive list now. ⚠ [:cntrl:] had to join it and the binary control caught its absence in the same run that introduced it (that fixture wraps the path in NULs).
  • Ancestor symlink — right, and it is an err rather than a skip, since skipping is how entries get passed over in silence.
  • grep -c . on an empty .bare — sharp catch: it aborts the gate under set -e exactly when the ratchet reaches the state it exists to permit. wc -l. ⚠ No control, and the memo says so rather than implying one: reaching an empty .bare needs every control to have a record.

⚠ 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. Narrowing it exposed a second defect: *" rev-parse "*" --verify "* can never match — the first half consumes the space the second needs — so the shim matched nothing and the control exercised an unshimmed git.

Mutation set 33/33 killed as named on bash 5.3 and 3.2.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ffb0910957

ℹ️ 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".

Comment thread .claude/tools/webref-generic-core-trip-wire.sh Outdated
Comment thread .claude/tools/webref-generic-core-trip-wire.sh
Comment thread .claude/tools/webref-generic-core-trip-wire.sh
…ail 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
@send

send commented Sep 21, 2026

Copy link
Copy Markdown
Owner Author

R5 disposition (fcb0fa1d; memo §10.4). All three of yours were right, and two of them landed alongside a CRIT that the mandated design re-gate found independently — so this round judged R4 wrong.

R4's leading-boundary rewrite made the 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 are live in the scanned tree: --opt=<path> is how cli.py spells its --help examples, and a backtick is how DESIGN.md (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: an exclusion class makes an unknown character 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 → green forever. In a required gate those are not symmetric. Exclusion class again, @ handled inside it beside +/%/-, six red-direction fixtures for the spellings above, and a mutation record.

  • -- ABSOLUTE in the printed verdict — you, and both re-gate axes, caught the same thing: R4's retraction reached the header and the memo but not the line CI shows, over a count that is the union of both predicates. The two report separately now. This was the sweep-three-faces failure: R4 swept the statement and neither the obligation (a control in both directions, unmet for the rule R4 itself wrote) nor the consequence.
  • The status audit — right, and worse than stale: it named rev-list -n1 --all as the positive test 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 is now re-derive when a mechanism changes, do not amend around it.
  • _ancestor_link ordering — right; with an external leaf symlink the [ -L "$f" ] arm won and the gate reported a K2 hit on bytes outside the tree. The ancestor question is asked first.

Also from the re-gate: "THE WHOLE LIST … THE ONE PLACE IT IS STATED" was stale three ways (items 6 and 7 added); "every other control proves the wire can RED" was false (10 of 53 are green-direction, two added three lines above the claim); §8 said zero slots while the loop had added obligations — three slots now, each with a fireable trigger and a date, at the per-PR cap of 3. 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.

⚠ The lesson I take is about the loop: 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. What caught it was the design re-gate firing because the loop was still diverging.

Mutation set 34/34 killed as named on bash 5.3 and 3.2.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fcb0fa1d9b

ℹ️ 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".

Comment thread docs/plans/2026-09-citation-hygiene-Ai-wire-k2-trip-wire.md Outdated
…ch-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
send and others added 26 commits September 23, 2026 17:22
…iagnostics said "staged"

`elif [ "$_mode" = 120000 ]` is reached from BOTH stored sources — the index's
`ls-files --stage` and HEAD's `ls-tree` — but every fixture that put a symlink
there only STAGED one (`catfail`, `catkill`, `stagedlink`, `nulblob`), and
`committed` commits a regular file. So the HEAD half was unasserted, and this
edit survived:

    sed 's/elif \[ "$_mode" = 120000 \]; then/elif [ "$_mode" = 120000 ] \&\& [ "$_src" = index ]; then/'

Measured on the pre-fix wire: exit 0, PASSED. With that arm narrowed to the
index, a symlink whose forbidden target lives only in the COMMIT — the bytes a
push sends — goes to the running-text predicate instead of the stored-path one.

The new `headlink` fixture commits the symlink and then replaces it, in the
index and the worktree, with a clean regular file, so mode 120000 reaches the
blob arm from `ls-tree` alone. Its target holds a SPACE for the reason
`stagedlink`'s does: a space ends a path in running text, so `$K2RE` cannot
find the same string by another route and the fixture discriminates between the
two predicates rather than between two spellings. Control:
"a COMMITTED symlink target is a stored path" — verified the sole control that
fails under the mutant above.

…and three diagnostics in that arm hard-coded the word "staged" while the
source may be HEAD: the NUL message, the blob-read failure, and the `_stored`
subject. They name `$_tag` now, so a reader is not sent to the index for a
target only the commit holds. `catfail`'s expected message moves with them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…n the checkout path

`REL_FILE="${SCOPE_FILE#"$ROOT"/}"` is the second site that strips the root
from a scope path, and nothing asked it: `glob[1]` passes a scope subdirectory
and no extra entry, so its control ran with `$SCOPE_FILE` empty. Removing those
inner quotes survived — measured on the pre-fix wire: exit 0, PASSED.

Adding a 6th argument to `glob[1]` does NOT kill it, and that is the finding
underneath this one. With `[1]` in the checkout path the unquoted strip fails
OUTRIGHT and leaves an absolute pathspec, which `ls-files` and `ls-tree` both
resolve to the same entry — measured, with a `glob[1]`-shaped fixture carrying
an extra entry, and again with the root reached through a symlink: identical
output, exit 0 both ways.

What discriminates is a pattern that matches a LONGER prefix than the literal
it came from. In `globextra*[e]`, `*[e]` cannot match `*[e]`, but `*` absorbs
up to `sid` and `[e]` takes the `e` of `side/`, so the unquoted strip removes
`…/side/` and hands git `entry` — a path that does not exist. The extra entry
then drops out of the inventory and the violation inside it is never read:
green over something nothing looked at, which is why the fixture's violation
lives IN the entry rather than beside it. Control: "a pattern character in the
checkout path does not misplace the entry script" — verified the sole control
that fails under the mutant, and verified NOT to fail under `REL_DIR`'s (whose
fallback to `.` widens the scan and finds the same violation), so the two sites
stay separable.

…and item 7 of WHAT THIS WIRE DOES NOT DECIDE said "the sibling site … IS
pinned" while there were two of them and one was not. It now says the sites
that strip `$ROOT` are pinned, each by a fixture whose own checkout path holds
a pattern character.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…o-read guard guarded nothing

`_entry` ends with `[ "$_read" -eq 0 ] || printf 'ok\t…'`, and that guard is
what makes `SCANNED` the number of entries actually READ rather than the length
of the inventory. Nothing asserted it — this edit survived:

    sed 's/\[ "$_read" -eq 0 \] || printf/printf/'

Measured on the pre-fix wire: exit 0, PASSED. With it applied, an entry that no
arm could read still prints `ok`, so the final `SCANNED -eq 0` refusal — the one
that stops this wire answering green for a reason that is not "there are none" —
can no longer be reached while any entry exists.

`empty` cannot pose the question: with no entries at all `SCANNED` is 0 either
way. The entries have to EXIST and go unread, which the new `unread` fixture
does with one tracked path whose blob sha was computed but never written:
`cat-file` fails in the index pass, and the path has no worktree copy, so the
worktree pass answers for it with no record either. Both sources leave `_read`
at 0. Control: "an inventoried entry that was never read is not counted as
scanned", exit 2 / "read 0 stored objects" — verified the sole control that
fails under the mutant (it gets exit 1 instead: the err record is reported, over
a count that now includes what produced it).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ot tighten

`_mut_regex_mutants` fails closed on an unterminated bracket expression, an
unterminated `[: :]` and a drop that would leave a class matching nothing — but
a `?` or a `{n,m}` fell through the `!= '['` test and was walked past as an
ordinary character. So a quantifier neither regex holds today could be added to
one tomorrow, no mutant would be generated for it, and the run would go on
printing "every rule those two regexes spell is pinned by a control": a rule
unwatched, reported as watched. The generator exists because a hand list cannot
see what it forgot; this was the same hole inside the mechanism meant to close
it.

POSIX ERE's quantifier set is CLOSED (`*`, `+`, `?`, `{…}`), so the new arm is
the COMPLEMENT of the two the scanner tightens rather than a list of shapes
somebody thought of — unknown lands on red, as everywhere else here.

No control pins it, for the reason the wire's item 7 already gives for this
generator's other fail-closed arms: its input is the wire's own source, and
nothing a fixture does makes that unparseable. Verified directly instead, on
bash 3.2 and 5.3:

    eval "$(awk '/^_mut_regex_mutants\(\) \{/,/^\}/' \
      .claude/tools/webref-generic-core-trip-wire.mutations.sh)"
    _mut_regex_mutants T 'a?b'    > /dev/null; echo $?   # 1
    _mut_regex_mutants T 'a{2,3}b' > /dev/null; echo $?  # 1
    _mut_regex_mutants T 'a[bc]+d' > /dev/null; echo $?  # 0, 3 mutants

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ring or asserting them

`_mut_gen_run` reads `$K2RE` and `$K2RE_PATH` from the running wire — that is
the half of its own precondition check that asks whether the assignment LINE
still holds what the wire HOLDS — but neither name was in this file's "WHAT IT
CONSUMES" list or in the guard that asserts it. The guard exists because "a
stated interface nobody checks drifts like any other unexecuted claim", and the
commit that added the generator widened the interface past both, which is the
drift itself rather than an example of it.

Both are now in the list and in the `for _n in …` guard. Verified:

    ( CTL=x _CONTROLS=x _HARNESS=x _MUTATIONS=x SELF=x SCRATCH=x K2RE=x \
      bash -c '. .claude/tools/webref-generic-core-trip-wire.mutations.sh' )
    # -> exit 2, "missing: $K2RE_PATH"

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…comment

`306 of the scan's 592 process spawns` was a pair of quantities that move with
every commit, with no command to reproduce them, describing a pipeline the same
sentence says no longer exists. The memo header's own rule is that a number that
matters appears as the command that produces it, so the figures are deleted
rather than re-measured; the header's record of where that rule was broken now
names this site as well as draft 1's.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The clause sat three lines above this comment's own `NO FIGURES HERE` rule and
restated the `~1s` justification that was already retired from `CLAUDE.md` —
where the ground for leaving the job ungated is the absence of a setup step, not
a duration. Deleted rather than re-measured: the block above says to derive the
runtime with `/usr/bin/time -p bash scripts/trip-wires.sh`, and `timeout-minutes`
is re-derived when a wire lands.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"it is below 1000 lines today" is a quantity that moves with every control this
PR adds — the defect the memo header forbids, in the bullet whose own subject is
that coupling. The claim is replaced by the check that answers it (`wc -l`) and a
pointer to §11.7 row 7, which records that the split it was guarding against has
already landed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…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>
…nes moving it

The before/after pair was measured against `origin/main`, and this PR's own diff
moves the baseline (`git show origin/main:.github/workflows/ci.yml | grep -n
timeout-minutes` -> 2 at that job; this branch -> 5), which is exactly the
disagreement the paragraph is about. The figures are deleted rather than
re-measured — the fact that matters, that #510 raises the budget, does not need
them, and the budget half is named as unowned three sentences later.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… now one

Row 22 opens by saying the slice memo is the one list and that the row does not
restate it, then restated §6's answer, its ground, its raised-not-imposed
standing and the budget half it leaves open; the cross-lane bullet restated the
same four things again. Both now point at §6, which keeps them: one issue, one
way. The bullet keeps only what is its own business — the act of raising it to
#510, and that the budget half has claimants but no owner.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…etires

The sentence that names the property the ungated-job decision rests on still
carried "the shell, `git` and `grep`" — the same three-tool enumeration the ⚠
four lines below it records as measured false by four reviewers, and the same one
`ci.yml`, `CLAUDE.md` and the wire header each name as retired. The list is
deleted, not corrected: a longer list is the failure shape the paragraph is
about. The surviving occurrences (:438, :473, ci.yml:134, the wire header,
CLAUDE.md) are all quotations marked as retired, verified by grepping both
spellings across the four sites.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…wo clumsy replacements

The header's new record of §9's breach credited the enumeration attestation with
finding it; §11.4's list of that attestation's memo findings does not contain the
spawn figures, so the attribution was asserted, not measured. It is dropped
rather than re-sourced. The two replacement clauses are reworded to say plainly
what a pipeline costs, with no figure either way.

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>
…ity and cannot return it

The audit table's 11 members live at `cat`, `readlink`, the `[ -L/-f/-e ]`
tests, `_absent`, `[ -s ]`, `: >` and the discarded `$(_scan)`; the grep
returns none of them. Measured on this head:

  /usr/bin/grep -n '=\$?\|^ *if ! _git\|elif ! _git\|)" || \|cmp -s' \
    .claude/tools/webref-generic-core-trip-wire.sh
  # -> 104 146 403 406 415 645 785 799 820 861 885 962 1037 1044 1062 1082
  #    1086 1099 1156 — none of the table's sites

The §11.4 sweep widened the table and left the derivation behind. This
file's own rule (item 5's ⚠, and the deleted seed above it) is that a
predicate which cannot return its population is a seed, not an authority,
so the sentence and its command are deleted rather than re-spelled.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Measured on this head: `ctl_ok=0` at :739, last assigned at :977,
consumed at :979 — two lines from the nearest assignment, 240 from the
first. No reading of the file gives three. The clause is deleted; the
sentence's point (these names belong to the controls, the data flow is
one-way) does not rest on it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…heck

"This memo states no quantity that moves with a commit" is a universal
over the whole file, and §4's "the four sibling wires" falsified it in
the same revision — a current-state count, not one of the historical
quantities the next sentence carves out. Narrowed to the rule it was
meant to be; the three sentences after it already read as a rule that
was hard to keep.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
§5 item 4 attributed `awk`, `sort`, `comm` and `wc` to "the four sibling
wires". Measured on this head:

  /usr/bin/grep -n '^[^#]*\bawk\b' .claude/tools/webref-generic-core-trip-wire*.sh
  # -> mutations.sh:438,544,593,600,610
  /usr/bin/grep -n '^[^#]*\bwc\b'  .claude/tools/webref-generic-core-trip-wire*.sh
  # -> mutations.sh:617

The split that created `mutations.sh` moved both into this instrument and
invalidated the attribution, and "the four" is a count that moves with a
commit. Both are dropped: the tools are named as the job's, which is what
the sentence needs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
§5 item 5 said "review rounds have since carried both files past the
threshold". Measured on this head:

  wc -l .claude/tools/webref-generic-core-trip-wire.sh          # 1259
  wc -l .claude/tools/webref-generic-core-trip-wire.controls.sh #  989

The harness split put the controls file back under, so the sentence is a
current-state quantity that is also false. Deleted; the adjacent
SUPERSEDED marker and §0's derivation command already carry what the
paragraph needs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…live, and its fixture claim is stale

Neither shape is in the scanned scope. Measured on this head:

  /usr/bin/grep -rn '=\.claude/'  .claude/tools/_webref .claude/tools/webref  # none
  /usr/bin/grep -rn '`\.claude/'  .claude/tools/_webref .claude/tools/webref  # none

`cli.py` spells its `--help` examples after whitespace, which is what the
controls' `textgreen` line (g) already says — so the memo and the
instrument contradicted each other. In the same paragraph, "every
red-direction fixture writes its path after a space or a quote" is
present tense over `linestart` (line start), `slashtext` (after `/`) and
`bnd` (`=`, `:`, a backtick, `**`, `,`), which were added by the round
being described.

Both are deleted rather than corrected — the R4 table above them already
shows the five spellings — and the disposition row's "two of them live in
scope" goes with them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…r the labels used

§11 uses D12 (§11.1's `PATH` row) and never uses D11. Measured on this
head:

  /usr/bin/grep -c '\bD11\b' docs/plans/2026-09-citation-hygiene-Ai-wire-k2-trip-wire.md  # 0
  /usr/bin/grep -c '\bD12\b' docs/plans/2026-09-citation-hygiene-Ai-wire-k2-trip-wire.md  # 1

So "D1–D10" is not the set of labels the section carries, and 3 CRIT + 7
IMP does not count them. Both are deleted; the rows below are the
enumeration.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"this one proves the wire can reach every verdict" contradicts this
file's own :9-11 ("Not all of them are covered — the verdict sites with
no control are a defer slot") and §8's slot
`#11-k2-wire-verdict-site-controls`. Measured on this head: 11 `exit 2`
verdict sites in the wire; 6 `_control` calls asserting exit 2, two of
them on the same site, plus the umask block — 5 sites uncovered (:401,
:437, :647, :1155, :1213).

Narrowed to what the file does: run the wire over a fixture and assert
the exit status.

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>
…ape past, then claimed every rule

`_mut_regex_mutants` handled bracket members and `*`/`+`, failed closed on
`?`/`{`, skipped `\X` at its second line, and walked `(` and `|` past as
ordinary characters. `$K2RE` holds three alternations and one escape and
`$K2RE_PATH` two and one, so the derived population of 38 contained no
alternation and no escape mutant — while the run printed "every rule
those two regexes spell is pinned by a control" and §11.7 row 6 said the
generator says *that* no rule is unwatched. Both are universals over a
population the generator did not return.

A fail-closed arm for `(`/`|` is not available: both live regexes hold
them. The missing mutants are derived instead, in the directions that
need no invented vocabulary — DROP-A-BRANCH, one per branch of each
alternation, and UNESCAPE, one per `\.`. Widening a branch list needs a
payload the scanner would have to make up, so it stays with the hand
records, and the printed sentence now says which half covers what.

Three new fail-closed arms come with the walk: a `|` outside any group,
an unmatched `)`, and a group left open at the end. Neither regex holds
one today, which is when such an arm is cheap.

Measured, 38 -> 50 mutants, `_mut_equivalent` still empty and no entry
added to it. All 50 killed, each raising a control:

  alt#1 without `^`            -> a reference at the start of a line fires
  alt#1 without the class      -> a reference written after a slash fires (+31 more)
  alt#2 without `skills`       -> K2 fires on the path A-i removed (+17 more)
  alt#2 without `tools`        -> K2 fires under the tools root too (+10 more)
  alt#3 without `<seg>/`       -> a ONE-character intermediate segment fires (+4 more)
  alt#3 without the final seg  -> K2 fires on a path never here (+29 more)
  escape#1 `\.`                -> running text that only looks like a two-segment
                                  reference stays green
  PATH alt#1 without `^`       -> an entry's own NAME is the hierarchy (+10 more)
  PATH alt#1 without `/`       -> a stored path naming .claude after a slash,
                                  under tools, fires
  PATH alt#2 without `skills`  -> an entry's own NAME is the hierarchy (+10 more)
  PATH alt#2 without `tools`   -> a stored path naming .claude after a slash,
                                  under tools, fires
  PATH escape#1 `\.`           -> a stored path that only looks like one stays green

The two unescape mutants widen, so both are caught by a GREEN control
going red — which is the direction a drop-a-branch mutant cannot reach.

No control and no hand record is added, so `_MUT_RECORDS_MIN` (95) and
`_MUT_UNRECORDED_MAX` (21) do not move, and the `trip-wires` job's
`timeout-minutes` is not re-derived: this half is opt-in behind
`WEBREF_WIRE_MUTANTS` and adds no fixture self-test to the gated run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…wo of its four edits

Self-review of the previous commit: three sibling statements of the
generated population were left behind by the sweep that widened it, and
one of them is the criterion the code is judged against.

* `mutations.sh` §"THE GENERATED SET": the derivation block enumerated
  only "member dropped" and "quantifier tightened". A spec narrower than
  the generator is the same defect as a claim wider than it — branch-drop
  and unescape are added, and the direction the scanner cannot reach
  (widening a branch list) is named there rather than left to the reader.
* `mutations.sh` fail-closed arm for `?`/`{`: it quoted the run's printed
  sentence, which the previous commit rewrote. Narrowed to the property
  the arm is about.
* memo §5 item 5's generator paragraph: same two-edit population, and
  the same "**that** every rule those two regexes spell is caught by one"
  the previous commit had removed from §11.7.

Comment-only; the wire is rc 0 and the measured population is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… it licensed

Two claims in the generated set's rationale, both left standing by round 4.

"Every boundary defect this wire has had was a member of a bracket
expression or the reach of a quantifier" is a universal over defects whose
record is not in this repo, so nothing here can falsify it — and round 4
falsified it anyway: the scanner was walking `(`, `|` and `\` past as
ordinary characters, so alternations and escapes were precisely where the
next defect lived. The sentence was the rationale for a scanner shape the
scanner no longer has, and it read as a map away from the gap. Deleted
rather than rewritten with the history appended; what survives is
present-tense and readable off the scanner.

"NEITHER IS DERIVABLE FROM THE OTHER" is true of the sets and false of four
records, now that the generator derives the group-drop and the unescape two
hand records each already pinned. An ambiguous universal is the instrument
this file exists to retire, so the clause goes and the permission stays.

Those four records are kept — removing them would strip their controls of a
record and push `_MUT_UNRECORDED_MAX` up, and a doubly-pinned mutant cannot
make the gate stay green wrongly. What they are is evidence: the data
showing the scanner skipped three constructs sat in this file for four
rounds, and no control reads it. That is stated where the overlap is.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@send

send commented Sep 26, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: 7881cb535b

ℹ️ 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".

@send
send merged commit e8f7889 into webref-cite-audit-tool Sep 26, 2026
@send
send deleted the webref-generic-core-trip-wire branch September 26, 2026 05:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant