@chrono-meta/fh-gate 2.4.0 โ†’ 2.5.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.
@@ -54,6 +54,26 @@ set -f
54
54
 
55
55
  RC_OK=0; RC_VIOLATION=1; RC_UNVERIFIABLE=3; RC_HARNESS=10
56
56
 
57
+ # ๐ŸŸฅ **๊ณ„๊ธฐ ์ „์ œ ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ** (2026-08-18, ๋„“์€-์งˆ๋ฌธ ํƒˆ์ƒ๊ด€ ํŒ”์ด known-pair ๋กœ ์žฌํ˜„).
58
+ # `_snapshot` ์˜ ํŒŒ์ผ ์ถ•์€ `โ€ฆ | xargs -0 shasum -a 256 2>/dev/null` ์ด๋‹ค. `shasum` ์ด ์—†๊ฑฐ๋‚˜
59
+ # ์ฃฝ์œผ๋ฉด before/after ๊ฐ€ **๋‘˜ ๋‹ค ๋นˆ ๋ฌธ์ž์—ด**์ด ๋˜์–ด `changed=0` โ†’ **`โœ… VERIFIED ยท ๊ด€์ธก=no-write`**.
60
+ # ์žฌํ˜„(๊ฐ™์€ capfile, PATH ๋งŒ ๋‹ค๋ฆ„): ์ •์ƒ `๐ŸŸฅ VIOLATION rc=1` / shasum=127 `โœ… VERIFIED rc=0`.
61
+ # โ‡’ ์ด ํŒŒ์ผ์ด ํ—ค๋”์—์„œ ๊ฒจ๋ˆˆ ใ€Œ๋ฏธ์ธก์ •์„ 0 ์œผ๋กœ ๋ Œ๋”ใ€์˜ ์ž๊ธฐ ํŒ๋ณธ์ด์—ˆ๊ณ , `UNVERIFIABLE` ์กฐ์ฐจ
62
+ # ์•„๋‹ˆ๋ผ **VERIFIED** ์˜€๋‹ค. ๊ณ„๊ธฐ๊ฐ€ ์ฃฝ์œผ๋ฉด ํŒ์ •์„ ๋‚ด์ง€ ์•Š๋Š”๋‹ค.
63
+ # โ˜…`2>/dev/null` ์€ ๋‚จ๊ธด๋‹ค โ€” ๊ฐœ๋ณ„ ํŒŒ์ผ ๊ถŒํ•œ ์˜ค๋ฅ˜๋กœ ์ „์ฒด๊ฐ€ ์ฃฝ์œผ๋ฉด ๊ทธ๊ฒŒ ๋” ๋‚˜์˜๋‹ค.
64
+ # ๋ง‰๋Š” ์ง€์ ์€ **์ „์ œ**(๋„๊ตฌ ๋ถ€์žฌ)์ด์ง€ ๊ฐœ๋ณ„ ํ•ญ๋ชฉ ์‹คํŒจ๊ฐ€ ์•„๋‹ˆ๋‹ค.
65
+ # โš ๏ธ **ํด๋ฐฑ์ด ํ•„์š”ํ•˜๋‹ค**(cross-family ์ง€๋ชฉ #3): `shasum` ์€ macOS/perl ๊ณ„์—ด ๊ด€ํ–‰์ด๊ณ 
66
+ # Linux/BusyBox ์†Œ๋น„์ž๋Š” `sha256sum` ๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ํ”ํ•˜๋‹ค. ์ด ํŒŒ์ผ์€ `package.json
67
+ # files[]` ๋กœ **์ถœํ•˜๋˜๋ฏ€๋กœ** shasum ๊ฐ•์ œ๋Š” ๊ณผ์ฐจ๋‹จ์ด๋‹ค.
68
+ HASHER=""
69
+ if command -v shasum >/dev/null 2>&1; then HASHER="shasum -a 256"
70
+ elif command -v sha256sum >/dev/null 2>&1; then HASHER="sha256sum"
71
+ else
72
+ echo "โŒ HARNESS_ERROR โ€” \`shasum\` ๋„ \`sha256sum\` ๋„ PATH ์— ์—†๋‹ค." >&2
73
+ echo " ์Šค๋ƒ…์ƒท์˜ ํ•ด์‹œ ์ถ•์ด ์ฃฝ์–ด ๊ฑฐ์ง“ \`VERIFIED\` ๊ฐ€ ๋‚œ๋‹ค. ํŒ์ •ํ•˜์ง€ ์•Š๊ณ  ์ค‘๋‹จํ•œ๋‹ค." >&2
74
+ exit "$RC_HARNESS"
75
+ fi
76
+
57
77
  # writes ์ถ• ์ˆœ์„œ (์ข์Œ โ†’ ๋„“์Œ). ๊ด€์ธก์ด ์„ ์–ธ๋ณด๋‹ค ๋„“์œผ๋ฉด VIOLATION.
58
78
  ORDER_writes="read-only write-local write-remote"
59
79
 
@@ -82,7 +102,8 @@ GIT_META_WATCH=""
82
102
  # ์•„๋‹ˆ๋ผ **ํŒŒ์ผ๋‹น ํ”„๋กœ์„ธ์Šค ์Šคํฐ**์ด์—ˆ๋‹ค. `xargs` ๋ฐฐ์น˜๋กœ ํ•œ ๋ฒˆ์— ๋„˜๊ธฐ๋ฉด ๊ฐ™์€ ๋Œ€์ƒ์„ ์žฌ๋ฉด์„œ
83
103
  # ๋น„์šฉ์ด ๋–จ์–ด์ง„๋‹ค โ€” ์ •ํ™•๋„๋ฅผ ๊นŽ์•„ ๋น„์šฉ์„ ๋งž์ถ”๋ ค๋˜ ๊ฒŒ ์ž˜๋ชป๋œ ํŠธ๋ ˆ์ด๋“œ์˜€๋‹ค.
84
104
 
85
- _snapshot() { # $1=dir โ†’ "sha path" ๋ชฉ๋ก (์ •๋ ฌ)
105
+ _snapshot() { # $1=dir โ†’ "file <path>" + "sha path" + dir/๊ธฐํƒ€ ์ถ• (์ •๋ ฌ)
106
+ local _flist; _flist=$(mktemp "${TMPDIR:-/tmp}/fh_flist.XXXXXX")
86
107
  {
87
108
  # `.git` ์€ ํ†ต์งธ๋กœ ์ œ์™ธํ•œ๋‹ค โ€” `git status` ๋ฅ˜๊ฐ€ `.git/index` ๋ฅผ ์ •๋‹นํ•˜๊ฒŒ ๊ฐฑ์‹ ํ•˜๋ฏ€๋กœ
88
109
  # ์ „์ฒด๋ฅผ ์žฌ๋ฉด ์ฝ๊ธฐ ์ „์šฉ capability ๊ฐ€ ๊ฑฐ์ง“ VIOLATION ์„ ๋ฐ›๋Š”๋‹ค. ๋Œ€์‹  ์•„๋ž˜์—์„œ
@@ -101,10 +122,19 @@ _snapshot() { # $1=dir โ†’ "sha path" ๋ชฉ๋ก (์ •๋ ฌ)
101
122
  case "$w" in "$1"/*|"$1") ;; *) continue ;; esac
102
123
  find "$w" -type f 2>/dev/null
103
124
  done
104
- } | LC_ALL=C sort -u \
105
- | tr '\n' '\0' \
106
- | xargs -0 -n 400 shasum -a 256 2>/dev/null \
125
+ } | LC_ALL=C sort -u > "$_flist"
126
+ # ๐ŸŸฅ **์ด๋ฆ„ ๋ชฉ๋ก ์ถ• โ€” ํ•ด์‹œ์™€ ๋ณ„๋„๋กœ ๋‚ธ๋‹ค** (2026-08-18, cross-family ์ง€๋ชฉ #1).
127
+ # ํ•ด์‹œ ์ถ•๋งŒ ๋‘๋ฉด ยซํ•ด์‹œ๊ฐ€ ์‹คํŒจํ•œ ํŒŒ์ผยป๊ณผ ยซ์—†๋Š” ํŒŒ์ผยป์ด **๊ตฌ๋ถ„ ๋ถˆ๊ฐ€**๋‹ค. ์‹ค์ธก ๋ฐ˜๋ก€ ๋‘˜:
128
+ # โ“ `shasum` ์ด ์กด์žฌํ•˜์ง€๋งŒ exit 1 ์ธ shim โ†’ ํ•ด์‹œ 0์ค„ โ†’ changed=0 โ†’ โœ… VERIFIED
129
+ # โ“‘ **๊ฐ€์งœ ๋„๊ตฌ ์—†์ด๋„** `touch f && chmod 000 f` โ†’ ๊ทธ ํŒŒ์ผ ํ•ด์‹œ๋งŒ ์‹คํŒจ โ†’
130
+ # `2>/dev/null` ์ด ์‚ผํ‚ด โ†’ โœ… VERIFIED
131
+ # โ‡’ ์ด๋ฆ„ ๋ชฉ๋ก์€ **ํ•ด์‹œ ๋„๊ตฌ์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ** ์ƒ์„ฑ/์‚ญ์ œ๋ฅผ ์žก๋Š”๋‹ค. ๋‘ ์ถ•์€ ์„œ๋กœ์˜ ํด๋ฐฑ์ด ์•„๋‹ˆ๋ผ
132
+ # **๋‹ค๋ฅธ ๊ฒƒ์„ ์žฐ๋‹ค**(์ด๋ฆ„=์กด์žฌ ยท ํ•ด์‹œ=๋‚ด์šฉ). ๋‘˜ ๋‹ค ํ•„์š”ํ•˜๋‹ค.
133
+ LC_ALL=C sed 's/^/file /' "$_flist"
134
+ tr '\n' '\0' < "$_flist" \
135
+ | xargs -0 -n 400 $HASHER 2>/dev/null \
107
136
  | LC_ALL=C sort
137
+ rm -f "$_flist"
108
138
  # ๐ŸŸฅ **๋””๋ ‰ํ† ๋ฆฌ ์กด์žฌ ์ถ•** (2026-08-17). ์œ„ ๋ธ”๋ก์€ `-type f` ๋ผ **ํŒŒ์ผ๋งŒ** ์„ผ๋‹ค โ€” ๋นˆ
109
139
  # ๋””๋ ‰ํ† ๋ฆฌ๋Š” ๊ด€์ธก๋ฉด์— ์•„์˜ˆ ์—†์—ˆ๊ณ , `mkdir -p uploads outputs tmp` ๋งŒ ํ•˜๋Š” capability ๊ฐ€
110
140
  # `writes: read-only` ์„ ์–ธ์œผ๋กœ **โœ… VERIFIED** ๋ฅผ ๋ฐ›์•˜๋‹ค(known-pair 3-arm ์‹ค์ธก).
@@ -285,6 +315,12 @@ probe_one() { # $1=capfile โ†’ rc
285
315
 
286
316
  local before after out rc
287
317
  before=$(_snapshot "$sandbox")
318
+ # ๐ŸŸฅ ์Šค๋ƒ…์ƒท์€ **์ ˆ๋Œ€ ๋น„์ง€ ์•Š๋Š”๋‹ค** โ€” ๋””๋ ‰ํ† ๋ฆฌ ์ถ•์ด ์ตœ์†Œํ•œ ๋ฃจํŠธ ์ž์‹ ์„ ์ฐ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
319
+ # ๋น„์—ˆ๋‹ค๋ฉด `find` ์กฐ์ฐจ ์‹คํŒจํ•œ ๊ฒƒ์ด๊ณ , ๊ทธ๊ฑด ๊ด€์ธก์ด ์•„๋‹ˆ๋ผ ๊ณ„๊ธฐ ์‚ฌ๋ง์ด๋‹ค.
320
+ if [ -z "$before" ]; then
321
+ echo " โŒ HARNESS_ERROR โ€” ์‚ฌ์ „ ์Šค๋ƒ…์ƒท์ด ๋น„์—ˆ๋‹ค($sandbox). ๊ด€์ธก๋ฉด์ด ์ฃฝ์—ˆ๋‹ค." >&2
322
+ return "$RC_HARNESS"
323
+ fi
288
324
  local out_before; out_before=$(_snapshot "$outside")
289
325
 
290
326
  # ์‹คํ–‰ โ€” **์–‘ arm ์„ ๊ฐ™์€ ์ƒŒ๋“œ๋ฐ•์Šค ์ •์ฑ…์œผ๋กœ** ๋Œ๋ฆฐ๋‹ค(2026-08-16 cross-family ์ง€๋ชฉ).
@@ -787,6 +823,106 @@ EOF
787
823
  fails=$((fails+1)); echo "โŒ L18 rc=$rc (1 ๊ธฐ๋Œ€) โ€” ๋น„์ •๊ทœ ๋…ธ๋“œ๊ฐ€ ๊ฐ์‹œ๋ฉด ๋ฐ–์ด๋‹ค"
788
824
  fi
789
825
 
826
+ # โ”€โ”€ L19 **์ง‘๊ณ„๊ฐ€ ์œ„๋ฐ˜์„ ยซ๋ชป ์Ÿ€์Œยป์œผ๋กœ ์‚ผํ‚ค์ง€ ์•Š๋Š”๋‹ค** โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
827
+ # RC_VIOLATION=1 ยท RC_UNVERIFIABLE=3 ์ด๋ผ ์ˆ˜์น˜ max ๋กœ ์ ‘์œผ๋ฉด exit 3 ์ด ๋‚˜์™”๋‹ค.
828
+ cat > "$d/agg_viol.cap" <<EOF
829
+ id: t:aggv
830
+ entry: bash -c 'touch aggregated_violation'
831
+ requires_cwd: $_rs
832
+ writes: read-only
833
+ EOF
834
+ out=$("$0" "$d/agg_viol.cap" "$d/nz_undeclared.cap" 2>&1); rc=$?
835
+ if [ "$rc" = "1" ] && printf '%s' "$out" | grep -q "nz_undeclared" \
836
+ && printf '%s' "$out" | grep -q "unverifiable=1"; then
837
+ pass=$((pass+1)); echo "โœ… L19 ์œ„๋ฐ˜+๋ฏธ์ธก์ • ๋ฐฐ์น˜: exit=VIOLATION ์ด๊ณ  ๋ฏธ์ธก์ •์ด ์š”์•ฝ์— ๋‚จ๋Š”๋‹ค"
838
+ else
839
+ fails=$((fails+1)); echo "โŒ L19 rc=$rc โ€” ์ง‘๊ณ„๊ฐ€ ์œ„๋ฐ˜์„ ์‚ผํ‚ค๊ฑฐ๋‚˜ ๋‘ ๋ฒˆ์งธ capfile ์„ ์•ˆ ์Ÿ€๋‹ค"
840
+ fi
841
+ # L19b **์ˆœ์„œ ๋ฐ˜์ „** โ€” cross-family ์ง€๋ชฉ #4: ์œ„๋ฐ˜์ด ๋จผ์ €๋ฉด short-circuit ํ‡ดํ–‰๋„ ์ดˆ๋ก์ด๋‹ค.
842
+ out=$("$0" "$d/nz_undeclared.cap" "$d/agg_viol.cap" 2>&1); rc=$?
843
+ if [ "$rc" = "1" ]; then
844
+ pass=$((pass+1)); echo "โœ… L19b ์ˆœ์„œ๋ฅผ ๋’ค์ง‘์–ด๋„ VIOLATION ์ด ์ด๊ธด๋‹ค(๋ฏธ์ธก์ •์ด ๋จผ์ €์—ฌ๋„)"
845
+ else
846
+ fails=$((fails+1)); echo "โŒ L19b rc=$rc (1 ๊ธฐ๋Œ€) โ€” ์ฒซ rc ์— ๊ฐ‡ํžˆ๊ฑฐ๋‚˜ ์‹ฌ๊ฐ๋„๊ฐ€ ๋’ค์ง‘ํžŒ๋‹ค"
847
+ fi
848
+ # L19c ์ปจํŠธ๋กค โ€” ์œ„๋ฐ˜์ด ์—†์œผ๋ฉด ์—ฌ์ „ํžˆ ๋ฏธ์ธก์ •(3)์ด๋‹ค(๊ณผ์ฐจ๋‹จ ๋ฐฉ์ง€).
849
+ out=$("$0" "$d/nz_undeclared.cap" 2>&1); rc=$?
850
+ if [ "$rc" = "3" ]; then
851
+ pass=$((pass+1)); echo "โœ… L19c ์ปจํŠธ๋กค โ€” ์œ„๋ฐ˜ ์—†๋Š” ๋ฐฐ์น˜๋Š” ์—ฌ์ „ํžˆ UNVERIFIABLE"
852
+ else
853
+ fails=$((fails+1)); echo "โŒ L19c rc=$rc (3 ๊ธฐ๋Œ€) โ€” ์‹ฌ๊ฐ๋„ ๋งคํ•‘์ด ๋ฏธ์ธก์ •์„ ์ž˜๋ชป ์ ‘๋Š”๋‹ค"
854
+ fi
855
+
856
+ # โ”€โ”€ L20 ๊ณ„์—ด **๊ณ„๊ธฐ๊ฐ€ ์ฃฝ์œผ๋ฉด ํŒ์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค ยท ์‚ด์•„ ์žˆ์œผ๋ฉด ๊ณผ์ฐจ๋‹จํ•˜์ง€ ์•Š๋Š”๋‹ค** โ”€โ”€โ”€โ”€โ”€โ”€
857
+ # ๐ŸŸฅ ์ดˆํŒ ๋ ˆ์ธ์€ ๋‘ ๋ฒˆ ํ‹€๋ ธ๋‹ค(๋‘˜ ๋‹ค ์ž๋ ฅ ์ ๋ฐœ 0):
858
+ # โ“ `PATH=/nonexistent` ๋กœ ์žฌ์„œ **capfile ํŒŒ์‹ฑ ์‹คํŒจ**๋ฅผ ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ๋กœ ์˜ค๊ท€์† โ€” ๋˜๋Œ๋ฆผ
859
+ # 3์ค‘ ํ”„๋กœ๋ธŒ๊ฐ€ ์ ๋ฐœ(์ˆ˜๋ฆฌ๋ฅผ ๋˜๋Œ๋ ค๋„ ์ดˆ๋ก์ด์—ˆ๋‹ค)
860
+ # โ“‘ shim ๋นŒ๋”๊ฐ€ `set -f`(์ „์—ญ noglob) ๋•Œ๋ฌธ์— ํ™•์žฅ์ด ์•ˆ ๋จ โ€” **์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ์ง**์ด ์ ๋ฐœ
861
+ # ์—ฌ๊ธฐ์„œ๋Š” ๋„๊ตฌ๋ฅผ **ํ•˜๋‚˜์”ฉ** ๋นผ๊ณ , ๋งค arm ์— ๊ธฐ๋Œ€๊ฐ’์„ ๋‹ค๋ฅด๊ฒŒ ๊ฑด๋‹ค.
862
+ # โ˜…PATH ์›์†Œ ๋ถ„ํ•ด๋Š” ๊ณต๋ฐฑ/๊ธ€๋กญ ์•ˆ์ „ํ•˜๊ฒŒ(`tr` โ†’ ์ค„ ๋‹จ์œ„). cross-family ์ง€๋ชฉ #7.
863
+ _mkshim() { # $1=shim๊ฒฝ๋กœ $2..=์ œ์™ธํ•  ๋„๊ตฌ๋ช…
864
+ local shimd="$1"; shift
865
+ mkdir -p "$shimd"
866
+ printf '%s\n' "$PATH" | tr ':' '\n' > "$d/_pathdirs"
867
+ local _p _f _b _x _skip
868
+ set +f
869
+ while IFS= read -r _p; do
870
+ [ -n "$_p" ] && [ -d "$_p" ] || continue
871
+ for _f in "$_p"/*; do
872
+ [ -e "$_f" ] || continue
873
+ _b=${_f##*/}; _skip=0
874
+ for _x in "$@"; do [ "$_b" = "$_x" ] && { _skip=1; break; }; done
875
+ [ "$_skip" = 1 ] && continue
876
+ [ -e "$shimd/$_b" ] || ln -s "$_f" "$shimd/$_b" 2>/dev/null
877
+ done
878
+ done < "$d/_pathdirs"
879
+ set -f
880
+ }
881
+
882
+ # L20 ํ•ด์‹œ ๋„๊ตฌ๊ฐ€ **๋‘˜ ๋‹ค** ์—†์œผ๋ฉด ํŒ์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค.
883
+ _mkshim "$d/bin_none" shasum sha256sum
884
+ out=$(PATH="$d/bin_none" "${BASH:-/bin/bash}" "$0" "$d/agg_viol.cap" 2>&1); rc=$?
885
+ if [ "$rc" = "10" ] && printf '%s' "$out" | grep -q "sha256sum"; then
886
+ pass=$((pass+1)); echo "โœ… L20 ํ•ด์‹œ ๋„๊ตฌ ์ „๋ฌด๋Š” HARNESS_ERROR (์ด์œ ๋„ ์ฐํžŒ๋‹ค)"
887
+ else
888
+ fails=$((fails+1)); echo "โŒ L20 rc=$rc (10 ๊ธฐ๋Œ€) โ€” ๊ณ„๊ธฐ ์‚ฌ๋ง์ด ํ†ต๊ณผ/ํŒ์ •์œผ๋กœ ๋ Œ๋”๋œ๋‹ค"
889
+ fi
890
+ # L20b **๊ณผ์ฐจ๋‹จ ๋ฐฉ์ง€** โ€” `shasum` ๋งŒ ์—†๊ณ  `sha256sum` ์ด ์žˆ์œผ๋ฉด ์ •์ƒ ํŒ์ •ํ•ด์•ผ ํ•œ๋‹ค.
891
+ # cross-family ์ง€๋ชฉ #3: ์ด ํŒŒ์ผ์€ files[] ๋กœ ์ถœํ•˜๋˜๊ณ  Linux ์†Œ๋น„์ž๋Š” sha256sum ๋งŒ ๊ฐ–๋Š”๋‹ค.
892
+ if command -v sha256sum >/dev/null 2>&1; then
893
+ _mkshim "$d/bin_s256" shasum
894
+ out=$(PATH="$d/bin_s256" "${BASH:-/bin/bash}" "$0" "$d/agg_viol.cap" 2>&1); rc=$?
895
+ if [ "$rc" = "1" ]; then
896
+ pass=$((pass+1)); echo "โœ… L20b shasum ๋ถ€์žฌ+sha256sum ์กด์žฌ โ†’ ํด๋ฐฑ์ด ์ •์ƒ ํŒ์ •(๊ณผ์ฐจ๋‹จ ์—†์Œ)"
897
+ else
898
+ fails=$((fails+1)); echo "โŒ L20b rc=$rc (1 ๊ธฐ๋Œ€) โ€” ํด๋ฐฑ์ด ์—†๊ฑฐ๋‚˜ ๊ณผ์ฐจ๋‹จํ•œ๋‹ค"
899
+ fi
900
+ else
901
+ echo "โญ L20b SKIP โ€” ์ด ๋จธ์‹ ์— sha256sum ์ด ์—†๋‹ค(๋ฏธ์ธก์ •, ํ†ต๊ณผ ์•„๋‹˜)"
902
+ fi
903
+ # L20c **ยซ์žˆ๋Š”๋ฐ ๊ณ ์žฅ๋‚œยป ํ•ด์‹œ ๋„๊ตฌ** โ€” cross-family ์ง€๋ชฉ #1. ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ๋Š” ํ†ต๊ณผํ•œ๋‹ค.
904
+ _mkshim "$d/bin_broken" shasum sha256sum
905
+ printf '#!/bin/sh\nexit 1\n' > "$d/bin_broken/shasum"; chmod +x "$d/bin_broken/shasum"
906
+ out=$(PATH="$d/bin_broken" "${BASH:-/bin/bash}" "$0" "$d/agg_viol.cap" 2>&1); rc=$?
907
+ if [ "$rc" = "1" ]; then
908
+ pass=$((pass+1)); echo "โœ… L20c ํ•ด์‹œ ๋„๊ตฌ๊ฐ€ ๊ณ ์žฅ๋‚˜๋„ ํŒŒ์ผ ์ƒ์„ฑ์€ ์žกํžŒ๋‹ค(์ด๋ฆ„ ๋ชฉ๋ก ์ถ•)"
909
+ else
910
+ fails=$((fails+1)); echo "โŒ L20c rc=$rc (1 ๊ธฐ๋Œ€) โ€” ๊ณ ์žฅ๋‚œ ๊ณ„๊ธฐ๊ฐ€ ๊ฑฐ์ง“ VERIFIED ๋ฅผ ๋‚ธ๋‹ค"
911
+ fi
912
+ # L20d **์ฝ์„ ์ˆ˜ ์—†๋Š” ํŒŒ์ผ** โ€” ๊ฐ€์งœ ๋„๊ตฌ ์—†์ด ์žฌํ˜„๋˜๋Š” ํ˜•ํƒœ(cross-family ์ง€๋ชฉ #1 ๋‘ ๋ฒˆ์งธ).
913
+ cat > "$d/unreadable.cap" <<EOF
914
+ id: t:unread
915
+ entry: bash -c 'touch hidden_regular && chmod 000 hidden_regular'
916
+ requires_cwd: $_rs
917
+ writes: read-only
918
+ EOF
919
+ out=$(probe_one "$d/unreadable.cap" 2>&1); rc=$?
920
+ if [ "$rc" = "1" ]; then
921
+ pass=$((pass+1)); echo "โœ… L20d chmod 000 ํŒŒ์ผ ์ƒ์„ฑ๋„ ์œ„๋ฐ˜์ด๋‹ค(ํ•ด์‹œ ์‹คํŒจ๊ฐ€ ์‚ผํ‚ค์ง€ ์•Š๋Š”๋‹ค)"
922
+ else
923
+ fails=$((fails+1)); echo "โŒ L20d rc=$rc (1 ๊ธฐ๋Œ€) โ€” ํ•ด์‹œ ์‹คํŒจ๊ฐ€ ํŒŒ์ผ ์ƒ์„ฑ์„ ์‚ผํ‚จ๋‹ค"
924
+ fi
925
+
790
926
  rm -rf "$d"
791
927
  echo "โ”€โ”€ capability_effect_probe lanes: $pass PASS / $fails FAIL โ”€โ”€"
792
928
  [ "$fails" = "0" ]
@@ -797,9 +933,41 @@ case "${1:-}" in
797
933
  "") echo "usage: $0 <capfile> [...] | --self-test" >&2; exit "$RC_HARNESS";;
798
934
  esac
799
935
 
936
+ # ๐ŸŸฅ **์ง‘๊ณ„๋Š” ์ˆ˜์น˜ max ๊ฐ€ ์•„๋‹ˆ๋ผ ์‹ฌ๊ฐ๋„ max ๋‹ค** (2026-08-18, ๋„“์€-์งˆ๋ฌธ ํƒˆ์ƒ๊ด€ ํŒ” ์ง€๋ชฉ).
937
+ # `RC_VIOLATION=1` ยท `RC_UNVERIFIABLE=3` ์ด๋ผ ์ˆ˜์น˜ `-gt` ๋กœ ์ ‘์œผ๋ฉด
938
+ # **์‹ค์ œ ์œ„๋ฐ˜(1) + ๋ชป ์Ÿ€์Œ(3) โ†’ exit 3** ์ด ๋œ๋‹ค. ํ—ค๋”๊ฐ€ 3 ์„ ใ€ŒํŒ์ • ์•„๋‹˜ใ€์œผ๋กœ ์ •์˜ํ•ด ๋†จ์œผ๋‹ˆ
939
+ # `rc==1` ๋กœ ์œ„๋ฐ˜์„ ๋ผ์šฐํŒ…ํ•˜๋Š” ์ƒ์œ„ ๊ฒŒ์ดํŠธ๋Š” **์กฐ์šฉํžˆ ๋†“์น˜๊ณ ** ์žฌ์‹œ๋„/์œ ์˜ˆ ๊ฒฝ๋กœ๋ฅผ ํƒ„๋‹ค.
940
+ # โ‡’ ์ˆ˜์น˜ ์ˆœ์„œ์™€ ์‹ฌ๊ฐ๋„ ์ˆœ์„œ๊ฐ€ ์–ด๊ธ‹๋‚˜ ์žˆ์—ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ช…์‹œ์ ์œผ๋กœ ๋งคํ•‘ํ•œ๋‹ค.
941
+ # โ˜…๋ฏธ์ง€์˜ ์ฝ”๋“œ๋Š” **๊ฐ€์žฅ ์‹ฌ๊ฐ**์œผ๋กœ ์ ‘๋Š”๋‹ค(fail-closed) โ€” ์ƒˆ rc ๊ฐ€ ์ƒ๊ฒผ์„ ๋•Œ ์กฐ์šฉํžˆ
942
+ # ํ†ต๊ณผํ•˜๋Š” ์ชฝ์œผ๋กœ ๊ธฐ์šธ์ง€ ์•Š๊ฒŒ.
943
+ _sev() { # ์ข…๋ฃŒ์ฝ”๋“œ โ†’ ์‹ฌ๊ฐ๋„(ํด์ˆ˜๋ก ์‹ฌ๊ฐ). ์ˆ˜์น˜ ํฌ๊ธฐ โ‰  ์‹ฌ๊ฐ๋„.
944
+ case "$1" in
945
+ "$RC_OK") printf '0' ;;
946
+ "$RC_UNVERIFIABLE") printf '1' ;;
947
+ "$RC_VIOLATION") printf '2' ;;
948
+ "$RC_HARNESS") printf '3' ;;
949
+ *) printf '3' ;;
950
+ esac
951
+ }
952
+
953
+ # ๐ŸŸฅ **๋ฐฐ์น˜๋Š” ยซ๊ฐ€์žฅ ์‹ฌ๊ฐํ•œ ๊ฒƒยป ํ•˜๋‚˜๋งŒ ์ข…๋ฃŒ์ฝ”๋“œ๋กœ ๋‚ผ ์ˆ˜ ์žˆ๋‹ค** โ€” ๊ทธ๋ž˜์„œ ์ ‘ํžˆ๋Š” ์ •๋ณด๊ฐ€ ์ƒ๊ธด๋‹ค.
954
+ # cross-family ์ง€๋ชฉ #2: ์‹ฌ๊ฐ๋„ ๋งคํ•‘์„ ๋„ฃ์€ ๋’ค ใ€Œ์œ„๋ฐ˜ + ๋ฏธ์ธก์ •ใ€ ๋ฐฐ์น˜๊ฐ€ `1` ๋กœ ๋‚˜๊ฐ€๋ฏ€๋กœ,
955
+ # `rc==3` ์œผ๋กœ ยซ๋ฏธ์ธก์ • ์žˆ์Œยป ์„ ๋ผ์šฐํŒ…ํ•˜๋˜ ์†Œ๋น„์ž๋Š” **๋ฏธ์ธก์ • capfile ์„ ์žƒ๋Š”๋‹ค.**
956
+ # โ‡’ ์ข…๋ฃŒ์ฝ”๋“œ๋Š” ์‹ฌ๊ฐ๋„๋กœ ๋‘๊ณ , **์ ‘ํžŒ ์ •๋ณด๋Š” ์š”์•ฝ ์ค„๋กœ ํ‘œ๋ฉดํ™”**ํ•œ๋‹ค(์‚ผํ‚ค์ง€ ์•Š๋Š”๋‹ค).
957
+ # ํ•œ ์ค„์ด๋ฉด ์ƒ์œ„๊ฐ€ grep ์œผ๋กœ ์ง‘์„ ์ˆ˜ ์žˆ๊ณ , ์ข…๋ฃŒ์ฝ”๋“œ ๊ณ„์•ฝ์€ ํ•˜๋‚˜๋กœ ์œ ์ง€๋œ๋‹ค.
800
958
  worst=0
959
+ n_viol=0; n_unver=0; n_harn=0; n_ok=0
801
960
  for c in "$@"; do
802
961
  probe_one "$c"; rc=$?
803
- [ "$rc" -gt "$worst" ] && worst=$rc
962
+ case "$rc" in
963
+ "$RC_OK") n_ok=$((n_ok+1)) ;;
964
+ "$RC_VIOLATION") n_viol=$((n_viol+1)) ;;
965
+ "$RC_UNVERIFIABLE") n_unver=$((n_unver+1)) ;;
966
+ *) n_harn=$((n_harn+1)) ;;
967
+ esac
968
+ [ "$(_sev "$rc")" -gt "$(_sev "$worst")" ] && worst=$rc
804
969
  done
970
+ if [ "$#" -gt 1 ]; then
971
+ echo "โ”€โ”€ BATCH SUMMARY: ok=$n_ok violation=$n_viol unverifiable=$n_unver harness=$n_harn (exit=$worst)"
972
+ fi
805
973
  exit "$worst"
@@ -85,13 +85,77 @@ FH="${CLAUDE_PROJECT_DIR:-$(cd "$SELF_DIR/.." && pwd)}"
85
85
  # โš ๏ธ ๊ฒ€์ฆ๊ธฐ๋Š” **๋„๊ตฌ**์ด๊ณ  FH ๋Š” **๋Œ€์ƒ**์ด๋‹ค โ€” ๋‘ ์ถ•์„ ๊ฐ™์€ ๋ณ€์ˆ˜๋กœ ๋ฌถ์œผ๋ฉด ๊ฒฉ๋ฆฌ ํ”ฝ์Šค์ฒ˜์—์„œ
86
86
  # ๋„๊ตฌ๊นŒ์ง€ ์ž„์‹œ ํŠธ๋ฆฌ์—์„œ ์ฐพ๋‹ค๊ฐ€ ์ฃฝ๋Š”๋‹ค(์‹ค์ธก). ๋„๊ตฌ๋Š” ์–ธ์ œ๋‚˜ ์ด ์Šคํฌ๋ฆฝํŠธ ์˜†์— ์žˆ๋‹ค.
87
87
  CHECKER="$SELF_DIR/utterance_landing_check.sh"
88
+
89
+ # โ”€โ”€ ์ฐฉ์ง€ ์Šค์ฝ”ํ”„ (2026-08-18, R1) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
90
+ # ๊ธฐ๋ณธ ์Šค์ฝ”ํ”„๋Š” **FH ์ž์‹ ์˜ ๋ฌธ๋ฒ•**์ด๋‹ค(`knowledge` ยท `CLAUDE.md` ยท gitignored `tracks/_meta`).
91
+ # ์œ„์„ฑ์ด ๊ฒจ๋ˆˆ ๋Œ€์ƒ ํ•˜๋„ค์Šค์—๋Š” ๊ทธ ์…‹์ด ์—†์–ด์„œ ํƒ€๊นƒ์ด 0๊ฑด โ†’ rc=10 ์ด ๋งค ๋Ÿฐ ์ฐํžŒ๋‹ค. ๊ทธ๊ฑด ์ •์งํ•œ
92
+ # ๊ฐ’์ด์ง€๋งŒ(๋ฏธ์ธก์ •โ‰ 0), ๊ณ„๊ธฐ๊ฐ€ **๊ตฌ์กฐ์ ์œผ๋กœ ์ฃฝ์€ ์ฑ„** ๋ฐฐ์„ ๋œ ๊ฒƒ๊ณผ ๊ฐ™๋‹ค.
93
+ # ๐ŸŸฅ ์Šค์ฝ”ํ”„๋ฅผ ยซ๋Ÿฌ๋„ˆ๊ฐ€ ์†์œผ๋กœ ๋ชฉ๋ก์„ ๋งŒ๋“ค์–ด ๋„˜๊ธฐ๋Š”ยป ์‹์œผ๋กœ ํ’€์ง€ ์•Š๋Š”๋‹ค โ€” ๊ทธ๋Ÿฌ๋ฉด ์„ ํ›„ ํ•„ํ„ฐ๊ฐ€
94
+ # ๋‘ ๋ฒŒ์ด ๋˜๊ณ  ๊ด€๋Œ€ํ•จ์ด ๊ฐˆ๋ฆฌ๋Š” ์ˆœ๊ฐ„ ํ•œ์ชฝ๋งŒ ํ†ต๊ณผํ•˜๋Š” ์ž…๋ ฅ์ด ๋ฌด์Œ ๋“œ๋กญ๋œ๋‹ค
95
+ # ([[feedback_divergent_leniency_duplicate_normalizers]]). ํ•„ํ„ฐ๋Š” ์—ฌ๊ธฐ ํ•œ ๊ณณ์— ๋‘๊ณ 
96
+ # **๋ฌด์—‡์„ ๋ณผ์ง€๋งŒ** ๋ฐ–์—์„œ ์ •ํ•œ๋‹ค.
97
+ # ๊ธฐ๋ณธ๊ฐ’์€ ์ข…์ „ ๊ทธ๋Œ€๋กœ โ€” FH ๊ฒฝ๋กœ ๋ฌด๋ณ€๊ฒฝ.
98
+ # โš ๏ธ **๋ช…๋ช…๋œ ์ž”์—ฌ (cross-family/codex F4)**: ์ด ๊ฐ’์€ **๊ณต๋ฐฑ ๋ถ„๋ฆฌ**๋œ ๋‹ค์ค‘ pathspec ์ด๋‹ค.
99
+ # ๋”ฐ๋ผ์„œ **๊ฒฝ๋กœ์— ๊ณต๋ฐฑ์ด ์žˆ์œผ๋ฉด ๊ฐˆ๋ฆฐ๋‹ค** โ€” `docs public` ์€ ยซํ•œ ๊ฒฝ๋กœยป๊ฐ€ ์•„๋‹ˆ๋ผ ๋‘ ๊ฒฝ๋กœ๊ฐ€ ๋œ๋‹ค.
100
+ # ๋‹ค์ค‘ ๊ฒฝ๋กœ ์ง€์›๊ณผ์˜ ํŠธ๋ ˆ์ด๋“œ์˜คํ”„๋ผ ์˜ค๋Š˜์€ **๋ฌธ์„œํ™”๋งŒ** ํ–ˆ๊ณ  ๊ธฐ๊ณ„ ๊ฒ€์‚ฌ๋Š” ์—†๋‹ค.
101
+ DLC_TRACKED_PATHS="${DLC_TRACKED_PATHS:-knowledge CLAUDE.md}" # git ์ถ”์ ์ถ• (์ปค๋ฐ‹์‹œ๊ฐ)
102
+ DLC_IGNORED_DIR="${DLC_IGNORED_DIR-tracks/_meta}" # gitignored ์ถ• (mtime). ๋นˆ ๊ฐ’ = ๊ทธ ์ถ• ์—†์Œ
88
103
  SECTION_RE='^## .*Immediate Application Candidates'
89
104
 
90
105
  # ํ›„๋ณด ํ‘œ์—์„œ (id, ํŒ๋ณ„ํ† ํฐ OR ์ •๊ทœ์‹) ์„ ๋ฝ‘๋Š”๋‹ค. ํ† ํฐ ์—†์œผ๋ฉด id ๋งŒ ๋‚ด๊ณ  ์ •๊ทœ์‹์€ ๋นˆ ๊ฐ’.
91
106
  _extract() { # $1 = digest path
92
107
  awk -v sec="$SECTION_RE" '
108
+ # ํŒ๋ณ„์ž ์ถ”์ถœ โ€” ํ‘œ/๋ฌธ๋‹จ **๋‘ ๊ฒฝ๋กœ๊ฐ€ ๊ณต์œ **ํ•œ๋‹ค(์ค‘๋ณต ์ •๊ทœํ™”๊ธฐ ๋ฐฉ์ง€).
109
+ function harvest(body, toks, tmp, w, t) {
110
+ tmp=body
111
+ while (match(tmp, /\[\[[^]]+\]\]/)) {
112
+ w=substr(tmp, RSTART+2, RLENGTH-4); tmp=substr(tmp, RSTART+RLENGTH)
113
+ if (length(w) >= 5) toks = (toks == "" ? w : toks "|" w)
114
+ }
115
+ tmp=body
116
+ while (match(tmp, /`[^`]+`/)) {
117
+ t=substr(tmp, RSTART+1, RLENGTH-2); tmp=substr(tmp, RSTART+RLENGTH)
118
+ sub(/[: ].*$/, "", t)
119
+ gsub(/^[[:space:]]+|[[:space:]]+$/, "", t)
120
+ if (length(t) < 5) continue
121
+ if (t ~ /[][(){}.*+?^$\\|]/) { if (t ~ /^[A-Za-z0-9_.-]+$/) { } else continue }
122
+ gsub(/\./, "\\.", t)
123
+ toks = (toks == "" ? t : toks "|" t)
124
+ }
125
+ return toks
126
+ }
93
127
  $0 ~ sec { inblk=1; next }
94
- inblk && /^## / { inblk=0 }
128
+ inblk && /^## / { if (pid != "") { print pid "\t" ptoks; pid="" } inblk=0; inpara=0 }
129
+ # โ”€โ”€ ๋ฌธ๋‹จ ํ˜•์‹ (2026-08-18 ์‹ ์„ค) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
130
+ # ๐ŸŸฅ ์ด ๊ณ„๊ธฐ๋Š” ํ›„๋ณด๋ฅผ **ํ‘œ**๋กœ๋งŒ ์ฝ์—ˆ๋‹ค. ์‹ค์ธก: ๋‹ค์ด์ œ์ŠคํŠธ 60๊ฑด ์ค‘ ํ‘œ ํ˜•์‹์€ **4๊ฑด**,
131
+ # ๋‚˜๋จธ์ง€๋Š” `**โ‘  โ€ฆ**` `**[A] โ€ฆ**` `**1. โ€ฆ**` `**#1 โ€ฆ**` ๊ฐ™์€ **๋ฌธ๋‹จ ํ˜•์‹**์ด๋‹ค.
132
+ # ์ฆ‰ ๊ณ„๊ธฐ๊ฐ€ ์‹ค๋ฌผ์˜ 6.7% ๋งŒ ์ฝ์„ ์ˆ˜ ์žˆ์—ˆ๊ณ , ๊ทธ๋ž˜์„œ ์ฒซ ์‹ค์ธก์ด rc=10(ยซํ›„๋ณด ์ ˆ์„ ๋ชป ์ฐพ์•˜๋‹คยป)
133
+ # ์„ ๋ƒˆ๋‹ค. ์•ˆ ๋“œ๋Ÿฌ๋‚œ ์ด์œ ๋Š” **ํ”„๋กœ๋•์…˜ ํ˜ธ์ถœ๋ถ€๊ฐ€ 0** ์ด์—ˆ๊ธฐ ๋•Œ๋ฌธ โ€” ์•„๋ฌด๋„ ์•ˆ ๋Œ๋ ธ๋‹ค.
134
+ # โš ๏ธ ๋จธ๋ฆฌ ํ‘œ๊ธฐ๋Š” ์—ฌ๋Ÿฌ ์ข…์ด๋ผ ํ•œ ๋ชจ์–‘์— ๋งž์ถ”์ง€ ์•Š๋Š”๋‹ค(์‹ค์ธก: โ‘  ยท [A] ยท 1. ยท #1 ยท ๊ทธ ์™ธ).
135
+ # **`**` ๋กœ ์—ด๋ฆฌ๋Š” ์ค„**์„ ํ•ญ๋ชฉ ์‹œ์ž‘์œผ๋กœ ๋ณด๊ณ , ๋‹ค์Œ ํ•ญ๋ชฉ/์ ˆ๊นŒ์ง€๋ฅผ ๋ณธ๋ฌธ์œผ๋กœ ๋ชจ์€๋‹ค.
136
+ # ๐ŸŸฅ ํŒ๋ณ„์ž ์ถ”์ถœ์€ **ํ‘œ ๊ฒฝ๋กœ์™€ ๊ฐ™์€ ์ฝ”๋“œ**๋ฅผ ์“ด๋‹ค โ€” ๋‘ ๋ฒŒ๋กœ ๊ฐˆ๋ฆฌ๋ฉด ๊ด€๋Œ€ํ•จ์ด ์–ด๊ธ‹๋‚˜
137
+ # ํ•œ์ชฝ๋งŒ ํ†ต๊ณผํ•˜๋Š” ์ž…๋ ฅ์ด ๋ฌด์Œ ๋“œ๋กญ๋œ๋‹ค(divergent leniency).
138
+ # ํ•ญ๋ชฉ ๋จธ๋ฆฌ **๋„ค** ํ˜•์‹์„ ๋‹ค ๋ฐ›๋Š”๋‹ค. ์‹ค์ธก(60๊ฑด ํ›„๋ณด ์ ˆ ์ „์ˆ˜, ํ•˜๋‚˜์”ฉ ์—ด์–ด์„œ ํ™•์ธ):
139
+ # `**โ€ฆ**` 74 ยท ํ‘œ `|` 28 ยท `### [M] 1.` 22 ยท **๋ฒˆํ˜ธ ๋ฆฌ์ŠคํŠธ `1. **โ€ฆ**`**(์ดˆ๊ธฐ ๋‹ค์ด์ œ์ŠคํŠธ์˜ ์ฃผ ํ˜•์‹)
140
+ # ๐ŸŸฅ ์ดˆํŒ์€ `**` ๋งŒ ๋ฐ›์•˜๊ณ , ํ‘œ๊ฐ€ ์„ž์ธ ์ ˆ์—์„œ **ํ‘œ ์•ž์˜ `**` ์ค„์„ ๋จผ์ € ์‚ผ์ผœ** ํ‘œ ํ–‰์„
141
+ # UNCHECKABLE ๋กœ ๋–จ์–ด๋œจ๋ ธ๋‹ค(ํšŒ๊ท€ ์‹ค์ธก). ๊ทธ๋ž˜์„œ **ํ‘œ ํ–‰์€ ํ•ญ์ƒ ํ‘œ ๊ฒฝ๋กœ๊ฐ€ ๋จผ์ € ๊ฐ€์ ธ๊ฐ„๋‹ค**.
142
+ inblk && (/^###+ / || /^\*\*/ || /^[0-9]+\. / || /^- \*\*/) {
143
+ if (pid != "") { print pid "\t" ptoks }
144
+ pid=$0; ptoks=""
145
+ sub(/^###+ /, "", pid); sub(/^[0-9]+\. /, "", pid); sub(/^- /, "", pid)
146
+ sub(/^\*\*/, "", pid); sub(/\*\*.*$/, "", pid)
147
+ gsub(/^[[:space:]]+|[[:space:]]+$/, "", pid)
148
+ # ๐ŸŸฅ substr ๋กœ ์ž๋ฅด์ง€ ์•Š๋Š”๋‹ค โ€” awk ๋Š” ๋กœ์ผ€์ผ์— ๋”ฐ๋ผ **๋ฐ”์ดํŠธ** ๋‹จ์œ„๋ผ ํ•œ๊ธ€/๊ธฐํ˜ธ๋ฅผ
149
+ # ์ค‘๊ฐ„์—์„œ ์ชผ๊ฐœ๊ณ  ๊ทธ ์ถœ๋ ฅ์ด UTF-8 ๋กœ ์•ˆ ์ฝํžŒ๋‹ค(์‹ค์ธก: ์ง‘๊ณ„ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ UnicodeDecodeError).
150
+ # id ๋Š” ํ‘œ์‹œ์šฉ์ด๋ฏ€๋กœ ์ž๋ฅด์ง€ ๋ง๊ณ  **๊ณต๋ฐฑ ๊ธฐ์ค€ ์•ž 6๋‚ฑ๋ง**๋งŒ ์“ด๋‹ค.
151
+ if (split(pid, _w, /[[:space:]]+/) > 6) {
152
+ pid=""; for (_i=1; _i<=6; _i++) pid = pid (_i>1 ? " " : "") _w[_i]
153
+ }
154
+ ptoks=harvest($0, ptoks)
155
+ inpara=1; next
156
+ }
157
+ # ํ‘œ ํ–‰์€ ์•„๋ž˜ ํ‘œ ๊ฒฝ๋กœ๊ฐ€ ์ฒ˜๋ฆฌํ•œ๋‹ค โ€” ์—ฌ๊ธฐ์„œ ์•ˆ ๋จน๋Š”๋‹ค(์šฐ์„ ์ˆœ์œ„ ๋ช…์‹œ).
158
+ inblk && inpara && !/^\|/ && !/^###+ / && !/^[0-9]+\. / && !/^- \*\*/ { ptoks=harvest($0, ptoks); next }
95
159
  inblk && /^\|/ {
96
160
  line=$0
97
161
  # ํ—ค๋”/๊ตฌ๋ถ„์„  ์ œ์™ธ
@@ -135,6 +199,7 @@ _extract() { # $1 = digest path
135
199
  }
136
200
  print id "\t" toks
137
201
  }
202
+ END { if (pid != "") print pid "\t" ptoks }
138
203
  ' "$1"
139
204
  }
140
205
 
@@ -143,8 +208,30 @@ do_extract() { # $1 = digest
143
208
  [ -f "$d" ] || { echo "โŒ digest ์—†์Œ: $d" >&2; return 10; }
144
209
  # ์ปจํŠธ๋กค โ€” ์ด ๊ณ„๊ธฐ๊ฐ€ ์‚ด์•„ ์žˆ๋Š”์ง€ ์ฆ๋ช…ํ•œ๋‹ค. ๋Œ€์ƒ ํŠธ๋ฆฌ์— ํ™•์‹คํžˆ ์กด์žฌํ•˜๋Š” ํ† ํฐ.
145
210
  # ์ปจํŠธ๋กค์ด ์ฃฝ์œผ๋ฉด ์ฐฉ์ง€ ๊ฒ€์ฆ๊ธฐ๊ฐ€ rc=10 ์„ ๋‚ด๊ณ  ํƒ€๊นƒ ๊ฒฐ๊ณผ๋ฅผ ์ธ์‡„ํ•˜์ง€ ์•Š๋Š”๋‹ค.
146
- printf 'CONTROL\tforge-harness\t์ปจํŠธ๋กค: ๋ ˆํฌ๋ช…\n'
147
- printf 'CONTROL\tsession\t์ปจํŠธ๋กค: ํ”ํ•œ ํ† ํฐ\n'
211
+ # ๐ŸŸฅ R1-b (2026-08-18) โ€” ์ปจํŠธ๋กค์ด `forge-harness`/`session` ์œผ๋กœ **ํ•˜๋“œ์ฝ”๋”ฉ**์ด์—ˆ๋‹ค.
212
+ # ์œ„์„ฑ์ด ๊ฒจ๋ˆˆ ๋ ˆํฌ์—๋Š” ๊ทธ ๋‘ ํ† ํฐ์ด ์—†์œผ๋ฏ€๋กœ **์ปจํŠธ๋กค์ด ๋งค๋ฒˆ ์ฃฝ๊ณ ** ๊ณ„๊ธฐ๋Š” rc=10 ๋งŒ ๋‚ธ๋‹ค.
213
+ # R1 ์˜ ์ธ์ž ๋ฒ„๊ทธ๋ฅผ ๊ณ ์ณ๋„ ์ด๊ฒŒ ๋‚จ์•„ ์žˆ์œผ๋ฉด ๊ณ„๊ธฐ๋Š” ์—ฌ์ „ํžˆ ๊ตฌ์กฐ์ ์œผ๋กœ ์ฃฝ์€ ์ฑ„๋‹ค โ€” ๊ทธ ์‚ฌ์‹ค์„
214
+ # ์ด ๋ ˆ์ธ์ด ์žก์•˜๋‹ค(์ˆ˜๋ฆฌ๊ฐ€ ์‹ ๊ทœ ๊ฒฐํ•จ์˜ ์ถœ์ฒ˜์ธ ๊ฒƒ๊ณผ ๊ฐ™์€ ์–ผ๊ตด: ๋ฐ˜์ชฝ ์ˆ˜๋ฆฌ).
215
+ # ๊ธฐ๋ณธ๊ฐ’์€ **์ž๊ธฐ ๋ ˆํฌ ์ด๋ฆ„**์ด๋ผ FH ์—์„œ๋Š” ์ข…์ „๊ณผ ๋™์ผ(`forge-harness`)ํ•˜๋‹ค.
216
+ # ๐ŸŸฅ ๋‘ ๊ฐˆ๋ž˜๋ฅผ ๊ฐˆ๋ผ์•ผ ํ•œ๋‹ค (cross-family/codex F3 ์ง€๋ชฉ, ์‹ค์ธก์œผ๋กœ **๋” ๋‚˜์œ ํ˜•ํƒœ** ํ™•์ธ):
217
+ # ์ดˆํŒ์€ `for _ctl in ${DLC_CONTROLS:-$(basename "$FH") session}` ์˜€๋Š”๋ฐ, ๋น„์ธ์šฉ ๋ช…๋ น์น˜ํ™˜์€
218
+ # ๋‹จ์–ด๋ถ„๋ฆฌ **์™€ ๊ธ€๋กœ๋น™**์„ ๋‘˜ ๋‹ค ํƒ„๋‹ค โ€” ๋ ˆํฌ๋ช…์ด `.*` ์ธ ๋””๋ ‰ํ„ฐ๋ฆฌ์—์„œ ์‹ค์ธกํ•˜๋‹ˆ ์ปจํŠธ๋กค์ด
219
+ # `.git` ๋“ฑ **4๊ฐœ๋กœ ๊ธ€๋กœ๋ธŒ ํ™•์žฅ**๋๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ์ปจํŠธ๋กค์€ ERE ๋กœ ์“ฐ์ด๋ฏ€๋กœ ๋ ˆํฌ๋ช…์— ์ •๊ทœ์‹
220
+ # ๋ฉ”ํƒ€๋ฌธ์ž๊ฐ€ ์žˆ์œผ๋ฉด ยซ์•„๋ฌด ๋‚ด์šฉ์—๋‚˜ ๋งค์น˜ยปํ•ด **๊ณ„๊ธฐ ์ƒ์กด์ด ์˜คํƒ**์ด ๋œ๋‹ค.
221
+ # โ‡’ ์œ ๋„ ๊ธฐ๋ณธ๊ฐ’์€ **๋ฆฌํ„ฐ๋Ÿด๋กœ ์ทจ๊ธ‰**(๋ฉ”ํƒ€๋ฌธ์ž ์ด์Šค์ผ€์ดํ”„) ยท ์‚ฌ์šฉ์ž ์ง€์ •๊ฐ’๋งŒ ์ •๊ทœ์‹์œผ๋กœ ๋‘”๋‹ค.
222
+ local _ctl _label=1
223
+ if [ -n "${DLC_CONTROLS:-}" ]; then
224
+ for _ctl in $DLC_CONTROLS; do # ๋ช…์‹œ๊ฐ’์€ ยซ์ •๊ทœ์‹ยป ๊ณ„์•ฝ โ€” ์˜๋„์  ๋ถ„๋ฆฌ
225
+ printf 'CONTROL\t%s\t์ปจํŠธ๋กค%s: %s\n' "$_ctl" "$_label" "$_ctl"
226
+ _label=$((_label+1))
227
+ done
228
+ else
229
+ local _repo; _repo="$(basename "$FH")"
230
+ # ERE ๋ฉ”ํƒ€๋ฌธ์ž ์ด์Šค์ผ€์ดํ”„ โ€” ์œ ๋„๊ฐ’์€ ยซ๊ทธ ๋ฌธ์ž์—ด์ด ์‹ค์ œ๋กœ ์žˆ๋Š”๊ฐ€ยป ๋ฅผ ๋ฌป๋Š” ๊ฒƒ์ด์ง€ ํŒจํ„ด์ด ์•„๋‹ˆ๋‹ค
231
+ _repo="$(printf '%s' "$_repo" | sed 's/[][\.^$*+?(){}|]/\\&/g')"
232
+ printf 'CONTROL\t%s\t์ปจํŠธ๋กค1: %s\n' "$_repo" "$_repo"
233
+ printf 'CONTROL\tsession\t์ปจํŠธ๋กค2: session\n'
234
+ fi
148
235
  while IFS=$'\t' read -r id toks; do
149
236
  [ -n "${id:-}" ] || continue
150
237
  n=$((n+1))
@@ -168,7 +255,14 @@ do_check() {
168
255
  [ -x "$CHECKER" ] || [ -f "$CHECKER" ] || {
169
256
  echo "โŒ ์ฐฉ์ง€ ๊ฒ€์ฆ๊ธฐ ๋ถ€์žฌ: $CHECKER (์ด ์Šคํฌ๋ฆฝํŠธ๋Š” ๊ฒ€์ฆ์„ ์ž์ฒด ๊ตฌํ˜„ํ•˜์ง€ ์•Š๋Š”๋‹ค)" >&2; return 10; }
170
257
 
171
- local -a targets
258
+ # ๐ŸŸฅ R7 (2026-08-19, **์ฒซ ์‹ค์‚ฌ์šฉ ๋ฐœ๊ฒฌ**) โ€” `set -u` + bash 3.2 ์—์„œ **๋นˆ ๋ฐฐ์—ด์˜ `${a[@]}` ๋Š”
259
+ # unbound ์—๋Ÿฌ**๋‹ค. ๋Œ€์ƒ ๋ ˆํฌ์— digest ์ดํ›„ ์ปค๋ฐ‹์ด ์—†์œผ๋ฉด targets ๊ฐ€ ๋น„๊ณ , ๊ทธ๋Ÿฌ๋ฉด ์•„๋ž˜
260
+ # ํ•„ํ„ฐ ๋ฃจํ”„๊ฐ€ ํ„ฐ์ง„๋‹ค. ๊ทธ ์ˆœ๊ฐ„ ์Šคํฌ๋ฆฝํŠธ๋Š” ํŒ์ •์„ ์ธ์‡„ํ•˜์ง€ ๋ชปํ•œ ์ฑ„ **rc=1 ๋กœ ๋๋‚˜๊ณ **,
261
+ # ๋Ÿฌ๋„ˆ๋Š” ๊ทธ 1 ์„ ใ€ŒSOME-UNLANDEDใ€๋กœ ๋กœ๊ทธ์— ์ ๋Š”๋‹ค โ€” ์ฆ‰ **์…ธ ์—๋Ÿฌ๊ฐ€ ์ฐฉ์ง€์œจ ์‹œ๊ณ„์—ด์—
262
+ # ์‹ค์ธก๊ฐ’์œผ๋กœ ๋“ค์–ด๊ฐ„๋‹ค**([[feedback_not_found_is_not_zero_family]] ์˜ ๊ฐ€์žฅ ์กฐ์šฉํ•œ ์–ผ๊ตด).
263
+ # ์‹ค์ธก: forge-wiki ๋Œ€์ƒ ์ฒซ ๋Ÿฐ์ด ์ •ํ™•ํžˆ ๊ทธ๋ ‡๊ฒŒ ยซSOME-UNLANDED (rc=1)ยป ์„ ๋‚จ๊ฒผ๊ณ  ๋ณธ๋ฌธ์€ ์—†์—ˆ๋‹ค.
264
+ # ์˜ฌ๋ฐ”๋ฅธ ๊ฐ’์€ rc=10(ํƒ€๊นƒ 0๊ฑด = HARNESS-ERROR)์ด๋‹ค. ๋นˆ ๋ฐฐ์—ด ํ™•์žฅ์„ ์ „๋ถ€ ๋ฐฉ์–ดํ•œ๋‹ค.
265
+ local -a targets=()
172
266
  if [ "$#" -gt 0 ]; then targets=("$@")
173
267
  else
174
268
  # ๊ธฐ๋ณธ ์Šค์ฝ”ํ”„ = ๊ณต๊ฐœ FH ์ž์‚ฐ + tracks. **๋น„๊ณต๊ฐœ store ์ œ์™ธ**(์šด์˜์ž ๊ฒฐ์ •).
@@ -176,7 +270,8 @@ do_check() {
176
270
  # โš ๏ธ CLAUDE.md ๋„ **์„ ํ›„ ํ•„ํ„ฐ๋ฅผ ๊ฑฐ์นœ๋‹ค.** ์ดˆํŒ์€ ๋ฌด์กฐ๊ฑด ์ถ”๊ฐ€ํ–ˆ๊ณ , ๊ทธ๋ž˜์„œ ์ด ํŒŒ์ผ ํ•˜๋‚˜๊ฐ€
177
271
  # ํ•„ํ„ฐ๋ฅผ ์šฐํšŒํ•ด ์˜คํƒ ์›์ฒœ์ด ๋๋‹ค โ€” ์†๊ฒ€์ฆ์—์„œ "M1 ์ฐฉ์ง€ 1ํŒŒ์ผ" ์˜ ๊ทธ 1ํŒŒ์ผ์ด CLAUDE.md
178
272
  # ์˜€๊ณ , ํ›„๋ณด์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ์›๋ž˜ ์žˆ๋˜ ํ† ํฐ์ด์—ˆ๋‹ค. ์˜ˆ์™ธ ๊ฒฝ๋กœ ํ•˜๋‚˜๊ฐ€ ํ•„ํ„ฐ ์ „์ฒด๋ฅผ ๋ฌด๋ ฅํ™”ํ•œ๋‹ค.
179
- [ -f "$FH/CLAUDE.md" ] && [ "$FH/CLAUDE.md" -nt "$d" ] && targets+=("$FH/CLAUDE.md")
273
+ case " $DLC_TRACKED_PATHS " in *" CLAUDE.md "*)
274
+ [ -f "$FH/CLAUDE.md" ] && [ "$FH/CLAUDE.md" -nt "$d" ] && targets+=("$FH/CLAUDE.md") ;; esac
180
275
  # โ˜… **digest ๋ณด๋‹ค ๋‚˜์ค‘์— ์ˆ˜์ •๋œ ํŒŒ์ผ๋งŒ** ๋ณธ๋‹ค. grep ์€ "ํ† ํฐ์ด ์žˆ๋‹ค" ๋งŒ ์žฌ๊ณ 
181
276
  # "์ด ํ›„๋ณด ๋•Œ๋ฌธ์— ์ƒ๊ฒผ๋‹ค" ๋Š” ๋ชป ์žฐ๋‹ค โ€” ์ด๋ฏธ ์žˆ๋˜ ๋ฌธ์„œ๊ฐ€ ์ฐฉ์ง€๋กœ ์žกํžŒ๋‹ค(์‹ค์ธก: ํ›„๋ณด ํ•˜๋‚˜๊ฐ€
182
277
  # 21ํŒŒ์ผ ํžˆํŠธ, ์ „๋ถ€ ๋ฌด๊ด€ํ•œ ๊ธฐ์กด ๋ฌธ์„œ์˜€๋‹ค). ์„ ํ›„ ํ•„ํ„ฐ๊ฐ€ ์ธ๊ณผ๋ฅผ ์ฃผ์ง€๋Š” ์•Š์ง€๋งŒ
@@ -211,11 +306,13 @@ do_check() {
211
306
  [ -n "$f" ] || continue
212
307
  case "$f" in *.md) ;; *) continue ;; esac
213
308
  [ -f "$FH/$f" ] && targets+=("$FH/$f")
214
- done < <(git -C "$FH" log --since="@$_dts" --name-only --pretty=format: -- knowledge CLAUDE.md 2>/dev/null | sort -u)
215
- while IFS= read -r f; do targets+=("$f"); done < <(
216
- find "$FH/tracks/_meta" -name '*.md' -type f -newer "$d" 2>/dev/null | head -400)
309
+ done < <(git -C "$FH" log --since="@$_dts" --name-only --pretty=format: -- $DLC_TRACKED_PATHS 2>/dev/null | sort -u)
310
+ if [ -n "$DLC_IGNORED_DIR" ] && [ -d "$FH/$DLC_IGNORED_DIR" ]; then
311
+ while IFS= read -r f; do targets+=("$f"); done < <(
312
+ find "$FH/$DLC_IGNORED_DIR" -name '*.md' -type f -newer "$d" 2>/dev/null | head -400)
313
+ fi
217
314
  # dirty tracked โ€” ์ปค๋ฐ‹ ์•ˆ ๋œ ์ˆ˜์ •๋ณธ์—” git ์‹œ๊ฐ ์ฆ๊ฑฐ๊ฐ€ ์—†๋‹ค. ์ดˆ๋ก์œผ๋กœ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ์…ˆ์— ๋‚จ๊ธด๋‹ค.
218
- DIRTY_TRACKED="$(git -C "$FH" diff --name-only -- knowledge CLAUDE.md 2>/dev/null | grep -c '[.]md$')" || true
315
+ DIRTY_TRACKED="$(git -C "$FH" diff --name-only -- $DLC_TRACKED_PATHS 2>/dev/null | grep -c '[.]md$')" || true
219
316
  DIRTY_TRACKED="${DIRTY_TRACKED//[^0-9]/}"; DIRTY_TRACKED="${DIRTY_TRACKED:-0}"
220
317
  fi
221
318
  # โ˜… ์ž๊ธฐ์ฐธ์กฐ ์ฐจ๋‹จ โ€” **์ด ๊ณ„๊ธฐ์˜ ์ฒซ ์‹ค๋ฌผ ์‹คํ–‰์—์„œ 100% ์˜คํƒ์„ ๋‚ธ ์›์ธ**์ด๋‹ค.
@@ -224,7 +321,7 @@ do_check() {
224
321
  local _dbase; _dbase="$(basename "$d")"
225
322
  local -a _filtered=()
226
323
  local _t
227
- for _t in "${targets[@]}"; do
324
+ for _t in ${targets[@]+"${targets[@]}"}; do
228
325
  case "$_t" in
229
326
  *"$_dbase") continue ;; # digest ์ž์‹ 
230
327
  */logs/*) continue ;; # ๊ทธ ์ƒ์„ฑ ๋กœ๊ทธ
@@ -232,7 +329,7 @@ do_check() {
232
329
  esac
233
330
  _filtered+=("$_t")
234
331
  done
235
- targets=("${_filtered[@]}")
332
+ targets=(${_filtered[@]+"${_filtered[@]}"})
236
333
  [ "${#targets[@]}" -gt 0 ] || { echo "โŒ ํƒ€๊นƒ 0๊ฑด" >&2; return 10; }
237
334
 
238
335
  local probes; probes="$(mktemp -t dlc.XXXXXX)" || return 10
@@ -244,7 +341,7 @@ do_check() {
244
341
  local unchk; unchk="$(grep -c '^# UNCHECKABLE' "$probes" 2>/dev/null)" || true
245
342
  unchk="${unchk//[^0-9]/}"; unchk="${unchk:-0}"
246
343
  echo "โ”€โ”€ digest ์ฐฉ์ง€ ๊ฒ€์ฆ: $(basename "$d") โ”€โ”€"
247
- echo " ์Šค์ฝ”ํ”„: ๊ณต๊ฐœ FH ์ž์‚ฐ + tracks/ (๋น„๊ณต๊ฐœ companion store ์ œ์™ธ โ€” '์กฐ์ง ์ „ํŒŒ'๊ฐ€ ์•„๋‹ˆ๋ผ 'ํ—ˆ๋ธŒ ๋‚ด๋ถ€ ์ฐฉ์ง€')"
344
+ echo " ์Šค์ฝ”ํ”„: git์ถ”์ [${DLC_TRACKED_PATHS}] + ignored[${DLC_IGNORED_DIR:-์—†์Œ}] (๋น„๊ณต๊ฐœ companion store ์ œ์™ธ โ€” '์กฐ์ง ์ „ํŒŒ'๊ฐ€ ์•„๋‹ˆ๋ผ '๋ ˆํฌ ๋‚ด๋ถ€ ์ฐฉ์ง€')"
248
345
  echo " ํƒ€๊นƒ ํŒŒ์ผ ${#targets[@]}๊ฑด (digest ์ดํ›„ ์ˆ˜์ •๋ถ„๋งŒ) ยท ํŒ๋ณ„๋ถˆ๊ฐ€ ํ›„๋ณด ${unchk}๊ฑด"
249
346
  echo " ์ถ•: git์ถ”์ =์ปค๋ฐ‹์‹œ๊ฐ ยท gitignored=mtime ยท dirty tracked ${DIRTY_TRACKED:-0}๊ฑด=UNMEASURED"
250
347
  echo " โš ๏ธ ์ด ๊ณ„๊ธฐ๋Š” **์„ ํ›„**๋ฅผ ์žฐ๋‹ค. ์ธ๊ณผ๊ฐ€ ์•„๋‹ˆ๋‹ค โ€” ํžˆํŠธ๋Š” ์—ด์–ด์„œ ํ™•์ธํ•˜๋ผ"
@@ -331,8 +428,66 @@ EOF
331
428
  touch knowledge/old.md
332
429
  printf 'forge-harness session control\n' > tracks/_meta/card.md
333
430
  ) >/dev/null 2>&1
334
- out="$( cd "$G" && CLAUDE_PROJECT_DIR="$G" bash "$SELF_DIR/$(basename "${BASH_SOURCE[0]}")" \
431
+ # ์ปจํŠธ๋กค์€ ํ”ฝ์Šค์ฒ˜๊ฐ€ ์‹ค์ œ๋กœ ๋‹ด๊ณ  ์žˆ๋Š” ํ† ํฐ์œผ๋กœ ๊ณ ์ •ํ•œ๋‹ค(๋ ˆํฌ๋ช…์ด mktemp ๋‚œ์ˆ˜๋ผ์„œ).
432
+ # ๐ŸŸฅ ์ด ๋ ˆ์ธ์˜ ์ฃผ์žฅ์€ **git/mtime ๋‘ ์ถ• ๋ถ„๋ฆฌ**์ง€ ์ปจํŠธ๋กค ์œ ๋„๊ฐ€ ์•„๋‹ˆ๋‹ค โ€” ์ถ•์„ ์„ž์ง€ ์•Š๋Š”๋‹ค.
433
+ out="$( cd "$G" && CLAUDE_PROJECT_DIR="$G" DLC_CONTROLS="forge-harness session" \
434
+ bash "$SELF_DIR/$(basename "${BASH_SOURCE[0]}")" \
335
435
  "$G/tracks/_meta/frontier_digest_2001_01_02.md" 2>&1 )"
436
+ # โ”€โ”€ โ˜…N-ctl (2026-08-18, R1-b) โ€” ์ปจํŠธ๋กค์ด **๋ ˆํฌ ์ด๋ฆ„์„ ๋”ฐ๋ผ๊ฐ„๋‹ค** โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
437
+ # ์ดˆํŒ์€ `forge-harness`/`session` ํ•˜๋“œ์ฝ”๋”ฉ์ด๋ผ **์œ„์„ฑ์ด ๊ฒจ๋ˆˆ ๋ ˆํฌ์—์„  ๋งค๋ฒˆ ์ปจํŠธ๋กค ์‚ฌ๋ง**
438
+ # (= rc=10)์ด์—ˆ๋‹ค. R1 ์˜ ์ธ์ž ๋ฒ„๊ทธ๋ฅผ ๊ณ ์ณ๋„ ๊ณ„๊ธฐ๋Š” ๊ตฌ์กฐ์ ์œผ๋กœ ์ฃฝ์€ ์ฑ„์˜€์„ ๊ฒƒ์ด๋‹ค.
439
+ local out_ctl rc_ctl
440
+ out_ctl="$( cd "$G" && CLAUDE_PROJECT_DIR="$G" bash "$SELF_DIR/$(basename "${BASH_SOURCE[0]}")" \
441
+ "$G/tracks/_meta/frontier_digest_2001_01_02.md" 2>&1 )"; rc_ctl=$?
442
+ # ํ”ฝ์Šค์ฒ˜ ๋ ˆํฌ ์ด๋ฆ„(mktemp ๋‚œ์ˆ˜)์€ ๋ณธ๋ฌธ์— ์—†๋‹ค โ‡’ ์œ ๋„๋œ ์ปจํŠธ๋กค์ด ์ฃฝ์–ด rc=10 ์ด ์ •์ƒ์ด๋‹ค.
443
+ # ์ด๊ฒƒ์ด ยซ์œ ๋„๊ฐ€ ์‹ค์ œ๋กœ ๋ˆ๋‹คยป์˜ ์ฆ๊ฑฐ๋‹ค(ํ•˜๋“œ์ฝ”๋”ฉ์ด๋ฉด ์—ฌ๊ธฐ์„œ rc=1 ์ด ๋‚˜์˜จ๋‹ค).
444
+ _t "โ˜…N-ctl ์ปจํŠธ๋กค์ด ๋ ˆํฌ๋ช…์„ ๋”ฐ๋ผ๊ฐ„๋‹ค(ํ•˜๋“œ์ฝ”๋”ฉ ์•„๋‹˜)" 10 "$rc_ctl"
445
+ # โ”€โ”€ โ˜…N-ctl-re (cross-family/codex F3) โ€” ์œ ๋„ ์ปจํŠธ๋กค์€ **๋ฆฌํ„ฐ๋Ÿด**์ด์ง€ ์ •๊ทœ์‹์ด ์•„๋‹ˆ๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€
446
+ # ์ดˆํŒ์€ `for _ctl in ${DLC_CONTROLS:-$(basename "$FH") session}` ์˜€๋‹ค. ๋น„์ธ์šฉ ๋ช…๋ น์น˜ํ™˜์ด๋ผ
447
+ # โ“ ๋ ˆํฌ๋ช…์ด ERE ๋ฉ”ํƒ€๋ฌธ์ž๋ฉด ยซ์•„๋ฌด ๋‚ด์šฉ์—๋‚˜ ๋งค์น˜ยปํ•ด ๊ณ„๊ธฐ ์ƒ์กด์ด **์˜คํƒ**์ด ๋˜๊ณ 
448
+ # โ“‘ ์‹ค์ธกํ•˜๋‹ˆ ๊ธ€๋กœ๋น™๊นŒ์ง€ ํƒ€์„œ ์ปจํŠธ๋กค์ด `.git` ๋“ฑ์œผ๋กœ **ํ™•์žฅ**๋˜๊ธฐ๋„ ํ–ˆ๋‹ค.
449
+ # ๐ŸŸฅ ํ”ฝ์Šค์ฒ˜๋Š” **ํŒ๋ณ„ํ•˜๋Š” ํ˜•ํƒœ**์—ฌ์•ผ ํ•œ๋‹ค. ์ฒซ ํŒ๋ณธ์€ ๋ ˆํฌ๋ช…์„ `.*` ๋กœ ์žก์•˜๋Š”๋ฐ, ๊ทธ๊ฑด ๊ธ€๋กœ๋น™์—
450
+ # ๊ฑธ๋ ค ์ฃฝ์€ ์ปจํŠธ๋กค์ด ์ƒ๊ธฐ๋Š” ๋ฐ”๋žŒ์— **๋ฒ„๊ทธ ํŒ๋ณธ๋„ rc=10** ์„ ๋ƒˆ๋‹ค โ€” ๋˜๋Œ๋ฆผ ํ”„๋กœ๋ธŒ๊ฐ€ ๊ทธ
451
+ # ์žฅ์‹์„ฑ์„ ์žก์•˜๋‹ค([[feedback_fixture_must_use_the_breaking_spelling]]).
452
+ # ๊ทธ๋ž˜์„œ ๋ ˆํฌ๋ช…์„ `a.b` ๋กœ ์“ด๋‹ค: ๊ธ€๋กœ๋ธŒ๋กœ๋Š” ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ๋งž์•„ ๊ทธ๋Œ€๋กœ ๋‚จ๊ณ (ํ™•์žฅ ์—†์Œ),
453
+ # ERE ๋กœ๋Š” `axb` ์— ๋งค์น˜๋œ๋‹ค. ๋Œ€์ƒ์— `axb` ๋งŒ ๋‘๋ฉด
454
+ # ๋ฒ„๊ทธ ํŒ๋ณธ โ†’ ์ปจํŠธ๋กค **์ƒ์กด(์˜คํƒ)** โ†’ rcโ‰ 10
455
+ # ์ˆ˜๋ฆฌ ํŒ๋ณธ โ†’ ๋ฆฌํ„ฐ๋Ÿด `a.b` ์—†์Œ โ†’ ์ปจํŠธ๋กค ์‚ฌ๋ง โ†’ rc=10
456
+ local RG; RG="$(mktemp -d -t 'dlc_re.XXXXXX')" || return 10
457
+ local RD="$RG/a.b"
458
+ (
459
+ mkdir -p "$RD/tracks/_meta" "$RD/knowledge" && cd "$RD" \
460
+ && git init -q . && git config user.email t@t && git config user.name t
461
+ printf '# d\n## ๐Ÿ“Œ FH Immediate Application Candidates\n\n| # | ํ‹ฐ์–ด | ๋‚ด์šฉ |\n|---|---|---|\n| **A1** | M | `zzz_absent_token` ํ›„๋ณด |\n\n## end\n' \
462
+ > tracks/_meta/frontier_digest_2001_01_01.md
463
+ touch -t 200101010000 tracks/_meta/frontier_digest_2001_01_01.md
464
+ # ๋ฆฌํ„ฐ๋Ÿด `a.b` ๋Š” **์—†๋‹ค**. `axb`(ERE ๋กœ๋งŒ ๋งค์น˜) ์™€ `session` ๋งŒ ์žˆ๋‹ค.
465
+ printf 'axb ๊ทธ๋ฆฌ๊ณ  session\n' > tracks/_meta/card.md
466
+ ) >/dev/null 2>&1
467
+ local rc_re
468
+ ( cd "$RD" && CLAUDE_PROJECT_DIR="$RD" bash "$SELF_DIR/$(basename "${BASH_SOURCE[0]}")" \
469
+ "$RD/tracks/_meta/frontier_digest_2001_01_01.md" ) >/dev/null 2>&1; rc_re=$?
470
+ _t "โ˜…N-ctl-re ๋ ˆํฌ๋ช…์ด ์ •๊ทœ์‹ ๋ฉ”ํƒ€๋ฌธ์ž์—ฌ๋„ ๋ฆฌํ„ฐ๋Ÿด๋กœ ์ทจ๊ธ‰(์ปจํŠธ๋กค ์˜คํƒ ์—†์Œ)" 10 "$rc_re"
471
+ rm -rf "$RG"
472
+
473
+ # โ”€โ”€ โ˜…N-empty (2026-08-19, R7) โ€” ํƒ€๊นƒ์ด 0๊ฑด์ด๋ฉด **rc=10** ์ด์ง€ rc=1 ์ด ์•„๋‹ˆ๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
474
+ # ๐ŸŸฅ `set -u` + bash 3.2 ์—์„œ ๋นˆ ๋ฐฐ์—ด ํ™•์žฅ์ด ํ„ฐ์ง€๋ฉด, ์Šคํฌ๋ฆฝํŠธ๋Š” ํŒ์ •์„ ๋ชป ๋‚ด๊ณ  **rc=1** ๋กœ
475
+ # ๋๋‚œ๋‹ค. ๋Ÿฌ๋„ˆ๋Š” ๊ทธ 1 ์„ ใ€ŒSOME-UNLANDEDใ€๋กœ ์ ๋Š”๋‹ค โ€” ์…ธ ์—๋Ÿฌ๊ฐ€ ์ฐฉ์ง€์œจ ์‹œ๊ณ„์—ด์— ์‹ค์ธก๊ฐ’์œผ๋กœ
476
+ # ๋“ค์–ด๊ฐ„๋‹ค. ์ฒซ ์‹ค์‚ฌ์šฉ(forge-wiki ๋Œ€์ƒ)์—์„œ ์ •ํ™•ํžˆ ๊ทธ ๋กœ๊ทธ๊ฐ€ ๋‚˜์™”๊ณ  ๋ณธ๋ฌธ์€ ๋น„์–ด ์žˆ์—ˆ๋‹ค.
477
+ local EG; EG="$(mktemp -d -t dlc_e.XXXXXX)" || return 10
478
+ (
479
+ mkdir -p "$EG/wiki" && cd "$EG" && git init -q . \
480
+ && git config user.email t@t && git config user.name t
481
+ printf '# d\n## ๐Ÿ“Œ FH Immediate Application Candidates\n\n| # | ํ‹ฐ์–ด | ๋‚ด์šฉ |\n|---|---|---|\n| **A1** | M | `zzz_tok` ํ›„๋ณด |\n\n## end\n' \
482
+ > wiki/frontier_digest_2001_01_01.md
483
+ ) >/dev/null 2>&1
484
+ # digest ์ดํ›„ ์ปค๋ฐ‹ 0 ยท ignored ์ถ• ์—†์Œ โ‡’ ํƒ€๊นƒ 0๊ฑด
485
+ local rc_e
486
+ ( cd "$EG" && CLAUDE_PROJECT_DIR="$EG" DLC_TRACKED_PATHS="wiki" DLC_IGNORED_DIR="" \
487
+ DLC_CONTROLS="zzz_tok" bash "$SELF_DIR/$(basename "${BASH_SOURCE[0]}")" \
488
+ "$EG/wiki/frontier_digest_2001_01_01.md" ) >/dev/null 2>&1; rc_e=$?
489
+ _t "โ˜…N-empty ํƒ€๊นƒ 0๊ฑด์€ HARNESS-ERROR(10)์ด์ง€ ๋ฏธ์ฐฉ์ง€(1)๊ฐ€ ์•„๋‹ˆ๋‹ค" 10 "$rc_e"
490
+ rm -rf "$EG"
336
491
  # โš ๏ธ **์ค„ ๋‹จ์œ„๋กœ** ๋ณธ๋‹ค. `case *"A1"*"๋ฏธ์ฐฉ์ง€"*` ๋Š” ๋งˆ์ง€๋ง‰ ์š”์•ฝ์ค„("N๊ฑด ์ค‘ M๊ฑด ๋ฏธ์ฐฉ์ง€")๊นŒ์ง€
337
492
  # ์‚ผ์ผœ ์˜ค๋งค์นญํ•œ๋‹ค โ€” ๋ฌธ์ž์—ด ์œ„์น˜๋กœ ํŒ์ •ํ•˜๋Š” prose-grep ํ•จ์ •([[feedback_typed_verdict_channel]]).
338
493
  if printf '%s\n' "$out" | grep -qE 'ํ›„๋ณด A1[[:space:]]+๋ฏธ์ฐฉ์ง€'; then
@@ -290,6 +290,77 @@ fi
290
290
  ( cd "$FH" && bash scripts/branch_claim.sh reap >/dev/null 2>&1 ) || true
291
291
  }
292
292
 
293
+ # โ”€โ”€ ๋งคํ•‘๋œ ํ”„๋กœ์ ํŠธ์˜ capability ํ‘œ๋ฉดํ™” (2026-08-18) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
294
+ # WHY HERE (branch-claim ๊ณผ ๊ฐ™์€ ์ž๋ฆฌ, early exit **์œ„**): ์ด๊ฑด Mode D ์ „์šฉ์ด ์•„๋‹ˆ๋‹ค.
295
+ # companion store ๊ฐ€ ์—†๋Š” ์„ค์น˜์—์„œ๋„ ํ”„๋กœ์ ํŠธ๋Š” ๋งคํ•‘๋˜๊ณ , ๊ทธ๋•Œ๋„ ํ˜•์ œ ํ•˜๋„ค์Šค์˜ ์Šคํ‚ฌ์€
296
+ # ์•ˆ ๋ณด์ธ๋‹ค. ์•„๋ž˜ early exit ๋ฐ‘์— ๋‘๋ฉด ๊ทธ ์„ค์น˜์—์„œ ํ†ต์งธ๋กœ ์ฃฝ๋Š”๋‹ค โ€” ๋ฐ”๋กœ ์œ„ branch-claim
297
+ # ๋ธ”๋ก์ด ๊ฐ™์€ ์ด์œ ๋กœ ์—ฌ๊ธฐ ์žˆ๋‹ค.
298
+ # โš ๏ธ **์ •๋ฐ€ํ™”(cross-family ์ ๋ฐœ)**: `tracks/` ๋Š” npm ์‚ฐ์ถœ๋ฌผ์— **์•ˆ ๋“ค์–ด๊ฐ„๋‹ค**(per-install ๋ฐ์ดํ„ฐ).
299
+ # ๊ทธ๋Ÿฌ๋‹ˆ ยซ๊ฐ“ ์„ค์น˜ํ•œยป ์†Œ๋น„์ž์—๊ฒŒ๋Š” ์ด ๋ธ”๋ก์ด ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ์ฐ๋Š”๋‹ค โ€” ๊ฐ’์€ ๊ทธ ์‚ฌ๋žŒ์ด ํ”„๋กœ์ ํŠธ๋ฅผ
300
+ # **๋งคํ•‘ํ•œ ๋’ค๋ถ€ํ„ฐ** ์ƒ๊ธด๋‹ค. ใ€Œ๊ณต๊ฐœ ์‚ฌ์šฉ์ž์—๊ฒŒ๋„ ์‚ฐ๋‹คใ€๋Š” ๊ทธ๋Ÿฐ ๋œป์ด์ง€ ยซ์„ค์น˜ ์ฆ‰์‹œ ๊ฐ’์ด ์žˆ๋‹คยป ๊ฐ€
301
+ # ์•„๋‹ˆ๋‹ค. (์‹ค์ธก: ํŒฉ ์‚ฐ์ถœ๋ฌผ์— tracks ์—†์Œ โ†’ ์นจ๋ฌต ยท tracks/someproject ์ƒ์„ฑ ํ›„ โ†’ ๋ฐœํ™”)
302
+ #
303
+ # WHY AT ALL: `CLAUDE.md ยงCross-Project Skill Bus` ๋Š” registry ๋ฅผ **์˜จ๋ณด๋”ฉ Step 1-c** ์—์„œ
304
+ # ์ฝ๋Š”๋ฐ, ยงActive Onboarding ์˜ Guards ๊ฐ€ ยซexplicit task-entry โ†’ skip onboarding menuยป ๋‹ค.
305
+ # ์ฒซ ๋ฐœํ™”๊ฐ€ task ๋ฉด ๋ฉ”๋‰ด์™€ ํ•จ๊ป˜ **๋ฐ์ดํ„ฐ ๋กœ๋“œ๊นŒ์ง€ ๊ฐ™์ด ๊บผ์ง„๋‹ค.** ๋ฉ”๋‰ด๋Š” UI ๊ณ  registry ๋Š”
306
+ # ๋ฐ์ดํ„ฐ์ธ๋ฐ ํ•œ ๋‹จ๊ณ„์— ๋ฌถ์—ฌ ์žˆ์–ด์„œ UI ๋ฅผ ๋„๋ฉด ๋ฐ์ดํ„ฐ๋„ ๊บผ์ง„๋‹ค.
307
+ # โ†’ Mode D companion-store ๋กœ๋“œ๋Š” ์ด ๋ณ‘์„ ์ด๋ฏธ ํ•œ ๋ฒˆ ๊ณ ์ณค๋‹ค(ยซ์ด๊ฑด ๋ฉ”๋‰ด๊ฐ€ ์•„๋‹ˆ๋ผ ๋ฐ์ดํ„ฐ
308
+ # ๋กœ๋“œ๋‹คยป carve-out + ์ด ์Šคํฌ๋ฆฝํŠธ). **registry ์—” ๊ทธ ์ฒ˜๋ฐฉ์ด ์•ˆ ๋ถ™์—ˆ๋‹ค** = ๋ฐ˜์ชฝ-ํ”ฝ์Šค
309
+ # ์ „ํŒŒ๊ฒฝ๊ณ„.
310
+ # ์‹ค์ธก(2026-08-18): `tracks/gstack` ์ด ๋งคํ•‘๋ผ ์žˆ๊ณ  SKILL.md ๊ฐ€ 55๊ฐœ์ธ๋ฐ, ์šด์˜์ž๊ฐ€ ์ด๋ฆ„์„
311
+ # ๋Œˆ ๋•Œ๊นŒ์ง€ ์„ธ์…˜์ด ๊ทธ ์กด์žฌ๋ฅผ ๋ชฐ๋ž๋‹ค. CATALOGยทCLAUDE.mdยทsim-conductor ์— ์ „๋ถ€ ๋“ฑ๋ก๋ผ ์žˆ์—ˆ๋‹ค.
312
+ #
313
+ # ๋น„์šฉ ๊ฒฝ๊ณ„: ์ด๋ฆ„๊ณผ ๊ฐœ์ˆ˜๋งŒ. ๋ชฉ๋ก ์ „๋Ÿ‰ ๋กœ๋“œ๋Š” ์•ˆ ํ•œ๋‹ค(ํ† ํฐ). ์‹ค๋ฌผ์ด ์—†๊ฑฐ๋‚˜ ์Šคํ‚ฌ์ด 0์ธ ํŠธ๋ž™์€
314
+ # ์•„์˜ˆ ์•ˆ ์ฐ๋Š”๋‹ค โ€” ๋งค ์„ธ์…˜ 13์ค„์ด ๋œจ๋ฉด ๊ทธ๊ฑด ๋ฐฐ๊ฒฝ ์†Œ์Œ์ด๊ณ  ์•„๋ฌด๋„ ์•ˆ ์ฝ๋Š”๋‹ค.
315
+ # ๐ŸŸฅ 0 ์„ ยซ์—†๋‹คยป ๋กœ ๋ Œ๋”ํ•˜์ง€ ์•Š๋Š”๋‹ค: ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ๋ฅผ ๋ชป ์ฐพ์œผ๋ฉด ๊ทธ๋ ‡๊ฒŒ ์ ๊ณ , ๊ฐœ์ˆ˜๋ฅผ 0 ์œผ๋กœ
316
+ # ์ ์ง€ ์•Š๋Š”๋‹ค(๋ถ€์žฌ โ‰  0).
317
+ _PROJ_ROOT="${FH_PROJECTS_ROOT:-$(dirname "$FH")}"
318
+ if [ -d "$FH/tracks" ]; then
319
+ _reg=""; _mapped=0; _resolved=0
320
+ for _t in "$FH"/tracks/*/; do
321
+ _n=$(basename "$_t")
322
+ case "$_n" in _*) continue ;; esac
323
+ [ "$_n" = "*" ] && continue
324
+ _mapped=$((_mapped + 1))
325
+ _d="$_PROJ_ROOT/$_n"
326
+ [ -d "$_d" ] || continue
327
+ _resolved=$((_resolved + 1))
328
+ # ๋ฌด๊ฑฐ์šด ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์ณ๋‚ธ๋‹ค โ€” ๋น„์šฉ ์ฃผ์žฅ์ด ยซ๋‚ด ๋จธ์‹ ์˜ ๋‚ด ํ”„๋กœ์ ํŠธ ์ง‘ํ•ฉยป ์œ„์— ์„œ ์žˆ์œผ๋ฉด
329
+ # ์•ˆ ๋œ๋‹ค(cross-family ์ง€์ ). node_modules/.venv/.git ์ด depth 3 ์•ˆ์— ์žˆ์œผ๋ฉด ์„ ํ˜•์œผ๋กœ ๋Š”๋‹ค.
330
+ _sk=$(find "$_d" -maxdepth 3 \( -name node_modules -o -name .git -o -name .venv \
331
+ -o -name venv -o -name target -o -name dist \) -prune -o \
332
+ -name SKILL.md -print 2>/dev/null | wc -l | tr -d ' ')
333
+ [ "${_sk:-0}" -gt 0 ] || continue
334
+ _reg="${_reg} โ–ธ ${_n} โ€” SKILL.md ${_sk}๊ฐœ (${_d})
335
+ "
336
+ done
337
+ # ๐ŸŸฅ **๋ถ€์žฌ โ‰  0.** ํŒ๋ณ„์ž๋Š” ยซ๋ฃจํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ๊ฐ€ ์žˆ๋‚˜ยป๊ฐ€ ์•„๋‹ˆ๋‹ค โ€” `dirname "$FH"` ๋Š” ๊ฑฐ์˜ ํ•ญ์ƒ
338
+ # ์กด์žฌํ•ด์„œ ๊ทธ ๋ถ„๊ธฐ๋Š” ๋ฐœํ™” ๋ถˆ๊ฐ€ํ•œ ์žฅ์‹์ด์—ˆ๋‹ค(์ดˆํŒ ๊ฒฐํ•จ, ๊ฐ™์€ ์ปค๋ฐ‹์—์„œ ์ž๋ ฅ ์ ๋ฐœ).
339
+ # ์‹ค์งˆ ํŒ๋ณ„์ž๋Š” **๋งคํ•‘๋œ ํŠธ๋ž™์ด ์žˆ๋Š”๋ฐ ํ•˜๋‚˜๋„ ์‹ค๋ฌผ๋กœ ํ•ด์†Œ๋˜์ง€ ์•Š์•˜๋‹ค** ์ด๊ณ , ๊ทธ๋•Œ๋งŒ
340
+ # ใ€Œ๋ชป ์Ÿ€๋‹คใ€๋ฅผ ๋งํ•œ๋‹ค. ์†Œ๋น„์ž์˜ ๋ ˆํฌ๊ฐ€ ๋‹ค๋ฅธ ๊ฒฝ๋กœ์— ์žˆ์œผ๋ฉด ์ •ํ™•ํžˆ ์ด ์ƒํƒœ๊ฐ€ ๋œ๋‹ค.
341
+ # ๐ŸŸฅ **all-or-nothing ์ด๋ฉด ์•ˆ ๋œ๋‹ค** (cross-family ์ ๋ฐœ, ์ดˆํŒ ๊ฒฐํ•จ): ยซ์ „๋ถ€ ๋ชป ์ฐพ์•˜์„ ๋•Œ๋งŒยป
342
+ # ๋งํ•˜๋ฉด 13๊ฐœ ์ค‘ 1๊ฐœ๋งŒ ํ•ด์†Œ๋˜๊ณ  12๊ฐœ๊ฐ€ ์—†์„ ๋•Œ ๊ทธ 12๊ฐœ๊ฐ€ **์™„์ „ํžˆ ์นจ๋ฌต**ํ•œ๋‹ค โ€” ์ด ๋ธ”๋ก์ด
343
+ # ์—†์• ๋ ค๋Š” ยซ๋ถ€์žฌ๋ฅผ 0์œผ๋กœ ๋ Œ๋”ยป ๋ฅผ ๋ธ”๋ก ์ž์‹ ์ด ์žฌํ˜„ํ•œ๋‹ค. ๋ฏธํ•ด์†Œ๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด ๋งํ•œ๋‹ค.
344
+ _unres=$((_mapped - _resolved))
345
+ if [ "$_unres" -gt 0 ]; then
346
+ _reg="${_reg} โš ๏ธ ๋งคํ•‘๋œ ํŠธ๋ž™ ${_mapped}๊ฐœ ์ค‘ ${_unres}๊ฐœ๋Š” ยซ${_PROJ_ROOT}ยป ๋ฐ‘์—์„œ ์‹ค๋ฌผ์„ ๋ชป ์ฐพ์•˜๋‹ค โ€” ๊ทธ ${_unres}๊ฐœ๋Š” ยซ0ยป ์ด ์•„๋‹ˆ๋ผ **๋ฏธ์ธก์ •**์ด๋‹ค (๊ฒฝ๋กœ๊ฐ€ ๋‹ค๋ฅด๋ฉด FH_PROJECTS_ROOT).
347
+ "
348
+ fi
349
+ if [ -n "$_reg" ]; then
350
+ if [ "$_resolved" -gt 0 ]; then
351
+ echo "๐Ÿงฉ [cross-project skill bus] ๋งคํ•‘๋œ ํ”„๋กœ์ ํŠธ์— SKILL.md ๊ฐ€ ์žˆ๋‹ค โ€” ํŒŒ์ผ ๊ฐœ์ˆ˜๋งŒ ์„ผ ๊ฒƒ์ด์ง€ ยซ์ง€๊ธˆ ์„ธ์…˜์—์„œ ํ˜ธ์ถœ ๊ฐ€๋Šฅํ•˜๋‹คยป ๋Š” ํ™•์ธ์ด ์•„๋‹ˆ๋‹ค."
352
+ printf "%s" "$_reg"
353
+ # ๋ชฉ๋ก์ด ์‹ค์ œ๋กœ ์žˆ์„ ๋•Œ๋งŒ ๋‚ธ๋‹ค. ๊ฐ•๋“ฑ(๋ชป ์ฐพ์Œ) ์ผ€์ด์Šค์— ์ด ์•ˆ๋‚ด๊ฐ€ ๋ถ™์œผ๋ฉด ยซ์ฝ์„ ๊ฒƒ์ด ์žˆ๋‹คยป ๋Š”
354
+ # ์ธ์ƒ์„ ์ฃผ๋Š”๋ฐ ๋ชฉ๋ก์€ ๋น„์–ด ์žˆ๋‹ค โ€” ์—†๋Š” ๊ฒƒ์„ ์žˆ๋‹ค๊ณ  ๋งํ•˜๋Š” ์ชฝ์ด๋‹ค.
355
+ echo " โš ๏ธ ์ด ์ค„์€ ยซ์žˆ๋‹คยป ๋งŒ ๋งํ•œ๋‹ค. ์“ฐ๊ธฐ ์ „์— ๊ทธ์ชฝ SKILL.md ๋ฅผ ์ฝ์–ด๋ผ โ€” ํ•„๋“œ ํ•˜๋„ค์Šค ์šฉ์–ด๋ฅผ"
356
+ echo " ์ผ๋ฐ˜ ๊ฐœ๋…์œผ๋กœ ์ •๊ทœํ™”ํ•˜๋Š” ๊ฒƒ์ด ์ด ๋ ˆํฌ์˜ ์ƒ์Šต ์‹คํŒจ๋‹ค."
357
+ else
358
+ echo "๐Ÿงฉ [cross-project skill bus] ๋งคํ•‘์€ ์žˆ๋Š”๋ฐ ์‹ค๋ฌผ์„ ๋ชป ์ฐพ์•˜๋‹ค โ€” ์•„๋ž˜๋Š” **๋ฏธ์ธก์ •**์ด๋‹ค."
359
+ printf "%s" "$_reg"
360
+ fi
361
+ fi
362
+ fi
363
+
293
364
  # Non-Mode-D / no companion store โ†’ silent no-op (this is the majority path for public users).
294
365
  [ -d "$BE/.git" ] || exit 0
295
366
 
@@ -703,6 +703,35 @@ else
703
703
  fail=1
704
704
  fi
705
705
 
706
+ # test_satellite_publish_gate_lanes โ€” ์œ„์„ฑ ๊ณต๊ฐœํ‘œ๋ฉด ๊ฒŒ์ดํŠธ(2026-08-18, ์›์ • 2์ฐจ).
707
+ # ๐ŸŸฅ ์ด ๋ฐฐ์„ ์ด ์—†์–ด์„œ CI ๊ฐ€ `lane-runner: lane suite(s) with no runner and no declaration` ๋กœ
708
+ # ๋นจ๊ฐฐ๋‹ค. ์Šค์œ„ํŠธ๋ฅผ ์‹ ์„คํ•˜๊ณ  ์•„๋ฌด ๋ฐ์„œ๋„ ์•ˆ ๋Œ๋ฆฐ ๊ฒƒ โ€” ๊ฒ€์‚ฌ๊ธฐ์˜ ํ‘œํ˜„๋Œ€๋กœ
709
+ # *"A suite nothing executes is prose."* ๊ทธ ๊ฒ€์‚ฌ๊ธฐ๊ฐ€ ๋‚ด ์‹ ์„ค ๋ ˆ์ธ์„ ์žก์•˜๋‹ค.
710
+ if [ ! -f scripts/test_satellite_publish_gate_lanes.sh ]; then
711
+ echo "FAIL test_satellite_publish_gate_lanes.sh: missing โ€” publish gate has no anchor"
712
+ fail=1
713
+ elif _out=$(bash scripts/test_satellite_publish_gate_lanes.sh < /dev/null 2>&1); then
714
+ echo "PASS test_satellite_publish_gate_lanes.sh ($(printf '%s\n' "$_out" | grep -oE '[0-9]+ passed, [0-9]+ failed' | tail -1))"
715
+ else
716
+ echo "FAIL test_satellite_publish_gate_lanes.sh: publish gate lanes failed"
717
+ _show_failure "$_out"
718
+ fail=1
719
+ fi
720
+
721
+ # test_evidence_root_psa_lanes โ€” ์›ŒํฌํŠธ๋ฆฌ์—์„œ ๊ธฐ๋ฐ€์„ฑ ์˜ค๋ฒ„๋ผ์ด๋“œ๋ฅผ ์ฐพ๋Š”๊ฐ€ (R4, 2026-08-18).
722
+ # ๐ŸŸฅ `EVIDENCE_ROOT` ์—๋Š” ๋ ˆ์ธ์ด **ํ•˜๋‚˜๋„ ์—†์—ˆ๋‹ค** โ€” ๊ทธ๋ž˜์„œ `tracks/` ๋งŒ ์˜ฎ๊ธฐ๊ณ  gitignored
723
+ # ํŒจํ„ด ํŒŒ์ผ์€ ์•ˆ ์˜ฎ๊ธด ๋ฐ˜์ชฝ-ํ”ฝ์Šค๊ฐ€ ๊ทธ๋Œ€๋กœ ์ถœํ•˜๋๋‹ค. ๋˜๋Œ๋ฆผ ํ”„๋กœ๋ธŒ๋กœ E1 ๋งŒ ์ ์ƒ‰ ํ™•์ธ.
724
+ if [ ! -f scripts/test_evidence_root_psa_lanes.sh ]; then
725
+ echo "FAIL test_evidence_root_psa_lanes.sh: missing โ€” EVIDENCE_ROOT ๊ธฐ๋ฐ€์„ฑ ๊ฒฝ๋กœ์— ์•ต์ปค ์—†์Œ"
726
+ fail=1
727
+ elif _out=$(bash scripts/test_evidence_root_psa_lanes.sh < /dev/null 2>&1); then
728
+ echo "PASS test_evidence_root_psa_lanes.sh ($(printf '%s\n' "$_out" | grep -oE '[0-9]+ passed, [0-9]+ failed' | tail -1))"
729
+ else
730
+ echo "FAIL test_evidence_root_psa_lanes.sh: evidence-root psa lanes failed"
731
+ _show_failure "$_out"
732
+ fail=1
733
+ fi
734
+
706
735
  # cluster_capability_scan โ€” wired 2026-08-16 (์ •์ฒด์„ฑ โ‘ -(a) cluster-wizard).
707
736
  # ์ข…๋‹จ ํŒ์ •์ค„์ด `โ€ฆ ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ํ†ต๊ณผ/์‹คํŒจ: N PASS / M FAIL` ์ด๋ผ ์œ„ `_subj` ๋ฃจํ”„์˜
708
737
  # ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ๊ฒŒ์ดํŠธ๋ฅผ **์ง„์งœ ํŒ์ •์ค„๋กœ** ๋งŒ์กฑํ•œ๋‹ค โ€” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์ œ๋ชฉ์ด ์•„๋‹ˆ๋‹ค.