@chrono-meta/fh-gate 2.6.0 โ 2.7.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 +26 -3
- package/.claude-plugin/marketplace.json +2 -2
- package/AGENTS.md +24 -3
- package/CLAUDE.md +39 -12
- package/README.ja.md +32 -8
- package/README.ko.md +32 -8
- package/README.md +112 -15
- package/README.zh.md +28 -8
- package/knowledge/shared/harness-core/field_verdict_crossfamily_gate.md +19 -5
- package/knowledge/shared/harness-core/harness_incubator_doctrine.md +12 -2
- package/knowledge/shared/harness-core/multi_model_sidecar_strategy.md +32 -0
- package/knowledge/shared/harness-core/ship_readiness_gate.md +77 -8
- package/knowledge/shared/learnings/subagent_invocations_log.yaml +90 -0
- package/knowledge/shared/rules/knowledge_layer_seam.md +1 -1
- package/package.json +13 -2
- 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 +111 -0
- package/plugins/fh-meta/agents/persona-innovator.md +170 -0
- package/plugins/fh-meta/skills/public-surface-audit/SKILL_detail.md +16 -1
- package/plugins/fh-meta/skills/steel-quench/SKILL.md +97 -0
- package/scripts/adapters/peer_resolve.sh +58 -6
- package/scripts/cluster_capability_scan.sh +42 -13
- package/scripts/digest_landing_check.sh +142 -2
- package/scripts/fh_hub_identity.sh +83 -0
- package/scripts/fh_session_load.sh +53 -5
- package/scripts/fh_track_resolve.sh +114 -0
- package/scripts/field_canon_preload.sh +50 -5
- package/scripts/package_coverage_check.sh +8 -0
- package/scripts/prior_art_prompt.sh +168 -0
- package/scripts/psa_scan_lib.sh +201 -15
- package/scripts/residency_admission_check.sh +204 -0
- package/scripts/selfcheck.sh +88 -0
- package/scripts/test_adapter_lanes.sh +67 -2
- package/scripts/test_heavy_classifier_lanes.sh +144 -0
- package/scripts/test_marker_defense_lanes.sh +152 -0
- package/scripts/test_marker_soul_check_lanes.sh +211 -0
- package/scripts/test_prior_art_prompt_lanes.sh +128 -0
- package/scripts/test_psa_singlefile_lanes.sh +351 -1
- package/scripts/test_residency_admission_lanes.sh +60 -0
- package/scripts/test_track_resolve_lanes.sh +158 -0
- package/templates/.git-hooks/pre-commit +400 -4
- package/templates/.git-hooks/pre-push +17 -2
- package/templates/settings.PriorArt.snippet.json +15 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# test_marker_defense_lanes.sh โ regression fixtures for pre-commit's validate_defense_leg
|
|
3
|
+
# (Wave 1-D defense line, 2026-08-20).
|
|
4
|
+
#
|
|
5
|
+
# WHY THIS FILE EXISTS AT ALL: the procedure was absorbed from a sibling harness whose own document
|
|
6
|
+
# asserted "the commit hook reads that line" and "pinned by scripts/test_marker_floor_lanes.sh".
|
|
7
|
+
# ๐ฅ Measured twice, with a control (`crossfamily` โ 21 hits in the same file): BOTH claims were
|
|
8
|
+
# **0 hits** there. The prose was portable; the machine was not. This lane is the machine, built
|
|
9
|
+
# here, so that FH's own claim is true when FH makes it.
|
|
10
|
+
#
|
|
11
|
+
# Fixtures assert BOTH directions (known-pair): every intended shape is admitted, and every hole the
|
|
12
|
+
# leg closes still blocks. A suite that only asserts BLOCK cannot tell "blocked" from "blocked for
|
|
13
|
+
# the wrong reason"; one that only asserts PASS cannot see a leg that admits everything.
|
|
14
|
+
#
|
|
15
|
+
# Usage: bash scripts/test_marker_defense_lanes.sh Exit: 0 = all behave; 1 = regression.
|
|
16
|
+
|
|
17
|
+
set -uo pipefail
|
|
18
|
+
# Script-relative, NOT `git rev-parse --show-toplevel` โ same reason as the sibling lanes: in a
|
|
19
|
+
# vendored tree rev-parse answers with the OUTER repo and the suite measures somebody else's files.
|
|
20
|
+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
21
|
+
HOOK="$REPO_ROOT/templates/.git-hooks/pre-commit"
|
|
22
|
+
T=$(mktemp -d); trap 'rm -rf "$T"' EXIT
|
|
23
|
+
|
|
24
|
+
sed -n '/^validate_defense_leg()/,/^}/p' "$HOOK" > "$T/fn.sh"
|
|
25
|
+
|
|
26
|
+
# Instrument calibration BEFORE any fixture runs. An empty extraction would let every BLOCK
|
|
27
|
+
# fixture "pass" against nothing and every PASS fixture fail โ and the suite would still print a
|
|
28
|
+
# verdict. Assert the body actually arrived.
|
|
29
|
+
if ! grep -q 'estimation-layer' "$T/fn.sh"; then
|
|
30
|
+
echo "โ HARNESS-ERROR โ validate_defense_leg did not extract from $HOOK."
|
|
31
|
+
echo " Fixtures below would measure an empty function. Aborting rather than reporting green."
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
pass=0; fail=0
|
|
36
|
+
mk() { printf '%s\n' "$2" > "$T/$1"; }
|
|
37
|
+
run() { bash -c "source '$T/fn.sh'; validate_defense_leg '$T/$1'" >/dev/null 2>&1; }
|
|
38
|
+
want() { # $1=fixture $2=expect(pass|block) $3=label
|
|
39
|
+
local rc; run "$1"; rc=$?
|
|
40
|
+
local got; [ "$rc" -eq 0 ] && got=pass || got=block
|
|
41
|
+
if [ "$got" = "$2" ]; then printf ' โ
%-6s %s\n' "$2" "$3"; pass=$((pass+1))
|
|
42
|
+
else printf ' โ %-6s %s โ got %s\n' "$2" "$3" "$got"; fail=$((fail+1)); fi
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
GOOD='axis2-defense: reproducibility=bash scripts/test_marker_defense_lanes.sh at 4c1f2ab fairness=both arms reps=3, same fixture dir, same shell estimation-layer=all measured; known-pair separated arm from control'
|
|
46
|
+
|
|
47
|
+
echo "[marker-defense] known-pair fixtures"
|
|
48
|
+
echo " โโ admitted (must not over-block; over-blocking teaches --no-verify) โโ"
|
|
49
|
+
mk ok.md "floor-status: sonnet-floor
|
|
50
|
+
$GOOD"
|
|
51
|
+
want ok.md pass "all three substantive"
|
|
52
|
+
mk multiline.md "floor-status: sonnet-floor
|
|
53
|
+
axis2-defense: reproducibility=git show 9cd7350 -- scripts/selfcheck.sh
|
|
54
|
+
fairness=arm and control both on 2.6.0 tarball, reps=1 each, named
|
|
55
|
+
estimation-layer=counts measured; the 2,367 b/day figure is a quotation"
|
|
56
|
+
want multiline.md pass "continuation lines are one value"
|
|
57
|
+
mk order.md "floor-status: below-floor
|
|
58
|
+
axis2-defense: estimation-layer=measured via npm pack --dry-run --json fairness=same tarball both arms reproducibility=npm pack @chrono-meta/fh-gate@2.6.0"
|
|
59
|
+
want order.md pass "sub-answers in any order"
|
|
60
|
+
|
|
61
|
+
echo " โโ blocked โโ"
|
|
62
|
+
mk none.md "floor-status: sonnet-floor"
|
|
63
|
+
want none.md block "no axis2-defense line at all"
|
|
64
|
+
mk empty.md "floor-status: sonnet-floor
|
|
65
|
+
axis2-defense:"
|
|
66
|
+
want empty.md block "key present, value empty (silence is not an answer)"
|
|
67
|
+
mk partial.md "floor-status: sonnet-floor
|
|
68
|
+
axis2-defense: reproducibility=bash scripts/selfcheck.sh completes rc=0 fairness=both arms on same tree"
|
|
69
|
+
want partial.md block "estimation-layer missing โ a partial form is not a defense"
|
|
70
|
+
# ๐ฅ rc IS NOT ENOUGH HERE โ measured by a revert probe on 2026-08-20, the day this was written.
|
|
71
|
+
# Deleting the completeness guard leaves `partial.md` STILL blocked, because an absent sub-answer
|
|
72
|
+
# also reads as an empty (vacuous) one and the next guard catches it. Gating on the exit code alone
|
|
73
|
+
# therefore certifies a guard that is doing nothing: the classic decorative anchor. What the
|
|
74
|
+
# completeness guard actually buys is the PRESCRIPTION โ "missing sub-answer(s): estimation-layer"
|
|
75
|
+
# tells the author which question they skipped, where "too short" sends them to rewrite the wrong
|
|
76
|
+
# field. A gate's output is half its product, so the lane measures the output.
|
|
77
|
+
want_msg() { # $1=fixture $2=substring $3=label
|
|
78
|
+
local out; out=$(bash -c "source '$T/fn.sh'; validate_defense_leg '$T/$1'" 2>&1)
|
|
79
|
+
if printf '%s' "$out" | grep -qF "$2"; then printf ' โ
%-6s %s\n' "msg" "$3"; pass=$((pass+1))
|
|
80
|
+
else printf ' โ %-6s %s โ output did not contain %s\n' "msg" "$3" "$2"; fail=$((fail+1)); fi
|
|
81
|
+
}
|
|
82
|
+
want_msg partial.md "missing sub-answer(s): estimation-layer" \
|
|
83
|
+
"prescription NAMES the skipped question (guard is load-bearing for the message)"
|
|
84
|
+
# (the short.md prescription control lives below, AFTER that fixture is created โ
|
|
85
|
+
# ๐ฅ it was first written here, before `mk short.md`, so it measured a NON-EXISTENT file and
|
|
86
|
+
# read the "no line at all" message. The lane was wrong, not the subject. Fixture order is
|
|
87
|
+
# part of the instrument.)
|
|
88
|
+
mk vacuous.md "floor-status: sonnet-floor
|
|
89
|
+
axis2-defense: reproducibility=ok fairness=yes estimation-layer=n/a"
|
|
90
|
+
want vacuous.md block "filled form, not an answer"
|
|
91
|
+
mk short.md "floor-status: sonnet-floor
|
|
92
|
+
axis2-defense: reproducibility=ran it fairness=same estimation-layer=nums"
|
|
93
|
+
want short.md block "too short to name a command, reps or layer"
|
|
94
|
+
want_msg short.md "vacuous answer(s)" \
|
|
95
|
+
"control โ the short case takes the OTHER prescription (the two are distinguishable)"
|
|
96
|
+
mk dup.md "floor-status: sonnet-floor
|
|
97
|
+
$GOOD
|
|
98
|
+
$GOOD"
|
|
99
|
+
want dup.md block "two lines โ the reader takes the first, so a correction is shadowed"
|
|
100
|
+
|
|
101
|
+
echo " โโ call-site pin (a function nobody calls is prose) โโ"
|
|
102
|
+
# ๐ฅ Found by cross-family review 2026-08-20 (codex/gpt-5.5), self-detection 0: this suite extracts
|
|
103
|
+
# the FUNCTION and calls it directly, so deleting the hook's call site left every lane green while
|
|
104
|
+
# the leg stopped running โ and the skill doc claimed "pre-commit runs this". That is the exact
|
|
105
|
+
# defect class this whole file was built to stop importing, reproduced one layer up.
|
|
106
|
+
# The pin is a grep, and its limit is stated rather than hidden: it proves the call EXISTS and sits
|
|
107
|
+
# in the full-gate marker block, not that the block is reached. Reachability is pinned by the hook's
|
|
108
|
+
# own end-to-end lanes, not here.
|
|
109
|
+
cs=$(grep -c 'validate_defense_leg "\$MARKER"' "$HOOK")
|
|
110
|
+
if [ "$cs" -eq 1 ]; then
|
|
111
|
+
printf ' โ
%-6s %s\n' "call" "hook calls validate_defense_leg exactly once"; pass=$((pass+1))
|
|
112
|
+
else
|
|
113
|
+
printf ' โ %-6s %s โ found %s call site(s)\n' "call" "hook calls validate_defense_leg exactly once" "$cs"; fail=$((fail+1))
|
|
114
|
+
fi
|
|
115
|
+
# and that the call is gated on the floor tiers the doc claims โ not on load-bearing, which is
|
|
116
|
+
# where it was first (wrongly) wired.
|
|
117
|
+
if grep -B4 'validate_defense_leg "\$MARKER"' "$HOOK" | grep -qE 'floor-status:.*sonnet-floor\|below-floor'; then
|
|
118
|
+
printf ' โ
%-6s %s\n' "call" "call is gated on floor-status (sonnet-floor|below-floor)"; pass=$((pass+1))
|
|
119
|
+
else
|
|
120
|
+
printf ' โ %-6s %s\n' "call" "call is NOT gated on floor-status โ scope drifted from the doc"; fail=$((fail+1))
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
echo " โโ prescriptions (rc alone certifies guards that do nothing) โโ"
|
|
124
|
+
# ๐ฅ Same shadowing as the completeness guard: removing the presence guard leaves none.md/empty.md
|
|
125
|
+
# still blocked by the missing-subanswer guard, so rc cannot see it. What presence buys is the
|
|
126
|
+
# prescription that shows the author the whole field shape.
|
|
127
|
+
want_msg none.md "no 'axis2-defense:' line" \
|
|
128
|
+
"presence guard is load-bearing for its own message"
|
|
129
|
+
want_msg empty.md "no 'axis2-defense:' line" \
|
|
130
|
+
"empty value takes the same prescription as absent (silence is silence)"
|
|
131
|
+
|
|
132
|
+
echo " โโ controls (the leg discriminates; it does not just fire) โโ"
|
|
133
|
+
# ๐ฅ known-NEGATIVE for over-blocking: a legitimate answer that merely LOOKS terse per-field but
|
|
134
|
+
# clears the bar. Without this, a leg that blocked everything would pass every BLOCK row above.
|
|
135
|
+
mk borderline.md "floor-status: sonnet-floor
|
|
136
|
+
axis2-defense: reproducibility=see PR #471 CI log job 96296828886 fairness=arms differ: control is v2.5.1 tarball โ stated estimation-layer=one measured, one quoted from CHANGELOG"
|
|
137
|
+
want borderline.md pass "control โ admits an honest answer that NAMES an asymmetry"
|
|
138
|
+
# ๐ฅ known-negative on the em-dash: `fairness` here contains a dash, which must NOT truncate parsing
|
|
139
|
+
mk dashes.md "floor-status: sonnet-floor
|
|
140
|
+
axis2-defense: reproducibility=git log main..HEAD --oneline fairness=both arms โ same reps, same env estimation-layer=measured; instrument calibrated on a known pair"
|
|
141
|
+
want dashes.md pass "control โ dashes inside a value do not truncate it"
|
|
142
|
+
|
|
143
|
+
echo
|
|
144
|
+
if [ "$fail" -eq 0 ]; then
|
|
145
|
+
echo "โ
marker-defense: $pass lanes hold (0 failed)"
|
|
146
|
+
echo " ๐ฅ SCOPE: this suite pins PRESENCE, COMPLETENESS and NON-VACUITY. It cannot pin whether"
|
|
147
|
+
echo " the answers are TRUE โ that is the operator's and the weekly audit's, like every other"
|
|
148
|
+
echo " marker field. A green line here is not a claim that the defense was actually mounted."
|
|
149
|
+
exit 0
|
|
150
|
+
fi
|
|
151
|
+
echo "โ marker-defense: $fail failed / $pass passed"
|
|
152
|
+
exit 1
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# test_marker_soul_check_lanes.sh โ regression fixtures for pre-commit's
|
|
3
|
+
# validate_soul_check_leg
|
|
4
|
+
# (โ ๊ฒฉ๋ฆฌ ๊ทธ๋ผ์ด๋ฉ โ ์ฌ์ ์ ์ธ์ผ๋ก ํ์ฅ, 2026-08-21).
|
|
5
|
+
#
|
|
6
|
+
# ๐ฅ NOT a seventh axis. `fh_three_layer_canon.md ยง1-a-2` splits axes by ยซ๋ฌด์์ ๋ฐ์๋๊ฐยป, and
|
|
7
|
+
# โ already receives ยซ์ ์๊ฐ ์ด ๋ฌธ์ฅ + ์ง๊ธ์ ํธ๋ฆฌยป โ identical to this leg's input. Tense
|
|
8
|
+
# (์ฌ์ ์ ์ธ vs ์ฌํ ์ฃผ์ฅ) is a posture, not an axis.
|
|
9
|
+
#
|
|
10
|
+
# WHY: `โ ์ํผ` has been required on every marker since 2026-08-09 and is written 4/4 on the real
|
|
11
|
+
# corpus, with ZERO consuming code (measured with a control: `crossfamily` = 21 hits in the hook,
|
|
12
|
+
# `โ ์ํผ`/`soul` = 0 lines that read it; `fh_4axis_gate.md` does not name the field). Slot with no
|
|
13
|
+
# consumer โ presence does the judging โ always "done".
|
|
14
|
+
#
|
|
15
|
+
# SCOPE โ channel, not judgment. These lanes assert the RECORD's properties: single ยท closed enum ยท
|
|
16
|
+
# non-vacuous ยท not wearing another axis's tokens ยท consistent with the โ ์ํผ line in the SAME file.
|
|
17
|
+
# They never assert the read-back reached the right conclusion.
|
|
18
|
+
#
|
|
19
|
+
# ๐ฅ NAMED RESIDUAL โ a fabricated `reflected(<fluent reason>)` on a marker that DOES carry an
|
|
20
|
+
# โ ์ํผ line PASSES. Provenance is not checkable from a file (the hook says so at the โ ์ํผ
|
|
21
|
+
# comment, and that part is correct). The hole is ยง4-b's โ cross-family reads the marker.
|
|
22
|
+
#
|
|
23
|
+
# Fixtures assert BOTH directions (known-pair): every intended shape is admitted, and every hole
|
|
24
|
+
# the lane closes still blocks.
|
|
25
|
+
#
|
|
26
|
+
# Usage: bash scripts/test_marker_soul_check_lanes.sh Exit: 0 = all behave; 1 = regression.
|
|
27
|
+
|
|
28
|
+
set -uo pipefail
|
|
29
|
+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
30
|
+
HOOK="$REPO_ROOT/templates/.git-hooks/pre-commit"
|
|
31
|
+
T=$(mktemp -d); trap 'rm -rf "$T"' EXIT
|
|
32
|
+
|
|
33
|
+
sed -n '/^validate_soul_check_leg()/,/^}/p' "$HOOK" > "$T/fn.sh"
|
|
34
|
+
|
|
35
|
+
# Instrument calibration โ an empty extraction would let every fixture "pass" against nothing.
|
|
36
|
+
if ! grep -q 'DEGRADED_NO_SOUL' "$T/fn.sh"; then
|
|
37
|
+
echo "โ HARNESS-ERROR โ validate_soul_check_leg did not extract from $HOOK."
|
|
38
|
+
echo " Fixtures below would measure an empty function. Aborting rather than reporting green."
|
|
39
|
+
exit 1
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
SOUL='โ ์ํผ: ์ฑ๊ณต ์ ์ = ยซ์๋น์ ๊ฒฝ๋ก์์ ์์ฃผํด rc=0 ์ ๋ด๊ณ ์ปจํธ๋กค๋ก ๊ฐ๋ฅธ๋คยป. ์ ๋ ์ ํจ = ยซFAIL ์ SKIP ์ผ๋ก ๋ฐ๊พธ๋ ๊ฒยป'
|
|
43
|
+
|
|
44
|
+
FAIL=0
|
|
45
|
+
lane() { # $1 = id $2 = expect(BLOCK|PASS) $3 = marker body
|
|
46
|
+
local id="$1" expect="$2" body="$3" rc out
|
|
47
|
+
printf '%s\n' "$body" > "$T/m.marker"
|
|
48
|
+
out=$( bash -c 'set -uo pipefail; . "$1"; validate_soul_check_leg "$2"' _ "$T/fn.sh" "$T/m.marker" 2>&1 ); rc=$?
|
|
49
|
+
local got=PASS; [ $rc -ne 0 ] && got=BLOCK
|
|
50
|
+
if [ "$got" = "$expect" ]; then
|
|
51
|
+
printf ' โ
%-40s %s\n' "$id" "$got"
|
|
52
|
+
else
|
|
53
|
+
printf ' โ %-40s expected %s, got %s\n %s\n' "$id" "$expect" "$got" "$(printf '%s' "$out" | head -3)"
|
|
54
|
+
FAIL=1
|
|
55
|
+
fi
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
echo "== soul-check lanes โ BLOCK side (holes that must stay closed) =="
|
|
59
|
+
lane G1-not-in-enum BLOCK "$SOUL
|
|
60
|
+
soul-check: done"
|
|
61
|
+
lane G2-bare-reflected BLOCK "$SOUL
|
|
62
|
+
soul-check: reflected"
|
|
63
|
+
lane G3-vacuous-grounds BLOCK "$SOUL
|
|
64
|
+
soul-check: reflected(ok)"
|
|
65
|
+
lane G4-duplicate-line BLOCK "$SOUL
|
|
66
|
+
soul-check: UNKNOWN
|
|
67
|
+
soul-check: reflected(cross-family agy ๊ฐ ๋ธํ๋ฅผ ์ฑ๊ณต์ ์์ ๋น์ถฐ 2๊ฑด ์ง์ )"
|
|
68
|
+
lane G5-crossaxis-tier2 BLOCK "$SOUL
|
|
69
|
+
soul-check: tier2(qasp)"
|
|
70
|
+
lane G6-crossaxis-checked BLOCK "$SOUL
|
|
71
|
+
soul-check: checked(prior art ์์)"
|
|
72
|
+
lane G7-crossaxis-panel BLOCK "$SOUL
|
|
73
|
+
soul-check: panel(codex,agy)"
|
|
74
|
+
echo " -- the consistency check (two fields, one record) --"
|
|
75
|
+
lane G8-reflected-no-soul BLOCK "axis2-model: opus
|
|
76
|
+
soul-check: reflected(๋ธํ๋ฅผ ์ฑ๊ณต์ ์์ ๋น์ถฐ ๋ดค๊ณ ์ด๊ธ๋จ ์์)"
|
|
77
|
+
lane G9-reflected-empty-soul BLOCK "โ ์ํผ: ์์
|
|
78
|
+
soul-check: reflected(๋ธํ๋ฅผ ์ฑ๊ณต์ ์์ ๋น์ถฐ ๋ดค๊ณ ์ด๊ธ๋จ ์์)"
|
|
79
|
+
lane G10-violated-no-soul BLOCK "axis2-model: opus
|
|
80
|
+
soul-check: violated(์ ๋์ํจ ์ ์ด๊ฒผ๋ค โ SKIP ์ผ๋ก ๋ฐ๊ฟจ๋ค)"
|
|
81
|
+
lane G11-nosoul-but-soul-is BLOCK "$SOUL
|
|
82
|
+
soul-check: DEGRADED_NO_SOUL(์ํผ ์ค์ด ์์ด์ ๋๋น์ถ ๋์ ์์ฒด๊ฐ ์๋ค)"
|
|
83
|
+
lane G11b-nosoul-but-soul-key BLOCK "soul: ์ฑ๊ณต ์ ์ = ์๋น์ ๊ฒฝ๋ก์์ ์์ฃผํ๋ค. ์ ๋ ์ ํจ = FAIL ์ SKIP ์ผ๋ก ๋ฐ๊พธ์ง ์๋๋ค
|
|
84
|
+
soul-check: DEGRADED_NO_SOUL(์ํผ ์ค์ด ์์ด์ ๋๋น์ถ ๋์ ์์ฒด๊ฐ ์๋ค)"
|
|
85
|
+
|
|
86
|
+
echo "== soul-check lanes โ PASS side (intended shapes must be admitted) =="
|
|
87
|
+
lane G12-absent-is-grace PASS "$SOUL
|
|
88
|
+
axis2-model: opus"
|
|
89
|
+
lane G13-reflected-ok PASS "$SOUL
|
|
90
|
+
soul-check: reflected(agy/gemini ๊ฐ ๋ธํ๋ฅผ ์ฑ๊ณต์ ์์ ๋น์ถฐ ์ฌ๊ฒ โ ์ ๋์ํจ ์๋ฐ 0, ์ฑ๊ณต์ ์ ๋ฏธ๋ฌ 0)"
|
|
91
|
+
lane G13b-reflected-soul-key PASS "soul: ์ฑ๊ณต ์ ์ = ์๋น์ ๊ฒฝ๋ก์์ ์์ฃผํ๋ค. ์ ๋ ์ ํจ = FAIL ์ SKIP ์ผ๋ก ๋ฐ๊พธ์ง ์๋๋ค
|
|
92
|
+
soul-check: reflected(codex ๊ฐ soul ํ๋๋ฅผ ์ฑ๊ณต์ ์์ ๋น์ถฐ ์ฌ๊ฒ โ ์๋ฐ 0)"
|
|
93
|
+
lane G14-violated-is-legal PASS "$SOUL
|
|
94
|
+
soul-check: violated(์ ๋์ํจ ยซFAIL ์ SKIP ์ผ๋กยป ๋ฅผ ์ด๊ฒผ๋ค โ ๋๋๋ฆฌ๊ณ ์ฃผ์ฒด๋ฅผ ์ด๋ฆ์ผ๋ก ์ฐ๊ฒ ๊ณ ์ณค๋ค)"
|
|
95
|
+
lane G15-unknown-bare-ok PASS "$SOUL
|
|
96
|
+
soul-check: UNKNOWN"
|
|
97
|
+
lane G16-degraded-not-run PASS "$SOUL
|
|
98
|
+
soul-check: DEGRADED_NOT_RUN(๋๋น์ถ ์ฌ์ด๋์นด๊ฐ ์์ด ์ด๋ฒ ์ปค๋ฐ์์ ์ ๋๋ ธ๋ค)"
|
|
99
|
+
lane G17-nosoul-when-truly PASS "axis2-model: opus
|
|
100
|
+
soul-check: DEGRADED_NO_SOUL(๊ฒฝ๋ ์์ธ ์ปค๋ฐ์ด๋ผ ์ํผ ์ค์ ์ ์ผ๋ค)"
|
|
101
|
+
lane G18-not-applicable PASS "$SOUL
|
|
102
|
+
soul-check: not-applicable(๋ฌธ์ ์คํ ์์ ์ด๋ผ ์ฑ๊ณต์ ์์ ๊ฑธ๋ฆฌ๋ ๋ธํ๊ฐ ์๋ค)"
|
|
103
|
+
lane G19-em-dash-reason PASS "$SOUL
|
|
104
|
+
soul-check: reflected(codex ๊ฐ ์ฑ๊ณต์ ์ ๋์กฐ โ ์ด๊ธ๋จ ์์) โ 2026-08-21"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# โโ โ ์ํผ presence lane (validate_soul_present_leg) โโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
108
|
+
sed -n '/^validate_soul_present_leg()/,/^}/p' "$HOOK" > "$T/fnp.sh"
|
|
109
|
+
if ! grep -q 'SOUL_PRESENT_GRACE' "$T/fnp.sh" && ! grep -q 'โ ์ํผ line' "$T/fnp.sh"; then
|
|
110
|
+
echo "โ HARNESS-ERROR โ validate_soul_present_leg did not extract. Aborting."
|
|
111
|
+
exit 1
|
|
112
|
+
fi
|
|
113
|
+
GRACE=$(grep -m1 '^SOUL_PRESENT_GRACE_DATE=' "$HOOK" | sed -E 's/.*"(.*)"/\1/')
|
|
114
|
+
|
|
115
|
+
planep() { # $1=id $2=expect $3=filename-date $4=body
|
|
116
|
+
local id="$1" expect="$2" d="$3" body="$4" rc out f
|
|
117
|
+
f="$T/.axes_23_passed_fix_x_${d}.marker"
|
|
118
|
+
printf '%s\n' "$body" > "$f"
|
|
119
|
+
out=$( bash -c 'set -uo pipefail; SOUL_PRESENT_GRACE_DATE="$3"; . "$1"; validate_soul_present_leg "$2"' \
|
|
120
|
+
_ "$T/fnp.sh" "$f" "$GRACE" 2>&1 ); rc=$?
|
|
121
|
+
local got=PASS; [ $rc -ne 0 ] && got=BLOCK
|
|
122
|
+
if [ "$got" = "$expect" ]; then printf ' โ
%-40s %s\n' "$id" "$got"
|
|
123
|
+
else printf ' โ %-40s expected %s, got %s\n %s\n' "$id" "$expect" "$got" "$(printf '%s' "$out"|head -2)"; FAIL=1; fi
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
echo
|
|
127
|
+
echo "== โ ์ํผ presence lanes (grace = $GRACE) =="
|
|
128
|
+
planep P1-missing-post-grace BLOCK "$GRACE" 'axes-run: โ=codex โ=โstandpoint
|
|
129
|
+
crossfamily: panel(codex,agy) โ ๊ฒน์น ์ง์ 0'
|
|
130
|
+
# ๐ฅ P2 flipped BLOCKโPASS on 2026-08-21: a bare `์์` is the value CLAUDE.md ยง์๊ธฐ ๋์กฐ
|
|
131
|
+
# explicitly permits, and blocking it punished the honest form while a padded ยซI didn't write
|
|
132
|
+
# oneยป paragraph passed. Found by a peer session's first real use, not by this suite.
|
|
133
|
+
planep P2-declared-absent-ok PASS "$GRACE" 'โ ์ํผ: ์์
|
|
134
|
+
axes-run: โ=codex'
|
|
135
|
+
planep P2b-empty-field-blocks BLOCK "$GRACE" 'soul:
|
|
136
|
+
axes-run: โ=codex'
|
|
137
|
+
planep P2c-absent-heading-form PASS "$GRACE" '## โ ์ํผ โ ์์
|
|
138
|
+
axes-run: โ=codex'
|
|
139
|
+
# fixture updated 2026-08-21: `์์` became a legal declared-absence value, so a truly vacuous
|
|
140
|
+
# field is now the discriminating input (the point of codex's lane was masking-by-next-field,
|
|
141
|
+
# not the token `์์`).
|
|
142
|
+
planep P2b-vacuous-before-fields BLOCK "$GRACE" 'โ ์ํผ: ok
|
|
143
|
+
axis2-engine: steel-quench
|
|
144
|
+
axis2-model: opus
|
|
145
|
+
floor-status: ok
|
|
146
|
+
axes-run: โ=codex โ=โstandpoint โ=x โ=x โ=x โ=x
|
|
147
|
+
controls: alive โ known-positive x 1 hit ยท known-negative 0'
|
|
148
|
+
planep P3-present-korean PASS "$GRACE" "$SOUL
|
|
149
|
+
axes-run: โ=codex"
|
|
150
|
+
planep P4-present-soul-key PASS "$GRACE" 'soul: ์ฑ๊ณต ์ ์ = ์๋น์ ๊ฒฝ๋ก์์ ์์ฃผํ๋ค. ์ ๋ ์ ํจ = FAIL ์ SKIP ์ผ๋ก ๋ฐ๊พธ์ง ์๋๋ค
|
|
151
|
+
axes-run: โ=codex'
|
|
152
|
+
planep P5-grace-old-exempt PASS "2026-08-01" 'axes-run: โ=codex
|
|
153
|
+
crossfamily: panel(codex,agy) โ ๊ฒน์น ์ง์ 0'
|
|
154
|
+
planep P6-real-corpus-negative BLOCK "$GRACE" "$(cat "$REPO_ROOT/tracks/_meta/.axes_23_passed_feat_target-freeze-gate_2026-08-18.marker" 2>/dev/null || echo 'axes-run: x')"
|
|
155
|
+
planep P7-real-corpus-positive PASS "$GRACE" "$(cat "$REPO_ROOT/tracks/_meta/.axes_23_passed_fix_witness-two-commit-discipline_2026-08-17.marker" 2>/dev/null || echo 'โ ์ํผ: ์ฑ๊ณต ์ ์ = ํ๋ ๋ ์
๋ท ๋ค์ฏ ์ฌ์ฏ')"
|
|
156
|
+
|
|
157
|
+
echo
|
|
158
|
+
echo "== cross-family findings โ regression lanes (codex/gpt-5.5, diff ์ถ, 2026-08-21) =="
|
|
159
|
+
# F1 self-referential FP: codex's own alignment fix flipped G8 to PASS because the
|
|
160
|
+
# `soul-check:` line contains ใ์ฑ๊ณต์ ์ใ and matched as its own evidence.
|
|
161
|
+
lane F1-selfref-soulcheck-only BLOCK 'axis2-model: opus
|
|
162
|
+
soul-check: reflected(๋ธํ๋ฅผ ์ฑ๊ณต์ ์์ ๋น์ถฐ ๋ดค๊ณ ์ ๋ ์ ํจ ๋ ์ ์ด๊ฒผ๋ค)'
|
|
163
|
+
# F4 grounds outside the parens
|
|
164
|
+
lane F4-grounds-outside-parens BLOCK "$SOUL
|
|
165
|
+
soul-check: reflected() โ ์์ฃผ ๊ธธ๊ณ ๊ทธ๋ด๋ฏํ ๊ผฌ๋ฆฌ๋ง์ด ์ฌ๊ธฐ ๋ถ์ด ์์ด์ ๊ธธ์ด๋ฅผ ์ฑ์ด๋ค"
|
|
166
|
+
# F3 near-miss key reads as absent
|
|
167
|
+
lane F3-nearmiss-key BLOCK "$SOUL
|
|
168
|
+
soul_check: reflected(๋ธํ๋ฅผ ์ฑ๊ณต์ ์์ ๋น์ถฐ ์ฌ๊ฒํ๋ค)"
|
|
169
|
+
lane F3b-nearmiss-space BLOCK "$SOUL
|
|
170
|
+
soul-check : reflected(๋ธํ๋ฅผ ์ฑ๊ณต์ ์์ ๋น์ถฐ ์ฌ๊ฒํ๋ค)"
|
|
171
|
+
planep F1b-presence-selfref BLOCK "$GRACE" 'axes-run: โ=codex
|
|
172
|
+
soul-check: reflected(์ฑ๊ณต ์ ์ ๋์กฐ ยท ์ ๋ ์ ํจ ํ์ธ)'
|
|
173
|
+
planep F1c-comment-not-soul BLOCK "$GRACE" '# ์ฑ๊ณต ์ ์ ๋ฅผ ๋์ค์ ์ธ ์์ ์ด๋ค ์ ๋ ์ ํจ ๋
|
|
174
|
+
axes-run: โ=codex'
|
|
175
|
+
# F2: unparseable date must NOT take the grace exit (was fail-open)
|
|
176
|
+
printf 'axes-run: a=codex\n' > "$T/.axes_23_passed_nodate.marker"
|
|
177
|
+
_o=$( bash -c 'set -uo pipefail; SOUL_PRESENT_GRACE_DATE="$3"; . "$1"; validate_soul_present_leg "$2"' \
|
|
178
|
+
_ "$T/fnp.sh" "$T/.axes_23_passed_nodate.marker" "$GRACE" 2>&1 ); _r=$?
|
|
179
|
+
if [ $_r -ne 0 ]; then printf ' โ
%-40s %s\n' "F2-unparseable-date-not-exempt" "BLOCK"
|
|
180
|
+
else printf ' โ %-40s expected BLOCK, got PASS\n' "F2-unparseable-date-not-exempt"; FAIL=1; fi
|
|
181
|
+
|
|
182
|
+
echo
|
|
183
|
+
echo "== cross-family findings โ regression lanes (agy/gemini-3.1-pro, ์ฃผ์ฅยท๊ธฐ๋ก ์ถ) =="
|
|
184
|
+
# A6 [S]: grounds counted with ${#} passed on a single long Korean token. Word count now.
|
|
185
|
+
lane A6-korean-onetoken-grounds BLOCK "$SOUL
|
|
186
|
+
soul-check: reflected(์ด๊ธ๋จ์์ํ์ธ์๋ฃํ์)"
|
|
187
|
+
# A6b [S]: the two legs disagreed on the SAME soul block (6 vs 4 words). Aligned to 6.
|
|
188
|
+
# 5 words under `wc -w` โ passed the old 4-word floor in the check leg while the present leg
|
|
189
|
+
# demanded 6 on the SAME block. Empirically calibrated, not guessed: `wc -w` does not equal a
|
|
190
|
+
# human word count on Korean (ยซโ ์ํผ: ์์ฃผยป reports 3), so the fixture was measured, not reasoned.
|
|
191
|
+
lane A6b-threshold-aligned BLOCK 'โ ์ํผ: ์ฑ๊ณต ์ ์
|
|
192
|
+
soul-check: reflected(๋ธํ๋ฅผ ์ฑ๊ณต์ ์์ ๋น์ถฐ ์ฌ๊ฒํ๊ณ ์ด๊ธ๋จ ์์)'
|
|
193
|
+
# A6-control: a genuinely grounded, multi-word reason still passes (this lane must NOT block).
|
|
194
|
+
lane A6c-control-passes PASS "$SOUL
|
|
195
|
+
soul-check: reflected(codex ๊ฐ ์ฑ๊ณต์ ์ ๋์กฐ โ ์ด๊ธ๋จ ์์)"
|
|
196
|
+
|
|
197
|
+
echo
|
|
198
|
+
echo "== ์ฒซ ์ค์ฌ์ฉ findings โ peer session (forge-harness-59, 2026-08-21) =="
|
|
199
|
+
# A marker that declares NO success definition cannot claim to have reflected against one.
|
|
200
|
+
lane N1-absent-soul-vs-reflected BLOCK 'soul: ์์
|
|
201
|
+
soul-check: reflected(๋ธํ๋ฅผ ์ฑ๊ณต์ ์์ ๋น์ถฐ ์ฌ๊ฒํ๊ณ ์ด๊ธ๋จ ์์)'
|
|
202
|
+
lane N2-absent-soul-degraded-ok PASS 'soul: ์์
|
|
203
|
+
soul-check: DEGRADED_NO_SOUL(์ค๊ณ ์ ์ ์ฑ๊ณต ์ ์๋ฅผ ์ฐ์ง ์์๋ค โ ๋๋น์ถ ๋์์ด ์๋ค)'
|
|
204
|
+
# The padded confession that passed in the field: it IS a real declaration of absence, and once
|
|
205
|
+
# `์์` is a first-class value the padded form is no longer the only way through.
|
|
206
|
+
lane N3-padded-confession PASS 'soul: ์์ โ ์ค๊ณ ์ ์ ์ ์ผ๋ค. ์ฌํ ์ฌ๊ตฌ์ฑ์ด ์๋๋ผ ๊ทธ ์ฌ์ค์ ์ ๋๋ค. ๋ถ์ก๊ณ ์๋ ๊ฒ์ ๋ฒ์ ๊ฒฐ์ ํ๋์๋ค
|
|
207
|
+
axes-run: โ=codex'
|
|
208
|
+
|
|
209
|
+
echo
|
|
210
|
+
if [ $FAIL -eq 0 ]; then echo "SOUL LANES: PASS"; else echo "SOUL LANES: FAIL"; fi
|
|
211
|
+
exit $FAIL
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# test_prior_art_prompt_lanes.sh โ T2 ํ
์ known-pair ์ต์ปค.
|
|
3
|
+
# ๐ฅ ์ด ํ
์ ์ฌํ์ ยซ๋ง๋ยป ๊ฐ ์๋๋ผ **ยซ์์์ด ์๋๊ฐยป** ๋ค. ๋๋
์๊ฐ ์ง๋ชฉํ ์๊ธฐ๋ฌด๋ ฅํ ๊ฒฝ๋ก:
|
|
4
|
+
# ํธ๋ฆฌ๊ฑฐ๊ฐ ๋ถ์ ํํ๋ฉด ํ๋ฃจ ์์ญ ๋ฒ ๋จ๊ณ , 3ํ ๊ฑฐ์ ์ต์ ๊ฐ ์ค์ ์ค์ ์ผ์ ธ์ ๊ธฐ๋ฅ์ด ์กฐ์ฉํ ์ฃฝ๋๋ค.
|
|
5
|
+
# ๊ทธ๋์ ์์ฑ ๋ ์ธ์ด ์์ฑ๋ณด๋ค ๋ง๋ค.
|
|
6
|
+
set -uo pipefail
|
|
7
|
+
FH="$(cd "$(dirname "$0")/.." && pwd)"
|
|
8
|
+
H="$FH/scripts/prior_art_prompt.sh"
|
|
9
|
+
PASS=0; FAIL=0
|
|
10
|
+
T="$(mktemp -d -t pap.XXXXXX)" || exit 3
|
|
11
|
+
trap 'rm -rf "$T"' EXIT INT TERM
|
|
12
|
+
chk(){ if [ "$2" = "$3" ]; then echo " โ
$1"; PASS=$((PASS+1)); else echo " โ $1 (got=$2 want=$3)"; FAIL=$((FAIL+1)); fi; }
|
|
13
|
+
# ๊ฐ ํธ์ถ์ ์ธ์
-์คํฌํ๋ฅผ ๊ฒฉ๋ฆฌํด์ผ ยซํ ๋ฒ๋งยป ๊ท์น์ ์๋ก ์ ๊ฑธ๋ฆฐ๋ค
|
|
14
|
+
fires(){ local d; d="$(mktemp -d -t papd.XXXXXX)"; mkdir -p "$d/.claude"
|
|
15
|
+
local o; o=$(printf '{"tool_input":{"file_path":"%s"}}' "$1" | CLAUDE_PROJECT_DIR="$d" bash "$H" 2>/dev/null)
|
|
16
|
+
rm -rf "$d"; [ -n "$o" ] && echo yes || echo no; }
|
|
17
|
+
|
|
18
|
+
echo "โโ ์์ฑ: ์ ยซ๋ฉ์ปค๋์ฆยป ์ ์ฐ๊ธฐ ์ง์ โโ"
|
|
19
|
+
chk "P1 ์ .sh" "$(fires "$T/new_gate.sh")" yes
|
|
20
|
+
chk "P2 ์ SKILL.md" "$(fires "$T/plugins/x/skills/y/SKILL.md")" yes
|
|
21
|
+
chk "P3 ์ agents/*.md" "$(fires "$T/plugins/x/agents/z.md")" yes
|
|
22
|
+
chk "P4 ์ .py" "$(fires "$T/tool.py")" yes
|
|
23
|
+
|
|
24
|
+
echo "โโ ์์ฑ: ์์์ด ๋๋ฉด ์ด ๋ฅ๋ ฅ์ด ์ฃฝ๋๋ค โโ"
|
|
25
|
+
printf 'x\n' > "$T/exists.sh"
|
|
26
|
+
chk "N1 ๐ฅ ยซ์ด๋ฏธ ์๋ ํ์ผ ํธ์งยป ์ ์๋ก ์ง๊ธฐ๊ฐ ์๋๋ค" "$(fires "$T/exists.sh")" no
|
|
27
|
+
chk "N2 ๊ธฐ๋ก/์ฐ์ถ๋ฌผ(.md ์ผ๋ฐ)" "$(fires "$T/notes.md")" no
|
|
28
|
+
chk "N3 tracks/ ์๋ ๊ธฐ๋ก" "$(fires "$T/tracks/_meta/x.sh")" no
|
|
29
|
+
chk "N4 ๋ก๊ทธ" "$(fires "$T/logs/a.sh")" no
|
|
30
|
+
chk "N5 json/lock" "$(fires "$T/a.json")" no
|
|
31
|
+
|
|
32
|
+
echo "โโ ๐ฅ ์ค์ฝํ๊ฐ ยซ์ธ์
ยป ์ด์ง ยซ๋ ์งยป ๊ฐ ์๋๋ค (์ดํ ๊ฒฐํจ์ ์ต์ปค) โโ"
|
|
33
|
+
# ์ดํ์ ์คํฌํ๋ฅผ ๋ ์ง๋ก ์ก์, ํ๋ฃจ์ ์ธ์
์ ์ฌ๋ฟ ๋๋ ํ๊ฒฝ์์ **์ฒซ ์ธ์
๋ง ๋จ๊ณ ๋๋จธ์ง๋ ์ ๋ถ
|
|
34
|
+
# ์นจ๋ฌต**ํ๋ค. ์ฃผ์์ ยซ์ธ์
๋นยป ์ด์๊ณ ๊ตฌํ์ ยซํ๋ฃจ๋นยป ์ด์๋ค โ ๊ทธ ๋์ด ๊ฐ๋ฆฌ๋ ๊ฒ์ด ์ด ๋ ์ธ์ด๋ค.
|
|
35
|
+
S="$(mktemp -d -t papsid.XXXXXX)"; mkdir -p "$S/.claude"
|
|
36
|
+
sid_fire(){ local o; o=$(printf '{"session_id":"%s","tool_input":{"file_path":"%s/%s.sh"}}' "$1" "$T" "$2" \
|
|
37
|
+
| CLAUDE_PROJECT_DIR="$S" bash "$H" 2>/dev/null); [ -n "$o" ] && echo yes || echo no; }
|
|
38
|
+
chk "S1 ์ธ์
A 1ํ์ฐจ โ ๋ฌ๋ค" "$(sid_fire sess-A f1)" yes
|
|
39
|
+
chk "S2 ์ธ์
A 2ํ์ฐจ โ ๋ฌด์" "$(sid_fire sess-A f2)" no
|
|
40
|
+
chk "S3 ๐ฅ ์ธ์
B 1ํ์ฐจ โ ๋ฌ๋ค (๊ฐ์ ๋ ๋ค๋ฅธ ์ธ์
)" "$(sid_fire sess-B f3)" yes
|
|
41
|
+
chk "S4 CONTROL โ session_id ์์ผ๋ฉด ๋ ์ง๋ก degrade(๋ฌด์ ์๋)" \
|
|
42
|
+
"$(printf '{"tool_input":{"file_path":"%s/f4.sh"}}' "$T" | CLAUDE_PROJECT_DIR="$(mktemp -d -t papnos.XXXXXX)" bash "$H" 2>/dev/null | grep -c additionalContext)" 1
|
|
43
|
+
rm -rf "$S"
|
|
44
|
+
|
|
45
|
+
echo "โโ ์ธ์
๋น ํ ๋ฒ (3ํ ๊ฑฐ์ ์ต์ ๋ก ์กฐ์ฉํ ์ฃฝ๋ ๊ฒฝ๋ก ์ฐจ๋จ) โโ"
|
|
46
|
+
D="$(mktemp -d -t paponce.XXXXXX)"; mkdir -p "$D/.claude"
|
|
47
|
+
o1=$(printf '{"tool_input":{"file_path":"%s/a.sh"}}' "$T" | CLAUDE_PROJECT_DIR="$D" bash "$H" 2>/dev/null)
|
|
48
|
+
o2=$(printf '{"tool_input":{"file_path":"%s/b.sh"}}' "$T" | CLAUDE_PROJECT_DIR="$D" bash "$H" 2>/dev/null)
|
|
49
|
+
chk "O1 ์ฒซ ๋ฒ์งธ๋ ๋ฌ๋ค" "$([ -n "$o1" ] && echo yes || echo no)" yes
|
|
50
|
+
chk "O2 ๋ ๋ฒ์งธ๋ ์ ๋ฌ๋ค" "$([ -n "$o2" ] && echo yes || echo no)" no
|
|
51
|
+
rm -rf "$D"
|
|
52
|
+
|
|
53
|
+
echo "โโ ๐ฅ ์ ๋ ์ ๋ง๋๋ค (๊ฐ์ญ ํ๋ฉด) โโ"
|
|
54
|
+
D2="$(mktemp -d -t papnb.XXXXXX)"; mkdir -p "$D2/.claude"
|
|
55
|
+
out=$(printf '{"tool_input":{"file_path":"%s/c.sh"}}' "$T" | CLAUDE_PROJECT_DIR="$D2" bash "$H" 2>/dev/null); rc=$?
|
|
56
|
+
chk "B1 exit 0" "$rc" 0
|
|
57
|
+
chk "B2 permissionDecision ์ ์ ๋ธ๋ค (์๋์น์ธ ์ญ์ ๊ธ์ง)" \
|
|
58
|
+
"$(printf '%s' "$out" | grep -c permissionDecision)" 0
|
|
59
|
+
chk "B3 ๋ชจ๋ธ ์ฑ๋(additionalContext)๋ก ๊ฐ๋ค" \
|
|
60
|
+
"$(printf '%s' "$out" | grep -c additionalContext)" 1
|
|
61
|
+
rm -rf "$D2"
|
|
62
|
+
|
|
63
|
+
echo "โโ D: Bash ๊ฒฝ๋ก โ ๐ฅ ์ฒซ ์ค์ฌ์ฉ์ด ยซ๋น๋ฐํยป ๋ก ๋ฌ๋ ์๋ฆฌ (2026-08-21) โโ"
|
|
64
|
+
# matcher ๊ฐ `Write` ๋ฟ์ด์๋๋ฐ auto-mode ๋ ํ์ผ์ **Bash ๋ฆฌ๋ค์ด๋ ํธ/heredoc** ์ผ๋ก ๋ง๋ ๋ค.
|
|
65
|
+
# ์ฆ ์ด ํ
์ด ๊ฒจ๋ฅํ ์๊ฐ์ด ๊ตฌ์กฐ์ ์ผ๋ก Write ๋ฅผ ์ ํ๋ค. ์๋๊ฐ ๊ทธ ์ฌํ์ด๋ค.
|
|
66
|
+
D3=$(mktemp -d); export CLAUDE_PROJECT_DIR="$D3"; mkdir -p "$D3/.claude"
|
|
67
|
+
chk "D1 Bash heredoc ๋ก ์ .sh โ ๋ฐํ" \
|
|
68
|
+
"$(printf '%s' '{"session_id":"d1","tool_input":{"command":"cat > scripts/new_thing.sh <<EOF\necho hi\nEOF"}}' | bash "$H" 2>/dev/null | grep -c additionalContext)" 1
|
|
69
|
+
rm -f "$D3/.claude/.prior_art_prompted_"*
|
|
70
|
+
chk "D2 printf ๋ฆฌ๋ค์ด๋ ํธ๋ก ์ SKILL.md โ ๋ฐํ" \
|
|
71
|
+
"$(printf '%s' '{"session_id":"d2","tool_input":{"command":"printf x > plugins/z/skills/q/SKILL.md"}}' | bash "$H" 2>/dev/null | grep -c additionalContext)" 1
|
|
72
|
+
rm -f "$D3/.claude/.prior_art_prompted_"*
|
|
73
|
+
# โ
์ปจํธ๋กค โ D1/D2 ๊ฐ ยซBash ๋ฉด ๋ฌด์กฐ๊ฑด ๋ฐํยป ๊ฐ ์๋์ ๋ณด์ธ๋ค. ์์์ด ์ด ํ
์ ์ฃฝ์ธ๋ค.
|
|
74
|
+
chk "D3 โ
์ปจํธ๋กค ๋ก๊ทธ ๋ฆฌ๋ค์ด๋ ํธ + 2>/dev/null โ ์นจ๋ฌต" \
|
|
75
|
+
"$(printf '%s' '{"session_id":"d3","tool_input":{"command":"echo x > /tmp/a.log 2>/dev/null"}}' | bash "$H" 2>/dev/null | wc -c | tr -d ' ')" 0
|
|
76
|
+
chk "D4 โ
์ปจํธ๋กค tracks/ ์ฐ์ถ๋ฌผ ๋ฆฌ๋ค์ด๋ ํธ โ ์นจ๋ฌต" \
|
|
77
|
+
"$(printf '%s' '{"session_id":"d4","tool_input":{"command":"cat > tracks/_meta/note.sh <<EOF\nx\nEOF"}}' | bash "$H" 2>/dev/null | wc -c | tr -d ' ')" 0
|
|
78
|
+
chk "D5 โ
์ปจํธ๋กค ๋ฆฌ๋ค์ด๋ ํธ ์๋ ๋ช
๋ น โ ์นจ๋ฌต" \
|
|
79
|
+
"$(printf '%s' '{"session_id":"d5","tool_input":{"command":"git status --short"}}' | bash "$H" 2>/dev/null | wc -c | tr -d ' ')" 0
|
|
80
|
+
chk "D6 โ
์ปจํธ๋กค ๊ฐ์ ์ธ์
๋ ๋ฒ์งธ Bash โ ์นจ๋ฌต (์ธ์
๋น 1ํ๊ฐ Bash ์์๋ ์ฐ๋ค)" \
|
|
81
|
+
"$( { printf '%s' '{"session_id":"d6","tool_input":{"command":"cat > scripts/a.sh <<EOF\nx\nEOF"}}' | bash "$H" >/dev/null 2>&1
|
|
82
|
+
printf '%s' '{"session_id":"d6","tool_input":{"command":"cat > scripts/b.sh <<EOF\nx\nEOF"}}' | bash "$H" 2>/dev/null | wc -c | tr -d ' '; } )" 0
|
|
83
|
+
# ๐ฅ E: cross-family 4 HIGH โ **์ ๋ถ ์ค๋ฐํ**๋ค (2026-08-21). ์ด ํ
์์ ์ค๋ฐํ๋ ๋ฏธ๋ฐํ๋ณด๋ค
|
|
84
|
+
# ํจ์ฌ ๋น์ธ๋ค: ์์์ด ๋๋ฉด ์ด์์๊ฐ ๋ฌด์ํ๊ณ ๋ฅ๋ ฅ์ด ์ฃฝ๋๋ค(์ ์ ์๊ฐ ยซ์๊ธฐ๋ฌด๋ ฅํ ๊ฒฝ๋กยป ๋ผ ๋ช
๋ช
).
|
|
85
|
+
rm -f "$D3/.claude/.prior_art_prompted_"*
|
|
86
|
+
chk "E1 โ
์ปจํธ๋กค tee_probe.py ์ธ๊ธ (tee ์ ๋ค ๊ฒฝ๊ณ ์๋ ์๋ฆฌ) โ ์นจ๋ฌต" \
|
|
87
|
+
"$(printf '%s' '{"session_id":"e1","tool_input":{"command":"rg tee_probe.py scripts"}}' | bash "$H" 2>/dev/null | wc -c | tr -d ' ')" 0
|
|
88
|
+
chk "E2 โ
์ปจํธ๋กค stderr ๋ฆฌ๋ค์ด๋ ํธ 2> โฆ/errors.sh โ ์นจ๋ฌต (>>? ๊ฐ 2> ์์ > ๋ฅผ ์ก๋ ์๋ฆฌ)" \
|
|
89
|
+
"$(printf '%s' '{"session_id":"e2","tool_input":{"command":"pytest 2> /tmp/pytest_errors.sh"}}' | bash "$H" 2>/dev/null | wc -c | tr -d ' ')" 0
|
|
90
|
+
chk "E2b โ
์ปจํธ๋กค stdout ๋ฒ๋ฆฌ๊ณ stderr ๋ง .sh ๋ก โ ์นจ๋ฌต" \
|
|
91
|
+
"$(printf '%s' '{"session_id":"e2b","tool_input":{"command":"make test > /dev/null 2> /tmp/failures.sh"}}' | bash "$H" 2>/dev/null | wc -c | tr -d ' ')" 0
|
|
92
|
+
chk "E3 โ
์ปจํธ๋กค ํ๋ก์ ํธ ๋ฐ ๋ฆฌํฌํธ git diff > /tmp/review_delta.sh โ ์นจ๋ฌต" \
|
|
93
|
+
"$(printf '%s' '{"session_id":"e3","tool_input":{"command":"git diff > /tmp/review_delta.sh"}}' | bash "$H" 2>/dev/null | wc -c | tr -d ' ')" 0
|
|
94
|
+
chk "E4 โ
์ปจํธ๋กค ๋ฏธํ์ฅ ๋ณ์ \$LOG_DIR/x.sh โ ์นจ๋ฌต (๋ฆฌํฐ๋ด๋ก ์กด์ฌ๊ฒ์ฌํ๋ฉด ๊ฑฐ์ง์ด๋ค)" \
|
|
95
|
+
"$(printf '%s' '{"session_id":"e4","tool_input":{"command":"echo more >> \"$LOG_DIR/x.sh\""}}' | bash "$H" 2>/dev/null | wc -c | tr -d ' ')" 0
|
|
96
|
+
# ๐ฅ E1b/E2c โ **ํ๋ก์ ํธ ยซ์ยป** ๊ฒฝ๋ก๋ก ๊ฐ์ ๋ ๊ฒฐํจ์ ์น๋ค. E1/E2 ๋ /tmp ๋ผ์
|
|
97
|
+
# ํ๋ก์ ํธ-๋ฒ์ ๊ท์น(โ)๋ง์ผ๋ก๋ ์นจ๋ฌตํ๋ค โ ๋๋๋ฆผ ์ค์ธก์์ ์ ๊ท์ ์๋ฆฌ๋ฅผ ๋๋๋ ค๋
|
|
98
|
+
# ์ ์์ด 0 ์ด์๊ณ (=์ฅ์), ๊ทธ๊ฒ ์ด ๋ ๋ ์ธ์ ๋ง๋ ์ด์ ๋ค. ์๋๋ โ ๊ฐ ๋ชป ์ก๋ ์๋ฆฌ๋ค.
|
|
99
|
+
rm -f "$D3/.claude/.prior_art_prompted_"*
|
|
100
|
+
chk "E1b โ
์ปจํธ๋กค ํ๋ก์ ํธ ์ tee_probe.sh ์ธ๊ธ โ ์นจ๋ฌต (tee ๋ค ๊ฒฝ๊ณ๋ฅผ ๊ฒฉ๋ฆฌํด์ ์น๋ค)" \
|
|
101
|
+
"$(printf '%s' '{"session_id":"e1b","tool_input":{"command":"rg tee_probe.sh scripts"}}' | bash "$H" 2>/dev/null | wc -c | tr -d ' ')" 0
|
|
102
|
+
chk "E2c โ
์ปจํธ๋กค ํ๋ก์ ํธ ์ stderr 2> scripts/errors.sh โ ์นจ๋ฌต (๋ฆฌ๋ค์ด๋ ํธ ์ ๊ฒฝ๊ณ๋ฅผ ๊ฒฉ๋ฆฌํด์ ์น๋ค)" \
|
|
103
|
+
"$(printf '%s' '{"session_id":"e2c","tool_input":{"command":"pytest 2> scripts/errors.sh"}}' | bash "$H" 2>/dev/null | wc -c | tr -d ' ')" 0
|
|
104
|
+
# E5/E6 โ session_id ๋ ์ ๋ขฐํ ์ ์๋ ์
๋ ฅ์ด๋ค
|
|
105
|
+
_ESC=$(dirname "$D3")/pap_lane_escape_$$
|
|
106
|
+
rm -f "$_ESC"
|
|
107
|
+
printf '%s' "{\"session_id\":\"x/../../../$(basename "$_ESC")\",\"tool_input\":{\"file_path\":\"scripts/zz_new.sh\"}}" | bash "$H" >/dev/null 2>&1
|
|
108
|
+
chk "E5 session_id ๊ฒฝ๋ก ํ์ถ โ ํ๋ก์ ํธ ๋ฐ์ ํ์ผ์ด ์ ์๊ธด๋ค" \
|
|
109
|
+
"$([ -e "$_ESC" ] && echo escaped || echo none)" none
|
|
110
|
+
rm -f "$_ESC"
|
|
111
|
+
rm -f "$D3/.claude/.prior_art_prompted_"*
|
|
112
|
+
chk "E6 session_id ๋์ ยซ/ยป โ ๋ ๋ฒ์งธ ํธ์ถ์ ์นจ๋ฌต (์คํฌํ๊ฐ ์ค์ ๋ก ์จ์ง๋ค)" \
|
|
113
|
+
"$( { printf '%s' '{"session_id":"x/","tool_input":{"file_path":"scripts/zz_a.sh"}}' | bash "$H" >/dev/null 2>&1
|
|
114
|
+
printf '%s' '{"session_id":"x/","tool_input":{"file_path":"scripts/zz_b.sh"}}' | bash "$H" 2>/dev/null | wc -c | tr -d ' '; } )" 0
|
|
115
|
+
# E7 โ ๐ฅ ยซadditionalContext ๊ฐ ๋ด๋คยป ๋ ํ์๊ฐ **์ณ์ ํ ํฐ**์ ๋ฝ์๋ค๋ ์ฆ๊ฑฐ๊ฐ ์๋๋ค(cross-family ๋ ์ธ ์ง์ ).
|
|
116
|
+
rm -f "$D3/.claude/.prior_art_prompted_"*
|
|
117
|
+
chk "E7 ์ถ์ถ๋ ๋์์ด ์ค์ ๋ฆฌ๋ค์ด๋ ํธ ๋์์ด๋ค (ํ์๊ฐ ์๋ฑํ ํ ํฐ์ ๋ฝ์๋ ํต๊ณผํ๋ ์๋ฆฌ)" \
|
|
118
|
+
"$(printf '%s' '{"session_id":"e7","tool_input":{"command":"cat > scripts/uniq_target_name.sh <<EOF\nx\nEOF"}}' | bash "$H" 2>/dev/null | grep -c 'uniq_target_name.sh')" 1
|
|
119
|
+
unset CLAUDE_PROJECT_DIR; rm -rf "$D3"
|
|
120
|
+
|
|
121
|
+
echo "โโ CONTROL: ๊ณ๊ธฐ๊ฐ ์ฃฝ์ผ๋ฉด ์กฐ์ฉํ ํต๊ณผ (advisory ๋ ์ธ์
์ ๋ชป ์ฃฝ์ธ๋ค) โโ"
|
|
122
|
+
chk "C1 ์
๋ ฅ์ด JSON ์ด ์๋๋ฉด ๋ฌด์ exit 0" \
|
|
123
|
+
"$(printf 'not json' | bash "$H" >/dev/null 2>&1; echo $?)" 0
|
|
124
|
+
chk "C2 file_path ์์ผ๋ฉด ๋ฌด์" "$(printf '{"tool_input":{}}' | bash "$H" 2>/dev/null | wc -c | tr -d ' ')" 0
|
|
125
|
+
|
|
126
|
+
echo
|
|
127
|
+
if [ "$FAIL" -eq 0 ]; then echo "โโโโ prior-art-prompt lanes: $PASS passed ยท 0 failed โโโโ"; exit 0
|
|
128
|
+
else echo "๐ฅ prior-art-prompt lanes: $FAIL ์คํจ / $((PASS+FAIL))"; exit 1; fi
|