oh-my-customcode 1.1.67 → 1.1.69

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/dist/cli/index.js CHANGED
@@ -217,7 +217,7 @@ var init_package = __esm(() => {
217
217
  workspaces: [
218
218
  "packages/*"
219
219
  ],
220
- version: "1.1.67",
220
+ version: "1.1.69",
221
221
  description: "Batteries-included agent harness for Claude Code",
222
222
  type: "module",
223
223
  bin: {
package/dist/index.js CHANGED
@@ -2326,7 +2326,7 @@ var package_default = {
2326
2326
  workspaces: [
2327
2327
  "packages/*"
2328
2328
  ],
2329
- version: "1.1.67",
2329
+ version: "1.1.69",
2330
2330
  description: "Batteries-included agent harness for Claude Code",
2331
2331
  type: "module",
2332
2332
  bin: {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "workspaces": [
4
4
  "packages/*"
5
5
  ],
6
- "version": "1.1.67",
6
+ "version": "1.1.69",
7
7
  "description": "Batteries-included agent harness for Claude Code",
8
8
  "type": "module",
9
9
  "bin": {
@@ -298,6 +298,10 @@ split("\n")
298
298
  # 미announce Read — 은 새로 발화한다(의도된 동작, v1.1.62 적대적 리뷰 재현 C1/C2).
299
299
  | ($an_tool + (if $an_spawn > $an_tool_agent then $an_spawn - $an_tool_agent else 0 end)) as $announce
300
300
  | ([ $blocks[] | select((.type? == "tool_use") and ((.name? // "") != "Skill")) ] | length) as $ntools
301
+ # 미접두 도구 이름 (#1687): $ntools와 동일한 필터(non-Skill tool_use)로 순서를 보존한 이름
302
+ # 목록을 뽑는다. $r008(누락 건수)이 어떤 도구인지 shell에서 드러내기 위한 부가 필드 —
303
+ # 판정식($r008 산출) 자체는 건드리지 않는다.
304
+ | ([ $blocks[] | select((.type? == "tool_use") and ((.name? // "") != "Skill")) | (.name? // "") ]) as $tool_names_list
301
305
  # 전체 tool_use(Skill 포함)가 0건인 턴은 forward 판정을 무조건 0으로 고정한다(#1625
302
306
  # 찐빠 #3, 이슈 제안 그대로). $ntools(Skill 제외) 기반 산식은 정상 입력에서는 이미
303
307
  # 0을 내지만, 명시 가드로 불변식을 코드에 못박아 향후 산식 변경이 이 보장을 조용히
@@ -322,7 +326,7 @@ split("\n")
322
326
  | ([ $lines[] | select(test("^\\[[^\\]]+\\]\\[[^\\]]+\\] ?(→|->|—>) ?Tool:")) ] | length) as $an_anchored
323
327
  # $nall_tools는 위 forward r008 가드에서 이미 바인딩됨 — 재바인딩하지 않고 재사용한다.
324
328
  | (if $nall_tools == 0 and $an_anchored > 0 then $an_anchored else 0 end) as $r008rev
325
- | [$tuuid, ($r007 | tostring), ($r008 | tostring), ($r008rev | tostring)] | @tsv
329
+ | [$tuuid, ($r007 | tostring), ($r008 | tostring), ($r008rev | tostring), ($tool_names_list | join(","))] | @tsv
326
330
  )
327
331
  end
328
332
  end
@@ -346,6 +350,8 @@ turn_uuid=$(printf '%s' "$result" | cut -f1)
346
350
  r007_violations=$(printf '%s' "$result" | cut -f2)
347
351
  r008_violations=$(printf '%s' "$result" | cut -f3)
348
352
  r008_reverse=$(printf '%s' "$result" | cut -f4)
353
+ # 미접두 도구 이름 목록 (#1687) — $ntools와 동일 필터의 순서 보존 목록, "," join.
354
+ tool_names=$(printf '%s' "$result" | cut -f5)
349
355
 
350
356
  : "${r007_violations:=0}"
351
357
  : "${r008_violations:=0}"
@@ -397,6 +403,26 @@ if [ "$r008_violations" -gt 0 ]; then
397
403
  violation_desc="R008 도구 식별 접두사 누락 ${r008_violations}건"
398
404
  instruction="모든 도구 호출에 [agent][model] → Tool: 접두사를 포함하십시오."
399
405
  fi
406
+ # 미접두 도구 이름 귀속 (#1687): announce는 턴 단위로 매칭되므로, $tool_names(순서 보존,
407
+ # non-Skill tool_use)의 마지막 r008_violations개를 부족분으로 귀속한다. 카운트 문구
408
+ # "R008 도구 식별 접두사 누락 N건"은 위에서 이미 확정되어 바이트 동일 유지 — 이 접미사는
409
+ # 항상 그 뒤에 이어붙인다(scripts/count-r007-r008.sh의 grep -oE 앵커와 무관).
410
+ if [ -n "$tool_names" ]; then
411
+ r008_missing_tools=$(printf '%s' "$tool_names" | awk -F',' -v n="$r008_violations" '{
412
+ total = NF
413
+ start = total - n + 1
414
+ if (start < 1) start = 1
415
+ out = ""
416
+ for (i = start; i <= total; i++) {
417
+ if (out != "") out = out ", "
418
+ out = out $i
419
+ }
420
+ print out
421
+ }')
422
+ if [ -n "$r008_missing_tools" ]; then
423
+ violation_desc="${violation_desc} (미접두 도구: ${r008_missing_tools})"
424
+ fi
425
+ fi
400
426
  fi
401
427
 
402
428
  if [ -n "$violation_desc" ]; then
@@ -597,13 +597,34 @@ raw_command=$(printf '%s' "$input" | jq -r '.tool_input.command // ""')
597
597
  # Distinguish "the same file edited 3 times with DIFFERENT content" (a normal
598
598
  # incremental-edit workflow — the #1641 false positive) from "the same edit
599
599
  # repeated 3 times" (a genuine stuck loop). Only the latter should hard-block.
600
- # Alphanumerics-only + length cap: deterministic, platform-independent (no
601
- # md5sum, absent on macOS) and safe to embed in a grep pattern.
600
+ # #1649: the original alphanumerics-only + 120-char-cut key had two defects —
601
+ # (M-1) edits differing only in punctuation/whitespace (e.g. re-aligning a
602
+ # markdown table) collapsed to the SAME key and were falsely blocked as
603
+ # "identical", and (M-2) Write calls sharing a long identical prefix (e.g.
604
+ # frontmatter) collided after the 120-char cut even when the body differed.
605
+ # New spec: collapse whitespace runs to one space (still deterministic,
606
+ # platform-independent, no md5sum) but PRESERVE punctuation, then key on
607
+ # "<len>#<full>" when the normalized string is <=120 chars (short strings fit
608
+ # whole, so no sum is needed), else "<len>#<codepoint sum>#<first 80 chars>
609
+ # #<last 40 chars>" — length + codepoint sum + head/tail. Adversarial review
610
+ # found the length+head+tail-only key (no sum) still collides when a
611
+ # same-length middle-only substitution falls entirely outside both the head
612
+ # and tail windows (e.g. this repo's own count/version-bump Writes: 80 "A"s +
613
+ # "version-115-count" + 40 "Z"s vs "...-116-..." vs "...-117-..." — all 137
614
+ # chars, identical head/tail). The codepoint sum changes whenever the changed
615
+ # substring's characters change, so a substitution is now caught by the sum;
616
+ # a same-sum transposition of the middle segment can still collide — an
617
+ # accepted residual risk, not fully eliminated.
602
618
  edit_hash=""
603
619
  if [ "$tool_name" = "Edit" ] || [ "$tool_name" = "Write" ]; then
604
620
  edit_hash=$(printf '%s' "$input" \
605
621
  | jq -r '(.tool_input.old_string // .tool_input.content // .tool_input.new_string // "")
606
- | gsub("[^A-Za-z0-9]"; "") | .[0:120]')
622
+ | gsub("[[:space:]]+"; " ") | ltrimstr(" ") | rtrimstr(" ")
623
+ | (length as $l
624
+ | if $l <= 120 then "\($l)#\(.)"
625
+ else ((explode | add // 0) as $sum
626
+ | "\($l)#\($sum)#\(.[0:80])#\(.[-40:])")
627
+ end)')
607
628
  fi
608
629
 
609
630
  # History entries are written by jq, so their "path" values are JSON-ENCODED.
@@ -615,6 +636,15 @@ fi
615
636
  target_key_json=$(jq -n --arg v "$target_key" '$v')
616
637
  path_match="\"path\":${target_key_json}"
617
638
 
639
+ # #1649 follow-up: edit_hash now preserves punctuation (see the edit_hash
640
+ # comment above), so it can contain quotes/backslashes just like a Bash
641
+ # command can. It is written to history the same JSON-encoded way "path" is
642
+ # (--arg ehash "$edit_hash" -> jq serializes it), so Check 1 / Check 3 below
643
+ # must match it with the SAME JSON-encoded literal, not the raw string — same
644
+ # fix as path_match above, applied to edit_hash.
645
+ edit_hash_json=$(jq -n --arg v "$edit_hash" '$v')
646
+ edit_hash_match="\"edit_hash\":${edit_hash_json}"
647
+
618
648
  is_readonly="false"
619
649
  if [ "$tool_name" = "Bash" ]; then
620
650
  is_readonly=$(is_readonly_bash_command "$raw_command")
@@ -761,7 +791,7 @@ if [ -f "$HISTORY_FILE" ]; then
761
791
  if [ "$is_readonly" != "true" ] && [ -n "$file_path" ]; then
762
792
  consecutive_file=$(printf '%s\n' "$last_n" \
763
793
  | grep -F -e "$path_match" \
764
- | grep -cF -e "\"edit_hash\":\"${edit_hash}\"" 2>/dev/null || true)
794
+ | grep -cF -e "$edit_hash_match" 2>/dev/null || true)
765
795
  [ -n "$consecutive_file" ] || consecutive_file=0
766
796
  if [ "$consecutive_file" -ge "$HARD_BLOCK_THRESHOLD" ]; then
767
797
  hard_block=true
@@ -791,7 +821,7 @@ if [ -f "$HISTORY_FILE" ]; then
791
821
  consecutive_tool_target=$(printf '%s\n' "$last_n" \
792
822
  | grep -F -e "\"tool\":\"${tool_name}\"" \
793
823
  | grep -F -e "$path_match" \
794
- | grep -cF -e "\"edit_hash\":\"${edit_hash}\"" 2>/dev/null || true)
824
+ | grep -cF -e "$edit_hash_match" 2>/dev/null || true)
795
825
  [ -n "$consecutive_tool_target" ] || consecutive_tool_target=0
796
826
  if [ "$consecutive_tool_target" -ge "$HARD_BLOCK_THRESHOLD" ]; then
797
827
  hard_block=true
@@ -356,6 +356,17 @@ git branch --list
356
356
 
357
357
  Origin: #1646 (v1.1.58 세션 — 커밋 위임서 `12e74a76` vs 실제 `e101a0b4`, 정리 위임서 '로컬 브랜치 2개 존재' vs 실제 부재; 원인은 `gh pr merge --delete-branch`가 체크아웃된 브랜치를 base로 전환·pull·삭제하는 부수효과였음 — 도구 부수효과를 모른 채 상태를 예측한 사례).
358
358
 
359
+ #### 출처 인용과 인접 문구 점검도 같은 규율 (Origin: #1688 — Iteration 3 #1, Iteration 4 #1·#2)
360
+
361
+ 위임서에 **Origin 이슈·CHANGELOG·메모리에서 가져온 사실**을 적을 때는 그 출처의 해당 문장을 `gh issue view <N> --json body` 또는 원문 파일에서 **인용 형태로 동봉합니다**. 기억이나 메모리 요약을 전제로 옮겨 적으면 서브에이전트가 그것을 사실로 기재하고, 위키까지 전파된 뒤에야 적대적 리뷰가 잡습니다 — v1.1.66에서 CHANGELOG에 없는 원인("부모가 mid-turn일 때")을, v1.1.67에서 메모리의 세션 번호를 릴리즈 번호로 잘못 옮긴 것("v1.1.61" — 실제 #1660은 v1.1.63 반복)이 각각 High로 적발되었습니다. R017 「메모리 TODO를 위임 전제로 쓸 때」의 위임서 각도이며, 위 「저장소 상태 기재도 같은 규율」이 SHA에 대해 요구하는 것을 **출처 문장**에 대해 요구합니다.
362
+
363
+ 함께, 룰·스킬에 **조항을 삽입하는 위임서**는 "같은 파일에서 같은 주제를 다루는 기존 문장을 `grep`해 모순·stale 참조를 함께 갱신"을 완료 조건에 넣습니다. v1.1.67에서 새 R010 행이 바로 위 CI/CD 행과 `gh run rerun` 소유를 두고 충돌하고, fsd 새 섹션이 도입부의 "Equivalent to running"과 충돌하며, homework 소스 재넘버링 후 Limitations의 "source (1)" 참조가 stale로 남은 3건이 같은 리뷰에서 적발되었습니다 — R020 Config-Schema-Before-Edit(상호의존 필드 열거)의 문서 편집 각도입니다.
364
+
365
+ | Anti-pattern | Required |
366
+ |--------------|----------|
367
+ | 메모리 요약·기억으로 Origin 사실을 위임서에 확정형 기재 | 출처 문장을 `gh issue view`/원문에서 인용해 동봉하고 "원문과 다르면 원문 우선"을 명시 |
368
+ | 삽입 위치와 문안만 지정한 조항 삽입 위임 | 같은 주제의 기존 문장 grep + 모순·stale 참조 갱신을 완료 조건에 포함 |
369
+
359
370
  #### 참인 전제 ≠ 참인 함의 — 브랜치 전환 위임 (Origin: #1595 #2)
360
371
 
361
372
  uncommitted 변경이 있는 상태의 브랜치 전환을 위임할 때, 위임서에 **전환의 결과를 확정형으로 예측해 적지 않는다**. "대상 브랜치에 그 파일이 없다"는 **사실**에서 "전환해도 안전하다"는 **함의**는 도출되지 않는다 — 파일이 **없기 때문에** checkout이 그 파일을 삭제해야 하고, modified 상태면 거부된다.
@@ -245,6 +245,15 @@ CC 버전 노트를 룰에 반영하기 **전**, `npm view @anthropic-ai/claude-
245
245
 
246
246
  Origin: #1584 #1 (v1.1.46 세션) — 이슈 생성(8/11~14)과 작업(8/15) 사이 5일 간극 동안 v2.1.233이 v2.1.232 Bash 권한 변경 2건을 롤백했으나 이를 모른 채 배치해 mgr-sauron이 **FAIL로 차단**(당시 저장소 전역 `2.1.233` 언급 0건). Cross-ref: 위 Pre-Release Target Version Ground-Truth Gate(동일 "스냅샷 ≠ ground-truth" 원리의 버전 각도), R020(Diagnostic Hypothesis Verification), R016(버전노트 보존정책 — *어느* 노트를 남길지는 R016, *반영 전 실측*은 이 게이트).
247
247
 
248
+ ### 묶음 버전 노트 위임서 — 문장별 (NNN) 태그와 합쇼체 예시 (Origin: #1688 — Iteration 3 #3·#4)
249
+
250
+ 여러 릴리즈의 항목을 한 노트(`> **v2.1.268/271+**:` 형식)로 묶어 위임할 때, 위임서는 **각 문장에 릴리즈 번호 태그 "(NNN)"를 의무화**하고 헤더는 태그의 합집합으로 도출합니다. 헤더 묶음만 주고 문장 태그를 생략하면 서브에이전트가 헤더 위치로 귀속해 오귀속이 생깁니다 — v1.1.66에서 `/tui`(273을 274 위치에), usage-limit 일시정지(271을 269 헤더 아래), 워크트리 거부(274를 "같은 릴리즈"로) 3건이 같은 리뷰에서 적발되었습니다. 함께 위임서에는 **합쇼체 예시 1문장**을 동봉하고, 인접 기존 노트가 반말(-다)이면 "인접 문체를 따르지 말 것"을 명시합니다 — 같은 릴리즈에서 R003 신규 노트 4문장이 인접 노트의 반말을 그대로 따라 작성되었습니다. 각 항목에는 CHANGELOG 원문 1줄을 인용해 동봉합니다(R010 「출처 인용과 인접 문구 점검도 같은 규율」).
251
+
252
+ | Anti-pattern | Required |
253
+ |--------------|----------|
254
+ | 헤더에 릴리즈 번호를 묶고 문장에는 태그 없이 위임 | 문장마다 "(NNN)" 태그, 헤더는 태그 합집합, 항목별 CHANGELOG 원문 1줄 동봉 |
255
+ | 영어 위임서에 "Korean 합쇼체"만 적고 예시 없음 | 합쇼체 예시 1문장 동봉 + 인접 반말 노트 추종 금지 명시 |
256
+
248
257
  ## Post-Gate Scope-Expansion Re-Run (Origin: #1433 #2)
249
258
 
250
259
  R017 게이트(mgr-sauron) 통과 선언 후 신규 결함 발견 등으로 스코프가 확장되면(추가 파일 편집), 커밋 전 게이트를 **최종 상태에서 재실행**한다. 게이트 통과 시점 이후의 변경은 형식적으로 미검증이므로, 확장분 미검증 커밋은 R017이 최종 산출물을 커버하지 못하게 만든다.
@@ -93,7 +93,7 @@ Trade-offs: RS256 is ~10x slower than HS256 but enables asymmetric key managemen
93
93
 
94
94
  기본 활성화 스타일: `korean-engineer` (`.claude/output-styles/korean-engineer.md`).
95
95
 
96
- > **v2.1.238+**: custom/project/plugin output style이 **세션 도중 default voice로 드리프트**하던 결함이 수정됐다. 이 저장소는 `korean-engineer` 커스텀 output style을 상시 활성화하므로 직접 해당한다 — 세션이 길어지면 격식체(R000 합쇼체)가 조용히 기본 voice로 돌아갈 수 있었다는 뜻이다. **회고적 함의**: 구버전에서는 세션 길이에 비례해 스타일 드리프트 위험이 있었으므로, 과거 세션에서 관측된 R000 합쇼체 이탈(feedback_honorific_register_drift 등)을 전부 모델의 규칙 위반으로만 귀속할 수 없다 — 일부 구간은 플랫폼 드리프트가 원인이었을 수 있다. **다만 이것을 면책으로 쓰지 말 것**: R000 준수 의무는 그대로이며, 이는 과거 관측의 재해석 근거일 뿐 향후 이탈을 정당화하지 않는다.
96
+ > **v2.1.238+**: custom/project/plugin output style이 **세션 도중 default voice로 드리프트**하던 결함이 수정되었습니다. 이 저장소는 `korean-engineer` 커스텀 output style을 상시 활성화하므로 직접 해당합니다 — 세션이 길어지면 격식체(R000 합쇼체)가 조용히 기본 voice로 돌아갈 수 있었다는 뜻입니다. **회고적 함의**: 구버전에서는 세션 길이에 비례해 스타일 드리프트 위험이 있었으므로, 과거 세션에서 관측된 R000 합쇼체 이탈(feedback_honorific_register_drift 등)을 전부 모델의 규칙 위반으로만 귀속할 수 없습니다 — 일부 구간은 플랫폼 드리프트가 원인이었을 수 있습니다. **다만 이것을 면책으로 쓰지 않습니다**: R000 준수 의무는 그대로이며, 이는 과거 관측의 재해석 근거일 뿐 향후 이탈을 정당화하지 않습니다.
97
97
 
98
98
  > **v2.1.269+**: `/output-style [name]`이 output style을 목록 조회·전환할 수 있게 되었으며, Remote Control과 cloud/headless 세션에서도 동작합니다. 이 저장소의 `korean-engineer` 커스텀 스타일을 세션 도중 `/output-style korean-engineer`로 재선택·재확인할 수 있게 되어, 위 v2.1.238-era 드리프트에 대한 직접 구제 수단이 생겼습니다 — `-p`/cloud 실행에서는 스타일이 실제로 활성 상태인지를 기본값에 의존하지 않고 보장하는 방법이기도 합니다. 참고로 (271) `--resume`/`/teleport` 관련 결함 수정은 R011 소관이므로 여기서 중복 서술하지 않습니다.
99
99
 
@@ -127,6 +127,12 @@ Origin: #1574 (v1.1.44 세션 — 병렬 위임 3건 모두 `bun run lint`를
127
127
 
128
128
  Origin: #1563 찐빠 #2 — R007/R008 advisor 발화 검증에 단일 "0바이트 아님" 프록시를 제시했으나, advisor는 준수 턴에서 침묵하는 것이 정상 동작이라 기준이 성립하지 않았다. Cross-reference: R020(Proxy Signal vs Canonical Ground-Truth — 프록시로 상태를 특성화하지 말 것), 아래 Detection Guard Delegation Standard(positive-match vs negative-context 구분의 가드 설계 각도).
129
129
 
130
+ **래퍼·재사용 스크립트 위임의 음성 픽스처 — 원본 전처리 필터 계열별 (Origin: #1688 — Iteration 4 #3)**: 기존 스크립트(훅·판정기)를 래핑하거나 그 판정을 재사용하는 스크립트를 위임할 때, 위임서는 **원본이 입력에서 제외하는 계열**(예: advisor의 `isSidechain` 레코드, `thinking` 블록, `agent_id` 세션 게이트)을 전부 열거하고 **계열별로 적용 또는 의도적 미적용을 판정해 사유를 기재**하도록 요구하며, **제외 계열마다 음성 픽스처**를 요구합니다. 양성/음성 짝이 있어도 제외 계열이 픽스처에 없으면 "1:1 재현" 주장은 검증되지 않은 것입니다 — v1.1.67에서 `scripts/count-r007-r008.sh`가 advisor의 사이드체인 필터를 누락해 사이드체인이 섞인 트랜스크립트에서 같은 턴을 이중 계상할 수 있었고, 픽스처가 전부 `isSidechain: false`라 적대적 리뷰 전까지 미탐지였습니다. 아래 Detection Guard Delegation Standard(positive/negative 문맥 구분)와 같은 계열입니다.
131
+
132
+ | Anti-pattern | Required |
133
+ |--------------|----------|
134
+ | 래퍼 스크립트 위임서에 경계 규칙만 지정하고 원본의 전처리 필터 미열거 | 원본 제외 계열 전수 열거 + 계열별 적용/미적용 판정과 사유 + 계열별 음성 픽스처 요구 |
135
+
130
136
  ## Detection Guard Delegation Standard (Origin: #1438 #3)
131
137
 
132
138
  Tier-1 shift-left 검출 가드(예: deprecated-pattern grep 가드)의 설계·수정을 서브에이전트에 위임할 때, 위임 프롬프트는 **positive-match(genuine defect mandate — `MUST`/`MANDATORY` 인접 문맥)와 negative-context(deprecation note — "no longer"/"deprecated"/"불필요"/"폐기됨" 설명 문구)를 구분**하도록 명시해야 한다. 이를 누락하면 올바르게 수정된 파일의 폐기-설명 문구까지 과잉매칭하여 자기모순 BLOCK을 유발한다.
@@ -48,6 +48,8 @@ The loop converges naturally when **both** conditions are met:
48
48
  1. The auto-dev-eligible issue set reaches 0
49
49
  2. All open PRs have been either merged or explicitly deferred
50
50
 
51
+ 수렴을 선언하기 전에(수렴 조건이 아니라 **선언 직전 게이트**로) 이 세션의 homework 아티팩트 수를 실측해 반복 수와 대조합니다. 불일치는 다음 반복을 돌리는 신호가 아니라 **누락분을 기록하라는 신호**이므로, 회상 기반(`[recall]` 표시)으로라도 기록한 뒤 수렴을 선언합니다. v1.1.65 반복은 아티팩트를 기록하지 않은 채 다음 반복으로 넘어갔고 Iteration 4 종료 후에야 누락이 발견되어 회상 기반으로 보완되었습니다(#1688 Iteration 2 #1).
52
+
51
53
  FSD processes **open PRs as part of each iteration**, not only issues. This includes dependabot PRs and any automatically created PRs. Issue eligibility follows `/pipeline auto-dev` label selection exactly:
52
54
 
53
55
  - **Included**: `verify-ready` (preferred), unlabeled auto-dev candidates
@@ -116,7 +118,7 @@ printf '%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "/tmp/.claude-fsd-$PPID"
116
118
  │ fix-then-merge (known CI failure pattern)
117
119
  │ defer+surface (design decision needed)
118
120
  └── Check convergence: eligible issues = 0 AND open PRs = 0 (merged or deferred)?
119
- ├── YES → [FSD Done] converged naturally → command rm -f /tmp/.claude-fsd-$PPID
121
+ ├── YES → record any missing homework artifact (recall-based) → [FSD Done] converged naturally → command rm -f /tmp/.claude-fsd-$PPID
120
122
  └── NO → cap reached or classifier block? → YES → [FSD Stop] → command rm -f /tmp/.claude-fsd-$PPID
121
123
  → NO → next iteration (re-write marker first)
122
124
  ```
@@ -129,7 +131,7 @@ FSD의 루프 드라이버는 **메인 대화(오케스트레이터) 자신**입
129
131
  |------------------------------|------|
130
132
  | 반복 시작 시 무인 마커 갱신(`/tmp/.claude-fsd-$PPID`) | 위 「무인 모드 마커」 |
131
133
  | `/pipeline auto-dev` 1회 → homework 아티팩트 1개 기록 → 열린 PR 처리 | 「Iteration Flow」 |
132
- | 반복 끝에 수렴 판정(적격 이슈 0 AND 열린 PR 0)을 실측으로 수행 | R020 |
134
+ | 반복 끝에 수렴 판정(적격 이슈 0 AND 열린 PR 0)을 실측으로 수행하고, 선언 직전 **반복 수 == homework 아티팩트 수**를 `ls .claude/outputs/sessions/{YYYY-MM-DD}/homework-*.md`로 대조 — 세션이 UTC 자정을 넘길 수 있으므로 세션이 걸친 **모든 날짜 디렉토리**를 포함합니다(예: `ls .claude/outputs/sessions/2026-09-1[78]/homework-*.md`) | R020, #1688 |
133
135
  | 종료 경로와 무관하게 마커 제거(`command rm -f`) | 「무인 모드 마커」 |
134
136
 
135
137
  `/goal`·`/loop`를 호출하는 경로는 여전히 유효하며, 세션이 무인(`claude -p`, 예약 실행)이라 자기 페이싱이 필요할 때 권장됩니다. 대화형 세션에서는 인라인 실행이 스킬 호출 오버헤드 없이 같은 계약을 만족합니다.
@@ -231,6 +231,7 @@ steps:
231
231
  포함되면 self-review로 대체하지 않고 mgr-sauron R017 검증을 **단일 목표 위임으로 필수
232
232
  실행**한다(Tier 2 lite의 R017 조항과 동일 원칙; Origin: v1.1.58 세션 — docs-only 티어였으나
233
233
  sauron이 R002/R010 모순 advisory 1건을 포착).
234
+ - Wiki resync + manifest reseed (R022) run AFTER the deep-verify substitute for this tier (self-review checklist, plus the mandatory mgr-sauron R017 delegation when `.claude/rules/**` is in scope) and any resulting corrections have landed — never in parallel with it; this is the implement step's #1688 EXCEPTION applied to Tier 1. Wiki pages summarize the rules, so a review-driven rule fix invalidates any wiki written earlier (v1.1.66: 3 pages reworked; v1.1.67 with review-first ordering: 0 rework — #1688 Iteration 3 #2).
234
235
  - Log: "[compression-mode] docs-only compression activated (scope={n}, all docs/yaml labels)"
235
236
  - ⚠ Analysis artifacts only. Every step's state-change side effect (milestone create/assign,
236
237
  label add/remove, issue assign/comment/close) still runs in full — see "Cross-tier —
@@ -257,6 +258,7 @@ steps:
257
258
  (template-sync + md5 multi-copy + counts + bun test), under a MANDATORY justification log:
258
259
  "[compression-mode] lite deep-verify — R017 spawn skipped (no structural surface); deterministic self-check only".
259
260
  (#1311, extends #1309 substitution principle.)
261
+ - Wiki resync/reseed only after deep-verify (adversarial review) findings are applied — same ordering rule as Tier 1; this overrides the implement-step CI-mimic wiki fix for rules/skills text changes (see the implement step's #1688 EXCEPTION) (#1688).
260
262
  - implement / verify-build / release / ci-check / post-release-followup: execute normally (no compression)
261
263
  - MANDATORY justification log (REQUIRED whenever a skill stage is replaced by integrated analysis):
262
264
  "[compression-mode] lite — skill 단계 통합 분석 대체. 정당화: scope={n}, 모든 이슈 저위험(라벨 {labels}), 구현 대상 이슈 본문 명시 {issue_refs}"
@@ -402,6 +404,7 @@ steps:
402
404
  If any fails:
403
405
  - For wiki-sync failures: delegate to wiki-curator to generate missing pages (`/omcustom:wiki ingest <path>`)
404
406
  (Regenerating the wiki source-hash manifest targets `wiki/.source-hashes.json` ALWAYS — NEVER `templates/manifest.json`. Command: `bash .github/scripts/lib/source-hash.sh generate wiki/.source-hashes.json`. Ref #1423.)
407
+ - EXCEPTION (#1688 ordering): when the change set is rules/skills TEXT only (no new or renamed entity), do NOT fix wiki drift here — record the drift and defer the wiki resync + `wiki/.source-hashes.json` reseed until AFTER deep-verify findings are applied, then re-run `verify-wiki-sync.sh` before release. Missing PAGES for newly created entities are still generated here (CI blocks on them).
405
408
  - For template-sync failures: delegate to mgr-updater to sync `.claude/` -> `templates/.claude/`
406
409
  - For validate-docs failures (count mismatch): delegate to mgr-updater to fix counts via EXHAUSTIVE grep across all docs — file-enumeration misses `.en`/`.ko` variants and secondary docs (#1521 — v1.1.32에서 validate-docs 누락으로 push 왕복 1회 발생)
407
410
  - After fixes, re-run the scripts until all pass
@@ -441,7 +444,7 @@ steps:
441
444
 
442
445
  - name: deep-verify
443
446
  skill: deep-verify
444
- description: "Multi-angle release quality verification — self-review checklist if docs-only; mgr-sauron R017 + core self-check if lite. MULTI-PHASE: 스킬을 그대로 spawn하지 말고 R020 「위임 경계를 Phase 개수로 설계」에 따라 단일 목표 위임으로 분할해 순차 발주한다 (#1595 #4). lite 분할 표준(#1652 #3-4): (1) mgr-sauron R017 구조 검증 단일 목표 위임 1건 + (2) 변경 성격별 적대적 리뷰 단일 목표 위임 1건 — 스크립트 변경이면 실행 재현 기반 adversarial-review, 룰/스킬/yaml 텍스트 변경이면 문구 정합·배선 리뷰. 근거: v1.1.59/60 두 반복 연속 적대적 리뷰가 신규 회귀(M-3/M-4, heredoc 위조)를 실행 재현으로 포착. 검증 위임 표준 문안: 오케스트레이터가 이미 실측한 항목(bun test·lint·typecheck·template-sync·wiki-sync·validate-docs·미러 md5)은 위임서에 재실행 금지 목록으로 열거하고 재실측 대상만 지정한다 — v1.1.61 세션에서 금지 목록 없는 sauron 위임이 bun test를 재실행하다 25턴 절단됐고, 금지 목록을 명시한 재위임은 16 tool_uses로 완주했다(R020 maxTurns 절단 누적 7건째)."
447
+ description: "Multi-angle release quality verification — self-review checklist if docs-only; mgr-sauron R017 + core self-check if lite. MULTI-PHASE: 스킬을 그대로 spawn하지 말고 R020 「위임 경계를 Phase 개수로 설계」에 따라 단일 목표 위임으로 분할해 순차 발주한다 (#1595 #4). lite 분할 표준(#1652 #3-4): (1) mgr-sauron R017 구조 검증 단일 목표 위임 1건 + (2) 변경 성격별 적대적 리뷰 단일 목표 위임 1건 — 스크립트 변경이면 실행 재현 기반 adversarial-review, 룰/스킬/yaml 텍스트 변경이면 문구 정합·배선 리뷰. 근거: v1.1.59/60 두 반복 연속 적대적 리뷰가 신규 회귀(M-3/M-4, heredoc 위조)를 실행 재현으로 포착. 검증 위임 표준 문안: 오케스트레이터가 이미 실측한 항목(bun test·lint·typecheck·template-sync·wiki-sync·validate-docs·미러 md5)은 위임서에 재실행 금지 목록으로 열거하고 재실측 대상만 지정한다 — v1.1.61 세션에서 금지 목록 없는 sauron 위임이 bun test를 재실행하다 25턴 절단됐고, 금지 목록을 명시한 재위임은 16 tool_uses로 완주했다(R020 maxTurns 절단 누적 7건째). Ordering: any wiki resync/manifest reseed for the changed rules/skills is dispatched after this step's findings are applied, not alongside it (#1688)."
445
448
  depends_on: verify-build
446
449
 
447
450
  - name: release
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.67",
2
+ "version": "1.1.69",
3
3
  "lastUpdated": "2026-09-03",
4
4
  "omcustomMinClaudeCode": "2.1.121",
5
5
  "omcustomMinClaudeCodeReason": "Sensitive-path direct Write/Edit on .claude/** under bypassPermissions (R010 deprecation, #1101)",
@@ -231,6 +231,7 @@ steps:
231
231
  포함되면 self-review로 대체하지 않고 mgr-sauron R017 검증을 **단일 목표 위임으로 필수
232
232
  실행**한다(Tier 2 lite의 R017 조항과 동일 원칙; Origin: v1.1.58 세션 — docs-only 티어였으나
233
233
  sauron이 R002/R010 모순 advisory 1건을 포착).
234
+ - Wiki resync + manifest reseed (R022) run AFTER the deep-verify substitute for this tier (self-review checklist, plus the mandatory mgr-sauron R017 delegation when `.claude/rules/**` is in scope) and any resulting corrections have landed — never in parallel with it; this is the implement step's #1688 EXCEPTION applied to Tier 1. Wiki pages summarize the rules, so a review-driven rule fix invalidates any wiki written earlier (v1.1.66: 3 pages reworked; v1.1.67 with review-first ordering: 0 rework — #1688 Iteration 3 #2).
234
235
  - Log: "[compression-mode] docs-only compression activated (scope={n}, all docs/yaml labels)"
235
236
  - ⚠ Analysis artifacts only. Every step's state-change side effect (milestone create/assign,
236
237
  label add/remove, issue assign/comment/close) still runs in full — see "Cross-tier —
@@ -257,6 +258,7 @@ steps:
257
258
  (template-sync + md5 multi-copy + counts + bun test), under a MANDATORY justification log:
258
259
  "[compression-mode] lite deep-verify — R017 spawn skipped (no structural surface); deterministic self-check only".
259
260
  (#1311, extends #1309 substitution principle.)
261
+ - Wiki resync/reseed only after deep-verify (adversarial review) findings are applied — same ordering rule as Tier 1; this overrides the implement-step CI-mimic wiki fix for rules/skills text changes (see the implement step's #1688 EXCEPTION) (#1688).
260
262
  - implement / verify-build / release / ci-check / post-release-followup: execute normally (no compression)
261
263
  - MANDATORY justification log (REQUIRED whenever a skill stage is replaced by integrated analysis):
262
264
  "[compression-mode] lite — skill 단계 통합 분석 대체. 정당화: scope={n}, 모든 이슈 저위험(라벨 {labels}), 구현 대상 이슈 본문 명시 {issue_refs}"
@@ -402,6 +404,7 @@ steps:
402
404
  If any fails:
403
405
  - For wiki-sync failures: delegate to wiki-curator to generate missing pages (`/omcustom:wiki ingest <path>`)
404
406
  (Regenerating the wiki source-hash manifest targets `wiki/.source-hashes.json` ALWAYS — NEVER `templates/manifest.json`. Command: `bash .github/scripts/lib/source-hash.sh generate wiki/.source-hashes.json`. Ref #1423.)
407
+ - EXCEPTION (#1688 ordering): when the change set is rules/skills TEXT only (no new or renamed entity), do NOT fix wiki drift here — record the drift and defer the wiki resync + `wiki/.source-hashes.json` reseed until AFTER deep-verify findings are applied, then re-run `verify-wiki-sync.sh` before release. Missing PAGES for newly created entities are still generated here (CI blocks on them).
405
408
  - For template-sync failures: delegate to mgr-updater to sync `.claude/` -> `templates/.claude/`
406
409
  - For validate-docs failures (count mismatch): delegate to mgr-updater to fix counts via EXHAUSTIVE grep across all docs — file-enumeration misses `.en`/`.ko` variants and secondary docs (#1521 — v1.1.32에서 validate-docs 누락으로 push 왕복 1회 발생)
407
410
  - After fixes, re-run the scripts until all pass
@@ -441,7 +444,7 @@ steps:
441
444
 
442
445
  - name: deep-verify
443
446
  skill: deep-verify
444
- description: "Multi-angle release quality verification — self-review checklist if docs-only; mgr-sauron R017 + core self-check if lite. MULTI-PHASE: 스킬을 그대로 spawn하지 말고 R020 「위임 경계를 Phase 개수로 설계」에 따라 단일 목표 위임으로 분할해 순차 발주한다 (#1595 #4). lite 분할 표준(#1652 #3-4): (1) mgr-sauron R017 구조 검증 단일 목표 위임 1건 + (2) 변경 성격별 적대적 리뷰 단일 목표 위임 1건 — 스크립트 변경이면 실행 재현 기반 adversarial-review, 룰/스킬/yaml 텍스트 변경이면 문구 정합·배선 리뷰. 근거: v1.1.59/60 두 반복 연속 적대적 리뷰가 신규 회귀(M-3/M-4, heredoc 위조)를 실행 재현으로 포착. 검증 위임 표준 문안: 오케스트레이터가 이미 실측한 항목(bun test·lint·typecheck·template-sync·wiki-sync·validate-docs·미러 md5)은 위임서에 재실행 금지 목록으로 열거하고 재실측 대상만 지정한다 — v1.1.61 세션에서 금지 목록 없는 sauron 위임이 bun test를 재실행하다 25턴 절단됐고, 금지 목록을 명시한 재위임은 16 tool_uses로 완주했다(R020 maxTurns 절단 누적 7건째)."
447
+ description: "Multi-angle release quality verification — self-review checklist if docs-only; mgr-sauron R017 + core self-check if lite. MULTI-PHASE: 스킬을 그대로 spawn하지 말고 R020 「위임 경계를 Phase 개수로 설계」에 따라 단일 목표 위임으로 분할해 순차 발주한다 (#1595 #4). lite 분할 표준(#1652 #3-4): (1) mgr-sauron R017 구조 검증 단일 목표 위임 1건 + (2) 변경 성격별 적대적 리뷰 단일 목표 위임 1건 — 스크립트 변경이면 실행 재현 기반 adversarial-review, 룰/스킬/yaml 텍스트 변경이면 문구 정합·배선 리뷰. 근거: v1.1.59/60 두 반복 연속 적대적 리뷰가 신규 회귀(M-3/M-4, heredoc 위조)를 실행 재현으로 포착. 검증 위임 표준 문안: 오케스트레이터가 이미 실측한 항목(bun test·lint·typecheck·template-sync·wiki-sync·validate-docs·미러 md5)은 위임서에 재실행 금지 목록으로 열거하고 재실측 대상만 지정한다 — v1.1.61 세션에서 금지 목록 없는 sauron 위임이 bun test를 재실행하다 25턴 절단됐고, 금지 목록을 명시한 재위임은 16 tool_uses로 완주했다(R020 maxTurns 절단 누적 7건째). Ordering: any wiki resync/manifest reseed for the changed rules/skills is dispatched after this step's findings are applied, not alongside it (#1688)."
445
448
  depends_on: verify-build
446
449
 
447
450
  - name: release