@chrono-meta/fh-gate 1.4.96 → 1.4.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/CLAUDE.md +11 -4
- package/README.md +19 -0
- package/knowledge/shared/learnings/subagent_invocations_log.yaml +70 -0
- package/package.json +5 -2
- package/plugins/fh-commons/.claude-plugin/plugin.json +1 -1
- package/plugins/fh-meta/.claude-plugin/plugin.json +1 -1
- package/scripts/compaction_probe.sh +153 -10
- package/scripts/consent_registry_check.sh +63 -0
- package/scripts/lane_runner_check.sh +425 -0
- package/scripts/package_coverage_check.sh +182 -35
- package/scripts/psa_scan_lib.sh +164 -0
- package/scripts/public_surface_scan_files.sh +30 -0
- package/scripts/selfcheck.sh +332 -29
- package/scripts/test_consent_registry.sh +54 -0
- package/scripts/test_marker_crossfamily_lanes.sh +10 -1
- package/scripts/test_marker_floor_lanes.sh +25 -1
- package/scripts/test_psa_singlefile_lanes.sh +288 -0
- package/scripts/test_reviewer_capability_conformance.sh +10 -1
- package/scripts/test_selfcheck_state_lanes.sh +173 -0
- package/templates/goal-quench-settings-merged.json +30 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# lane_runner_check.sh — a lane suite that nothing executes is prose, not an anchor.
|
|
3
|
+
#
|
|
4
|
+
# WHY (measured 2026-08-12, reship axis, card §🔱⑮ A):
|
|
5
|
+
# The card recorded three repairs as "지워도 레인 초록" — delete the repair, the lanes stay green,
|
|
6
|
+
# i.e. the anchor is decorative. Investigating those three found the class is much wider: of 43 lane
|
|
7
|
+
# and test suites under scripts/, **12 had no runner anywhere** — not selfcheck.sh, not the git
|
|
8
|
+
# hooks, not the CI workflows (all three surfaces enumerated, not assumed). 9 of the 12 ship to npm
|
|
9
|
+
# consumers (`npm pack --dry-run --json`, 263 files — a tarball measurement, not a files[] reading).
|
|
10
|
+
# ⚠️ This header said **11 / 8** until 2026-08-13 while the DEBT block below said 12, and the
|
|
11
|
+
# discrepancy is not a typo: 11 was the HAND-ROLLED probe's count, 12 is what this check found on
|
|
12
|
+
# its first run (the hand probe had read a pre-commit COMMENT as wiring). The corrected number went
|
|
13
|
+
# into the array and the prose above it was left alone, so the file carried both. Caught by
|
|
14
|
+
# cross-family review, not by re-reading. ★ A file that states its own measurement twice will
|
|
15
|
+
# eventually state it two different ways — and the stale copy is the one a reader meets first.
|
|
16
|
+
# The sharpest case was scripts/test_marker_floor_lanes.sh: pre-commit's
|
|
17
|
+
# validate_marker_floor() is live and blocks real commits, while its own known-pair calibration has
|
|
18
|
+
# never executed. A shipped gate whose calibration is dead is exactly the defect this repo spent the
|
|
19
|
+
# 2026-08-11/12 campaign closing, one file at a time.
|
|
20
|
+
#
|
|
21
|
+
# WHY A DERIVED CHECK AND NOT 12 MORE ANCHORS (the actual design decision):
|
|
22
|
+
# "Wire each one" closes today's 12 and is blind to the 13th — and the 13th is not hypothetical: the
|
|
23
|
+
# first run of THIS check found one (test_marker_crossfamily_lanes.sh) that the hand-rolled probe
|
|
24
|
+
# behind the original count had misread, because the hook names it only in a comment.
|
|
25
|
+
#
|
|
26
|
+
# ⚠️ THE JUSTIFICATION FOR BUILDING THIS IS THE MEASUREMENT, NOT A RECURRENCE COUNT — and the first
|
|
27
|
+
# draft of this header got that wrong. It claimed N=3 for "hardcoded list where a derived one is
|
|
28
|
+
# available" (citing selfcheck's `for _subj in compaction_probe judgment_circuit_lint
|
|
29
|
+
# novelty_claim_check`, test_selfcheck_state_lanes' four-name list, and the same-day ACCEPTED_ABSENT
|
|
30
|
+
# fix) and leaned on [[feedback_mechanize_at_repetition_prose_before]]'s N≥3 threshold. An
|
|
31
|
+
# independent scan refuted the count using this repo's own discriminator — "첫 발생 직후 고쳤다면
|
|
32
|
+
# 나머지가 막혔겠는가": the ACCEPTED_ABSENT fix is what CREATED the helper that exposed the second
|
|
33
|
+
# site, so those two are one discovery, not two recurrences; and the compaction_probe fix runs the
|
|
34
|
+
# OPPOSITE direction (no declaration existed there, so the correct fix was to start consulting the
|
|
35
|
+
# environment and assert both arms). Honest count for that class: **N=1–2, below threshold.**
|
|
36
|
+
#
|
|
37
|
+
# What actually justifies this file is a direct measurement, which needs no recurrence argument:
|
|
38
|
+
# **12 of 43 lane suites execute nowhere**, 8 of them shipped, including the calibrations for two
|
|
39
|
+
# gates that block real commits. That is a present hole, not a predicted one. Where the derived form
|
|
40
|
+
# is genuinely doing work is narrower and worth stating plainly: it is what makes the DEBT list
|
|
41
|
+
# shrink-only and what fails on the 13th — not a claim that hardcoded lists are a recurring disease
|
|
42
|
+
# here.
|
|
43
|
+
#
|
|
44
|
+
# THREE-VALUED, and the middle value is the whole point:
|
|
45
|
+
# WIRED — some runner invokes it (selfcheck · git hook · CI workflow · another script's dispatch)
|
|
46
|
+
# EXEMPT — declared below with a reason it must NOT be auto-run (cost, live CLI, network)
|
|
47
|
+
# DEBT — known-unwired, listed below, counted loudly on every run, does NOT block
|
|
48
|
+
# An undeclared unwired suite is none of these and FAILS. That is the regrowth this file exists to
|
|
49
|
+
# stop: today's 11 are debt, tomorrow's 12th is a failure.
|
|
50
|
+
#
|
|
51
|
+
# WHY DEBT DOESN'T BLOCK: 11 suites cannot be wired in one sitting, and a check that fails for weeks
|
|
52
|
+
# is a check that trains `--no-verify` — this repo has logged that trade explicitly
|
|
53
|
+
# ([[feedback_overblock_traded_for_failopen]]). The DEBT list is a decision surface, not a silencer:
|
|
54
|
+
# every entry is printed on every run, and the count is a number someone has to look at.
|
|
55
|
+
#
|
|
56
|
+
# Usage: bash scripts/lane_runner_check.sh [--list-debt]
|
|
57
|
+
# Exit: 0 = every suite is WIRED, EXEMPT, or declared DEBT · 1 = an undeclared suite has no runner,
|
|
58
|
+
# or the instrument itself broke (zero suites scanned / dead control).
|
|
59
|
+
set -uo pipefail
|
|
60
|
+
|
|
61
|
+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
62
|
+
cd "$REPO_ROOT" || exit 1
|
|
63
|
+
|
|
64
|
+
# ── EXEMPT — declared reasons a suite must NOT be auto-run ────────────────────────────────────
|
|
65
|
+
# Same rule as package_coverage_check.sh's ACCEPTED_ABSENT: if you cannot write the sentence, the
|
|
66
|
+
# suite probably belongs in a runner instead of here.
|
|
67
|
+
#
|
|
68
|
+
# test_sessionstart_multihook_lanes.sh — spends live `claude` CLI calls (auth + tokens) on whoever
|
|
69
|
+
# runs it. selfcheck DOES reference it, via the SessionStart anchor-pair loop, and routes its
|
|
70
|
+
# exit 2 to NOT EXERCISED; it is listed here only so a future reader does not "fix" that loop
|
|
71
|
+
# into an unconditional run.
|
|
72
|
+
EXEMPT=(
|
|
73
|
+
"test_sessionstart_multihook_lanes.sh"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# ── DEBT — measured unwired on 2026-08-12, each awaiting a runner ─────────────────────────────
|
|
77
|
+
# This list is the todo, and it must only ever shrink. Adding a line here is a decision that needs a
|
|
78
|
+
# reason in the commit message; the check does not care, but the reviewer should.
|
|
79
|
+
# 🟥 WHAT `DEBT: 0` DOES NOT MEAN — read before quoting the number anywhere.
|
|
80
|
+
# The scope of this check is a NAME CONVENTION: `suites` is globbed as `test_*.sh` / `*_lanes.sh`
|
|
81
|
+
# (see the glob above). A lane suite that lives INSIDE its subject as a `--self-test` dispatcher has
|
|
82
|
+
# no such filename and is structurally invisible here. Measured 2026-08-13, after DEBT hit zero:
|
|
83
|
+
# scripts/chamber_witness.sh --self-test 16 lanes --self-test callers: 0
|
|
84
|
+
# scripts/capability_registry_check.sh --self-test 7 lanes --self-test callers: 0
|
|
85
|
+
# scripts/digest_landing_check.sh --self-test 10 lanes --self-test callers: 0
|
|
86
|
+
# scripts/directional_diff_gate.sh --self-test --self-test callers: 0
|
|
87
|
+
# 🟥 READ THAT COLUMN EXACTLY: it counts dispatches of `--self-test`, NOT callers of the script.
|
|
88
|
+
# The two come apart, and collapsing them does real damage in both directions. chamber_witness.sh
|
|
89
|
+
# has FOUR live production callers (chamber_run.sh:118·137·158·182) and zero self-test dispatches:
|
|
90
|
+
# writing that as "zero callers" would falsify the evidence sentence that ship_readiness_gate.md's
|
|
91
|
+
# identity-② promotion rests on ("wired into chamber_run.sh steps 2–5"), and ② would be overturned
|
|
92
|
+
# for a reason that is not true. The reverse shorthand is just as wrong: having production callers
|
|
93
|
+
# does NOT discharge the self-test debt — a witness generator whose known-pair never runs can break
|
|
94
|
+
# silently while every run that uses it still reports success, which is the fail-open the promotion
|
|
95
|
+
# criterion is supposed to exclude. (Both halves named by a peer session on 2026-08-13, after my
|
|
96
|
+
# own summary of this block used the collapsing shorthand.)
|
|
97
|
+
# (callers = grep over selfcheck.sh + .github/workflows/*.yml + templates/.git-hooks/*, the same
|
|
98
|
+
# three surfaces this check enumerates. All four SHIP.) selfcheck.sh wires exactly three embedded
|
|
99
|
+
# self-tests by name — compaction_probe · judgment_circuit_lint · novelty_claim_check — and these
|
|
100
|
+
# four are not among them. So the debt number below is true of the filename-convention population
|
|
101
|
+
# and false of "every lane suite in this repo executes". A second lens over `--self-test` dispatchers is
|
|
102
|
+
# the honest next step and is NOT built here; it is carried to the card as a measured residual so
|
|
103
|
+
# the number in this file cannot be read as a claim it does not make.
|
|
104
|
+
# (Raised by adversarial review against this delta, which called C1 "partially refuted" for exactly
|
|
105
|
+
# this reason. It was right: the denominator was mine to state and I had stated it as if it were the
|
|
106
|
+
# population.)
|
|
107
|
+
#
|
|
108
|
+
# ── 12 → 2 as of 2026-08-13 (PR: reship — lane-debt wiring) ──────────────────────────────────
|
|
109
|
+
# TEN of the twelve are discharged by the pair-loop in scripts/selfcheck.sh. TWO are back here,
|
|
110
|
+
# and the point of this block is that THE REASON CHANGED. Before today the entry meant "nothing
|
|
111
|
+
# runs this, and we do not know what happens if it does". Now it means "we ran it, and it fails
|
|
112
|
+
# outside this operator's machine" — which is a different, smaller, and actionable debt.
|
|
113
|
+
#
|
|
114
|
+
# What the twelve were: capability_entrypoint_shipping · chamber_run · destructive_pre_gate ·
|
|
115
|
+
# env_purity · field_canon · frontier_digest_retry · knowledge_seam · marker_crossfamily ·
|
|
116
|
+
# marker_floor · residency_closure · reviewer_capability_conformance · stale_clone_guard.
|
|
117
|
+
# Nine were in the published tarball, so consumers carried nine suites nothing called. The two
|
|
118
|
+
# that mattered most were the marker pair: test_marker_crossfamily_lanes.sh calibrates the
|
|
119
|
+
# `crossfamily:` enum that has hard-blocked commits since 2026-08-08 (the hook names it only in a
|
|
120
|
+
# COMMENT — templates/.git-hooks/pre-commit:1068 — which is what made a hand-rolled probe report
|
|
121
|
+
# 11 not 12), and test_marker_floor_lanes.sh calibrates pre-commit's live validate_marker_floor().
|
|
122
|
+
# Both are wired now.
|
|
123
|
+
#
|
|
124
|
+
# 🟥 THE TWO BELOW WERE WIRED, MEASURED RED IN CI, AND DELIBERATELY MOVED BACK. Making them green
|
|
125
|
+
# was available and is the wrong move: their failures are TRUE — the suites really do depend on
|
|
126
|
+
# things a CI runner does not have — so forcing a pass would be routing a real failure to green in
|
|
127
|
+
# the same delta that spent nine repairs closing exactly that. A suite whose preconditions are
|
|
128
|
+
# undeclared belongs in the todo list, not in the mandatory path.
|
|
129
|
+
DEBT=(
|
|
130
|
+
# PASS 19 · FAIL 0 locally; PASS 12 · FAIL 7 in CI. Reproduced locally by pointing HOME at an
|
|
131
|
+
# empty directory — 12/7, the same split — so the dependency is exact and not a guess:
|
|
132
|
+
# field_canon_preload.sh resolves `${HOME}/projects` and seven lanes assume the operator's
|
|
133
|
+
# mapped-project layout is there. Nothing in the suite declares that precondition, so on a
|
|
134
|
+
# machine without it the suite reports a REGRESSION rather than "not exercised here".
|
|
135
|
+
# Fix before re-wiring: the suite must detect the missing layout and exit NOT-EXERCISED (the
|
|
136
|
+
# shape test_sessionstart_multihook_lanes.sh already uses for its CLI dependency), or build its
|
|
137
|
+
# own fixture HOME for those seven the way it already does for the no-HOME lane.
|
|
138
|
+
"test_field_canon_lanes.sh"
|
|
139
|
+
# 17/17 locally; 2/17 in CI. And this one was PREDICTED: the adversarial review of this very
|
|
140
|
+
# delta flagged `elapsed < 10` as a wall-clock assertion that would go falsely red on a loaded CI
|
|
141
|
+
# runner, naming this file and that line. It was filed as a low-severity residual and not acted
|
|
142
|
+
# on; CI then produced exactly it. ★ The finding named a MECHANISM (a wall-clock assertion is now
|
|
143
|
+
# on a mandatory path), and a mechanism does not become less true for being labelled R.
|
|
144
|
+
# Fix before re-wiring: give the timing assertions headroom or gate them behind an explicit
|
|
145
|
+
# opt-in, so the default run measures logic and not the runner's load.
|
|
146
|
+
"test_stale_clone_guard_lanes.sh"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
if [ "${1:-}" = "--list-debt" ]; then
|
|
150
|
+
# Same bash-3.2 empty-array guard as the scan call below. This site was MISSED when that one was
|
|
151
|
+
# fixed in the same commit — the fix stopped at the two sites the failing run happened to touch,
|
|
152
|
+
# and `--list-debt` (a documented interface, see Usage above) still died with `unbound variable`.
|
|
153
|
+
# Caught by adversarial review, not by me. [[feedback_half_fix_propagation_boundary]]: the
|
|
154
|
+
# question a repair must ask is "where else does this fact have to reach", and "the sites my
|
|
155
|
+
# repro exercised" is not an answer to it.
|
|
156
|
+
printf '%s\n' "${DEBT[@]+"${DEBT[@]}"}"
|
|
157
|
+
exit 0
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
# ── SELF-REFERENCE: this checker is not a lane suite, so it does not appear in its own scanned set
|
|
161
|
+
# (the name pattern below matches `test_*.sh` / `*_lanes.sh`, and this is neither). That gap is the
|
|
162
|
+
# exact defect this file exists to detect, one level up: unwire it and nothing notices, because the
|
|
163
|
+
# only thing that would notice is itself. Measured by a revert probe on the day it was written —
|
|
164
|
+
# removing its call from selfcheck.sh left every check green, this one included.
|
|
165
|
+
# Guarded on selfcheck.sh's presence so a tree that legitimately lacks it does not fail here.
|
|
166
|
+
if [ -f scripts/selfcheck.sh ] && ! grep -qE '^[[:space:]]*(if !? ?)?bash scripts/lane_runner_check\.sh' scripts/selfcheck.sh; then
|
|
167
|
+
echo "FAIL lane-runner: scripts/selfcheck.sh no longer invokes this check — the checker that"
|
|
168
|
+
echo " detects unrun suites is itself unrun. Restore the call in selfcheck.sh."
|
|
169
|
+
exit 1
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
# `"${ARR[@]+"${ARR[@]}"}"` and not the plain `"${ARR[@]}"`: on bash 3.2 (stock macOS) `set -u`
|
|
173
|
+
# treats an EMPTY array's expansion as an unbound variable and aborts. DEBT is now empty by design,
|
|
174
|
+
# which is exactly the state the plain form cannot survive — measured here 2026-08-13, and it
|
|
175
|
+
# aborted so early that the script still printed PASS (see the rc routing further down).
|
|
176
|
+
out=$(python3 - "${#EXEMPT[@]}" "${EXEMPT[@]+"${EXEMPT[@]}"}" "${DEBT[@]+"${DEBT[@]}"}" <<'PY'
|
|
177
|
+
import os, re, sys, glob, json
|
|
178
|
+
|
|
179
|
+
n_exempt = int(sys.argv[1])
|
|
180
|
+
exempt = set(sys.argv[2:2 + n_exempt])
|
|
181
|
+
debt = set(sys.argv[2 + n_exempt:])
|
|
182
|
+
|
|
183
|
+
# Suites: deduped by NAME. An earlier draft globbed `scripts/*_lanes.sh` and `scripts/test_*.sh`
|
|
184
|
+
# separately and summed them — every `test_*_lanes.sh` matched both, inflating 43 to 75. The count
|
|
185
|
+
# was never published; it was caught because a hand-check of one case disagreed with it
|
|
186
|
+
# (CLAUDE.md §Instrument-Calibration, hand-verify-one-sample). Keep this a set.
|
|
187
|
+
suites = sorted({os.path.basename(f) for f in glob.glob('scripts/*.sh')
|
|
188
|
+
if re.match(r'^(test_.*|.*_lanes)\.sh$', os.path.basename(f))})
|
|
189
|
+
|
|
190
|
+
# Runner surfaces, enumerated rather than assumed. All three were checked by hand when this file was
|
|
191
|
+
# written: CI runs `bash scripts/selfcheck.sh` + count_check + the plugin validators and nothing else.
|
|
192
|
+
SELF = os.path.basename(__file__) if '__file__' in dir() else 'lane_runner_check.sh'
|
|
193
|
+
runners = []
|
|
194
|
+
for pat in ('scripts/*.sh', 'templates/.git-hooks/*', '.github/workflows/*.yml'):
|
|
195
|
+
runners += [p for p in glob.glob(pat) if os.path.isfile(p)]
|
|
196
|
+
# This file names every DEBT and EXEMPT suite in its own arrays. Scanning itself would read each of
|
|
197
|
+
# those declarations as evidence the suite is run — the check would certify its own todo list as
|
|
198
|
+
# done. Caught by the known-negative control below on the first execution.
|
|
199
|
+
runners = [r for r in runners if os.path.basename(r) != 'lane_runner_check.sh']
|
|
200
|
+
|
|
201
|
+
# An invocation is `bash <path-ending-in-suite>`, not a mention of the name. The bounded `.{0,60}?`
|
|
202
|
+
# spans wrappers like `exec bash "$(dirname "$0")/x.sh"` (which contains a space inside the command
|
|
203
|
+
# substitution) without running to the end of an arbitrary line.
|
|
204
|
+
INVOKE = re.compile(r'\b(?:exec\s+)?(?:bash|sh)\s+.{0,60}?')
|
|
205
|
+
|
|
206
|
+
def has_runner(suite):
|
|
207
|
+
"""A mention is not an invocation. Comments, package.json files[] entries and prose references in
|
|
208
|
+
tracks/ all name suites without running them — that conflation is what made the original count
|
|
209
|
+
wrong (75 vs the real 43).
|
|
210
|
+
|
|
211
|
+
Two measured failures shaped this predicate, both caught by the controls rather than by review:
|
|
212
|
+
· `\\b(bash|sh)\\b` matched the `sh` inside the `.sh` extension itself, so ANY line naming a
|
|
213
|
+
suite counted as running it — every suite read as WIRED, including the known-negative.
|
|
214
|
+
· An earlier quote-anchored regex missed `exec bash "$(dirname "$0")/x.sh"` and reported NONE
|
|
215
|
+
for a suite a hand-check had already confirmed was dispatched.
|
|
216
|
+
Both are the same class: the predicate was re-spelled instead of being pinned to a known pair."""
|
|
217
|
+
for r in runners:
|
|
218
|
+
if os.path.basename(r) == suite:
|
|
219
|
+
continue
|
|
220
|
+
try:
|
|
221
|
+
txt = open(r, encoding='utf-8', errors='replace').read()
|
|
222
|
+
except OSError:
|
|
223
|
+
continue
|
|
224
|
+
if runner_dispatches(suite, txt):
|
|
225
|
+
return True
|
|
226
|
+
return False
|
|
227
|
+
|
|
228
|
+
def runner_dispatches(suite, txt):
|
|
229
|
+
"""The whole predicate, over ONE runner's text. Split out from has_runner so the controls below
|
|
230
|
+
can drive it with synthetic fixtures instead of with whatever the repo happens to look like
|
|
231
|
+
today — see the CONTROL block for why that mattered."""
|
|
232
|
+
direct = re.compile(r'\b(?:exec\s+)?(?:bash|sh)\s+.{0,60}?' + re.escape(suite))
|
|
233
|
+
lines = txt.split('\n')
|
|
234
|
+
# Does this runner invoke ANYTHING through a variable? If so, a suite named in one of its
|
|
235
|
+
# list constructs is plausibly dispatched by that loop.
|
|
236
|
+
indirect_dispatch = any(
|
|
237
|
+
re.search(r'\b(?:exec\s+)?(?:bash|sh)\s+"?\$', ln)
|
|
238
|
+
for ln in lines if not ln.strip().startswith('#'))
|
|
239
|
+
for line in lines:
|
|
240
|
+
if suite not in line or line.strip().startswith('#'):
|
|
241
|
+
continue
|
|
242
|
+
if direct.search(line):
|
|
243
|
+
return True
|
|
244
|
+
# for-list idiom, used twice in selfcheck.sh:
|
|
245
|
+
# for _anchor in scripts/a.sh scripts/b.sh; do ... bash "$_anchor" ... done
|
|
246
|
+
# for _pair in "subject|scripts/x.sh|mode" ...; do ... bash "$_anc" ... done
|
|
247
|
+
# The literal name is in the list; the invocation is through the variable, so the direct
|
|
248
|
+
# pattern above structurally cannot see it. Hand-verified 2026-08-12 for both
|
|
249
|
+
# test_session_close_lanes.sh and test_wizard_snippet_merge_lanes.sh — the strict
|
|
250
|
+
# detector called both UNWIRED and both are genuinely run.
|
|
251
|
+
# Gated on the file actually containing a variable dispatch, so a prose mention in a
|
|
252
|
+
# script that never runs anything indirectly does not get a free pass.
|
|
253
|
+
if indirect_dispatch and re.match(r'\s*(for\s+\w+\s+in\b|["\']?\S*\|)', line):
|
|
254
|
+
return True
|
|
255
|
+
return False
|
|
256
|
+
|
|
257
|
+
wired = {s for s in suites if has_runner(s)}
|
|
258
|
+
|
|
259
|
+
# ── CONTROL: the instrument must be able to see a suite known to be wired, and must NOT see one
|
|
260
|
+
# known to be dead. Without both arms a broken detector reports "all clean" or "all broken" and
|
|
261
|
+
# either reads as a verdict. [[feedback_absence_measurement_needs_control]]
|
|
262
|
+
CTL_POS = 'test_selfcheck_state_lanes.sh' # selfcheck.sh invokes this DIRECTLY
|
|
263
|
+
CTL_POS2 = 'test_session_close_lanes.sh' # selfcheck.sh:613 for-list + `bash "$_anchor"` — the
|
|
264
|
+
# INDIRECT arm. Pins the second detection branch: the
|
|
265
|
+
# strict detector called this UNWIRED and a hand-check
|
|
266
|
+
# showed it runs. Without this control that branch
|
|
267
|
+
# could silently rot back to blind.
|
|
268
|
+
# ── the known-NEGATIVE arm is now synthetic, and that is a repair, not a weakening ────────────
|
|
269
|
+
# It used to name a real suite (test_residency_closure_lanes.sh) that had zero callers. On
|
|
270
|
+
# 2026-08-13 the DEBT list was discharged, that suite gained a runner, and the control fired:
|
|
271
|
+
# "known-negative read as WIRED — the detector over-matches". The detector was fine. The CONTROL
|
|
272
|
+
# had been anchored to WORK NOT YET DONE, so doing the work broke the instrument. A negative
|
|
273
|
+
# control that lives on the todo list dies the moment the todo list is emptied — and it dies
|
|
274
|
+
# LOUDLY, as a false accusation against the thing it was guarding, which is the worst possible
|
|
275
|
+
# time to be debugging your own instrument.
|
|
276
|
+
# So the negative arm is driven with fixture text instead. The three fixtures are the three ways a
|
|
277
|
+
# name appears WITHOUT being run, all of them observed in this repo:
|
|
278
|
+
# · in a comment (every DEBT/EXEMPT declaration, and the pre-commit:1068 mention that fooled a
|
|
279
|
+
# hand-rolled probe into reporting 11 instead of 12)
|
|
280
|
+
# · in a manifest-style list with no dispatch anywhere in the file (package.json files[])
|
|
281
|
+
# · next to a `bash -n "$f"` syntax-check loop over a glob — flagged 2026-08-13 by a peer session
|
|
282
|
+
# as the way a DEBT count could be silently understated, since that loop touches every script
|
|
283
|
+
# in the tree. Pinned here so the answer stays measured rather than argued: syntax-checking a
|
|
284
|
+
# file is not running its lanes, and `bash -n` must never satisfy this predicate.
|
|
285
|
+
# 🟥 NAMED RESIDUAL — the indirect branch is a KNOWN BYPASS, and the claim is narrowed accordingly.
|
|
286
|
+
# Both an in-family adversarial review and an independent cross-family audit (codex/gpt-5.5) landed
|
|
287
|
+
# on this same hole on 2026-08-13, and the cross-family one reproduced it against the predicate
|
|
288
|
+
# itself: a file that contains `bash "$ANY_VAR"` ANYWHERE, plus a line of the shape
|
|
289
|
+
# `"x|scripts/test_future_lanes.sh|y"`, reads as WIRED even when nothing dispatches that list.
|
|
290
|
+
# So "an undeclared unwired suite cannot regrow" is true of a suite nobody MENTIONS and false of one
|
|
291
|
+
# added decoratively to an existing pair table. It is documented rather than closed because
|
|
292
|
+
# narrowing the branch to same-loop-body variable matching would put both real known-positives
|
|
293
|
+
# (selfcheck.sh:723 and :630) at risk, and this file sits exactly where "the repair is the main
|
|
294
|
+
# source of the next defect" has already been measured. The fixture below pins the CURRENT
|
|
295
|
+
# permissive behaviour so that a future narrowing is a visible, deliberate change rather than a
|
|
296
|
+
# silent one — it asserts what IS, not what should be.
|
|
297
|
+
CTL_BYPASS_FIXTURE = (
|
|
298
|
+
'#!/usr/bin/env bash\nbash "$UNRELATED"\n'
|
|
299
|
+
' "subject|scripts/test_control_never_wired_lanes.sh|mode"\n')
|
|
300
|
+
CTL_NEG_NAME = 'test_control_never_wired_lanes.sh'
|
|
301
|
+
CTL_NEG_FIXTURES = [
|
|
302
|
+
("comment-only mention",
|
|
303
|
+
'#!/usr/bin/env bash\nbash "$SOME_OTHER"\n# see test_control_never_wired_lanes.sh for detail\n'),
|
|
304
|
+
("manifest-style list, no dispatch in file",
|
|
305
|
+
'{\n "files": [\n "scripts/test_control_never_wired_lanes.sh"\n ]\n}\n'),
|
|
306
|
+
("bash -n glob loop + prose mention",
|
|
307
|
+
'#!/usr/bin/env bash\nfor f in scripts/*.sh; do bash -n "$f" || fail=1; done\n'
|
|
308
|
+
'echo "coverage includes scripts/test_control_never_wired_lanes.sh"\n'),
|
|
309
|
+
]
|
|
310
|
+
ctl = []
|
|
311
|
+
if CTL_POS in suites and CTL_POS not in wired:
|
|
312
|
+
ctl.append(f"known-positive {CTL_POS} read as UNWIRED — the direct detector is blind")
|
|
313
|
+
if CTL_POS2 in suites and CTL_POS2 not in wired:
|
|
314
|
+
ctl.append(f"known-positive {CTL_POS2} read as UNWIRED — the for-list/indirect branch is blind")
|
|
315
|
+
for _why, _txt in CTL_NEG_FIXTURES:
|
|
316
|
+
if runner_dispatches(CTL_NEG_NAME, _txt):
|
|
317
|
+
ctl.append(f"known-negative ({_why}) read as WIRED — the detector over-matches")
|
|
318
|
+
# The fixtures above drive `runner_dispatches` DIRECTLY, which leaves the layer between it and
|
|
319
|
+
# `has_runner` uncontrolled — runner enumeration, and in particular the self-exclusion filter that
|
|
320
|
+
# keeps this file out of its own scanned set. That filter is load-bearing: without it, every name
|
|
321
|
+
# declared in the arrays here reads as evidence that the suite runs, and the check certifies its own
|
|
322
|
+
# todo list as done. The old real-suite known-negative used to cover that path incidentally; the
|
|
323
|
+
# fixtures do not, so the loss is pinned explicitly rather than left as an unstated regression
|
|
324
|
+
# (raised by adversarial review, which was right that C4 was a strengthening AND a narrowing).
|
|
325
|
+
if any(os.path.basename(r) == 'lane_runner_check.sh' for r in runners):
|
|
326
|
+
ctl.append("self-exclusion filter is gone — this file is in its own runner set, so every name "
|
|
327
|
+
"in DEBT/EXEMPT would read as WIRED")
|
|
328
|
+
if not runners:
|
|
329
|
+
ctl.append("runner enumeration collapsed to zero — every suite would read as UNWIRED")
|
|
330
|
+
# And the positive arm on fixture text too, so the negative arm cannot pass by the predicate simply
|
|
331
|
+
# having gone blind — a detector that answers False to everything satisfies three negatives.
|
|
332
|
+
if not runner_dispatches(CTL_NEG_NAME, 'bash scripts/test_control_never_wired_lanes.sh\n'):
|
|
333
|
+
ctl.append("fixture known-positive read as UNWIRED — the predicate answers False to everything")
|
|
334
|
+
# Pins the documented bypass above. If this ever stops holding, someone narrowed the indirect branch
|
|
335
|
+
# — which may well be the right move, but it must be a decision, and both real known-positives above
|
|
336
|
+
# have to be re-confirmed at the same time. Update this line and the residual note together.
|
|
337
|
+
if not runner_dispatches(CTL_NEG_NAME, CTL_BYPASS_FIXTURE):
|
|
338
|
+
ctl.append("the documented indirect-branch bypass no longer reproduces — the predicate was "
|
|
339
|
+
"narrowed. That is not a failure, but the residual note above is now stale and the "
|
|
340
|
+
"two real for-list known-positives must be re-verified before removing this check.")
|
|
341
|
+
if ctl:
|
|
342
|
+
print("CONTROL_FAILED\t" + " · ".join(ctl))
|
|
343
|
+
raise SystemExit(2)
|
|
344
|
+
|
|
345
|
+
if not suites:
|
|
346
|
+
print("EXTRACTOR_BROKE\tzero lane suites found under scripts/")
|
|
347
|
+
raise SystemExit(2)
|
|
348
|
+
|
|
349
|
+
undeclared = sorted(s for s in suites if s not in wired and s not in exempt and s not in debt)
|
|
350
|
+
# A DEBT entry that has since gained a runner is resolved — say so, so the list shrinks by evidence
|
|
351
|
+
# rather than by someone remembering. Same shape as package_coverage_check.sh's STALE report.
|
|
352
|
+
resolved = sorted(s for s in debt if s in wired)
|
|
353
|
+
# A DEBT entry that no longer exists at all (renamed/deleted) is also stale.
|
|
354
|
+
gone = sorted(s for s in debt if s not in suites)
|
|
355
|
+
|
|
356
|
+
print(f"COUNTS\t{len(suites)}\t{len(wired)}\t{len(exempt)}\t{len(debt)}")
|
|
357
|
+
for s in undeclared:
|
|
358
|
+
print(f"UNDECLARED\t{s}")
|
|
359
|
+
for s in resolved:
|
|
360
|
+
print(f"RESOLVED\t{s}")
|
|
361
|
+
for s in gone:
|
|
362
|
+
print(f"GONE\t{s}")
|
|
363
|
+
PY
|
|
364
|
+
)
|
|
365
|
+
rc=$?
|
|
366
|
+
|
|
367
|
+
if [ "$rc" -eq 2 ]; then
|
|
368
|
+
echo "FAIL lane-runner: the instrument broke, it did not pass"
|
|
369
|
+
printf '%s\n' "$out" | sed 's/^/ /'
|
|
370
|
+
exit 1
|
|
371
|
+
fi
|
|
372
|
+
|
|
373
|
+
# ANY other non-zero is also the instrument failing, and it used to fall straight through to the
|
|
374
|
+
# PASS line below. Measured 2026-08-13, on this file, by the change that emptied DEBT: under
|
|
375
|
+
# `set -u` on bash 3.2 (stock macOS) an EMPTY array expanded with "${DEBT[@]}" is an UNBOUND
|
|
376
|
+
# VARIABLE, so the heredoc never ran, `out` was empty, every count parsed as 0 via the `${1:-0}`
|
|
377
|
+
# defaults — and the script printed `PASS lane-runner: 0 suites`. A dead instrument reported a
|
|
378
|
+
# clean tree. Only rc==2 was handled because only rc==2 had ever been produced deliberately;
|
|
379
|
+
# everything else was assumed impossible rather than routed. That assumption is the defect class
|
|
380
|
+
# this whole file exists to catch, reproduced inside the catcher.
|
|
381
|
+
if [ "$rc" -ne 0 ]; then
|
|
382
|
+
echo "FAIL lane-runner: the scan exited $rc — the instrument did not complete, so this run"
|
|
383
|
+
echo " measured nothing. It is not a pass. (An empty result set is NOT an empty todo list.)"
|
|
384
|
+
printf '%s\n' "$out" | head -5 | sed 's/^/ /'
|
|
385
|
+
exit 1
|
|
386
|
+
fi
|
|
387
|
+
|
|
388
|
+
COUNTS=$(printf '%s\n' "$out" | awk -F'\t' '$1=="COUNTS"{print $2" "$3" "$4" "$5}')
|
|
389
|
+
set -- $COUNTS
|
|
390
|
+
TOTAL="${1:-0}"; WIRED="${2:-0}"; N_EXEMPT="${3:-0}"; N_DEBT="${4:-0}"
|
|
391
|
+
|
|
392
|
+
UNDECLARED=$(printf '%s\n' "$out" | awk -F'\t' '$1=="UNDECLARED"{print $2}')
|
|
393
|
+
RESOLVED=$(printf '%s\n' "$out" | awk -F'\t' '$1=="RESOLVED"{print $2}')
|
|
394
|
+
GONE=$(printf '%s\n' "$out" | awk -F'\t' '$1=="GONE"{print $2}')
|
|
395
|
+
|
|
396
|
+
if [ -n "$UNDECLARED" ]; then
|
|
397
|
+
echo "FAIL lane-runner: lane suite(s) with no runner and no declaration:"
|
|
398
|
+
printf '%s\n' "$UNDECLARED" | sed 's/^/ /'
|
|
399
|
+
echo " A suite nothing executes is prose. Fix by ONE of:"
|
|
400
|
+
echo " · wire it into scripts/selfcheck.sh (the usual answer)"
|
|
401
|
+
echo " · add it to EXEMPT here WITH the reason it must not be auto-run"
|
|
402
|
+
echo " · add it to DEBT here if it is known-unwired work you are deferring"
|
|
403
|
+
exit 1
|
|
404
|
+
fi
|
|
405
|
+
|
|
406
|
+
# Advisory, never blocking — a stale DEBT entry is hygiene, and converting a clean run into a red
|
|
407
|
+
# gate over bookkeeping is how the check stops being read.
|
|
408
|
+
if [ -n "$RESOLVED" ]; then
|
|
409
|
+
echo "⚠️ lane-runner: DEBT entry(ies) now have a runner — remove them from DEBT:"
|
|
410
|
+
printf '%s\n' "$RESOLVED" | sed 's/^/ /'
|
|
411
|
+
fi
|
|
412
|
+
if [ -n "$GONE" ]; then
|
|
413
|
+
echo "⚠️ lane-runner: DEBT entry(ies) no longer exist (renamed/deleted?) — remove them:"
|
|
414
|
+
printf '%s\n' "$GONE" | sed 's/^/ /'
|
|
415
|
+
fi
|
|
416
|
+
|
|
417
|
+
if [ "$N_DEBT" -gt 0 ]; then
|
|
418
|
+
echo "⚠️ lane-runner: ${N_DEBT} suite(s) still have NO runner (declared debt — see DEBT for the"
|
|
419
|
+
echo " per-entry reason and the date each was measured; they are not all from one measurement)."
|
|
420
|
+
echo " They are shipped or present but never execute — see DEBT in this file. This number must"
|
|
421
|
+
echo " only go down; a new one fails the check rather than joining the list silently."
|
|
422
|
+
fi
|
|
423
|
+
|
|
424
|
+
echo "PASS lane-runner: ${TOTAL} suites — ${WIRED} wired · ${N_EXEMPT} exempt · ${N_DEBT} declared debt"
|
|
425
|
+
exit 0
|