@walwal-harness/cli 5.7.0 → 5.7.1

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/bin/init.js CHANGED
@@ -1017,15 +1017,14 @@ function main() {
1017
1017
  log('║ Then say: "하네스 엔지니어링 시작" ║');
1018
1018
  log('║ Or invoke: /harness-dispatcher ║');
1019
1019
  log('║ ║');
1020
- log('║ After Planner completes: ║');
1021
- log('║ /harness-team → Team mode (auto parallel) ║');
1022
- log('║ /harness-solo → Solo mode (prompting sequential) ║');
1020
+ log('║ 기본은 Solo 모드 (순차 진행) — 입력 불필요. ║');
1021
+ log('║ 병렬 3팀 실행을 원하면 파이프라인 확정 후 /harness-team ║');
1023
1022
  log('╚═══════════════════════════════════════════════════════════╝');
1024
1023
  } else {
1025
1024
  log('Next steps:');
1026
1025
  log(' 1. Restart Claude Code session (/exit → re-enter directory)');
1027
1026
  log(' 2. Say "하네스 엔지니어링 시작" or /harness-dispatcher');
1028
- log(' 3. After Planner: /harness-team (team) or keep prompting (solo)');
1027
+ log(' 3. Solo 모드는 자동. Team 모드 원할 때만 파이프라인 확정 후 /harness-team');
1029
1028
  }
1030
1029
  console.log('');
1031
1030
  }
package/gotchas/README.md CHANGED
@@ -19,19 +19,36 @@
19
19
  ## 항목 형식
20
20
 
21
21
  ```markdown
22
- ### [G-NNN] 간결한 제목
22
+ ### [G-NNN] 간결한 제목 <!-- rule_id: <unique-key> -->
23
+ - **Status**: unverified | verified | resolved
23
24
  - **Date**: YYYY-MM-DD
24
- - **Trigger**: 사용자가 한 말 (원문 요약)
25
+ - **Source**: <작성 주체> (예: "evaluator-functional:F-003" / "dispatcher:manual")
26
+ - **Trigger**: 사용자가 한 말 또는 "Eval 자동 감지"
25
27
  - **Wrong**: 에이전트가 했던 잘못된 행동
26
28
  - **Right**: 올바른 행동
27
29
  - **Why**: 왜 잘못인지 근거
28
30
  - **Scope**: 이 규칙이 적용되는 조건/범위
31
+ - **Occurrences**: 1
32
+ - **Last-Seen**: YYYY-MM-DD
29
33
  ```
30
34
 
35
+ ## 작성 주체
36
+
37
+ - **Dispatcher**: 사용자의 명시적 실수 지적을 Gotcha Flow 로 기록
38
+ - **Evaluator (code-quality / functional / visual)**: evaluation-*.md 의 `gotcha_candidates` JSON 블록을 통해 자동 등록 (v5.7.1+). `harness-next.sh` 가 Evaluator 완료 직후 `scripts/harness-gotcha-register.sh --scan-evaluations` 로 처리.
39
+
40
+ ## Status 라이프사이클 (v5.7.1+)
41
+
42
+ - **unverified**: 신규 자동/수동 등록 기본값. Generator 는 참조하지만 페널티 강도 낮음.
43
+ - **verified**: Planner/사용자 리뷰 후 승격. 이후 위반 시 하드 페널티.
44
+ - **resolved**: 근본 원인이 코드/스킬/컨벤션에 반영되어 더 이상 재발하지 않는 항목. 삭제 대신 태그 유지.
45
+
46
+ Planner 는 스프린트 전환 시 `unverified` 항목을 검토해 `verified` 또는 제거 판정을 내린다 (AGENTS.md "메모리 오염 방어" 섹션).
47
+
31
48
  ## 관리 규칙
32
49
 
33
- - Dispatcher만 gotchas 파일에 쓰기 가능
50
+ - Dispatcher + Evaluator 만 gotchas 파일에 쓰기 가능 (자동 등록 포함)
34
51
  - 각 에이전트는 자신의 gotchas 파일을 읽기 전용으로 참조
35
- - 중복 항목 금지 — 같은 실수는 기존 항목에 횟수 증가
36
- - 해결된 항목은 삭제하지 않고 `[RESOLVED]` 태그 추가
37
- - 항목이 20개 초과 시 가장 오래된 RESOLVED 항목부터 정리
52
+ - 중복 항목 금지 — 동일 `rule_id` 는 `Occurrences` + `Last-Seen` 만 갱신
53
+ - 해결된 항목: `Status: resolved` 또는 제목 뒤 `[RESOLVED]` 태그
54
+ - 항목이 20개 초과 시 가장 오래된 resolved 항목부터 정리
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@walwal-harness/cli",
3
- "version": "5.7.0",
3
+ "version": "5.7.1",
4
4
  "description": "Production harness for AI agent engineering — Solo/Team mode, Planner, Generator(BE/FE), Evaluator chain (Code-Quality → Functional → Visual), optional Brainstormer. Supports React, Next.js, and Flutter FE stacks.",
5
5
  "bin": {
6
6
  "walwal-harness": "bin/init.js"
@@ -0,0 +1,259 @@
1
+ #!/bin/bash
2
+ # harness-gotcha-register.sh — Evaluator → Gotcha 자동 등록 파이프라인
3
+ #
4
+ # 사용법:
5
+ # 1) 단일 항목 등록 (수동/스크립트):
6
+ # bash harness-gotcha-register.sh <project-root> \
7
+ # --target <agent> \
8
+ # --rule-id <rule-id> \
9
+ # --title "제목" \
10
+ # --wrong "잘못된 행동" \
11
+ # --right "올바른 행동" \
12
+ # --why "근거" \
13
+ # --scope "적용 범위" \
14
+ # --source "evaluator-functional:F-003"
15
+ #
16
+ # 2) 일괄 등록 (JSON stdin/파일):
17
+ # bash harness-gotcha-register.sh <project-root> --from-json <path>
18
+ # bash harness-gotcha-register.sh <project-root> --scan-evaluations
19
+ # └ .harness/actions/evaluation-*.md 의 ```gotcha_candidates``` 블록 전부 스캔
20
+ #
21
+ # 동작:
22
+ # - 대상 파일: .harness/gotchas/<target>.md (없으면 생성)
23
+ # - 중복 감지: 동일 rule_id 가 있으면 Occurrences +1, last_seen 갱신 (본문 수정 없음)
24
+ # - 신규: 다음 G-NNN 할당, Status: unverified 로 기록
25
+ # - 등록 성공 로그: .harness/progress.log 에 한 줄 append
26
+ #
27
+ # 등록 형식:
28
+ # ### [G-NNN] <title> <!-- rule_id: <rule-id> -->
29
+ # - **Status**: unverified
30
+ # - **Date**: YYYY-MM-DD
31
+ # - **Source**: <source> (예: "evaluator-functional:F-003")
32
+ # - **Trigger**: Eval 자동 감지
33
+ # - **Wrong**: <wrong>
34
+ # - **Right**: <right>
35
+ # - **Why**: <why>
36
+ # - **Scope**: <scope>
37
+ # - **Occurrences**: 1
38
+ # - **Last-Seen**: YYYY-MM-DD
39
+
40
+ set -euo pipefail
41
+
42
+ if [ $# -lt 1 ]; then
43
+ echo "usage: harness-gotcha-register.sh <project-root> [options]" >&2
44
+ exit 1
45
+ fi
46
+
47
+ PROJECT_ROOT="$1"
48
+ shift
49
+ PROJECT_ROOT="$(cd "$PROJECT_ROOT" && pwd)"
50
+
51
+ command -v jq >/dev/null 2>&1 || { echo "[gotcha-register] ERROR: jq required" >&2; exit 1; }
52
+
53
+ GOTCHAS_DIR="$PROJECT_ROOT/.harness/gotchas"
54
+ ACTIONS_DIR="$PROJECT_ROOT/.harness/actions"
55
+ mkdir -p "$GOTCHAS_DIR"
56
+
57
+ TODAY="$(date +%Y-%m-%d)"
58
+
59
+ # ─────────────────────────────────────────
60
+ # 단일 항목을 .harness/gotchas/<target>.md 에 append
61
+ # $1: target agent (generator-backend, generator-frontend, evaluator-functional, ...)
62
+ # $2: rule_id (dedup key)
63
+ # $3: title
64
+ # $4: wrong
65
+ # $5: right
66
+ # $6: why
67
+ # $7: scope
68
+ # $8: source
69
+ # ─────────────────────────────────────────
70
+ register_one() {
71
+ local target="$1" rule_id="$2" title="$3" wrong="$4" right="$5" why="$6" scope="$7" source="$8"
72
+ local file="$GOTCHAS_DIR/${target}.md"
73
+
74
+ # Ensure file exists with header
75
+ if [ ! -f "$file" ]; then
76
+ cat > "$file" <<EOF
77
+ # Gotchas — $target
78
+
79
+ > Dispatcher + Evaluator 가 관리. $target 은 세션 시작 시 이 파일을 읽고 같은 실수를 반복하지 않습니다.
80
+ > 신규 항목은 \`Status: unverified\` 로 기록되고, Planner 리뷰 후 \`verified\` 로 승격됩니다.
81
+
82
+ EOF
83
+ fi
84
+
85
+ # Dedup by rule_id marker comment
86
+ if grep -qE "<!-- rule_id: ${rule_id} -->" "$file" 2>/dev/null; then
87
+ # Bump Occurrences + Last-Seen for matching block
88
+ awk -v rid="$rule_id" -v today="$TODAY" '
89
+ BEGIN { in_block = 0 }
90
+ /^### \[G-[0-9]+\].*<!-- rule_id: / {
91
+ in_block = (index($0, "rule_id: " rid " ") > 0 || index($0, "rule_id: " rid "\n") > 0 || $0 ~ ("rule_id: " rid " -->"))
92
+ }
93
+ in_block && /^- \*\*Occurrences\*\*:/ {
94
+ n = $NF + 0
95
+ print "- **Occurrences**: " (n + 1)
96
+ next
97
+ }
98
+ in_block && /^- \*\*Last-Seen\*\*:/ {
99
+ print "- **Last-Seen**: " today
100
+ next
101
+ }
102
+ /^### / && !/<!-- rule_id: / { in_block = 0 }
103
+ { print }
104
+ ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
105
+ echo "[gotcha-register] $target: dedup $rule_id (occurrence bumped)"
106
+ return 0
107
+ fi
108
+
109
+ # Allocate next G-NNN (|| true — pipefail-safe when no existing entries)
110
+ local next_num=""
111
+ next_num=$(grep -oE '^### \[G-[0-9]+\]' "$file" 2>/dev/null | grep -oE '[0-9]+' | sort -n | tail -1 || true)
112
+ next_num=$((${next_num:-0} + 1))
113
+ local g_id
114
+ g_id=$(printf 'G-%03d' "$next_num")
115
+
116
+ # Append new block
117
+ {
118
+ echo ""
119
+ echo "### [$g_id] $title <!-- rule_id: $rule_id -->"
120
+ echo "- **Status**: unverified"
121
+ echo "- **Date**: $TODAY"
122
+ echo "- **Source**: $source"
123
+ echo "- **Trigger**: Eval 자동 감지"
124
+ echo "- **Wrong**: $wrong"
125
+ echo "- **Right**: $right"
126
+ echo "- **Why**: $why"
127
+ echo "- **Scope**: $scope"
128
+ echo "- **Occurrences**: 1"
129
+ echo "- **Last-Seen**: $TODAY"
130
+ } >> "$file"
131
+
132
+ echo "[gotcha-register] $target: registered $g_id ($rule_id) — unverified"
133
+
134
+ # Log to progress.log if present
135
+ local progress_log="$PROJECT_ROOT/.harness/progress.log"
136
+ if [ -f "$progress_log" ]; then
137
+ echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) [gotcha] $target $g_id unverified — $title (source: $source)" >> "$progress_log"
138
+ fi
139
+ }
140
+
141
+ # ─────────────────────────────────────────
142
+ # JSON 배열에서 일괄 등록
143
+ # schema: [{ target, rule_id, title, wrong, right, why, scope, source }]
144
+ # ─────────────────────────────────────────
145
+ register_from_json() {
146
+ local json="$1"
147
+ local count
148
+ count=$(echo "$json" | jq 'length' 2>/dev/null || echo 0)
149
+ if [ "$count" -eq 0 ]; then
150
+ return 0
151
+ fi
152
+
153
+ local i
154
+ for ((i=0; i<count; i++)); do
155
+ local t r ti w ri wh sc so
156
+ t=$(echo "$json" | jq -r ".[$i].target // empty")
157
+ r=$(echo "$json" | jq -r ".[$i].rule_id // empty")
158
+ ti=$(echo "$json" | jq -r ".[$i].title // empty")
159
+ w=$(echo "$json" | jq -r ".[$i].wrong // empty")
160
+ ri=$(echo "$json" | jq -r ".[$i].right // empty")
161
+ wh=$(echo "$json" | jq -r ".[$i].why // empty")
162
+ sc=$(echo "$json" | jq -r ".[$i].scope // \"항상\"")
163
+ so=$(echo "$json" | jq -r ".[$i].source // \"evaluator:auto\"")
164
+
165
+ if [ -z "$t" ] || [ -z "$r" ] || [ -z "$ti" ]; then
166
+ echo "[gotcha-register] skip: missing target/rule_id/title at index $i" >&2
167
+ continue
168
+ fi
169
+ register_one "$t" "$r" "$ti" "$w" "$ri" "$wh" "$sc" "$so"
170
+ done
171
+ }
172
+
173
+ # ─────────────────────────────────────────
174
+ # evaluation-*.md 스캔 — ```gotcha_candidates ... ``` JSON fenced block 추출
175
+ # ─────────────────────────────────────────
176
+ scan_evaluations() {
177
+ if [ ! -d "$ACTIONS_DIR" ]; then return 0; fi
178
+ local f
179
+ for f in "$ACTIONS_DIR"/evaluation-*.md; do
180
+ [ -f "$f" ] || continue
181
+
182
+ # Enumerate blocks — simple per-file awk that prints each block into a
183
+ # uniquely-named temp file. Avoids macOS awk \0 quirks.
184
+ local blocks_prefix
185
+ blocks_prefix=$(mktemp -d)
186
+ awk -v dir="$blocks_prefix" '
187
+ BEGIN { idx=0 }
188
+ /^```gotcha_candidates[[:space:]]*$/ { flag=1; buf=""; next }
189
+ /^```[[:space:]]*$/ && flag {
190
+ flag=0
191
+ idx++
192
+ outfile = sprintf("%s/block-%03d.json", dir, idx)
193
+ print buf > outfile
194
+ close(outfile)
195
+ buf=""
196
+ next
197
+ }
198
+ flag { buf = buf $0 "\n" }
199
+ ' "$f"
200
+
201
+ local blockfile
202
+ for blockfile in "$blocks_prefix"/block-*.json; do
203
+ [ -f "$blockfile" ] || continue
204
+ if jq empty "$blockfile" 2>/dev/null; then
205
+ register_from_json "$(cat "$blockfile")"
206
+ else
207
+ echo "[gotcha-register] skip: invalid JSON block in $(basename "$f")" >&2
208
+ fi
209
+ done
210
+ rm -rf "$blocks_prefix"
211
+ done
212
+ }
213
+
214
+ # ─────────────────────────────────────────
215
+ # Parse CLI
216
+ # ─────────────────────────────────────────
217
+ TARGET=""
218
+ RULE_ID=""
219
+ TITLE=""
220
+ WRONG=""
221
+ RIGHT=""
222
+ WHY=""
223
+ SCOPE="항상"
224
+ SOURCE="evaluator:auto"
225
+ MODE="single"
226
+ FROM_JSON=""
227
+
228
+ while [ $# -gt 0 ]; do
229
+ case "$1" in
230
+ --target) TARGET="$2"; shift 2 ;;
231
+ --rule-id) RULE_ID="$2"; shift 2 ;;
232
+ --title) TITLE="$2"; shift 2 ;;
233
+ --wrong) WRONG="$2"; shift 2 ;;
234
+ --right) RIGHT="$2"; shift 2 ;;
235
+ --why) WHY="$2"; shift 2 ;;
236
+ --scope) SCOPE="$2"; shift 2 ;;
237
+ --source) SOURCE="$2"; shift 2 ;;
238
+ --from-json) MODE="json"; FROM_JSON="$2"; shift 2 ;;
239
+ --scan-evaluations) MODE="scan"; shift ;;
240
+ *) echo "[gotcha-register] unknown arg: $1" >&2; exit 1 ;;
241
+ esac
242
+ done
243
+
244
+ case "$MODE" in
245
+ single)
246
+ if [ -z "$TARGET" ] || [ -z "$RULE_ID" ] || [ -z "$TITLE" ]; then
247
+ echo "[gotcha-register] usage: --target X --rule-id Y --title Z [...]" >&2
248
+ exit 1
249
+ fi
250
+ register_one "$TARGET" "$RULE_ID" "$TITLE" "$WRONG" "$RIGHT" "$WHY" "$SCOPE" "$SOURCE"
251
+ ;;
252
+ json)
253
+ if [ ! -f "$FROM_JSON" ]; then echo "[gotcha-register] file not found: $FROM_JSON" >&2; exit 1; fi
254
+ register_from_json "$(cat "$FROM_JSON")"
255
+ ;;
256
+ scan)
257
+ scan_evaluations
258
+ ;;
259
+ esac
@@ -314,6 +314,23 @@ if [ "$agent_status" = "completed" ]; then
314
314
  verify_file_ownership "$PROJECT_ROOT" || audit_gate "file-ownership" "warn" "boundary violation detected"
315
315
  fi
316
316
 
317
+ # ─────────────────────────────────────────
318
+ # Auto Gotcha Registration — Evaluator 완료 직후 evaluation-*.md 스캔
319
+ # evaluation-*.md 내부의 ```gotcha_candidates``` JSON 블록을 읽어
320
+ # .harness/gotchas/<target>.md 에 unverified 상태로 등록/dedup.
321
+ # ─────────────────────────────────────────
322
+ case "$current_agent" in
323
+ evaluator-*)
324
+ if [ "$agent_status" = "completed" ] || [ "$agent_status" = "failed" ]; then
325
+ if [ -x "$SCRIPT_DIR/harness-gotcha-register.sh" ]; then
326
+ bash "$SCRIPT_DIR/harness-gotcha-register.sh" "$PROJECT_ROOT" --scan-evaluations 2>&1 \
327
+ | grep -E '^\[gotcha-register\]' || true
328
+ audit_gate "gotcha-register" "scan" "$current_agent"
329
+ fi
330
+ fi
331
+ ;;
332
+ esac
333
+
317
334
  # ─────────────────────────────────────────
318
335
  # Run Pre-Eval Gate (if applicable)
319
336
  # ─────────────────────────────────────────
@@ -83,6 +83,7 @@ fi
83
83
  # ─────────────────────────────────────────
84
84
  if [ "$sprint_status" = "init" ]; then
85
85
  echo "# Harness ready — say \"하네스 엔지니어링 시작\" or /harness-dispatcher"
86
+ echo "# 기본은 Solo 모드. 병렬 3팀 실행을 원하면 Planner 완료 후 /harness-team."
86
87
  exit 0
87
88
  fi
88
89
 
@@ -152,6 +152,28 @@ AGENTS.md 비하네스 → 기존 백업 + 리빌드
152
152
 
153
153
  `.harness/actions/pipeline.json` 생성 → 사용자 확인 → Session Boundary Protocol On Complete 실행
154
154
 
155
+ ### Mode Recommendation (v5.7.1+)
156
+
157
+ ⚠️ **Dispatcher → Planner 전환 시에는 mode 질문을 하지 않는다.** Planner 는 mode 와 무관한 단일 실행이다. 과거의 "harness-solo 를 입력하세요" 안내는 제거.
158
+
159
+ 파이프라인이 확정되면 (Planner 호출 직전) **단 한 문단** 으로 Mode 추천을 출력하되, 응답을 기다리지 않고 **default=solo 로 그대로 진행**한다. 사용자가 team 을 원하면 언제든 `/harness-team` 으로 전환 가능.
160
+
161
+ 추천 로직:
162
+ - Planner 가 feature-list.json 을 확정한 뒤 `features.length >= 3` 이고 서로 의존성이 낮으면 → "Team 모드 권장" 안내
163
+ - `features.length < 3` 또는 단일 feature 연속 작업 → "Solo 모드 권장" 안내
164
+ - Dispatcher 단계에서는 feature 수를 모를 수 있으므로 **기본은 Solo 진행**, Planner 완료 후 자동으로 재평가
165
+
166
+ 출력 예:
167
+ ```
168
+ Pipeline: FULLSTACK 확정. Solo 모드로 자동 진행합니다.
169
+ (병렬 3팀 실행을 원하면 Planner 완료 후 /harness-team 입력)
170
+ ```
171
+
172
+ **금지**:
173
+ - "solo 입력하세요 / team 입력하세요" 식의 선택 강요
174
+ - mode 결정을 기다리며 Planner 호출을 보류하는 것
175
+ - 이미 mode 가 설정된 상태(`progress.json.mode` 존재)에서 재질문하는 것
176
+
155
177
  ### evaluator_chain 필드 (모든 파이프라인 필수)
156
178
 
157
179
  `pipeline.json` 에 **`evaluator_chain`** 배열을 기록한다. `config.json.flow.pipeline_selection.evaluator_chains.<pipeline>` 의 값을 복사:
@@ -158,6 +158,34 @@ Cross-Validation 데이터 블록 포함 (Functional/Visual 이 참조):
158
158
  }
159
159
  ```
160
160
 
161
+ ## Auto Gotcha Registration — v5.7.1+
162
+
163
+ **필수 emission**: `actions/evaluation-code-quality.md` 끝부분에 `gotcha_candidates` JSON 블록을 반드시 포함 (후보 없으면 `[]`). `harness-next.sh` 가 Evaluator 완료 직후 이 블록을 스캔해 자동 등록한다.
164
+
165
+ ````
166
+ ```gotcha_candidates
167
+ [
168
+ {
169
+ "target": "generator-backend",
170
+ "rule_id": "be-any-type-leak",
171
+ "title": "서비스 레이어 any 남용",
172
+ "wrong": "UserService.findAll() 반환 타입을 any[] 로 선언",
173
+ "right": "api-contract.json 의 DTO 타입을 재사용하거나 shared-dto 에 정의",
174
+ "why": "C4 Type Safety 축은 25% 가중. evidence 없는 any 는 Score 0.",
175
+ "scope": "모든 BE service/controller 레이어",
176
+ "source": "evaluator-code-quality:F-002"
177
+ }
178
+ ]
179
+ ```
180
+ ````
181
+
182
+ 등록 규칙:
183
+ - `target`: 실수를 반복할 대상 에이전트 (`generator-backend`, `generator-frontend`, `planner` 등).
184
+ - `rule_id`: dedup 키 (동일 rule_id 는 Occurrences +1, 본문 미변경).
185
+ - 신규 항목은 `Status: unverified`. Planner 리뷰 후 `verified` 승격.
186
+ - **FAIL 시**: 실패 근본 원인 1건 이상을 반드시 등록.
187
+ - **PASS 시**: 발견된 경미한 위반이 있으면 등록 (스코어 미반영이지만 반복 방지).
188
+
161
189
  ## Adversarial Rules
162
190
 
163
191
  - "동작하니 PASS" 금지. 여기서는 구조를 본다.
@@ -137,16 +137,38 @@ Evaluator 는 스택마다 다른 검증 도구를 가진다. `scan-result.json.
137
137
  - false → evaluation-functional.md 에 "MANUAL_REQUIRED: {manual_check}" 기록, Visual 은 __skip__
138
138
  ```
139
139
 
140
- ### Auto Gotcha Registration (안티패턴 자동 등록)
140
+ ### Auto Gotcha Registration (안티패턴 + 평가 실패 자동 등록) — v5.7.1+
141
+
142
+ **필수 emission**: `actions/evaluation-functional.md` 끝부분에 아래 fenced JSON 블록을 반드시 포함한다 (후보 없으면 빈 배열 `[]`). `harness-next.sh` 가 Evaluator 완료 직후 이 블록을 스캔해 `scripts/harness-gotcha-register.sh` 로 자동 등록한다.
143
+
144
+ ````
145
+ ```gotcha_candidates
146
+ [
147
+ {
148
+ "target": "generator-frontend",
149
+ "rule_id": "fe-console-error-ignored",
150
+ "title": "콘솔 JS 에러 방치",
151
+ "wrong": "렌더 직후 발생하는 TypeError 를 수정하지 않고 PASS 주장",
152
+ "right": "콘솔 JS 에러 0 이 될 때까지 수정 후 재제출",
153
+ "why": "Evaluator-Functional 콘솔 청결 축은 15% 가중 하드 임계 (0개)",
154
+ "scope": "모든 FE Feature",
155
+ "source": "evaluator-functional:F-003"
156
+ }
157
+ ]
158
+ ```
159
+ ````
141
160
 
142
- `validation.anti_pattern_rules` 실행에서 위반 1건 이상 발견 시 — Dispatcher 경유로 자동 gotcha 등록:
161
+ 등록 규칙:
162
+ - `target`: 실수를 반복할 **대상 에이전트** (예: `generator-frontend`, `generator-backend`, `planner`). 본인(`evaluator-*`) 대상도 가능.
163
+ - `rule_id`: 전역 유일 식별자. 동일 rule_id 는 Occurrences 증가 + Last-Seen 갱신 (본문 미변경).
164
+ - `source`: 출처 — `<agent>:<feature-id>` 형식 권장.
165
+ - 신규 항목은 `Status: unverified` 로 기록. Planner 리뷰 후 수동으로 `verified` 승격.
166
+ - 대상 파일: `.harness/gotchas/<target>.md` (스택별 파일 필요 시 `<target>-<stack>.md` 를 `target` 에 명시).
143
167
 
144
- - 대상 파일: `.harness/gotchas/generator-<role>-<stack>.md` (없으면 생성)
145
- - 항목 포맷: `### [G-NNN] <rule_id>` / severity / occurrences / last_seen(file:line) / snippet / source feature
146
- - 중복 rule_id: Occurrences 카운터 +1 + last_seen 업데이트
147
- - 상세 계약: `api-contract.json.contracts["gotcha_register_interface"]`
168
+ **FAIL 시**: 실패 근본 원인 1건 이상을 반드시 candidate 로 등록 (중복 실수 방지가 목적).
169
+ **PASS 시**: 발견된 안티패턴/경미한 위반이 있으면 등록 (스코어에는 반영 안 됐지만 반복 방지).
148
170
 
149
- 이 메커니즘이 작동하려면 Dispatcher 의 "Auto Gotcha Registration" 섹션을 참고하라.
171
+ Dispatcher 경유 수동 등록은 여전히 가능하지만, **이 자동 파이프라인이 기본 경로**다.
150
172
 
151
173
  ## Evaluation Steps
152
174
 
@@ -121,6 +121,34 @@ jq '.agent_status = "completed" | .completed_agents += ["planner"]' .harness/p
121
121
 
122
122
  **어떤 차원이든 하드 임계값 미달 → FAIL**
123
123
 
124
+ ## Auto Gotcha Registration — v5.7.1+
125
+
126
+ **필수 emission**: `actions/evaluation-visual.md` 끝부분에 `gotcha_candidates` JSON 블록을 반드시 포함 (후보 없으면 `[]`). `harness-next.sh` 가 Evaluator 완료 직후 이 블록을 스캔해 자동 등록한다.
127
+
128
+ ````
129
+ ```gotcha_candidates
130
+ [
131
+ {
132
+ "target": "generator-frontend",
133
+ "rule_id": "fe-contrast-fail",
134
+ "title": "텍스트 대비 WCAG AA 미달",
135
+ "wrong": "버튼 #888 on #aaa — 3.0:1 (AA 4.5:1 미만)",
136
+ "right": "primary 버튼은 body 컬러 대비 4.5:1 이상 보장. Tailwind tokens 활용.",
137
+ "why": "접근성은 Evaluator-Visual 하드 임계",
138
+ "scope": "모든 인터랙티브 엘리먼트",
139
+ "source": "evaluator-visual:F-004"
140
+ }
141
+ ]
142
+ ```
143
+ ````
144
+
145
+ 등록 규칙:
146
+ - `target`: 실수를 반복할 대상 에이전트 (일반적으로 `generator-frontend`, 디자인 토큰 결함은 `planner`).
147
+ - `rule_id`: dedup 키.
148
+ - 신규 항목은 `Status: unverified`. Planner 리뷰 후 `verified` 승격.
149
+ - **FAIL 시**: 실패 근본 원인 1건 이상 반드시 등록.
150
+ - **PASS 시**: 감지된 경미한 디자인 편차가 있으면 등록 (반복 방지).
151
+
124
152
  ## After Evaluation
125
153
 
126
154
  - **PASS** → Session Boundary Protocol On Complete (PASS) 실행