@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.
- package/.claude/rules/fh_4axis_gate.md +38 -0
- package/.claude-plugin/marketplace.json +2 -2
- package/CLAUDE.md +1 -1
- package/README.md +6 -1
- package/knowledge/shared/harness-core/fh_three_layer_canon.md +47 -0
- package/knowledge/shared/harness-core/field_verdict_crossfamily_gate.md +10 -0
- package/knowledge/shared/harness-core/measurement-integrity-checklist.md +15 -1
- package/knowledge/shared/harness-core/ship_readiness_gate.md +20 -3
- package/knowledge/shared/learnings/subagent_invocations_log.yaml +111 -0
- package/package.json +9 -1
- package/plugins/fh-commons/.claude-plugin/plugin.json +1 -1
- package/plugins/fh-meta/.claude-plugin/plugin.json +1 -1
- package/plugins/fh-meta/CHANGELOG.md +49 -0
- package/plugins/fh-meta/skills/salience-splitter/SKILL.md +1 -1
- package/scripts/backtick_guard.sh +194 -0
- package/scripts/capability_effect_probe.sh +14 -1
- package/scripts/context_continuity_score.sh +106 -12
- package/scripts/fh-gate.sh +3 -3
- package/scripts/files_manifest_shipping_check.sh +19 -0
- package/scripts/gate_pathspec_check.sh +1 -1
- package/scripts/package_coverage_check.sh +25 -2
- package/scripts/proposal_hook.sh +89 -0
- package/scripts/public_surface_scan_files.sh +11 -2
- package/scripts/revert_probe.sh +250 -0
- package/scripts/selfcheck.sh +67 -3
- package/scripts/sim_isolated_run.sh +97 -7
- package/scripts/test_backtick_guard_lanes.sh +115 -0
- package/scripts/test_degrade_scan_shell_probes.sh +7 -7
- package/scripts/test_files_manifest_shipping_lanes.sh +5 -5
- package/scripts/test_heavy_classifier_lanes.sh +1 -1
- package/scripts/test_lane_runner_lanes.sh +59 -33
- package/scripts/test_mapped_tracks_lanes.sh +1 -1
- package/scripts/test_marker_soul_check_lanes.sh +24 -0
- package/scripts/test_node_check_lanes.sh +34 -34
- package/scripts/test_package_coverage_lanes.sh +53 -27
- package/scripts/test_pipe_verdict_guard_lanes.sh +5 -5
- package/scripts/test_precommit_pointer_index_lanes.sh +33 -0
- package/scripts/test_preprep_drift_anchor.sh +13 -4
- package/scripts/test_preprep_drift_anchor_lanes.sh +23 -0
- package/scripts/test_proposal_hook_lanes.sh +36 -0
- package/scripts/test_revert_probe_lanes.sh +146 -0
- package/scripts/test_session_close_lanes.sh +3 -5
- package/scripts/test_sim_isolated_run_lanes.sh +17 -0
- package/scripts/test_verdict_watermark_lanes.sh +27 -1
- package/scripts/utterance_landing_check.sh +2 -2
- package/templates/.git-hooks/pre-commit +27 -4
- package/templates/settings.PreToolUse.snippet.json +37 -1
- 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
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
#
|
|
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
|
-
|
|
34
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
133
|
-
if [ "$
|
|
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
|
-
|
|
143
|
-
if [ "$
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
||
|
|
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
|
-
||
|
|
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
|
-
||
|
|
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
|
-
||
|
|
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
|
-
|
|
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
|
-
|
|
391
|
+
bad "IDX6 index_source_note is defined but the FAIL path does not call it"
|
|
366
392
|
fi
|
|
367
393
|
|
|
368
394
|
echo "----"
|