@chrono-meta/fh-gate 2.15.0 β†’ 3.0.0

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.
Files changed (48) hide show
  1. package/.claude/rules/fh_4axis_gate.md +38 -0
  2. package/.claude-plugin/marketplace.json +2 -2
  3. package/CLAUDE.md +1 -1
  4. package/README.md +6 -1
  5. package/knowledge/shared/harness-core/fh_three_layer_canon.md +47 -0
  6. package/knowledge/shared/harness-core/field_verdict_crossfamily_gate.md +10 -0
  7. package/knowledge/shared/harness-core/measurement-integrity-checklist.md +15 -1
  8. package/knowledge/shared/harness-core/ship_readiness_gate.md +20 -3
  9. package/knowledge/shared/learnings/subagent_invocations_log.yaml +111 -0
  10. package/package.json +9 -1
  11. package/plugins/fh-commons/.claude-plugin/plugin.json +1 -1
  12. package/plugins/fh-meta/.claude-plugin/plugin.json +1 -1
  13. package/plugins/fh-meta/CHANGELOG.md +49 -0
  14. package/plugins/fh-meta/skills/salience-splitter/SKILL.md +1 -1
  15. package/scripts/backtick_guard.sh +194 -0
  16. package/scripts/capability_effect_probe.sh +14 -1
  17. package/scripts/context_continuity_score.sh +106 -12
  18. package/scripts/fh-gate.sh +3 -3
  19. package/scripts/files_manifest_shipping_check.sh +19 -0
  20. package/scripts/gate_pathspec_check.sh +1 -1
  21. package/scripts/package_coverage_check.sh +25 -2
  22. package/scripts/proposal_hook.sh +89 -0
  23. package/scripts/public_surface_scan_files.sh +11 -2
  24. package/scripts/revert_probe.sh +250 -0
  25. package/scripts/selfcheck.sh +67 -3
  26. package/scripts/sim_isolated_run.sh +97 -7
  27. package/scripts/test_backtick_guard_lanes.sh +115 -0
  28. package/scripts/test_degrade_scan_shell_probes.sh +7 -7
  29. package/scripts/test_files_manifest_shipping_lanes.sh +5 -5
  30. package/scripts/test_heavy_classifier_lanes.sh +1 -1
  31. package/scripts/test_lane_runner_lanes.sh +59 -33
  32. package/scripts/test_mapped_tracks_lanes.sh +1 -1
  33. package/scripts/test_marker_soul_check_lanes.sh +24 -0
  34. package/scripts/test_node_check_lanes.sh +34 -34
  35. package/scripts/test_package_coverage_lanes.sh +53 -27
  36. package/scripts/test_pipe_verdict_guard_lanes.sh +5 -5
  37. package/scripts/test_precommit_pointer_index_lanes.sh +33 -0
  38. package/scripts/test_preprep_drift_anchor.sh +13 -4
  39. package/scripts/test_preprep_drift_anchor_lanes.sh +23 -0
  40. package/scripts/test_proposal_hook_lanes.sh +36 -0
  41. package/scripts/test_revert_probe_lanes.sh +146 -0
  42. package/scripts/test_session_close_lanes.sh +3 -5
  43. package/scripts/test_sim_isolated_run_lanes.sh +17 -0
  44. package/scripts/test_verdict_watermark_lanes.sh +27 -1
  45. package/scripts/utterance_landing_check.sh +2 -2
  46. package/templates/.git-hooks/pre-commit +27 -4
  47. package/templates/settings.PreToolUse.snippet.json +37 -1
  48. package/plugins/fh-commons/README.md +0 -38
@@ -46,6 +46,18 @@
46
46
  # same clone, --tools "", no --restricted β†’ "🐿️" (memory PRESENT)
47
47
  # One variable, opposite answers. ([[feedback_instrument_cannot_discriminate_hypotheses]])
48
48
  #
49
+ # πŸŸ₯ THE SAME FLAG ALSO KILLS `act` MODE'S WRITE PATH β€” measured 2026-09-03, known-pair.
50
+ # `--restricted` ignores settings for PERMISSIONS too, not just memory, and `-p` has no TTY to
51
+ # ask a human β€” so `act`+`--no-harness` cannot Write/Edit AT ALL, regardless of what the model
52
+ # decides. Confirmed with one variable (`--restricted` on/off, same prompt, same --tools): Edit
53
+ # succeeds without it; with it every rep says "The edit was blocked β€” permission to write to
54
+ # file.txt wasn't granted." Deterministic, not a race β€” this is why a real run reads 5/5.
55
+ # β‡’ A "did not edit" result from `act --no-harness` is NOT evidence the base model chose not to
56
+ # write. Use `--no-harness` as an observe-mode control (memory presence, per the pair above)
57
+ # only β€” never to ask whether a write would have happened. Workaround not built: `--restricted`
58
+ # still honors an explicit `--settings <file>` (per `claude --help`), so a minimal file carrying
59
+ # only Write/Edit approval could restore act-mode fidelity here β€” filed, not implemented.
60
+ #
49
61
  # 🟒 AND THE DEFECT IS REUSABLE AS AN INSTRUMENT. `--no-harness` answers a question this repo
50
62
  # asks constantly and usually by eye: **does this behaviour come from FH, or would the base
51
63
  # model have done it anyway?** Run the same prompt with and without the flag; a behaviour that
@@ -69,17 +81,74 @@
69
81
  # FH defect (a normal session has Bash and can `ls`) β€” but scoring an arm without knowing it
70
82
  # produces a confident zero from a fixture that was never observable.
71
83
  #
72
- # πŸŸ₯ PROJECT HOOKS DO NOT RUN IN A DISPOSABLE CLONE β€” so this runner cannot measure anything
73
- # that depends on one. Measured 2026-08-30: an arm copied `.claude/settings.json` into its clone
74
- # to make the PreToolUse PriorArt hook live; not one of the three clones grew
75
- # `.claude/.prior_art_events.tsv`, while the live repo's copy carries entries from the same hour.
76
- # The hook never fired, so the "hook vs no-hook" contrast was HOOK ≑ NOHOOK and either verdict
77
- # would have been false. β‡’ Before claiming a hook-dependent result, check the hook's own
78
- # evidence file INSIDE the clone; absence of that file invalidates the arm, not the hypothesis.
84
+ # πŸŸ₯ PROJECT HOOKS DO RUN IN A DISPOSABLE CLONE β€” an earlier version of this paragraph said the
85
+ # opposite, and it was wrong (RETRACTED 2026-09-03). It read: "PROJECT HOOKS DO NOT RUN IN A
86
+ # DISPOSABLE CLONE … measured 2026-08-30: an arm copied `.claude/settings.json` into its clone to
87
+ # make the PreToolUse PriorArt hook live; not one of the three clones grew
88
+ # `.claude/.prior_art_events.tsv`". That absence was read as "hooks never fire here" with NO
89
+ # control arm whose hook was known to fire β€” and it narrowed two rounds of the identity-β‘€
90
+ # design (the hook-layer arm was declared unmeasurable). Known pair, 2026-09-03: a PreToolUse
91
+ # Bash hook that appends to `$CLAUDE_PROJECT_DIR/_hook_evidence.txt`, installed via
92
+ # `--setup 'cp <settings.json> .claude/settings.json'`, FIRED inside this runner's own clone
93
+ # (act mode, deny settings.local.json present) and in a bare `claude -p` clone, trusted or not.
94
+ # Why the 2026-08-30 arm saw nothing β€” CONFIRMED the same day, one more known pair: with the
95
+ # real project hook set copied into a clone, an arm asked to build a new mechanism script FOUND
96
+ # PRIOR ART and never called Write (identity-β‘£ behaviour), so the Write-matched PriorArt hook had
97
+ # nothing to fire on; an arm forced to Write a new scripts/*.sh produced `.prior_art_events.tsv`
98
+ # with a FIRE row inside the clone. The stimulus never reached the hook β€” a hook that is never
99
+ # triggered looks identical to a hook that cannot run, which is why a control arm whose hook is
100
+ # KNOWN to fire is mandatory. Signal: tracks/_meta/fh_signal_2026-09-03_runner-hooks-do-fire.md
101
+ # What SURVIVES from the old paragraph: before claiming a hook-dependent result, check the
102
+ # hook's own evidence file INSIDE the clone; absence of that file invalidates the ARM, never the
103
+ # hypothesis. And `--setup` writing an UNTRACKED file (.claude/settings.json is gitignored) is
104
+ # not contamination β€” the tree baseline is taken after setup, and git status never sees it.
79
105
  #
80
106
  # πŸŸ₯ CONTROL IS NOT OPTIONAL. Always run at least one arm whose correct answer is "the thing
81
107
  # being measured should NOT fire". An instrument that fires on everything measures nothing
82
108
  # ([[feedback_control_presence_is_not_discrimination]]).
109
+ #
110
+ # ── β“’ 격리 κ·ΈλΌμš΄λ”© β€” λ‚ μ§œ μ˜€μ—Ό ν†΅μ œ (six_axis_review_2026-09-04 κ°•ν™” #3, RECORD ONLY) ──────────
111
+ # WHY: LiveCodeBench (arXiv 2403.07974) and the contamination-taxonomy literature
112
+ # (frontier_verification_map_2026-09-04.md Β§β“’) filter benchmark items by RELEASE DATE precisely
113
+ # because a model can have memorized β€” not reasoned about β€” anything published before its
114
+ # training cutoff. This runner has the same exposure: a sim arm's "correct" answer about a
115
+ # doc/rule/gate can be recall of that doc's OWN CONTENT (if the doc predates the model's cutoff
116
+ # and the model happened to see this repo, or a near-identical one, during training) rather than
117
+ # evidence the harness under test actually delivers the behaviour to a cold session.
118
+ # THIS IS A RECORDING, NOT A GATE β€” per CLAUDE.md Β§Mechanization Boundary, "what the right value
119
+ # IS" stays judgment; only "was it recorded" is a channel. Below writes two fields per rep to
120
+ # `<out>/<arm>_r<rep>.meta.tsv` and does NOT compare them or fail a run on their basis:
121
+ # corpus_head_date β€” the clone's HEAD commit date (ISO 8601). PROXY, named honestly: this
122
+ # runner cannot resolve which files a given PROMPT actually cites, so it
123
+ # records the whole corpus's most recent commit as an upper bound on
124
+ # "how fresh could the cited material be", not a per-file citation date.
125
+ # sim_model / sim_model_cutoff β€” the `--model` value and a best-effort known cutoff via
126
+ # `_model_known_cutoff()` below, `UNKNOWN` when not recorded there. This
127
+ # table WILL go stale as new models ship β€” it is deliberately not treated
128
+ # as authoritative; a scoring session should verify the cutoff it cites
129
+ # rather than trust this file's guess (Β§Instrument-Calibration).
130
+ #
131
+ # ── β“’ 격리 κ·ΈλΌμš΄λ”© β€” 일회용 μƒŒλ“œλ°•μŠ€ ν‘œμ€€ (six_axis_review_2026-09-04 κ°•ν™” #3) ─────────────────
132
+ # ν”„λŸ°ν‹°μ–΄ λŒ€μ‘°ν‘œκ°€ "ephemeral wipe-and-reseed μƒŒλ“œλ°•μŠ€(E2B/Modal/Runloop)"λ₯Ό λ„μž… ν›„λ³΄λ‘œ λ“ λ‹€.
133
+ # 쑰직 μ œμ•½μƒ μ™ΈλΆ€ λ„κ΅¬λŠ” 보λ₯˜ν•˜κ³ (Β§λ„μž… 후보 3), 이 λŸ¬λ„ˆκ°€ "이미 κ·Έλ ‡κ²Œ λ™μž‘ν•˜λŠ” λΆ€λΆ„"κ³Ό
134
+ # "μ•„λ‹Œ λΆ€λΆ„"을 μ •μ§ν•˜κ²Œ 갈라 μ λŠ”λ‹€ β€” 맀번 μž¬λ°œκ²¬ν•˜μ§€ μ•Šλ„λ‘.
135
+ #
136
+ # WIPE (λ§€ rep λ§ˆλ‹€ μƒˆλ‘œ λ§Œλ“ λ‹€ β€” μž¬μ‚¬μš© μ—†μŒ):
137
+ # βœ… 이미 μ°Έ β€” λ§€ rep 이 λ…λ¦½λœ `git clone` (Β§μœ„ "A disposable clone per REP") + λ…λ¦½λœ λΆ€λͺ¨
138
+ # 디렉터리(Β§L10). 였늘 μ‹€ν–‰ν•œ μ‹€μΈ‘ (`test_sim_isolated_run_lanes.sh`):
139
+ # βœ… L10 no clone shares a parent with another (2 clones, 0 co-parented)
140
+ # βœ… L10b control β€” 2 clones found (L10 did not pass on an empty set)
141
+ # (μž¬ν˜„: `bash scripts/test_sim_isolated_run_lanes.sh` β€” μœ„ 두 쀄이 κ·ΈλŒ€λ‘œ λ‚˜μ˜¨λ‹€.)
142
+ # RESEED (νŒ”μ΄ λͺ» 보면 μ•ˆ λ˜λŠ” μžμ‚°μ„ ν΄λ‘ μ—μ„œ μ§€μš΄λ‹€):
143
+ # βœ… 이미 μ°Έ β€” ARM_BLIND_PATHS 제거(Β§μ•„λž˜) + κ·Έ μžμ²΄κ°€ known-pair 둜 검정됨:
144
+ # βœ… L24 νŒ” λˆˆκ°€λ¦Ό μžμ‚°μ΄ ν΄λ‘ μ—μ„œ μ œκ±°λœλ‹€ (히트 >0 β†’ 0)
145
+ # 기계-ν‘œλ©΄ 리셋 (LaunchAgents/crontab/settings β€” VM 리셋과 달리 "μ§€μš°κ³  λ‹€μ‹œ λ§Œλ“€μ§€" μ•ŠλŠ”λ‹€):
146
+ # πŸŸ₯ 아직 λΆ€λΆ„ β€” observe λͺ¨λ“œλŠ” 도ꡬ μžμ²΄κ°€ μ—†μ–΄ λͺ» κ±΄λ“œλ¦¬κ³ (ꡬ쑰적 예방), act λͺ¨λ“œλŠ” μ‹€μ œ
147
+ # 변경을 λ§Œλ“€κ³  λ‚˜μ„œ **탐지**만 ν•œλ‹€(Β§L7). "λ§€ rep μ „ 기계 μƒνƒœλ₯Ό μ΄ˆκΈ°ν™”"λŠ” ν•˜μ§€ μ•ŠλŠ”λ‹€ β€”
148
+ # E2B/Modal κΈ‰ VM wipe-and-reseedμ™€μ˜ μ‹€μ œ λΈνƒ€λŠ” 이 ν•œ 쀄이닀. μ§„μ§œ OS μƒŒλ“œλ°•μŠ€κ°€ ν•„μš”ν•œ
149
+ # μ΄μœ λŠ” 헀더 상단 "WHAT THIS GIVES YOU" 절이 이미 λ§ν•œλ‹€ β€” μ—¬κΈ°μ„œ λ˜ν’€μ΄ν•˜μ§€ μ•ŠλŠ”λ‹€.
150
+ # μš”μ•½: νŒŒμΌμ‹œμŠ€ν…œ μ½”νΌμŠ€ μΆ•(WIPE+RESEED)은 클둠 λ‹¨μœ„λ‘œ 이미 wipe-and-reseedλ‹€. 기계 ν‘œλ©΄ 좕은
151
+ # μ•„λ‹ˆλ‹€ β€” 탐지기이지 리셋기가 μ•„λ‹ˆλ‹€. 이 두 λ¬Έμž₯이 "μƒŒλ“œλ°•μŠ€ ν‘œμ€€"의 μ •μ§ν•œ μ „λΆ€λ‹€.
83
152
 
84
153
  set -uo pipefail
85
154
 
@@ -274,6 +343,16 @@ snapshot() {
274
343
  } > "$f"
275
344
  }
276
345
 
346
+ # β“’ λ‚ μ§œ μ˜€μ—Ό ν†΅μ œ β€” 기둝 μ „μš© 헬퍼(§헀더 μ°Έμ‘°). νŒμ • μ•„λ‹˜, 있으면 κ°’Β·μ—†μœΌλ©΄ UNKNOWN.
347
+ # πŸŸ₯ 이 ν‘œλŠ” λΆ€νŒ¨ν•œλ‹€(stale) β€” μƒˆ λͺ¨λΈμ΄ λ‚˜μ˜¬ λ•Œλ§ˆλ‹€ μ†μœΌλ‘œ κ°±μ‹ ν•΄μ•Ό ν•œλ‹€. μ—¬κΈ° 적힌 값을
348
+ # Β«κ²€μ¦λ¨Β»μœΌλ‘œ μΈμš©ν•˜μ§€ 마라: 이 슀크립트 μžμ‹ μ΄ κ·Έλ ‡κ²Œ 적어두라고 μš”κ΅¬ν•œλ‹€(Β§Instrument-Calibration).
349
+ _model_known_cutoff() { # $1=--model κ°’ β†’ ISO μ›” λ˜λŠ” UNKNOWN
350
+ case "$1" in
351
+ *sonnet-5*|sonnet) printf '2026-01' ;; # 이 μ„Έμ…˜μ˜ μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈκ°€ 슀슀둜 적은 κ°’
352
+ *) printf 'UNKNOWN' ;;
353
+ esac
354
+ }
355
+
277
356
  echo "── sim_isolated_run ──────────────────────────────────────────────"
278
357
  echo "arm=$ARM mode=$MODE model=$MODEL reps=$REPS timeout=${TIMEOUT}s"
279
358
  echo "out=$OUTDIR"
@@ -318,6 +397,17 @@ for r in $(seq 1 "$REPS"); do
318
397
  continue
319
398
  fi
320
399
 
400
+ # β“’ λ‚ μ§œ μ˜€μ—Ό ν†΅μ œ β€” 기둝만, νŒμ • μ•„λ‹˜(§헀더). corpus_head_date λŠ” "ν”„λ‘¬ν”„νŠΈκ°€ μΈμš©ν•˜λŠ”
401
+ # νŒŒμΌλ“€"의 λ‚ μ§œκ°€ μ•„λ‹ˆλΌ κ·Έ μƒν•œ(μ½”νΌμŠ€ 전체 HEAD)이닀 β€” λŸ¬λ„ˆλŠ” ν”„λ‘¬ν”„νŠΈκ°€ 무엇을 μΈμš©ν•˜λŠ”μ§€
402
+ # λͺ¨λ₯΄λ―€λ‘œ 더 쒁게 잴 수 μ—†λ‹€. κ·Έλ ‡κ²Œ μ’ν˜€ μ λŠ”λ‹€.
403
+ _corpus_date=$(git -C "$WORK" log -1 --format=%cI 2>/dev/null); [ -n "$_corpus_date" ] || _corpus_date="UNKNOWN"
404
+ _cutoff=$(_model_known_cutoff "$MODEL")
405
+ {
406
+ printf 'corpus_head_date\t%s\n' "$_corpus_date"
407
+ printf 'sim_model\t%s\n' "$MODEL"
408
+ printf 'sim_model_cutoff\t%s\n' "$_cutoff"
409
+ } > "$OUTDIR/${ARM}_r${r}.meta.tsv"
410
+
321
411
  # ── πŸŸ₯ νŒ”μ΄ 읽으면 μ•ˆ λ˜λŠ” tracked μžμ‚°μ„ «클둠 μ•ˆμ—μ„œΒ» μ œκ±°ν•œλ‹€ (2026-09-01) ──────
322
412
  # μ™œ: μ–Όλ¦° μ •λ‹΅μ§€(`scripts/fixtures/knownpair_refusal_48_*`)κ°€ tracked κ°€ λ˜λ©΄μ„œ
323
413
  # **λͺ¨λ“  νŒ”μ˜ 클둠에 λ“€μ–΄κ°”λ‹€.** μ‹€μΈ‘ β€” negative λ¬Έν•­μ˜ 핡심 λͺ…사ꡬ가 κ·Έ μ•ˆμ— μžˆλ‹€
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env bash
2
+ # test_backtick_guard_lanes.sh β€” known pairs for scripts/backtick_guard.sh. Written BEFORE the detector.
3
+ #
4
+ # WHAT IS BEING GUARDED
5
+ # A backtick inside a shell DOUBLE-QUOTING CONTEXT β€” an unquoted heredoc body (`<<EOF`) or a
6
+ # "double-quoted string" β€” is command substitution: the text between the backticks is REPLACED by
7
+ # the command's output. With no such command the output is empty, so the text is DELETED; with one,
8
+ # foreign content is INSERTED. The sentence stays grammatical (only its subject is gone), the only
9
+ # signal is one `command not found` line at the top of the output, and every marker/record hook
10
+ # checks a field's presence, not its completeness.
11
+ # Measured 7Γ— (2026-08-10 Β· 2026-09-01 Γ—3 Β· 2026-09-02 Γ—4 β€” marker, RESULT doc, fh_completed echo Γ—2)
12
+ # with a resident memory rule that failed each time because the actor's task had a different NAME
13
+ # (writing a marker Β· a failure message Β· a seal). Nβ‰₯3 β†’ mechanize (weekly_audit_2026-09-02 HIGH #1).
14
+ #
15
+ # BT1 β€” unquoted heredoc body (`<<TAG`, `<<-TAG`; NOT `<<'TAG'` / `<<"TAG"` / `<<\TAG`) containing `
16
+ # BT2 β€” double-quoted string containing ` (single-quoted text and `\`` are literal β†’ CLEAN)
17
+ #
18
+ # Surface = the Bash tool call itself (interactively-composed commands), same reasoning as
19
+ # pipe_verdict_guard: every recurrence was in a composed command, none in a shipped file.
20
+
21
+ set -u
22
+ G="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/backtick_guard.sh"
23
+ pass=0; fail=0
24
+
25
+ # expect <label> <HIT|CLEAN> <command-string> (the command text is passed raw via --stdin-raw)
26
+ expect() {
27
+ local label="$1" want="$2" cmd="$3" out got
28
+ out=$(printf '%s' "$cmd" | bash "$G" --stdin-raw 2>&1)
29
+ # want may be HIT Β· CLEAN Β· HIT:BT1@2 (rule and line asserted β€” a hit on the WRONG line is a miss)
30
+ if printf '%s' "$out" | grep -q 'BACKTICK'; then got=HIT; else got=CLEAN; fi
31
+ case "$want" in HIT:*) printf '%s' "$out" | grep -q "${want#HIT:BT}" 2>/dev/null; :; esac
32
+ if [ "$got" = HIT ] && [ "${want%%:*}" = HIT ] && [ "$want" != HIT ]; then
33
+ local r="${want#HIT:}"; r="${r%@*}"; local l="${want##*@}"
34
+ printf '%s' "$out" | grep -q "$r L$l " || got="HIT-WRONG($(printf '%s' "$out" | grep -oE 'BT[12] L[0-9]+' | head -1))"
35
+ [ "$got" = HIT ] && got="$want"
36
+ fi
37
+ if [ "$got" = "$want" ]; then
38
+ printf ' βœ… %-56s %s (expected %s)\n' "$label" "$got" "$want"; pass=$((pass+1))
39
+ else
40
+ printf ' ❌ %-56s %s (expected %s)\n' "$label" "$got" "$want"; fail=$((fail+1))
41
+ printf ' cmd: %s\n out: %s\n' "$cmd" "$out"
42
+ fi
43
+ }
44
+ BT='`' # one backtick, spelled once so the lanes below never carry a live one in double quotes
45
+ NL=$'\n'
46
+
47
+ echo "[backtick-guard] known pairs"
48
+ echo "-- BT1: unquoted heredoc body --"
49
+ # 2026-09-02 ⓐ β€” the measured shape: a marker written through an unquoted heredoc so a $VAR expands.
50
+ expect "BT1 measured: marker heredoc" HIT:BT1@3 "cat > m.marker <<EOF${NL}date: \$TODAY${NL}axis2-evidence: λŸ¬λ„ˆκ°€ ${BT}--keep-blind-paths${BT} λ₯Ό μ‚ΌμΌ°λ‹€${NL}EOF"
51
+ expect "BT1 <<-TAG (tab-stripped) form" HIT "cat <<-EOF${NL} note ${BT}x${BT}${NL} EOF"
52
+ expect "BT1 markdown fence in heredoc" HIT "cat > r.md <<EOF${NL}\`\`\`${NL}out${NL}\`\`\`${NL}EOF"
53
+ expect "BT1 second of two heredocs on a line" HIT:BT1@4 "diff <(cat <<'A') <(cat <<B)${NL}${BT}a${BT}${NL}A${NL}${BT}b${BT}${NL}B"
54
+ expect "BT1 quoted <<'EOF' is CLEAN" CLEAN "cat > m.marker <<'EOF'${NL}evidence: ${BT}--keep-blind-paths${BT} μ‚Όν‚΄${NL}EOF"
55
+ expect "BT1 quoted <<\"EOF\" is CLEAN" CLEAN "cat <<\"EOF\"${NL}${BT}x${BT}${NL}EOF"
56
+ expect "BT1 escaped <<\\EOF is CLEAN" CLEAN "cat <<\\EOF${NL}${BT}x${BT}${NL}EOF"
57
+ expect "BT1 backslash-escaped backtick CLEAN" CLEAN "cat <<EOF${NL}see \\${BT}x\\${BT}${NL}EOF"
58
+ expect "BT1 backtick AFTER the body ends" CLEAN "cat <<EOF${NL}plain${NL}EOF${NL}echo '${BT}later${BT}'"
59
+ expect "BT1 <<< herestring is not a heredoc" CLEAN "grep -c x <<< 'a ${BT}b${BT}'"
60
+
61
+ echo "-- BT2: double-quoted string --"
62
+ # 2026-09-02 β“‘ β€” the measured shape: a completion-log append through echo "…".
63
+ expect "BT2 measured: echo append" HIT:BT2@1 "echo \"- βœ… λŸ¬λ„ˆ ${BT}sim_isolated_run.sh${BT} 헀더 κ²½κ³ \" >> tracks/_meta/fh_completed.md"
64
+ expect "BT2 failure-message string (09-01)" HIT "printf '%s\\n' \"(${BT}nameleak_check.sh gen${BT} 을 써라)\""
65
+ expect "BT2 single quote inside dq is inert" HIT "echo \"don't ${BT}x${BT}\""
66
+ expect "BT2 single-quoted is CLEAN" CLEAN "printf '%s\\n' '- βœ… λŸ¬λ„ˆ ${BT}sim_isolated_run.sh${BT} 헀더' >> log.md"
67
+ expect "BT2 escaped \\\` is CLEAN" CLEAN "echo \"see \\${BT}x\\${BT}\""
68
+ expect "BT2 dq inside single quotes is CLEAN" CLEAN "echo '\"${BT}x${BT}\"'"
69
+ expect "BT2 sq inside \$( ) inside dq CLEAN" CLEAN "echo \"\$(printf '%s' '${BT}x${BT}')\""
70
+ expect "BT2 no backtick at all" CLEAN "echo \"\$(git log -1) done\" && cat <<EOF${NL}plain \$X${NL}EOF"
71
+ expect "BT2 bare backtick outside quotes" CLEAN "V=${BT}date${BT}; echo ok" # live command substitution on purpose, not a text context
72
+
73
+ echo "-- Axis-2 pass 2026-09-03 (challenger, repros executed by the governor) --"
74
+ # A1: the first build stripped single-quoted spans BEFORE matching heredoc operators, so <<'EOF' was
75
+ # never a heredoc β€” three symptoms from one cause. Each pinned in its real shape.
76
+ expect "A1a quoted body with dq+backtick CLEAN" CLEAN "cat <<'EOF'${NL}axis2-evidence: λ©”μ‹œμ§€ \"use ${BT}x${BT}\" κ°€ λ–΄λ‹€${NL}EOF"
77
+ expect "A1b quoted A then unquoted B: only B" CLEAN "diff <(cat <<'A') <(cat <<B)${NL}${BT}a${BT}${NL}A${NL}plain${NL}B"
78
+ expect "A1c apostrophe in quoted body, then echo" HIT:BT2@4 "cat <<'EOF'${NL}don't${NL}EOF${NL}echo \"${BT}x${BT}\" >> log"
79
+ # A2: a comment's apostrophe must not open a single-quote context that swallows the next line.
80
+ expect "A2 comment apostrophe then echo" HIT:BT2@2 "# don't re-run this${NL}echo \"${BT}x${BT}\" >> f.md"
81
+ expect "A2 url fragment is not a comment" HIT:BT2@1 "curl \"https://x/a#frag ${BT}x${BT}\""
82
+ # B3: <<TAG inside a double-quoted string (commit message) opens no heredoc.
83
+ expect "B3 <<EOF in commit message is CLEAN" CLEAN "git commit -m \"docs: prefer <<EOF for markers\"${NL}V=${BT}date${BT}; echo ok"
84
+ # B5: escaped backslash + LIVE backtick.
85
+ expect "B5 \\\\ then live backtick HITs" HIT:BT1@2 "cat <<EOF${NL}path\\\\${BT}x${BT}${NL}EOF"
86
+ # B2: ANSI-C $'…' with an escaped apostrophe does not end early.
87
+ expect "B2 \$'don\\'t' then dq backtick" HIT:BT2@1 "echo \$'don\\'t' \"${BT}x${BT}\""
88
+ # B1: backtick inside \$( ) re-entered from dq is live substitution β€” deliberately NOT flagged.
89
+ expect "B1 backtick inside \$( ) in dq CLEAN" CLEAN "echo \"\$(echo ${BT}x${BT})\""
90
+
91
+ echo "-- hook mode: JSON payload in β†’ JSON out (A4: detection is worthless if delivery is 0) --"
92
+ jexp() { # <label> <expect-substring-in-additionalContext|SILENT> <env> <payload>
93
+ local label="$1" want="$2" env_="$3" payload="$4" out ctx
94
+ out=$(printf '%s' "$payload" | env $env_ bash "$G" 2>/dev/null)
95
+ if [ "$want" = SILENT ]; then
96
+ if [ -z "$out" ]; then printf ' βœ… %-56s SILENT\n' "$label"; pass=$((pass+1)); else printf ' ❌ %-56s expected SILENT, got: %s\n' "$label" "${out:0:80}"; fail=$((fail+1)); fi
97
+ return
98
+ fi
99
+ ctx=$(printf '%s' "$out" | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["hookSpecificOutput"]["additionalContext"])' 2>/dev/null)
100
+ if printf '%s' "$ctx" | grep -q "$want"; then printf ' βœ… %-56s JSON additionalContext carries %s\n' "$label" "$want"; pass=$((pass+1))
101
+ else printf ' ❌ %-56s no JSON/context (%s)\n' "$label" "${out:0:80}"; fail=$((fail+1)); fi
102
+ }
103
+ P='{"tool_name":"Bash","tool_input":{"command":"echo \"- done `x.sh` ok\""}}'
104
+ jexp "JSON payload β†’ additionalContext" "BT2 L1" "X=1" "$P"
105
+ jexp "ascii PYTHONIOENCODING still emits" "BT2 L1" "PYTHONIOENCODING=ascii" "$P"
106
+ jexp "non-Bash tool is SILENT" SILENT "X=1" '{"tool_name":"Write","tool_input":{"content":"`x`"}}'
107
+ jexp "unparseable payload is SILENT" SILENT "X=1" 'not json'
108
+
109
+ echo "-- opt-out / payload --"
110
+ expect "noqa exempts" CLEAN "echo \"${BT}x${BT}\" # noqa: backtick"
111
+ expect "empty payload" CLEAN ""
112
+
113
+ echo
114
+ echo "[backtick-guard] $pass passed, $fail failed"
115
+ [ "$fail" -eq 0 ]
@@ -81,7 +81,7 @@ EOF
81
81
  cat > "$TMP/non_detections.sh" <<'EOF'
82
82
  #!/usr/bin/env bash
83
83
  # (a) integer sanitization β€” the PRESCRIBED remedy for the pipefail-fallback class, not the defect.
84
- count=$(grep -c pattern file)
84
+ count=$(grep -c pattern file) # portability-noqa: fixture text written by a quoted heredoc, never executed β€” statically grepped by degrade_direction_scan.sh only
85
85
  if [ "${count:-0}" -gt 0 ]; then echo "found"; fi
86
86
  # (b) SCOPE guards β€” "this run does not apply here" is not a claim that a check passed.
87
87
  [ -d "$HOME/projects" ] || exit 0
@@ -165,11 +165,11 @@ N=$(find /nope . -maxdepth 1 2>/dev/null | grep -c . || echo 0)
165
165
  M=$(git log --oneline 2>/dev/null | wc -l || echo 0)
166
166
  # WIDENED 2026-08-04. Every line below was INVISIBLE to the narrowed rule, and each was verified to
167
167
  # actually produce "0\n0" before being pinned here (line count measured, not assumed):
168
- P=$(cat /etc/hosts | grep -c . | tr -d ' ' || echo 0) # transparent filter after the counter
169
- Q=$(grep -c "^nosuchline$" /etc/hosts 2>/dev/null | tr -d ' ' || echo 0) # the PR #251 shape
170
- R=$(grep -Ec "^nosuchline$" /etc/hosts || echo 0) # combined flag cluster -Ec
171
- S=$(grep --count "^nosuchline$" /etc/hosts || echo 0) # long option
172
- T=$(grep -Fcx "nosuchline" /etc/hosts || echo 0) # -Fcx
168
+ P=$(cat /etc/hosts | grep -c . | tr -d ' ' || echo 0) # transparent filter after the counter # portability-noqa: fixture text, never executed
169
+ Q=$(grep -c "^nosuchline$" /etc/hosts 2>/dev/null | tr -d ' ' || echo 0) # the PR #251 shape # portability-noqa: fixture text, never executed
170
+ R=$(grep -Ec "^nosuchline$" /etc/hosts || echo 0) # combined flag cluster -Ec # portability-noqa: fixture text, never executed
171
+ S=$(grep --count "^nosuchline$" /etc/hosts || echo 0) # long option # portability-noqa: fixture text, never executed
172
+ T=$(grep -Fcx "nosuchline" /etc/hosts || echo 0) # -Fcx # portability-noqa: fixture text, never executed
173
173
  U=$(false | grep -c . | cat || echo 0) # trailing stage that always emits
174
174
  V=$(false | grep -c . | grep -v nosuch || echo 0) # trailing grep whose pattern misses the "0"
175
175
  EOF
@@ -688,7 +688,7 @@ fi
688
688
  # flips to a hit β€” proves the exclusion is load-bearing for this specific fixture, not just
689
689
  # present somewhere in the file.
690
690
  _scan_reverted="$TMP/scan_reverted.sh"
691
- _excl_line=$(grep -n "grep -vE 'in \[A-Z_\]" "$SCAN" | head -1 | cut -d: -f1)
691
+ _excl_line=$(grep -n "grep -vE 'in \[A-Z_\]" "$SCAN" | head -1 | cut -d: -f1) # portability-noqa: this file has no `set -e` (top line 22 is `set -uo pipefail` only) and the next line already guards empty via -z
692
692
  if [ -z "$_excl_line" ]; then
693
693
  bad "C2-REVERT could not locate the exclusion line by its known text β€” fixture cannot run"
694
694
  else
@@ -46,9 +46,9 @@ trap 'rm -rf "$LANE2_DIR"' EXIT
46
46
  cp package.json "$LANE2_DIR/package.json.orig"
47
47
  node -e '
48
48
  const fs = require("fs");
49
- const pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
49
+ const pkg = JSON.parse(fs.readFileSync("package.json", "utf8")); // # portability-noqa: cwd is REPO_ROOT (line 18) -- this is the subject under tests own manifest, not a foreign fixture
50
50
  pkg.files.push("scripts/__test_fixture_does_not_exist__.sh");
51
- fs.writeFileSync("package.json", JSON.stringify(pkg, null, 2) + "\n");
51
+ fs.writeFileSync("package.json", JSON.stringify(pkg, null, 2) + "\n"); // # portability-noqa: same as above -- writes back to the same repo-relative manifest it read
52
52
  '
53
53
  restore_pkg() { cp "$LANE2_DIR/package.json.orig" package.json; }
54
54
 
@@ -132,7 +132,7 @@ D6="$(fixture_dir)"
132
132
  mkdir -p "$D6/.git"
133
133
  node -e '
134
134
  const fs = require("fs");
135
- const pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
135
+ const pkg = JSON.parse(fs.readFileSync("package.json", "utf8")); // # portability-noqa: cwd is REPO_ROOT -- seeds the fixture from the subject own real manifest, then mutates a copy
136
136
  pkg.files = ".";
137
137
  fs.writeFileSync(process.argv[1], JSON.stringify(pkg, null, 2) + "\n");
138
138
  ' "$D6/package.json"
@@ -152,7 +152,7 @@ D7="$(fixture_dir)"
152
152
  mkdir -p "$D7/.git"
153
153
  node -e '
154
154
  const fs = require("fs");
155
- const pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
155
+ const pkg = JSON.parse(fs.readFileSync("package.json", "utf8")); // # portability-noqa: cwd is REPO_ROOT -- seeds the fixture from the subject own real manifest, then mutates a copy
156
156
  pkg.files.push("missing\nPASS\\t999 entries checked, 0 phantom, 0 unpacked");
157
157
  fs.writeFileSync(process.argv[1], JSON.stringify(pkg, null, 2) + "\n");
158
158
  ' "$D7/package.json"
@@ -175,7 +175,7 @@ mkdir -p "$D8/.git" "$D8/scripts_dummy"
175
175
  echo x > "$D8/scripts_dummy/foo.sh"
176
176
  node -e '
177
177
  const fs = require("fs");
178
- const pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
178
+ const pkg = JSON.parse(fs.readFileSync("package.json", "utf8")); // # portability-noqa: cwd is REPO_ROOT -- seeds the fixture from the subject own real manifest, then mutates a copy
179
179
  pkg.files = ["scripts_dummy"];
180
180
  delete pkg.scripts.prepare;
181
181
  delete pkg.scripts.prepublishOnly;
@@ -103,7 +103,7 @@ check carveout "README.md" "npm-shipped surface β€” first-scre
103
103
  check carveout "README.ko.md" "language variants route the same way"
104
104
  check carveout "README.zh-CN.md" "πŸŸ₯ 5-char locale forms too β€” cross-family caught [a-z]{2} missing these"
105
105
  check uncovered ".claude/registry/README.md" "πŸŸ₯ STILL UNCOVERED β€” in files[] but not root; named, not closed"
106
- check uncovered "package.json" "files[] / version changes are unclassified"
106
+ check uncovered "package.json" "files[] / version changes are unclassified" # portability-noqa: "package.json" is a string literal fed to classify()'s regex test, never opened from disk β€” a ported repo without this exact file still exercises the same classifier logic
107
107
  check uncovered ".github/workflows/validate.yml" "πŸŸ₯ CI definition β€” changing what CI runs is unclassified"
108
108
  check uncovered "scripts/memory_link_check.py" "πŸŸ₯ .py is not .sh β€” shipped python is unclassified"
109
109
 
@@ -30,18 +30,32 @@ mkfixture() { # $1 = dir
30
30
  printf '#!/usr/bin/env bash\nbash scripts/lane_runner_check.sh\n' > "$d/scripts/selfcheck.sh"
31
31
  printf '#!/usr/bin/env bash\n: orphan lane suite\n' > "$d/scripts/test_orphan_lanes.sh"
32
32
  }
33
- run() { ( cd "$1" && bash scripts/lane_runner_check.sh 2>&1 ); }
34
- rcof() { ( cd "$1" && bash scripts/lane_runner_check.sh >/dev/null 2>&1; echo $? ); }
33
+ # ONE execution per fixture, stdout AND rc from the SAME run β€” never two separate invocations.
34
+ # Until 2026-09-03 this was split into run()+rcof(), each running lane_runner_check.sh on its own.
35
+ # lane_runner_check.sh reads live filesystem/git state on every invocation (its own mktemp, a
36
+ # `.git` up-chain walk, `git ls-files -z`, a python3 subprocess) and is not guaranteed to answer
37
+ # identically twice in a row under CI resource pressure β€” so a call site combining `$(run "$D")`
38
+ # with a SEPARATE `$(rcof "$D")` could silently pair stdout from one run with the exit code of a
39
+ # DIFFERENT run. That produced an impossible-looking CI flake: rc=0 with the literal substring
40
+ # "declared debt" absent from $out, even though every rc=0 exit path in lane_runner_check.sh
41
+ # unconditionally prints that substring (traced exhaustively β€” see
42
+ # tracks/_meta/armC_armC-wt2_report2_2026-09-03.md). Sets LRC_OUT/LRC_RC as globals: this file is
43
+ # flat top-level (no `local` scoping across call sites), and bash functions cannot return two
44
+ # values through their exit status alone.
45
+ run_check() { # $1 = fixture dir
46
+ LRC_OUT="$(cd "$1" && bash scripts/lane_runner_check.sh 2>&1)"; LRC_RC=$?
47
+ }
35
48
 
36
49
  # ── L1 known-POSITIVE: an undeclared orphan suite must FAIL ───────────────────────────────────
37
50
  # Without this arm every lane below proves nothing: a checker that passed unconditionally would
38
51
  # satisfy all the "declaration suppresses it" lanes.
39
52
  D="$T/l1"; mkfixture "$D"
40
- out=$(run "$D"); rc=$(rcof "$D")
53
+ run_check "$D"; out="$LRC_OUT"; rc="$LRC_RC"
41
54
  if [ "$rc" = "1" ] && printf '%s' "$out" | grep -q 'test_orphan_lanes.sh'; then
42
55
  ok "L1 known-positive: undeclared orphan suite β†’ rc=1 and it is named"
43
56
  else
44
57
  bad "L1 known-positive did not fire (rc=$rc) β€” every lane below is meaningless without it"
58
+ printf '%s\n' "$out" | sed 's/^/ β”‚ /'
45
59
  fi
46
60
 
47
61
  # ── IDX7 the FAIL path must EXECUTE the provenance note, not merely contain a call to it ──────
@@ -55,7 +69,7 @@ fi
55
69
  # It asserts the SHAPE of provenance, not the exact sentence: the fixture is a non-git dir, so the
56
70
  # honest answer there is the DISK one, and pinning the index wording would make the lane wrong.
57
71
  D="$T/idx7"; mkfixture "$D"
58
- out=$(run "$D")
72
+ run_check "$D"; out="$LRC_OUT"
59
73
  if printf '%s' "$out" | grep -qE 'unbound variable|command not found|syntax error'; then
60
74
  bad "IDX7 the FAIL path errored: $(printf '%s' "$out" | grep -E 'unbound|not found|syntax' | head -1)"
61
75
  elif printf '%s' "$out" | grep -qE 'β“˜|πŸŸ₯'; then
@@ -67,41 +81,45 @@ fi
67
81
  # ── L2 NO-OP: no declaration file β†’ behaviour is exactly the L1 behaviour ─────────────────────
68
82
  # This is the arm that protects THIS repo, which ships no company/ directory.
69
83
  D="$T/l2"; mkfixture "$D"
70
- out=$(run "$D")
84
+ run_check "$D"; out="$LRC_OUT"
71
85
  if ! printf '%s' "$out" | grep -q 'lane_declarations'; then
72
86
  ok "L2 no-op: absent declaration file is silent (no mention in output)"
73
87
  else
74
88
  bad "L2 no-op: output mentions the declaration file when none exists"
89
+ printf '%s\n' "$out" | sed 's/^/ β”‚ /'
75
90
  fi
76
91
 
77
92
  # ── L3 org EXEMPT suppresses the orphan ───────────────────────────────────────────────────────
78
93
  D="$T/l3"; mkfixture "$D"; mkdir -p "$D/company"
79
94
  printf 'exempt:\n - test_orphan_lanes.sh # org-owned, runs in the org CI only\n' > "$D/company/lane_declarations.yaml"
80
- out=$(run "$D"); rc=$(rcof "$D")
95
+ run_check "$D"; out="$LRC_OUT"; rc="$LRC_RC"
81
96
  if [ "$rc" = "0" ] && printf '%s' "$out" | grep -q '1 exempt'; then
82
97
  ok "L3 org exempt: declared suite no longer fails the check (rc=0, counted exempt)"
83
98
  else
84
- bad "L3 org exempt did not suppress (rc=$rc) β€” out: $(printf '%s' "$out" | tail -1)"
99
+ bad "L3 org exempt did not suppress (rc=$rc)"
100
+ printf '%s\n' "$out" | sed 's/^/ β”‚ /'
85
101
  fi
86
102
 
87
103
  # ── L4 org DEBT suppresses AND is counted as debt ─────────────────────────────────────────────
88
104
  D="$T/l4"; mkfixture "$D"; mkdir -p "$D/company"
89
105
  printf 'debt:\n - test_orphan_lanes.sh\n' > "$D/company/lane_declarations.yaml"
90
- out=$(run "$D"); rc=$(rcof "$D")
106
+ run_check "$D"; out="$LRC_OUT"; rc="$LRC_RC"
91
107
  if [ "$rc" = "0" ] && printf '%s' "$out" | grep -q 'declared debt'; then
92
108
  ok "L4 org debt: declared suite suppressed and reported as debt"
93
109
  else
94
110
  bad "L4 org debt did not land (rc=$rc)"
111
+ printf '%s\n' "$out" | sed 's/^/ β”‚ /'
95
112
  fi
96
113
 
97
114
  # ── L5 VISIBILITY: an org-declared list must never look like this repo's own zero ─────────────
98
115
  D="$T/l5"; mkfixture "$D"; mkdir -p "$D/company"
99
116
  printf 'debt:\n - test_orphan_lanes.sh\n' > "$D/company/lane_declarations.yaml"
100
- out=$(run "$D")
117
+ run_check "$D"; out="$LRC_OUT"
101
118
  if printf '%s' "$out" | grep -q 'org-declared'; then
102
119
  ok "L5 visibility: output names the org file and its counts"
103
120
  else
104
121
  bad "L5 visibility: org declarations are invisible in the output"
122
+ printf '%s\n' "$out" | sed 's/^/ β”‚ /'
105
123
  fi
106
124
 
107
125
  # ── L6 FAIL-CLOSED on an unparseable file ─────────────────────────────────────────────────────
@@ -109,41 +127,46 @@ fi
109
127
  # render UNMEASURED as ZERO, and it would do so on the arm where a fork is relying on the file.
110
128
  D="$T/l6"; mkfixture "$D"; mkdir -p "$D/company"
111
129
  printf 'exempt:\n this line is not an entry\n' > "$D/company/lane_declarations.yaml"
112
- out=$(run "$D"); rc=$(rcof "$D")
130
+ run_check "$D"; out="$LRC_OUT"; rc="$LRC_RC"
113
131
  if [ "$rc" = "2" ] && printf '%s' "$out" | grep -q 'UNMEASURED'; then
114
132
  ok "L6 fail-closed: unparseable declaration file β†’ rc=2 and says UNMEASURED"
115
133
  else
116
134
  bad "L6 fail-closed FAILED (rc=$rc) β€” a malformed file was read as 'no declarations'"
135
+ printf '%s\n' "$out" | sed 's/^/ β”‚ /'
117
136
  fi
118
137
 
119
138
  # ── L6b control for L6: the SAME orphan tree with a WELL-FORMED file must not exit 2 ──────────
120
139
  # Without this, L6 would also pass on a checker that exits 2 for any declaration file at all.
121
140
  D="$T/l6b"; mkfixture "$D"; mkdir -p "$D/company"
122
141
  printf 'exempt:\n - test_orphan_lanes.sh\n' > "$D/company/lane_declarations.yaml"
123
- if [ "$(rcof "$D")" != "2" ]; then
142
+ run_check "$D"; out="$LRC_OUT"; rc="$LRC_RC"
143
+ if [ "$rc" != "2" ]; then
124
144
  ok "L6b control: a well-formed file does NOT trip the fail-closed arm"
125
145
  else
126
146
  bad "L6b control: every declaration file exits 2 β€” L6 proved nothing"
147
+ printf '%s\n' "$out" | sed 's/^/ β”‚ /'
127
148
  fi
128
149
 
129
150
  # ── L7 unknown section is a parse failure, not a silent skip ──────────────────────────────────
130
151
  D="$T/l7"; mkfixture "$D"; mkdir -p "$D/company"
131
152
  printf 'allowed:\n - test_orphan_lanes.sh\n' > "$D/company/lane_declarations.yaml"
132
- out=$(run "$D")
133
- if [ "$(rcof "$D")" = "2" ] && printf '%s' "$out" | grep -q "unknown section"; then
153
+ run_check "$D"; out="$LRC_OUT"; rc="$LRC_RC"
154
+ if [ "$rc" = "2" ] && printf '%s' "$out" | grep -q "unknown section"; then
134
155
  ok "L7 unknown section β†’ rc=2 and names the section"
135
156
  else
136
- bad "L7 unknown section was tolerated β€” a typo'd header would silently declare nothing"
157
+ bad "L7 unknown section was tolerated β€” a typo'd header would silently declare nothing (rc=$rc)"
158
+ printf '%s\n' "$out" | sed 's/^/ β”‚ /'
137
159
  fi
138
160
 
139
161
  # ── L8 the same name in both sections is ambiguous, not last-wins ─────────────────────────────
140
162
  D="$T/l8"; mkfixture "$D"; mkdir -p "$D/company"
141
163
  printf 'exempt:\n - test_orphan_lanes.sh\ndebt:\n - test_orphan_lanes.sh\n' > "$D/company/lane_declarations.yaml"
142
- out=$(run "$D")
143
- if [ "$(rcof "$D")" = "2" ] && printf '%s' "$out" | grep -q "both exempt and debt"; then
164
+ run_check "$D"; out="$LRC_OUT"; rc="$LRC_RC"
165
+ if [ "$rc" = "2" ] && printf '%s' "$out" | grep -q "both exempt and debt"; then
144
166
  ok "L8 same suite in both sections β†’ rc=2 (ambiguous, not silently resolved)"
145
167
  else
146
- bad "L8 double declaration was silently resolved"
168
+ bad "L8 double declaration was silently resolved (rc=$rc)"
169
+ printf '%s\n' "$out" | sed 's/^/ β”‚ /'
147
170
  fi
148
171
 
149
172
  # ── L9 a stale entry WARNS but does not block (same voice as upstream DEBT hygiene) ───────────
@@ -151,20 +174,23 @@ fi
151
174
  # would train forks to delete the file, which costs more than a stale line.
152
175
  D="$T/l9"; mkfixture "$D"; mkdir -p "$D/company"
153
176
  printf 'exempt:\n - test_orphan_lanes.sh\n - test_deleted_lanes.sh\n' > "$D/company/lane_declarations.yaml"
154
- out=$(run "$D"); rc=$(rcof "$D")
177
+ run_check "$D"; out="$LRC_OUT"; rc="$LRC_RC"
155
178
  if [ "$rc" = "0" ] && printf '%s' "$out" | grep -q 'test_deleted_lanes.sh'; then
156
179
  ok "L9 stale entry: warns and names it, does not block (rc=0)"
157
180
  else
158
181
  bad "L9 stale entry handling wrong (rc=$rc)"
182
+ printf '%s\n' "$out" | sed 's/^/ β”‚ /'
159
183
  fi
160
184
 
161
185
  # ── L10 comments and blank lines are not entries ──────────────────────────────────────────────
162
186
  D="$T/l10"; mkfixture "$D"; mkdir -p "$D/company"
163
187
  printf '# org lane declarations\n\nexempt:\n\n - test_orphan_lanes.sh # reason lives here\n' > "$D/company/lane_declarations.yaml"
164
- if [ "$(rcof "$D")" = "0" ]; then
188
+ run_check "$D"; out="$LRC_OUT"; rc="$LRC_RC"
189
+ if [ "$rc" = "0" ]; then
165
190
  ok "L10 comments/blank lines tolerated (a file people can annotate)"
166
191
  else
167
- bad "L10 a commented, spaced file failed to parse"
192
+ bad "L10 a commented, spaced file failed to parse (rc=$rc)"
193
+ printf '%s\n' "$out" | sed 's/^/ β”‚ /'
168
194
  fi
169
195
 
170
196
  # ── L11/L12 embedded --self-test subjects (foundβ†’extend, 2026-08-14) ──────────────────────────
@@ -186,7 +212,7 @@ mkfixture_clean() { # $1 = dir
186
212
  # L11 known-POSITIVE: an unwired --self-test subject is reported, advisory (rc stays 0).
187
213
  D="$T/l11"; mkfixture_clean "$D"
188
214
  printf '#!/usr/bin/env bash\n[ "${1:-}" = "--self-test" ] && { echo ok; exit 0; }\n' > "$D/scripts/orphan_probe.sh"
189
- out=$(run "$D"); rc=$(rcof "$D")
215
+ run_check "$D"; out="$LRC_OUT"; rc="$LRC_RC"
190
216
  if [ "$rc" = "0" ] && printf '%s' "$out" | grep -q 'orphan_probe'; then
191
217
  ok "L11 known-positive: unwired --self-test subject named, advisory (rc=0)"
192
218
  else
@@ -206,7 +232,7 @@ for _subj in orphan_probe; do
206
232
  bash "scripts/$_subj.sh" --self-test
207
233
  done
208
234
  SC
209
- out=$(run "$D")
235
+ run_check "$D"; out="$LRC_OUT"
210
236
  if ! printf '%s' "$out" | grep -q 'orphan_probe'; then
211
237
  ok "L12 known-negative: --self-test subject wired via _subj for-loop is not reported"
212
238
  else
@@ -228,7 +254,7 @@ bash scripts/lane_runner_check.sh
228
254
  bash scripts/test_ok_lanes.sh
229
255
  bash scripts/orphan_probe.sh --self-test >/dev/null 2>&1
230
256
  SC
231
- out=$(run "$D")
257
+ run_check "$D"; out="$LRC_OUT"
232
258
  if ! printf '%s' "$out" | grep -q 'orphan_probe'; then
233
259
  ok "L13 known-negative: --self-test subject wired via direct dispatch is not reported"
234
260
  else
@@ -262,7 +288,7 @@ cat > "$D/scripts/orphan_probe.sh" <<'SUBJ'
262
288
  # bash scripts/orphan_probe.sh --self-test # known-pair calibration
263
289
  [ "${1:-}" = "--self-test" ] && { echo ok; exit 0; }
264
290
  SUBJ
265
- out=$(run "$D"); rc=$(rcof "$D")
291
+ run_check "$D"; out="$LRC_OUT"; rc="$LRC_RC"
266
292
  if [ "$rc" = "0" ] && printf '%s' "$out" | grep -q 'orphan_probe'; then
267
293
  ok "L14 known-positive: subject's own usage comment is not a caller β€” still reported unwired"
268
294
  else
@@ -280,7 +306,7 @@ bash scripts/lane_runner_check.sh
280
306
  bash scripts/test_ok_lanes.sh
281
307
  # historical note: we used to run `bash scripts/orphan_probe.sh --self-test` here, removed 2026-01-01
282
308
  SC
283
- out=$(run "$D"); rc=$(rcof "$D")
309
+ run_check "$D"; out="$LRC_OUT"; rc="$LRC_RC"
284
310
  if [ "$rc" = "0" ] && printf '%s' "$out" | grep -q 'orphan_probe'; then
285
311
  ok "L15 known-positive: a commented-out dispatch in another file is not a caller"
286
312
  else
@@ -302,7 +328,7 @@ usage() { echo "run: bash scripts/orphan_probe.sh --self-test"; }
302
328
  [ "${1:-}" = "--self-test" ] && { echo ok; exit 0; }
303
329
  usage
304
330
  SUBJ
305
- out=$(run "$D"); rc=$(rcof "$D")
331
+ run_check "$D"; out="$LRC_OUT"; rc="$LRC_RC"
306
332
  if [ "$rc" = "0" ] && printf '%s' "$out" | grep -q 'orphan_probe'; then
307
333
  ok "L16 known-positive: a subject's own NON-comment self-reference is not a caller"
308
334
  else
@@ -323,36 +349,36 @@ fi
323
349
  # ([[feedback_not_found_is_not_zero_family]]).
324
350
  _ISN=$(mktemp); sed -n '/^index_source_note()/,/^}/p' "$CHECK" > "$_ISN"
325
351
  if ! grep -q 'UNMEASURED' "$_ISN"; then
326
- no "IDX-harness β€” index_source_note did not extract from $CHECK (lanes would measure nothing)"
352
+ bad "IDX-harness β€” index_source_note did not extract from $CHECK (lanes would measure nothing)"
327
353
  else
328
354
  # shellcheck disable=SC1090
329
355
  . "$_ISN"
330
356
  o=$(index_source_note "index")
331
357
  printf '%s' "$o" | grep -q "INDEX κΈ°μ€€" && printf '%s' "$o" | grep -q "μŠ€ν…Œμ΄μ§•" \
332
358
  && ok "IDX1 index mode names the index AND the staging remedy" \
333
- || no "IDX1 index mode note missing/incomplete: $o"
359
+ || bad "IDX1 index mode note missing/incomplete: $o"
334
360
 
335
361
  o=$(index_source_note "nongit")
336
362
  printf '%s' "$o" | grep -q "DISK" && ok "IDX2 nongit mode says DISK, not index" \
337
- || no "IDX2 nongit: $o"
363
+ || bad "IDX2 nongit: $o"
338
364
 
339
365
  o=$(index_source_note "UNMEASURED")
340
366
  printf '%s' "$o" | grep -q "λͺ» μ…Œλ‹€" && ok "IDX3 UNMEASURED says Β«could not countΒ», not Β«noneΒ»" \
341
- || no "IDX3 UNMEASURED: $o"
367
+ || bad "IDX3 UNMEASURED: $o"
342
368
 
343
369
  # πŸŸ₯ CONTROL β€” an unknown/empty mode must stay SILENT. Inventing a source line for a state the
344
370
  # check does not recognise is worse than saying nothing, and without this lane the function
345
371
  # could pass IDX1–IDX3 while emitting the index sentence for every input.
346
372
  o=$(index_source_note "")
347
373
  [ -z "$o" ] && ok "IDX4 control β€” empty mode is silent (no invented provenance)" \
348
- || no "IDX4 control β€” empty mode spoke: $o"
374
+ || bad "IDX4 control β€” empty mode spoke: $o"
349
375
 
350
376
  # πŸŸ₯ CONTROL 2 β€” the three states must be DISTINGUISHABLE from each other, not merely non-empty.
351
377
  a=$(index_source_note "index"); b=$(index_source_note "nongit"); c=$(index_source_note "UNMEASURED")
352
378
  if [ "$a" != "$b" ] && [ "$b" != "$c" ] && [ "$a" != "$c" ]; then
353
379
  ok "IDX5 control β€” the three states produce three different sentences"
354
380
  else
355
- no "IDX5 control β€” states collapsed into the same sentence"
381
+ bad "IDX5 control β€” states collapsed into the same sentence"
356
382
  fi
357
383
  fi
358
384
  rm -f "$_ISN"
@@ -362,7 +388,7 @@ if sed -n '/lane suite(s) with no runner and no declaration/,/Fix by ONE of/p' "
362
388
  | grep -q 'index_source_note'; then
363
389
  ok "IDX6 the note is CALLED on the FAIL path (not just defined)"
364
390
  else
365
- no "IDX6 index_source_note is defined but the FAIL path does not call it"
391
+ bad "IDX6 index_source_note is defined but the FAIL path does not call it"
366
392
  fi
367
393
 
368
394
  echo "----"