oh-my-customcode 1.1.44 → 1.1.45
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 +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/templates/.claude/hooks/scripts/r007-r008-drift-advisor.sh +11 -1
- package/templates/.claude/hooks/scripts/session-env-check.sh +33 -5
- package/templates/.claude/hooks/scripts/session-reflection.sh +7 -1
- package/templates/.claude/hooks/scripts/user-prompt-preprocessor.sh +74 -15
- package/templates/.claude/rules/MAY-optimization.md +1 -1
- package/templates/.claude/rules/MUST-agent-design.md +1 -1
- package/templates/.claude/rules/MUST-completion-verification.md +25 -4
- package/templates/.claude/rules/MUST-continuous-improvement.md +1 -1
- package/templates/.claude/rules/MUST-enforcement-policy.md +7 -5
- package/templates/.claude/rules/MUST-orchestrator-coordination.md +21 -1
- package/templates/.claude/rules/MUST-permissions.md +1 -1
- package/templates/.claude/rules/MUST-sync-verification.md +10 -0
- package/templates/.claude/rules/SHOULD-memory-integration.md +1 -1
- package/templates/.claude/rules/SHOULD-verification-ladder.md +11 -1
- package/templates/.claude/skills/pipeline/workflows/auto-dev.yaml +19 -1
- package/templates/manifest.json +1 -1
- package/templates/workflows/auto-dev.yaml +19 -1
package/dist/cli/index.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -74,6 +74,16 @@
|
|
|
74
74
|
# R008 explicitly exempts from the `[N]` prefix). Excluding this notation would recreate
|
|
75
75
|
# exactly the false positive this fix removes (N Agent tool_use blocks, 0 `Tool:` lines).
|
|
76
76
|
#
|
|
77
|
+
# Tool calls EXCLUDED from the denominator:
|
|
78
|
+
# * `Skill` — R008 §"Tier-3 Interaction Tool Prefix" exempts it verbatim:
|
|
79
|
+
# "Skill | NO separate R008 prefix — identified via R007 `claude → {skill-name}`
|
|
80
|
+
# integrated header instead"
|
|
81
|
+
# A compliant skill invocation therefore emits a `┌─ Agent: claude → homework` header and
|
|
82
|
+
# NO `→ Tool:` line, so counting the Skill tool_use scored `R008 접두사=1` against a turn
|
|
83
|
+
# that follows the rule exactly (verified against the R008 table, #1569). The exclusion
|
|
84
|
+
# lives in the SHARED verdict, so session-reflection.sh carries the identical select or
|
|
85
|
+
# the next copy re-contaminates.
|
|
86
|
+
#
|
|
77
87
|
# R007 detection (first line of the turn's first text block) is unchanged.
|
|
78
88
|
#
|
|
79
89
|
# ── Performance ───────────────────────────────────────────────────────────────────────
|
|
@@ -182,7 +192,7 @@ split("\n")
|
|
|
182
192
|
| ([ $lines[] | select(test("^[[:space:]]*\\[[0-9]+\\][[:space:]].*(→|->|—>)")) ] | length) as $an_spawn_item
|
|
183
193
|
| ([ $lines[] | select(test("\\[.+\\]\\[.+\\] ?(→|->|—>) ?Spawning:")) ] | length) as $an_spawn_hdr
|
|
184
194
|
| ($an_tool + (if $an_spawn_item > 0 then $an_spawn_item else $an_spawn_hdr end)) as $announce
|
|
185
|
-
| ([ $blocks[] | select(.type? == "tool_use") ] | length) as $ntools
|
|
195
|
+
| ([ $blocks[] | select((.type? == "tool_use") and ((.name? // "") != "Skill")) ] | length) as $ntools
|
|
186
196
|
| (if $ntools > $announce then $ntools - $announce else 0 end) as $r008
|
|
187
197
|
| [$tuuid, ($r007 | tostring), ($r008 | tostring)] | @tsv
|
|
188
198
|
end
|
|
@@ -82,8 +82,10 @@ if command -v git >/dev/null 2>&1 && git rev-parse --is-inside-work-tree >/dev/n
|
|
|
82
82
|
mkdir -p "$SESSION_STATE_DIR"
|
|
83
83
|
|
|
84
84
|
PROJECT_HASH=$(echo "$(pwd)" | md5 2>/dev/null || echo "$(pwd)" | md5sum 2>/dev/null | cut -c1-8)
|
|
85
|
-
# md5 on macOS outputs "MD5 (stdin) = <hash>", extract just the hash
|
|
86
|
-
|
|
85
|
+
# md5 on macOS outputs "MD5 (stdin) = <hash>", extract just the hash.
|
|
86
|
+
# Guarded for the same reason as json_string_field below: on a platform where the fallback
|
|
87
|
+
# already yields an 8-char digest this grep matches nothing and would abort the hook.
|
|
88
|
+
PROJECT_HASH=$(echo "$PROJECT_HASH" | grep -oE '[a-f0-9]{32}' | cut -c1-8 || printf '')
|
|
87
89
|
STATE_FILE="${SESSION_STATE_DIR}/${PROJECT_HASH}.last-head"
|
|
88
90
|
|
|
89
91
|
CURRENT_HEAD=$(git log -1 --format="%H" 2>/dev/null || echo "")
|
|
@@ -126,15 +128,41 @@ OMCUSTOM_UPDATE_STATUS="unknown"
|
|
|
126
128
|
INSTALLED_VERSION=""
|
|
127
129
|
CACHED_LATEST=""
|
|
128
130
|
|
|
131
|
+
# Extract a "<key>": "<value>" pair from a JSON file using grep only (no jq dependency).
|
|
132
|
+
# EVERY grep here is guarded with `|| printf ''`: this script runs under `set -euo pipefail`,
|
|
133
|
+
# where an unmatched grep exits 1 and (via pipefail) kills the ENTIRE SessionStart hook —
|
|
134
|
+
# measured as exit 1 with 0 bytes of stdout and 11 failing tests, including the script's own
|
|
135
|
+
# "should always exit with code 0" contract (#1570).
|
|
136
|
+
json_string_field() {
|
|
137
|
+
local file="$1" key="$2"
|
|
138
|
+
grep -o "\"${key}\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" "$file" 2>/dev/null \
|
|
139
|
+
| head -1 \
|
|
140
|
+
| grep -o '"[^"]*"$' \
|
|
141
|
+
| tr -d '"' \
|
|
142
|
+
|| printf ''
|
|
143
|
+
}
|
|
144
|
+
|
|
129
145
|
# Read installed version from .omcustomrc.json
|
|
130
146
|
if [ -f ".omcustomrc.json" ]; then
|
|
131
|
-
INSTALLED_VERSION=$(
|
|
147
|
+
INSTALLED_VERSION=$(json_string_field ".omcustomrc.json" "version")
|
|
132
148
|
fi
|
|
133
149
|
|
|
134
|
-
# Read cached latest version (no network call)
|
|
150
|
+
# Read cached latest version (no network call).
|
|
151
|
+
#
|
|
152
|
+
# Schema note (MEASURED 2026-08-10, #1570): TWO writers produce this exact path with
|
|
153
|
+
# DIFFERENT key names, and BOTH are current — neither is a legacy schema:
|
|
154
|
+
# * .claude/hooks/scripts/omcustom-auto-update.sh → {"version","timestamp","source"}
|
|
155
|
+
# * src/core/self-update.ts writeCache() → {"checkedAt","latestVersion"}
|
|
156
|
+
# The live cache on this machine was the auto-update shape ({source,timestamp,version}), so
|
|
157
|
+
# the hard-coded "latestVersion" lookup matched nothing. Read `latestVersion` first, then fall
|
|
158
|
+
# back to `version`. The `"version"` pattern includes the opening quote, so it cannot
|
|
159
|
+
# accidentally match the tail of `"latestVersion"`.
|
|
135
160
|
CACHE_FILE="$HOME/.oh-my-customcode/self-update-cache.json"
|
|
136
161
|
if [ -f "$CACHE_FILE" ]; then
|
|
137
|
-
CACHED_LATEST=$(
|
|
162
|
+
CACHED_LATEST=$(json_string_field "$CACHE_FILE" "latestVersion")
|
|
163
|
+
if [ -z "$CACHED_LATEST" ]; then
|
|
164
|
+
CACHED_LATEST=$(json_string_field "$CACHE_FILE" "version")
|
|
165
|
+
fi
|
|
138
166
|
fi
|
|
139
167
|
|
|
140
168
|
if [ -n "$INSTALLED_VERSION" ] && [ -n "$CACHED_LATEST" ]; then
|
|
@@ -105,6 +105,12 @@ ISO8601="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
|
105
105
|
# 없음)도 포함 — 에이전트당 단위는 번호 라인이고, 번호 라인이 없을 때만(단일 spawn) 헤더를 1로 센다.
|
|
106
106
|
# 위반 샘플은 announce가 모자란 만큼 턴의 마지막 tool_use들을 보고한다(결손 개수 기준).
|
|
107
107
|
#
|
|
108
|
+
# 분모에서 제외하는 도구: `Skill` (#1569). R008 §"Tier-3 Interaction Tool Prefix" 표는 Skill을
|
|
109
|
+
# 명시 면제한다 — "Skill | NO separate R008 prefix — identified via R007 `claude → {skill-name}`
|
|
110
|
+
# integrated header instead". 즉 준수한 스킬 호출은 `┌─ Agent: claude → homework` 통합 헤더만
|
|
111
|
+
# 남기고 `→ Tool:` 라인을 쓰지 않으므로, Skill tool_use를 세면 규칙을 정확히 지킨 턴에
|
|
112
|
+
# `R008 접두사=1` 오탐이 찍힌다.
|
|
113
|
+
#
|
|
108
114
|
# 이 판정은 r007-r008-drift-advisor.sh와 공유된다 — 한쪽만 고치면 재오염된다.
|
|
109
115
|
#
|
|
110
116
|
# 성능: 줄마다 jq를 포크하던 구조를 jq 1회 포크로 교체.
|
|
@@ -137,7 +143,7 @@ split("\n")
|
|
|
137
143
|
| ([ $lines[] | select(test("^[[:space:]]*\\[[0-9]+\\][[:space:]].*(→|->|—>)")) ] | length) as $an_spawn_item
|
|
138
144
|
| ([ $lines[] | select(test("\\[.+\\]\\[.+\\] ?(→|->|—>) ?Spawning:")) ] | length) as $an_spawn_hdr
|
|
139
145
|
| ($an_tool + (if $an_spawn_item > 0 then $an_spawn_item else $an_spawn_hdr end)) as $announce
|
|
140
|
-
| ([ $blocks[] | select(.type? == "tool_use") ]) as $tus
|
|
146
|
+
| ([ $blocks[] | select((.type? == "tool_use") and ((.name? // "") != "Skill")) ]) as $tus
|
|
141
147
|
| (if ($tus | length) > $announce then ($tus | length) - $announce else 0 end) as $r008n
|
|
142
148
|
| if $r008n > 0
|
|
143
149
|
then [ $tus[(($tus | length) - $r008n):][]
|
|
@@ -1,32 +1,91 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# UserPromptSubmit hook
|
|
3
|
-
#
|
|
4
|
-
# Advisory
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# user-prompt-preprocessor.sh — UserPromptSubmit hook: advisory hints from the user's prompt
|
|
3
|
+
#
|
|
4
|
+
# Advisory-only: ALWAYS exits 0, NEVER blocks prompt submission.
|
|
5
|
+
#
|
|
6
|
+
# ── Two measured defects this file fixes (#1568) ──────────────────────────────────────
|
|
7
|
+
#
|
|
8
|
+
# 1. SELECTOR. The previous implementation read `.user_input`, but the Claude Code
|
|
9
|
+
# UserPromptSubmit payload carries the text in `prompt`. The `[ -z "$user_input" ]` guard
|
|
10
|
+
# on the next line therefore ALWAYS took the early-return branch, so the detection blocks
|
|
11
|
+
# below were unreachable — the hook was a pure pass-through.
|
|
12
|
+
# Live probe (2026-08-10):
|
|
13
|
+
# platform-shaped {"prompt":"끝"} → NO hint (defect)
|
|
14
|
+
# script-shaped {"user_input":"끝"} → "[Hook] Session-end signal detected"
|
|
15
|
+
# `.prompt` is now read first, with `.user_input` retained as a fallback so any
|
|
16
|
+
# script-shaped caller (and the pre-existing test corpus) keeps working.
|
|
17
|
+
#
|
|
18
|
+
# 2. DELIVERY CHANNEL. The hints were written to stderr only. Per the official hook spec,
|
|
19
|
+
# stderr on exit 0 is NEVER fed into the model's context for ANY event — it is visible in
|
|
20
|
+
# transcript debug mode, i.e. to a human, not to Claude. Fixing the selector alone would
|
|
21
|
+
# have left the hook functionally silent. Hints are now delivered through
|
|
22
|
+
# `hookSpecificOutput.additionalContext` (JSON on stdout, exit 0), the same contract used
|
|
23
|
+
# by the sibling UserPromptSubmit advisors r007-r008-drift-advisor.sh and
|
|
24
|
+
# fail-axis-cause-advisor.sh. The stderr line is kept purely as a human audit trail.
|
|
25
|
+
#
|
|
26
|
+
# `hookEventName` MUST echo the ACTUAL firing event — a wrong value invalidates the
|
|
27
|
+
# output — so a missing `hook_event_name` is a hard `exit 0` with no guessed default.
|
|
28
|
+
# A top-level `decision` field is NEVER emitted: `"decision": "block"` would turn this
|
|
29
|
+
# advisory into an enforcement gate, exactly what R021 (advisory-first) forbids.
|
|
30
|
+
#
|
|
31
|
+
# ── Why the stdin pass-through (`echo "$input"`) was removed ──────────────────────────
|
|
32
|
+
# It was never part of the UserPromptSubmit contract. For UserPromptSubmit, plain stdout on
|
|
33
|
+
# exit 0 is injected into the model's context, so echoing the payload back would inject the
|
|
34
|
+
# raw hook JSON as context noise. The repo's own convention agrees: of the four scripts wired
|
|
35
|
+
# to UserPromptSubmit in .claude/hooks/hooks.json, the three that were written or repaired
|
|
36
|
+
# against the measured spec — r007-r008-drift-advisor.sh, session-autofix-prompt.sh,
|
|
37
|
+
# fail-axis-cause-advisor.sh — all exit 0 WITHOUT echoing stdin. This file was the only
|
|
38
|
+
# hold-out. Pass-through echo is a Stop-hook idiom (see session-reflection.sh, which chains),
|
|
39
|
+
# not a UserPromptSubmit one.
|
|
5
40
|
|
|
41
|
+
set -euo pipefail
|
|
42
|
+
|
|
43
|
+
# ── stdin 읽기 ──
|
|
6
44
|
input=$(cat)
|
|
7
|
-
|
|
45
|
+
|
|
46
|
+
# ── jq 의존성 체크 (graceful degrade) ──
|
|
47
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
48
|
+
exit 0
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# ── 입력 필드 추출 ──
|
|
52
|
+
# `.prompt`(플랫폼 실제 필드)를 우선 읽고 `.user_input`(스크립트형 호출자)로 폴백한다.
|
|
53
|
+
# prompt 본문은 탭/개행을 포함할 수 있으므로 @tsv 로 묶지 않고 개별 추출한다.
|
|
54
|
+
user_input=$(printf '%s' "$input" | jq -r '(.prompt // .user_input // "")' 2>/dev/null) || exit 0
|
|
55
|
+
hook_event_name=$(printf '%s' "$input" | jq -r '(.hook_event_name // "")' 2>/dev/null) || exit 0
|
|
8
56
|
|
|
9
57
|
if [ -z "$user_input" ]; then
|
|
10
|
-
echo "$input"
|
|
11
58
|
exit 0
|
|
12
59
|
fi
|
|
13
60
|
|
|
14
|
-
#
|
|
61
|
+
# ── 패턴 탐지 ──
|
|
15
62
|
hints=""
|
|
16
63
|
|
|
17
64
|
# Korean session-end signals
|
|
18
|
-
if
|
|
19
|
-
hints="${hints}[Hook] Session-end signal detected — R011 memory saves will be triggered\n
|
|
65
|
+
if printf '%s' "$user_input" | grep -qiE '(끝|종료|마무리|done|wrap up|end session)'; then
|
|
66
|
+
hints="${hints}[Hook] Session-end signal detected — R011 memory saves will be triggered"$'\n'
|
|
20
67
|
fi
|
|
21
68
|
|
|
22
69
|
# Workflow invocation
|
|
23
|
-
if
|
|
24
|
-
hints="${hints}[Hook] Slash command detected\n
|
|
70
|
+
if printf '%s\n' "$user_input" | grep -qE '^/'; then
|
|
71
|
+
hints="${hints}[Hook] Slash command detected"$'\n'
|
|
25
72
|
fi
|
|
26
73
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
printf "%b" "$hints" >&2
|
|
74
|
+
if [ -z "$hints" ]; then
|
|
75
|
+
exit 0
|
|
30
76
|
fi
|
|
31
77
|
|
|
32
|
-
|
|
78
|
+
# 사람이 보는 감사 추적용 (exit 0에서는 모델에 전달되지 않음 — 위 주석 2번 참고)
|
|
79
|
+
printf '%s' "$hints" >&2
|
|
80
|
+
|
|
81
|
+
# hook_event_name 이 없으면 hookSpecificOutput.hookEventName 을 정확히 채울 수 없다.
|
|
82
|
+
# 잘못된 기본값은 출력을 무효화하므로 추측하지 않는다.
|
|
83
|
+
if [ -z "$hook_event_name" ]; then
|
|
84
|
+
exit 0
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# 실제 전달 경로: additionalContext. decision 필드는 절대 포함하지 않는다 (R021).
|
|
88
|
+
jq -cn --arg event "$hook_event_name" --arg ctx "$hints" \
|
|
89
|
+
'{hookSpecificOutput: {hookEventName: $event, additionalContext: $ctx}}'
|
|
90
|
+
|
|
91
|
+
exit 0
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
|
|
35
35
|
<!-- RETIRED (은퇴 릴리즈 v1.1.44, 보존 기준 v2.1.212 미만): > **v2.1.208+**: Fixed several tool-reliability bugs: env vars like `CLAUDE_CODE_MAX_OUTPUT_TOKENS` silently used only the mantissa of scientific-notation values (`1e6` became `1`); Edit now succeeds on a file modified after being read, as long as the target text still matches uniquely; Read no longer misreports empty files as "shorter than offset"; Grep no longer silently returns "No files found" for invalid regex, no longer under-reports paginated count-mode totals; and Glob no longer crashes on a null byte in pattern/path/cwd. -->
|
|
36
36
|
|
|
37
|
-
> **v2.1.210+**: Bash/PowerShell 명령이 timeout으로 auto-background될 때의 메시지가 개선되어 모델이 hang과 명시적 background 요청을 구분할 수 있으며, auto-background된 명령 내 `cd`는 적용되지 않고 tool result가 working directory 불변을 명시합니다 — auto-background 이후 cwd 의존 후속 명령은 절대 경로로 수행합니다. 또한 Grep content mode가 결과 끝을 지난 페이지네이션에서 "No matches found"를 반환하던 문제가 수정되었습니다(v2.1.208 Grep 페이지네이션 수정의 연장) — 구버전에서 이 응답은 "패턴 미존재"가 아니라 "페이지 끝"일 수 있습니다.
|
|
37
|
+
<!-- RETIRED (은퇴 릴리즈 v1.1.45, 보존 기준 v2.1.212 미만): > **v2.1.210+**: Bash/PowerShell 명령이 timeout으로 auto-background될 때의 메시지가 개선되어 모델이 hang과 명시적 background 요청을 구분할 수 있으며, auto-background된 명령 내 `cd`는 적용되지 않고 tool result가 working directory 불변을 명시합니다 — auto-background 이후 cwd 의존 후속 명령은 절대 경로로 수행합니다. 또한 Grep content mode가 결과 끝을 지난 페이지네이션에서 "No matches found"를 반환하던 문제가 수정되었습니다(v2.1.208 Grep 페이지네이션 수정의 연장) — 구버전에서 이 응답은 "패턴 미존재"가 아니라 "페이지 끝"일 수 있습니다. -->
|
|
38
38
|
|
|
39
39
|
> **v2.1.212+**: MCP 도구 호출이 2분(기본값, `CLAUDE_CODE_MCP_AUTO_BACKGROUND_MS`로 임계값 조정·비활성) 초과 시 자동으로 백그라운드로 이동해 세션이 계속 사용 가능해집니다 — 위 v2.1.210 Bash/PowerShell auto-background의 MCP 도구 확장. 느린 MCP 호출(ontology-rag `rebuild_ontology`, code-review-graph 인덱싱 등)을 hang으로 오판하지 말고, 2분 초과 시 백그라운드 전환을 전제로 후속 작업을 진행합니다.
|
|
40
40
|
|
|
@@ -488,7 +488,7 @@ Key optional fields: `scope`, `context`, `version`, `effort`, `model`, `agent`,
|
|
|
488
488
|
> **v2.1.199+**: 스택된 slash-skill 호출(`/skill-a /skill-b do XYZ`)이 이제 leading skill을 최대 5개까지 모두 로드합니다(이전에는 첫 번째만 로드). oh-my-customcode의 라우팅 스킬 체이닝(예: `/omcustom:fsd`가 여러 스킬을 연쇄 호출하는 패턴)에서 다중 스킬 스택 호출 시 컨텍스트 손실이 줄어듭니다. 또한 subagent 조회 중 `/model`·`/fast`를 입력하면 lead의 model picker가 열리며 notice가 표시됩니다.
|
|
489
489
|
-->
|
|
490
490
|
|
|
491
|
-
> **v2.1.210+**: 스킬/커맨드 본문에서 인자 없이 호출된(unmatched) `$1`/`$2` positional placeholder가 조용히 제거되던(silently stripped) 동작이 수정되어 이제 리터럴 `$1`로 verbatim 보존됩니다 — 인자 부재 시 `$1`이 확장된 프롬프트에 그대로 남아 지시가 깨지므로, silent stripping에 옵션-인자 처리를 의존하지 말고 인자 부재 케이스를 명시 처리(default text / `$ARGUMENTS` guard / `argument-hint`)해야 합니다. (위 v2.1.163+ `\$1` escape는 항상 리터럴 `$` 출력용 별개 메커니즘으로 이번 변경 대상이 아니며, 이번 수정은 치환 의도의 bare `$1`이 unmatched일 때만 적용됩니다.)
|
|
491
|
+
<!-- RETIRED (은퇴 릴리즈 v1.1.45, 보존 기준 v2.1.212 미만): > **v2.1.210+**: 스킬/커맨드 본문에서 인자 없이 호출된(unmatched) `$1`/`$2` positional placeholder가 조용히 제거되던(silently stripped) 동작이 수정되어 이제 리터럴 `$1`로 verbatim 보존됩니다 — 인자 부재 시 `$1`이 확장된 프롬프트에 그대로 남아 지시가 깨지므로, silent stripping에 옵션-인자 처리를 의존하지 말고 인자 부재 케이스를 명시 처리(default text / `$ARGUMENTS` guard / `argument-hint`)해야 합니다. (위 v2.1.163+ `\$1` escape는 항상 리터럴 `$` 출력용 별개 메커니즘으로 이번 변경 대상이 아니며, 이번 수정은 치환 의도의 bare `$1`이 unmatched일 때만 적용됩니다.) -->
|
|
492
492
|
|
|
493
493
|
> **v2.1.222+**: 스킬 frontmatter의 `disable-model-invocation: true`(모델이 스스로 그 스킬을 호출하지 못하게 막고 사용자/파이프라인의 명시적 호출만 허용하는 필드)가 설정된 스킬을 모델이 호출하려 할 때의 refusal 문구가 개선되어, 모델에게 **워크플로우를 스스로 복제하지 말고 사용자에게 실행을 요청하라**고 지시합니다. 무인 루프(`/fsd` 등)가 이런 스킬을 모델 호출 경로에 두면 실행 대신 refusal이 반환되므로, 해당 스킬은 **사용자/파이프라인 명시 호출**로 설계합니다.
|
|
494
494
|
|
|
@@ -73,9 +73,9 @@ Never accept "pre-existing" without direct base-branch evidence. A false "pre-ex
|
|
|
73
73
|
|
|
74
74
|
### Verification-Delegation Non-Termination (검증 위임 판정 종료 보장)
|
|
75
75
|
|
|
76
|
-
구조 검증(mgr-sauron R017)·판정·품질 게이트를 서브에이전트에 위임할 때, 위임 프롬프트에 **"최종 PASS/FAIL 판정 없이 turn을 종료하지 말라"**를 명시한다 — 단 이 clause는 **보조 수단**일 뿐 1차 방어선이 아니다. clause를 명시해도 mid-step 종료가 **누적
|
|
76
|
+
구조 검증(mgr-sauron R017)·판정·품질 게이트를 서브에이전트에 위임할 때, 위임 프롬프트에 **"최종 PASS/FAIL 판정 없이 turn을 종료하지 말라"**를 명시한다 — 단 이 clause는 **보조 수단**일 뿐 1차 방어선이 아니다. clause를 명시해도 mid-step 종료가 **누적 14회** 재발했다(v1.1.13/14/17/18/19 … v1.1.44, 아래 Origin 참조). **예방의 1차 방어선은 위임 경계 분할**(아래 「위임 경계를 Phase 개수로 설계」)이고, **사후 1차 방어선은 오케스트레이터의 직접 ground-truth 실측**이다.
|
|
77
77
|
|
|
78
|
-
mid-step 종료는 예상 가능한 정상 실패 모드로 취급한다 — 발생 시 즉시 ground-truth를 실측해 실제 진행 상태를 확인한다. **증상만으로 결과를 넘겨짚지 않는다**: 같은 "...중" 한 줄 종료라도 실측 결과는
|
|
78
|
+
mid-step 종료는 예상 가능한 정상 실패 모드로 취급한다 — 발생 시 즉시 ground-truth를 실측해 실제 진행 상태를 확인한다. **증상만으로 결과를 넘겨짚지 않는다**: 같은 "...중" 한 줄 종료라도 실측 결과는 **세 방향 모두** 관측됐다 — (a) 보고=완료("merging now" → 실측 시 PR 이미 MERGED, resume 불필요), (b) 보고=미완료("CI 실행 중" → 실측 시 PR OPEN 미머지, resume 필요), (c) **실제가 보고보다 앞섬**("커밋 1 완료, 커밋 2 스테이징으로 이어갑니다" → 실측 시 3개 커밋 전부 완료). 세 방향이 모두 나온 이상 증상 기반 진행도 추론은 **원리적으로 불가능**하며, 실측만이 유일한 판정 수단이다. 미완이면 SendMessage로 resume하되, 오케스트레이터가 실측한 값(예: "CI 전부 통과, mergeStateStatus=CLEAN")을 resume 메시지에 동봉해 에이전트가 재폴링 후 재종료하는 루프를 끊는다.
|
|
79
79
|
|
|
80
80
|
| Anti-pattern | Required |
|
|
81
81
|
|--------------|----------|
|
|
@@ -83,7 +83,17 @@ mid-step 종료는 예상 가능한 정상 실패 모드로 취급한다 — 발
|
|
|
83
83
|
| mid-step 종료 증상(예: "merging now")으로 결과를 넘겨짚음 | 매번 `gh pr view`/`gh run list` 등으로 실측 후 완료/미완료 판정 |
|
|
84
84
|
| resume 시 빈 재촉만 전달 | 실측값을 resume 메시지에 동봉해 재폴링 루프 차단 |
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
#### 위임 경계를 Phase 개수로 설계 (예방 1차 방어선)
|
|
87
|
+
|
|
88
|
+
다중 Phase 작업을 한 에이전트에 위임하면 **Phase 경계가 곧 종료 유혹 지점**이 된다 — 완료 조건 번호 명시와 종료 금지 clause를 넣어도 동일하다. 위임 단위는 **단일 목표 1개**로 자르고, Phase가 2개 이상이면 분할해 순차 발주한다.
|
|
89
|
+
|
|
90
|
+
| Anti-pattern | Required |
|
|
91
|
+
|--------------|----------|
|
|
92
|
+
| 다중 Phase 작업(3-Phase 검증, 3-커밋 시퀀스)을 한 에이전트에 위임하고 clause로 종료를 막으려 함 | 위임 단위를 단일 목표 1개로 분할해 순차 발주 — 경계 분할이 clause 강화보다 실효적 |
|
|
93
|
+
|
|
94
|
+
대조 실증(#1574, v1.1.44 세션): 단일 목표 위임(PR 생성 / 머지 / 브랜치 정리 / 버전 범프) **4건 전원 완주**, 다중 Phase 위임(mgr-sauron 3-Phase, mgr-gitnerd 3-커밋) **2건 모두 mid-step 종료**. 같은 세션에서 릴리즈 단계를 push+범프 / PR 생성 / 머지로 3분할한 것이 이 설계의 적용례다.
|
|
95
|
+
|
|
96
|
+
Origin: #1443 (Session 126 회고 찐빠 #1) — v1.1.3 R017 검증에서 mgr-sauron이 source-hash 대조 중 판정 없이 종료 → resume 후 PASS. v1.1.4에서 "판정 반드시 출력" 명시로 1회 완료(대조 실증). **5회 재발 확인(#1492, Session 132)**: v1.1.13/14/17(clause 명시에도 재발) → v1.1.18(완료조건 6항목+종료금지 명시에도 "merging now" 한 줄 남기고 종료, 실측 결과 이미 완료) → v1.1.19(위임 프롬프트에 "4회 무시됨"까지 명시했으나 "CI 실행 중" 한 줄 남기고 종료, 실측 결과 미완료). Session 132에서 2회 모두 오케스트레이터 직접 실측으로 복구 — clause 강화가 아니라 실측 습관화가 유일하게 실증된 방어선. **누적 11회 확인(#1518 찐빠 #2, Session 136)**: v1.1.30 릴리즈 세션에서도 "완료 조건 5항목 실측 + 판정 없이 종료 금지" 명시에도 mgr-gitnerd가 "폴링 완료 통지를 기다리겠습니다" 한 줄만 남기고 종료 → 오케스트레이터 직접 실측으로 복구(lockfile push 완료 / CI pending / PR OPEN); 이번엔 "대기 중" 증상이 실제 미완료였고 Session 132의 "머지 중" 증상은 실제 완료였다는 대비로 증상→결과 추론 금지가 재확인됨. **누적 14회 + 3방향째 확인(#1574, v1.1.44 세션)**: mgr-sauron 3-Phase / mgr-gitnerd 3-커밋 위임 2건이 Phase 경계에서 종료했고(위 「위임 경계를 Phase 개수로 설계」의 대조 실증), 그중 mgr-gitnerd는 "커밋 2로 이어가겠다"고 보고했으나 실측 시 3개 커밋이 이미 전부 완료 — 실제가 보고보다 앞서는 세 번째 방향.
|
|
87
97
|
|
|
88
98
|
Cross-reference: R018 (Member Completion Verification), `feedback_release_delegation_phasing`, `feedback_orchestrator_direct_verify` (release delegation phasing을 verification 위임에도 확장).
|
|
89
99
|
|
|
@@ -93,7 +103,7 @@ Cross-reference: R018 (Member Completion Verification), `feedback_release_delega
|
|
|
93
103
|
> **v2.1.200+**: rate limit으로 어떤 텍스트 출력도 내기 전에 잘린 subagent가 이전에는 빈 결과(empty result)를 반환하던 것을 clean failure로 반환하도록 수정되었습니다 — v2.1.199 partial-work 반환에 이어, 출력 이전 rate-limit 차단 시 조용한 빈 결과 대신 명시적 실패를 parent에 보고합니다. 플랫폼이 false-success/silent-empty 자가보고를 추가로 줄였으나, "actual outcome ≠ attempt" ground-truth 검증 원칙(R020 Core Rule)은 여전히 유지됩니다 — subagent 보고를 그대로 신뢰하지 말고 git status/grep/validation script로 재확인합니다.
|
|
94
104
|
-->
|
|
95
105
|
|
|
96
|
-
> **v2.1.211+**: CC의 background agent 결과 보고가 개선되어, Claude가 아직 실행 중인 agent의 상태를 그대로 보고하고 **결과를 지어내지 않고 실제 완료를 기다립니다**(previously fabricated results). v2.1.199/200(false-success·silent-empty 자가보고 감소)에 이은 플랫폼 개선으로 오케스트레이터의 fabricated-completion 리스크를 추가로 낮추지만, "actual outcome ≠ attempt" ground-truth 검증 원칙(Core Rule)은 여전히 유지됩니다 — subagent/background agent 보고를 그대로 신뢰하지 말고 `git status`/`grep`/validation script로 재확인합니다.
|
|
106
|
+
<!-- RETIRED (은퇴 릴리즈 v1.1.45, 보존 기준 v2.1.212 미만): > **v2.1.211+**: CC의 background agent 결과 보고가 개선되어, Claude가 아직 실행 중인 agent의 상태를 그대로 보고하고 **결과를 지어내지 않고 실제 완료를 기다립니다**(previously fabricated results). v2.1.199/200(false-success·silent-empty 자가보고 감소)에 이은 플랫폼 개선으로 오케스트레이터의 fabricated-completion 리스크를 추가로 낮추지만, "actual outcome ≠ attempt" ground-truth 검증 원칙(Core Rule)은 여전히 유지됩니다 — subagent/background agent 보고를 그대로 신뢰하지 말고 `git status`/`grep`/validation script로 재확인합니다. -->
|
|
97
107
|
|
|
98
108
|
## Common False Completion Patterns — 8 anti-patterns including "Command executed" without exit code check, "Waiting for manual publish" when CI auto-publishes, "UI changes done" without browser render. See full table via Read tool.
|
|
99
109
|
|
|
@@ -261,6 +271,17 @@ Origin: #1266 ④.
|
|
|
261
271
|
|
|
262
272
|
이는 Read-Before-Characterize의 **자기 적용** 각도다 — 진단 대상이 외부 로그가 아니라 자기 자신의 transcript일 때에도 "읽기 전 특성화 금지"가 동일하게 적용된다.
|
|
263
273
|
|
|
274
|
+
#### 자율 루프 세션의 턴 경계 정의 (계수 전 확정 필수)
|
|
275
|
+
|
|
276
|
+
위 파싱 레시피는 **"사용자 프롬프트 = 턴 경계"**를 암묵 전제한다. `/fsd` 같은 자율 루프는 사용자 프롬프트가 거의 없어(실측: 사용자 프롬프트 4개 대 assistant 응답 30여 회) 이 전제로는 경계 재구성이 실패하고, 계수 자체가 성립하지 않는다. 자율 루프 transcript를 셀 때는 대안 경계 정의(예: **`tool_result` 직후 첫 text 블록을 응답 시작으로 간주**)를 먼저 확정하고, 정의를 확정하기 전에는 **위반 횟수를 단정하지 않는다**.
|
|
277
|
+
|
|
278
|
+
| Anti-pattern | Required |
|
|
279
|
+
|--------------|----------|
|
|
280
|
+
| 자율 루프 transcript를 사용자 프롬프트 경계로 파싱해 위반 N회로 단정 | 대안 경계 정의를 먼저 확정; 확정 전에는 횟수 단정 금지 |
|
|
281
|
+
| 경계 재구성 실패를 "위반 없음"으로 해석 | 경계 무관 지표로 대체 보고 — `┌─ Agent:` 헤더 총량, tool_use 대 announce 라인 비율 |
|
|
282
|
+
|
|
283
|
+
Origin: #1574 (v1.1.44 세션 — 자율 루프에서 R007 헤더 누락 계수를 시도했으나 사용자 프롬프트 4개로 턴 경계 재구성 불가). Cross-ref: R005(계수/매칭 방법 확인 — 도구 기본 동작 미확인 시 결과 오해석).
|
|
284
|
+
|
|
264
285
|
### Proxy Signal vs Canonical Ground-Truth (#1336 ①②)
|
|
265
286
|
|
|
266
287
|
> Origin: #1336 ①② — transcription was alarmed as "stopped" because `.txt` files looked stale, but the canonical DB had transcripts current to 06-09 21:30 (.txt is not the whisper collector's output — it emits only to the DB). Separately, SMS was over-diagnosed as "fully blocked" from one empty OneDrive XML path + a single 401, while the DB held 17 SMS rows ingested via the app path.
|
|
@@ -90,7 +90,7 @@ R016의 승격 루프(위반 지적 → 규칙 조항 추가)는 코퍼스의 **
|
|
|
90
90
|
|
|
91
91
|
1. **발동 추적**: `/homework` 회고·위반 지적 시 인용된 규칙 ID/조항을 feedback memory에 기록한다 (가벼운 추적 — 완전 자동화는 불요).
|
|
92
92
|
2. **후보 선정**: 마이너 2릴리즈 무발동 + 행동 지시 가치 소멸 조항을 은퇴 후보로 선정한다.
|
|
93
|
-
3. **HTML-comment화**: 조항을 `<!-- RETIRED (은퇴 릴리즈 vX.Y.Z,
|
|
93
|
+
3. **HTML-comment화**: 조항을 `<!-- RETIRED (은퇴 릴리즈 vX.Y.Z, <사유>): 원문 -->` 로 감싸 auto-injection에서 제외한다. `<사유>`는 위 「은퇴 대상」 두 범주에 대응한다 — 장기 무발동은 `N릴리즈 무발동`, 수정 완료된 플랫폼 버그 서사는 `보존 기준 v2.1.NNN 미만`. Read 도구로 열람 가능하므로 무손실이다 (R005 Context Optimization via HTML Comments).
|
|
94
94
|
4. **부활**: 동일 패턴이 재발하면 uncomment하여 즉시 복원한다 — 승격 루프와 대칭이다.
|
|
95
95
|
|
|
96
96
|
### 버전노트 보존정책
|
|
@@ -14,10 +14,12 @@ oh-my-customcode uses an **advisory-first enforcement model**. Most rules are en
|
|
|
14
14
|
| Soft Block | Stop hook prompt | R011 session-end saves | Auto-performs then approves |
|
|
15
15
|
| Conversation Block | PostToolUse hook + `continueOnBlock` (CC v2.1.139+), exit 2 | stuck-detector, context-budget-advisor, cost-cap-advisor | Feeds rejection reason into conversation; Claude continues with awareness |
|
|
16
16
|
| Advisory | PostToolUse hooks | R007, R008, R009, R010, R018 | Warns via stderr, never blocks |
|
|
17
|
-
| Advisory (proactive) | UserPromptSubmit + SubagentStop hooks | R007, R008 (`r007-r008-drift-advisor.sh` — #1229 UserPromptSubmit, #1545 SubagentStop) | Reads last assistant turn; emits advisory if header/prefix absent. SubagentStop wiring (#1545) closes the no-user-input autonomous-loop gap (`/fsd`). Complements retroactive Stop-hook (`session-reflection.sh`, #1190).
|
|
17
|
+
| Advisory (proactive) | UserPromptSubmit + SubagentStop + PostToolUse hooks | R007, R008 (`r007-r008-drift-advisor.sh` — #1229 UserPromptSubmit, #1545 SubagentStop, #1553 PostToolUse) | Reads last assistant turn; emits advisory if header/prefix absent. SubagentStop wiring (#1545) closes the no-user-input autonomous-loop gap (`/fsd`); PostToolUse (#1553) covers the orchestrator-only stretch before the first subagent spawn. Complements retroactive Stop-hook (`session-reflection.sh`, #1190). **v1.1.43부터 실제 발화 — 아래 각주 참조.** |
|
|
18
|
+
| Advisory (telemetry) | PostToolUseFailure hook | — (계측 전용, 규칙 강제 없음) | `failure-ledger.sh` (#1561, v1.1.44) — 도구 실패를 JSONL 원장에 append. stdout/stderr 무출력이라 모델에 도달하지 않으며 절대 차단하지 않음 |
|
|
19
|
+
| Advisory (proactive) | UserPromptSubmit hook | R020 (원인 진단) | `fail-axis-cause-advisor.sh` (#1561, v1.1.44) — 원장에 실패 기록이 있는데 원인 진술 없는 재촉 프롬프트가 오면 `hookSpecificOutput.additionalContext`로 "원인 가설 되묻기" advisory 전달. 원장 부재 시 조용히 통과 |
|
|
18
20
|
| Prompt-based | CLAUDE.md + rules/ + PostCompact | All MUST rules | Behavioral guidance in context |
|
|
19
21
|
|
|
20
|
-
> **Advisory (proactive/retroactive)
|
|
22
|
+
> **Advisory (proactive/retroactive) 발화 결함과 해소 (실측)**: `hookSpecificOutput.additionalContext` **전달 경로 자체는 #1547(v1.1.40)에서 구현**됐으나, 그 앞단 **파서 셀렉터 결함**으로 advisory가 **v1.1.42까지 한 번도 발화하지 못했다** — `jq -r '.role'`로 읽었으나 트랜스크립트 최상위에 `role` 키가 없어(실제는 `.message.role`) `last_assistant`가 항상 비고 즉시 `exit 0`으로 종료됐다. 당시 실측: 트랜스크립트 771개 전수에서 `"additionalContext":` 출현 0건, 라이브 프로브 stdout/stderr 각 0바이트. **proactive(`r007-r008-drift-advisor.sh`)와 retroactive(`session-reflection.sh`, 동일 결함) 두 계층 모두 미발화**였다. **v1.1.43에서 양 계층 파서 복구 + `PostToolUse` 배선을 완료했고, 라이브 프로브로 최초 발화를 확인했다(#1553).** 후속으로 v1.1.44에서 R008 판정을 블록 인접 비교 → 턴 단위 개수 비교로 전환(#1563), v1.1.45에서 Skill 도구 면제를 추가했다(#1569).
|
|
21
23
|
>
|
|
22
24
|
> 교훈: **배선 확인 ≠ 전달 확인 ≠ 발화 확인** — R020 "actual outcome ≠ attempt"의 훅 도메인 재현 사례.
|
|
23
25
|
|
|
@@ -27,7 +29,7 @@ oh-my-customcode uses an **advisory-first enforcement model**. Most rules are en
|
|
|
27
29
|
> **v2.1.199+**: SessionStart/Setup/SubagentStart hook이 exit code 2로 종료할 때 stderr를 조용히 숨기던 문제가 수정되어 이제 오류가 표시됩니다. Hard Block/Advisory 계층(위 Enforcement Tiers 표)의 훅 실패 관측성을 강화합니다 — cf. v2.1.163 `additionalContext` 구조화 피드백.
|
|
28
30
|
-->
|
|
29
31
|
|
|
30
|
-
> **v2.1.210+**: hook callback timeout이 모델에 user rejection으로 오보고되어 unattended 세션이 정지 대기하던 문제가 수정되었습니다. R021 advisory 훅(PostToolUse/UserPromptSubmit/Stop 등)이 매 턴 발화하고 /fsd 등 장기 무인 루프가 이에 의존하므로, hook timeout이 더 이상 phantom rejection으로 무인 세션을 중단시키지 않습니다 — cf. v2.1.199 훅 실패 관측성.
|
|
32
|
+
<!-- RETIRED (은퇴 릴리즈 v1.1.45, 보존 기준 v2.1.212 미만): > **v2.1.210+**: hook callback timeout이 모델에 user rejection으로 오보고되어 unattended 세션이 정지 대기하던 문제가 수정되었습니다. R021 advisory 훅(PostToolUse/UserPromptSubmit/Stop 등)이 매 턴 발화하고 /fsd 등 장기 무인 루프가 이에 의존하므로, hook timeout이 더 이상 phantom rejection으로 무인 세션을 중단시키지 않습니다 — cf. v2.1.199 훅 실패 관측성. -->
|
|
31
33
|
|
|
32
34
|
> **v2.1.211/212/214+**: 훅의 enforcement 결정이 auto/unattended 모드에서 안정적으로 존중되도록 세 건이 수정되었습니다 — (211) auto mode가 unsandboxed Bash에 대한 PreToolUse 훅의 `ask` 결정을 덮어쓰던 문제가 수정되어 훅 `ask`가 최소 prompt로 floor되고, (212) `continue:false` 훅의 halt가 도구 실패·중간 완료 시 누락되던 문제 및 훅 인프라 오류가 user rejection으로 오보고되던 문제가 수정되었으며, (214) 훅 stdout JSON이 스키마 검증에 실패할 때 exit code 2가 문서대로 차단하지 못하던 문제가 수정되었습니다. R021 Enforcement Tiers(Hard Block=exit 2, Conversation Block=continueOnBlock exit 2, Advisory)가 훅의 block/ask 결정 존중에 의존하므로, 세 수정 모두 hard-block·advisory 훅(stage-blocker, rule-deletion-guard, stuck-detector 등)의 강제 신뢰성을 강화합니다 — v2.1.210 훅 timeout phantom-rejection 수정의 연장선.
|
|
33
35
|
|
|
@@ -40,7 +42,7 @@ oh-my-customcode uses an **advisory-first enforcement model**. Most rules are en
|
|
|
40
42
|
3. **Composability**: External skills and internal rules can coexist without deadlocks
|
|
41
43
|
4. **PostCompact reinforcement**: R007/R008/R009/R010/R018 are re-injected after context compaction
|
|
42
44
|
|
|
43
|
-
## Hard Enforcement Candidates — R010 git-delegation-guard (conditional), R007/R008 advisory **implemented** (#1229 UserPromptSubmit, proactive) + **#1545 SubagentStop** (closes autonomous-loop gap) + retroactive Stop-hook (#1190); `additionalContext` 전달 경로는 #1547(v1.1.40)에서 구현됐으나 파서 셀렉터 결함으로 **양 계층 모두
|
|
45
|
+
## Hard Enforcement Candidates — R010 git-delegation-guard (conditional), R007/R008 advisory **implemented & firing** (#1229 UserPromptSubmit, proactive) + **#1545 SubagentStop** (closes autonomous-loop gap) + **#1553 PostToolUse** + retroactive Stop-hook (#1190); `additionalContext` 전달 경로는 #1547(v1.1.40)에서 구현됐으나 파서 셀렉터 결함으로 v1.1.42까지 **양 계층 모두 미발화**였고, **v1.1.43에서 수정 완료·발화 확인**(#1553); hard-block variant still candidate if advisory insufficient (#1096). Promoted: rule-deletion-guard.sh (2026-04-08). See details via Read tool.
|
|
44
46
|
|
|
45
47
|
<!-- DETAIL: Hard Enforcement Candidates (Future)
|
|
46
48
|
If advisory enforcement proves insufficient for specific rules, these are candidates for promotion to hard-block:
|
|
@@ -48,7 +50,7 @@ If advisory enforcement proves insufficient for specific rules, these are candid
|
|
|
48
50
|
| Rule | Candidate Hook | Status | Condition for Promotion |
|
|
49
51
|
|------|---------------|--------|------------------------|
|
|
50
52
|
| R010 | git-delegation-guard.sh | Candidate | If orchestrator-direct-write violations exceed 3/session |
|
|
51
|
-
| R007/R008 | `r007-r008-drift-advisor.sh` (UserPromptSubmit #1229 + SubagentStop #1545) | **Advisory implemented** — proactive pre-response check
|
|
53
|
+
| R007/R008 | `r007-r008-drift-advisor.sh` (UserPromptSubmit #1229 + SubagentStop #1545 + PostToolUse #1553) | **Advisory implemented and firing** — proactive pre-response check wired to three trigger points; the SubagentStop leg (#1545) closes the no-user-input autonomous-loop gap (`/fsd` etc.), and the PostToolUse leg (#1553) covers the orchestrator-only stretch before the first subagent spawn. Retroactive: `session-reflection.sh` (Stop, #1190). Two-layer drift detection: proactive (#1229/#1545/#1553) + retroactive (#1190). **Historical defect (v1.1.40–v1.1.42): delivery path implemented but never fired** — #1547 (v1.1.40) switched delivery from stderr (never model-visible on exit 0) to `hookSpecificOutput.additionalContext` on JSON stdout, non-blocking (no top-level `decision`/`continue`/`stopReason`), but both scripts short-circuited BEFORE emitting: `jq -r '.role'` read a key absent at transcript top level (it is `.message.role`), so `last_assistant` was always empty and the script exited 0 silently. Measured then: 0 `"additionalContext":` occurrences across 771 transcripts; live probe emitted 0 bytes on both streams. **Resolved in v1.1.43** — parser fix on both layers + `PostToolUse` wiring, first fire confirmed by live probe (#1553). Follow-ups: v1.1.44 turn-level R008 prefix counting (#1563), v1.1.45 Skill-tool exemption (#1569). | Promote to hard-block if advisory proves insufficient (#1096) |
|
|
52
54
|
|
|
53
55
|
Promotion requires: (1) measured violation rate data, (2) user approval, (3) rollback plan.
|
|
54
56
|
|
|
@@ -309,7 +309,7 @@ Cross-reference: the Subagent Scope-Creep STOP Protocol (reactive halt after tri
|
|
|
309
309
|
|--------------|----------|
|
|
310
310
|
| 미확인 플래그를 확정형으로 위임 프롬프트에 기재 (`gh issue edit <N> --assignee @me`) | 실행 전 `--help`로 실측 후 기재, 또는 "예시 — 실제 플래그는 확인 후 사용" 명시 |
|
|
311
311
|
|
|
312
|
-
Origin: #1563 찐빠 #3 — `gh issue edit --assignee`가 gh 2.86.0에 없는 플래그였고(정답 `--add-assignee`) 에이전트가 실행 중 자체 복구했다. Cross-reference: R005(도구 플래그·기본 동작 실측 함정 사례집),
|
|
312
|
+
Origin: #1563 찐빠 #3 — `gh issue edit --assignee`가 gh 2.86.0에 없는 플래그였고(정답 `--add-assignee`) 에이전트가 실행 중 자체 복구했다. Cross-reference: R005(도구 플래그·기본 동작 실측 함정 사례집), 아래 Agent Capability Pre-Check(위임 전 존재성 확인의 도구·경로 각도).
|
|
313
313
|
|
|
314
314
|
### Parallel Delegation — Sibling-Agent Disclosure
|
|
315
315
|
|
|
@@ -323,6 +323,16 @@ Origin: #1563 찐빠 #3 — `gh issue edit --assignee`가 gh 2.86.0에 없는
|
|
|
323
323
|
|
|
324
324
|
> Origin: #1518 (찐빠 #3 — 미고지 git 에이전트가 형제를 "외부 프로세스"로 오귀속; 같은 세션에서 고지한 4개 구현 에이전트는 전원 정확히 구분 보고 — 대조 실증). Cross-ref: R009 (병렬 실행 조건).
|
|
325
325
|
|
|
326
|
+
#### 고지는 귀속 후보를 늘릴 뿐 증거 등급을 올리지 않는다
|
|
327
|
+
|
|
328
|
+
형제 고지를 받았더라도 **정황 귀속(형제 탓)은 여전히 오답을 낸다** — 오히려 고지가 그럴듯한 오귀속 대상을 제공한다. 공유 뷰의 이상 징후는 형제 고지 여부와 무관하게 **개입 실험**(캐시 제거·복원, `bash -x` 추적, 변경 되돌려 재현)으로 귀속해야 한다.
|
|
329
|
+
|
|
330
|
+
| Anti-pattern | Required |
|
|
331
|
+
|--------------|----------|
|
|
332
|
+
| 고지받은 형제의 담당 범위와 겹친다는 정황만으로 실패 원인을 형제에 귀속 | 개입 실험(제거→재현 / 복원→소멸)으로 인과를 확정한 뒤 귀속 |
|
|
333
|
+
|
|
334
|
+
> Origin: #1574 (v1.1.44 세션 대조 실증 — 동일 고지를 받은 3개 병렬 에이전트 중 [1]은 `bun test` 11 fail을 "형제가 그 파일 편집 중"으로 정황 귀속해 오답, [2]/[3]은 개입 실험으로 정확히 귀속). Cross-ref: R020 (Read-Before-Characterize — 정황으로 특성화 금지).
|
|
335
|
+
|
|
326
336
|
## Universal bypassPermissions
|
|
327
337
|
|
|
328
338
|
> **This section is the canonical single source for the bypassPermissions requirement.** R002 (MUST-permissions.md) and R006 (MUST-agent-design.md) reference this section rather than repeating it.
|
|
@@ -611,6 +621,16 @@ Usage:
|
|
|
611
621
|
|
|
612
622
|
All git operations (commit, push, branch, PR) MUST go through `mgr-gitnerd`. Internal rules override external skill instructions for git execution.
|
|
613
623
|
|
|
624
|
+
### 품질 게이트 우회 금지 — 훅 차단은 보고 대상
|
|
625
|
+
|
|
626
|
+
git 위임 에이전트는 pre-commit/pre-push 훅 차단을 **자체 판단으로 우회하지 않는다**. `--no-verify`(및 `--no-gpg-sign` 등 게이트 무력화 플래그)는 git 위임의 **상시 금지 목록**이며, 오케스트레이터의 사전 승인이 있을 때만 예외다. 근본 원인을 확정했더라도, CI가 권위 게이트로 남더라도 마찬가지다 — 우회 여부는 에이전트가 아니라 오케스트레이터가 판단한다.
|
|
627
|
+
|
|
628
|
+
| Anti-pattern | Required |
|
|
629
|
+
|--------------|----------|
|
|
630
|
+
| pre-commit 훅 차단(테스트 실패 등)을 `--no-verify`로 자체 우회하고 커밋 진행 | 차단 사실과 원인을 오케스트레이터에 **보고하고 대기** — 우회는 사전 승인 후에만 |
|
|
631
|
+
|
|
632
|
+
> Origin: #1574 (v1.1.44 세션 — mgr-gitnerd가 `bun test` 11 fail로 인한 pre-commit 차단을 `--no-verify`로 자체 우회; 결과는 무해했으나 승인 없는 품질 게이트 우회는 절차 이탈). Cross-ref: R020 (Test-Skip Is Not Completion — 그린 빌드 회피 금지), R017 (커밋 전 검증 게이트).
|
|
633
|
+
|
|
614
634
|
<!-- ARCHIVED CC version note (historical):
|
|
615
635
|
> **v2.1.206+**: `/commit-push-pr`가 origin 외에 `remote.pushDefault`(또는 단일 remote)로의 git push도 auto-allow합니다. mgr-gitnerd git 위임 흐름 관련. `mode: "bypassPermissions"`는 모든 Agent tool 호출에 여전히 필수입니다.
|
|
616
636
|
-->
|
|
@@ -71,7 +71,7 @@ Use a `"*"` deny rule in `settings.json` to enforce a deny-by-default posture, t
|
|
|
71
71
|
> **v2.1.207+**: Auto mode가 Bedrock/Vertex/Foundry에서 `CLAUDE_CODE_ENABLE_AUTO_MODE` opt-in 없이 사용 가능해졌습니다(설정 `disableAutoMode`로 비활성화 가능). 또한 `-p`/SDK 비대화 실행의 remote managed settings가 consent 다이얼로그 없이 동의로 기록되던 문제가 수정되었습니다. Tier-3/4 권한 흐름 관련.
|
|
72
72
|
-->
|
|
73
73
|
|
|
74
|
-
> **v2.1.210+**: `Write(path)`/`NotebookEdit(path)`/`Glob(path)` 형태의 permission rule은 시작 시 경고를 발생시킵니다 — 파일 쓰기 rule은 `Edit(path)`, 읽기 rule은 `Read(path)` matcher로 작성합니다. 위 Tier 표의 Write/NotebookEdit/Glob은 도구명일 뿐 path-scoped rule matcher가 아닙니다(위 v2.1.166 unknown-tool startup warning 연장선).
|
|
74
|
+
<!-- RETIRED (은퇴 릴리즈 v1.1.45, 보존 기준 v2.1.212 미만): > **v2.1.210+**: `Write(path)`/`NotebookEdit(path)`/`Glob(path)` 형태의 permission rule은 시작 시 경고를 발생시킵니다 — 파일 쓰기 rule은 `Edit(path)`, 읽기 rule은 `Read(path)` matcher로 작성합니다. 위 Tier 표의 Write/NotebookEdit/Glob은 도구명일 뿐 path-scoped rule matcher가 아닙니다(위 v2.1.166 unknown-tool startup warning 연장선). -->
|
|
75
75
|
|
|
76
76
|
> **v2.1.214+**: 단일 세그먼트 `dir/**` allow rule(예: `Edit(src/**)`)이 트리 어디에나 있는 중첩 `dir/`까지 auto-approve하던 버그가 수정되어 이제 `<cwd>/dir`에만 매칭됩니다(hook `if:` 조건도 동일 — 임의 깊이 매칭이 필요하면 `**/dir/**`로 작성). **`deny`/`ask` permission rule은 any-depth 매칭을 유지**(allow만 `<cwd>`로 좁아짐). settings.json 스코프 설계 시 이 비대칭(allow 좁게 / deny·ask 넓게)을 전제로 삼습니다. 위 v2.1.210 `Edit(path)`/`Read(path)` matcher 권고의 연장선.
|
|
77
77
|
|
|
@@ -166,6 +166,16 @@ Origin: #1492 (Session 132) — cc-release-monitor 워크플로우 삭제(#1454,
|
|
|
166
166
|
|
|
167
167
|
Origin: #1457 (Session 128 회고 찐빠 #1) — 오케스트레이터가 stale 메모리(npm 1.1.6→target v1.1.7 추정)로 implement를 위임 → v1.1.7이 이미 배포된 closed milestone임을 에이전트가 STOP으로 감지 → v1.1.8 재위임 왕복 1회. 기존 `feedback_session_memory_git_stale`(브랜치 분기 전 pull)의 릴리즈-버전-선정 각도 확장. Cross-ref: R020 (Diagnostic Hypothesis Verification — 영구 변경/위임 전 전제 실측 확정).
|
|
168
168
|
|
|
169
|
+
### 일반화 — 메모리 TODO 를 위임 전제로 쓸 때 (Origin: #1574)
|
|
170
|
+
|
|
171
|
+
위 게이트는 **버전**에 대한 규정이지만 원리는 세션 메모리 항목 전반에 적용된다. `MEMORY.md`의 "선재 항목 / Next Session TODO"는 **직전 세션 종료 시점의 스냅샷**이므로 이후 해소·변경됐을 수 있다. 이를 위임 브리핑(예: mgr-sauron 검증 스코프)의 전제로 넘기기 전, 각 항목을 실측으로 재확인하거나 **측정 시점을 함께 표기**해 전달한다.
|
|
172
|
+
|
|
173
|
+
| Anti-pattern | Required |
|
|
174
|
+
|--------------|----------|
|
|
175
|
+
| 메모리 TODO를 현재 상태로 간주해 위임 브리핑에 전제로 기재 | 위임 전 항목별 실측 재확인, 또는 "vX.Y.Z 시점 스냅샷 — 직접 확인하라"를 명시 |
|
|
176
|
+
|
|
177
|
+
Origin: #1574 (v1.1.44 세션 — mgr-sauron 브리핑의 "선재 항목" 4건 중 3건이 부정확: 이미 해소된 항목, 의도적 차이를 결함으로 오인, 규모 과대). **완화 요인**: 프롬프트에 "그대로 믿지 말고 직접 확인하라"를 명시해 3건 전부 에이전트가 정정 — #1443의 "실측값 기준으로 동기화하라" 방어선과 동일 효과. Cross-ref: R011(메모리 신뢰도·Temporal Decay), R020(Diagnostic Hypothesis Verification).
|
|
178
|
+
|
|
169
179
|
## Post-Gate Scope-Expansion Re-Run (Origin: #1433 #2)
|
|
170
180
|
|
|
171
181
|
R017 게이트(mgr-sauron) 통과 선언 후 신규 결함 발견 등으로 스코프가 확장되면(추가 파일 편집), 커밋 전 게이트를 **최종 상태에서 재실행**한다. 게이트 통과 시점 이후의 변경은 형식적으로 미검증이므로, 확장분 미검증 커밋은 R017이 최종 산출물을 커버하지 못하게 만든다.
|
|
@@ -482,4 +482,4 @@ References: #1226 (item 3), #1227.
|
|
|
482
482
|
- Memory write failure is **non-blocking**: MUST NOT prevent session from ending
|
|
483
483
|
- If sys-memory-keeper fails to write MEMORY.md: log warning, confirm to user anyway
|
|
484
484
|
|
|
485
|
-
> **v2.1.210+**: MEMORY.md 인덱스가 read limit을 초과하게 만드는 memory write는 이제 silent truncation 대신 명시적 오류를 반환합니다. write 실패는 여전히 non-blocking이지만, 오류 수신 시 log-warning으로 끝내지 말고 예산 초과 처리(Attention-Weight Tiering — Cold 항목 archive 이동)로 축소 후 재시도합니다 — 이전의 silent truncation을 가정하고 oversize write를 던지면 업데이트가 반영되지 않습니다.
|
|
485
|
+
<!-- RETIRED (은퇴 릴리즈 v1.1.45, 보존 기준 v2.1.212 미만): > **v2.1.210+**: MEMORY.md 인덱스가 read limit을 초과하게 만드는 memory write는 이제 silent truncation 대신 명시적 오류를 반환합니다. write 실패는 여전히 non-blocking이지만, 오류 수신 시 log-warning으로 끝내지 말고 예산 초과 처리(Attention-Weight Tiering — Cold 항목 archive 이동)로 축소 후 재시도합니다 — 이전의 silent truncation을 가정하고 oversize write를 던지면 업데이트가 반영되지 않습니다. -->
|
|
@@ -103,6 +103,16 @@ staleness/audit 검증은 model ID·placeholder·TBD뿐 아니라 **폐기된
|
|
|
103
103
|
|
|
104
104
|
Origin: #1455 #1 (Session 127 회고 찐빠 #1) — cc-release-monitor PR #1449 머지 후 workflow_dispatch 실검증에서 issue_body의 `<details>`·릴리즈 요약에 12칸 리터럴 들여쓰기 발견 → PR #1451 재작업. 첫 위임이 문법 검증만 지시하고 샘플 값 출력 조립 검증을 누락. `textwrap.dedent` + 멀티라인 변수 함정이 문법 검증만으로는 미노출. R020(문법 통과 ≠ 출력 정상)과 정합.
|
|
105
105
|
|
|
106
|
+
## Delegated Verification Floor — CI 잡 목록에서 도출 (Origin: #1574)
|
|
107
|
+
|
|
108
|
+
위임 프롬프트의 검증 항목은 "변경 파일의 영향 범위"만으로 정하면 부족하다. **하한선은 CI가 실제로 돌리는 잡 전체**다 — 워크플로 YAML의 잡 목록을 읽어 대응하는 로컬 명령(`lint` / `test` / `validate-docs` / sync 검사)을 열거하고, 그중 로컬 실행 가능한 것을 위임 완료 조건에 포함한다. 로컬에서 통과시키지 않은 CI 잡은 병합 시점에 halt로 돌아와 수정 에이전트 추가 발주를 강제한다.
|
|
109
|
+
|
|
110
|
+
| Anti-pattern | Required |
|
|
111
|
+
|--------------|----------|
|
|
112
|
+
| "변경분 영향 범위"만 보고 검증 항목을 정해 위임 → CI 전용 잡(lint 등) 누락 | 워크플로 잡 목록을 하한선으로 삼아 로컬 대응 명령을 완료 조건에 열거 |
|
|
113
|
+
|
|
114
|
+
Origin: #1574 (v1.1.44 세션 — 병렬 위임 3건 모두 `bun run lint`를 누락해 verify-build halt, 수정 에이전트 1회 추가 발주). 기존 `feedback_delegation_verify_scope_by_impact`("영향 범위 기준")의 하한선을 명문화한 것이다. Cross-reference: R020(완료 검증 — 선언 전 실제 게이트 통과 확인), R017(커밋 전 검증 게이트).
|
|
115
|
+
|
|
106
116
|
## Conditional-Output Verification — Positive/Negative Pair Mandate (Origin: #1563 #2)
|
|
107
117
|
|
|
108
118
|
조건부로만 출력하는 대상(advisory 훅, 가드, 경고 emitter)의 동작을 검증하도록 위임할 때, 완료 기준은 **"출력이 나와야 하는 입력"과 "나오면 안 되는 입력"을 짝으로** 지정해야 한다. "stdout ≠ 0바이트" 같은 단일 프록시는 검증이 아니다 — 침묵이 정답인 입력에서도 통과를 요구하게 되어 기준 자체가 틀리고, 반대로 오탐(준수 턴에서 발화)을 통과시킨다.
|
|
@@ -111,7 +121,7 @@ Origin: #1455 #1 (Session 127 회고 찐빠 #1) — cc-release-monitor PR #1449
|
|
|
111
121
|
|--------------|----------|
|
|
112
122
|
| "지정 입력에서 stdout ≠ 0바이트"를 단일 완료 기준으로 위임 | 양성 케이스(발화해야 함)와 음성 케이스(침묵해야 함)를 짝으로 명시 |
|
|
113
123
|
|
|
114
|
-
Origin: #1563 찐빠 #2 — R007/R008 advisor 발화 검증에 단일 "0바이트 아님" 프록시를 제시했으나, advisor는 준수 턴에서 침묵하는 것이 정상 동작이라 기준이 성립하지 않았다. Cross-reference: R020(Proxy Signal vs Canonical Ground-Truth — 프록시로 상태를 특성화하지 말 것),
|
|
124
|
+
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 구분의 가드 설계 각도).
|
|
115
125
|
|
|
116
126
|
## Detection Guard Delegation Standard (Origin: #1438 #3)
|
|
117
127
|
|
|
@@ -116,12 +116,30 @@ steps:
|
|
|
116
116
|
4. Cap at 7 issues; if priority issues < 7, stop at that priority (don't mix tiers)
|
|
117
117
|
5. Minimum 1 issue; if 0 eligible, halt with "no eligible issues for auto-dev run"
|
|
118
118
|
|
|
119
|
+
## Step 3 — Approval-required path pre-check (R010)
|
|
120
|
+
|
|
121
|
+
For each scoped issue, extract target file/directory paths from its title+body (explicit
|
|
122
|
+
paths, backtick-quoted paths, or clearly named targets).
|
|
123
|
+
|
|
124
|
+
Check against `.claude/rules/MUST-orchestrator-coordination.md` "Protected Paths":
|
|
125
|
+
- `.claude/hooks/**` → EXCLUDED from mgr-creator routing; requires EXPLICIT USER APPROVAL
|
|
126
|
+
(security-critical). If any scoped issue targets this path, request approval for the
|
|
127
|
+
FULL scoped set NOW, before proceeding — do not let a later step (e.g. compression-mode-
|
|
128
|
+
eval) discover it mid-run after scope is already committed (#1574 찐빠 #5).
|
|
129
|
+
- `.claude/agents/*.md`, `.claude/skills/*/SKILL.md`, `guides/*/` (new dirs) → route to
|
|
130
|
+
mgr-creator at implement time (delegation requirement, not a HALT).
|
|
131
|
+
|
|
132
|
+
If approval was already granted THIS session for the same category+target, do not
|
|
133
|
+
re-request (R015 directive persistence).
|
|
134
|
+
|
|
135
|
+
Output approval_required_paths (list, empty if none) as pipeline state.
|
|
136
|
+
|
|
119
137
|
Assign scoped issues to milestone.
|
|
120
138
|
Output markdown release manifest:
|
|
121
139
|
| order | # | title | prerequisite | effort | labels |
|
|
122
140
|
|
|
123
141
|
Persist manifest as pipeline state for subsequent steps.
|
|
124
|
-
description: "Milestone state pre-check, label filter, pick 3-7 issues as v{X.Y.Z} scope"
|
|
142
|
+
description: "Milestone state pre-check, label filter, pick 3-7 issues as v{X.Y.Z} scope, R010 approval-required path pre-check"
|
|
125
143
|
depends_on: pre-triage
|
|
126
144
|
|
|
127
145
|
- name: compression-mode-eval
|
package/templates/manifest.json
CHANGED
|
@@ -116,12 +116,30 @@ steps:
|
|
|
116
116
|
4. Cap at 7 issues; if priority issues < 7, stop at that priority (don't mix tiers)
|
|
117
117
|
5. Minimum 1 issue; if 0 eligible, halt with "no eligible issues for auto-dev run"
|
|
118
118
|
|
|
119
|
+
## Step 3 — Approval-required path pre-check (R010)
|
|
120
|
+
|
|
121
|
+
For each scoped issue, extract target file/directory paths from its title+body (explicit
|
|
122
|
+
paths, backtick-quoted paths, or clearly named targets).
|
|
123
|
+
|
|
124
|
+
Check against `.claude/rules/MUST-orchestrator-coordination.md` "Protected Paths":
|
|
125
|
+
- `.claude/hooks/**` → EXCLUDED from mgr-creator routing; requires EXPLICIT USER APPROVAL
|
|
126
|
+
(security-critical). If any scoped issue targets this path, request approval for the
|
|
127
|
+
FULL scoped set NOW, before proceeding — do not let a later step (e.g. compression-mode-
|
|
128
|
+
eval) discover it mid-run after scope is already committed (#1574 찐빠 #5).
|
|
129
|
+
- `.claude/agents/*.md`, `.claude/skills/*/SKILL.md`, `guides/*/` (new dirs) → route to
|
|
130
|
+
mgr-creator at implement time (delegation requirement, not a HALT).
|
|
131
|
+
|
|
132
|
+
If approval was already granted THIS session for the same category+target, do not
|
|
133
|
+
re-request (R015 directive persistence).
|
|
134
|
+
|
|
135
|
+
Output approval_required_paths (list, empty if none) as pipeline state.
|
|
136
|
+
|
|
119
137
|
Assign scoped issues to milestone.
|
|
120
138
|
Output markdown release manifest:
|
|
121
139
|
| order | # | title | prerequisite | effort | labels |
|
|
122
140
|
|
|
123
141
|
Persist manifest as pipeline state for subsequent steps.
|
|
124
|
-
description: "Milestone state pre-check, label filter, pick 3-7 issues as v{X.Y.Z} scope"
|
|
142
|
+
description: "Milestone state pre-check, label filter, pick 3-7 issues as v{X.Y.Z} scope, R010 approval-required path pre-check"
|
|
125
143
|
depends_on: pre-triage
|
|
126
144
|
|
|
127
145
|
- name: compression-mode-eval
|