# 2026-06-10 — `.claude/` 문서관리 하네스 전수 감사 보고 - **의뢰**: "하네스가 잘 동작하긴 하는데 한번씩 하네스대로 동작하지 않고 결과물을 내는 경우가 있다. agents·command·hooks·skills 를 하나씩 분석해 극한으로 동작시키기 위한 개선점을 찾아라." - **범위**: `.claude/agents/` 10 · `.claude/commands/` 22 · `.claude/hooks/` 8 · `settings*.json` 2 · `.claude/skills/wiki-workflow/SKILL.md` 1 (+ 교차참조: `CLAUDE.md`, `rules/`, `templates/`, 3-플랫폼 미러) - **방법**: 집행 레이어(hooks·settings)는 컨트롤러 직접 정독, agents/commands 는 병렬 research lane 4개(agents / capture·transform commands / output·invest commands / Claude Code 훅 스키마 공식 문서 검증), 핵심 가설 3건은 **라이브 세션 실측**으로 확정. - **Verdict: NOT-READY** (개선 필요 — P0 6건 / P1 9건 / P2 7건). 골격은 견고하나 배선 결함 3종이 증상을 직접 유발. --- ## §0. 한 줄 결론 하네스의 골격(2단 게이트 파이프라인 + 훅 4종)은 잘 설계되어 있고 **실제로 작동 중**이다. 그러나 "한번씩 하네스대로 동작하지 않는" 증상의 주범은 *모델의 우회*가 아니라 — **① 훅↔에이전트 출력 계약 불일치로 인한 오차단→이탈 재시도, ② 진입점(SKILL.md) 라우팅 공백으로 인한 폴스루, ③ 파생·invest 레이어의 결정론 게이트 부재** — 즉 하네스 자체의 배선 결함 3종이다. ## §1. 실측으로 확인한 사실 (라이브 세션 재현) 훅에 임시 이벤트 덤프를 넣고 probe subagent 를 돌려 검증 (실험 후 원복 완료, `git diff` 클린 확인): | 검증 항목 | 결과 | |---|---| | `SubagentStop.last_assistant_message` 존재 여부 | ✅ 존재 — 게이트는 살아있음 (공식 문서엔 스키마 미기재였음) | | `SubagentStart` `additionalContext` 주입 | ✅ subagent transcript 에서 주입 문자열 확인 | | **증상 재현** | ✅ **재현됨** — probe(Explore 에이전트)가 `Verdict: COMPLETE` 라고 말하자 게이트가 차단 → probe 는 본래 임무 출력 대신 **사과문 형태의 이탈된 재시도 출력**을 반환 | | `stop_hook_active=true` 재시도 | ✅ 재시도 메시지는 **무검증 통과** (one-retry enforcement) | | 게이트 적용 범위 | ⚠️ 이벤트에 `agent_type` 필드가 있는데도 게이트가 **모든 subagent**(Explore/general-purpose/Plan 포함)에 무차별 적용 | | PreToolUse `matcher: "*"` | ⚠️ Read/Grep 포함 **모든 도구 호출마다** python 프로세스 1개 스폰 확인 | → 사용자가 보는 "하네스 미준수 출력"의 상당수는 **게이트가 안 돌아서가 아니라, 게이트가 잘못된 대상을 차단한 뒤 그 이탈 재시도가 무검증으로 통과**하는 메커니즘. 확인된 SubagentStop 이벤트 필드 (실측): `session_id, transcript_path, cwd, permission_mode, agent_id, agent_type, hook_event_name, stop_hook_active, agent_transcript_path, last_assistant_message, background_tasks, session_crons` ## §2. 근본 원인 체인 5개 ### RC1 — 훅↔출력계약 불일치 (오차단 → 이탈 → 무검증 통과) [최우선] `wiki_claim_gate.py:162-179` 의 SubagentStop 게이트와 에이전트 출력 템플릿의 충돌: | 에이전트 | 충돌 | 결과 | |---|---|---| | `wiki-adversarial-reviewer.md:102` | `**Verdict:** COMPLETE` 를 강제하면서 출력 템플릿이 요구 문자열 3종(`Claim ID`/`Decision Evidence Map`/`UNSUPPORTED_DECISION`) 출력을 보장하지 않음 (`UNSUPPORTED_DECISION` 은 파일 전체에 부재) | COMPLETE 선언 시 상시 차단 위험 | | `wiki-research-lane.md:122` | 동일 — 절차(step 5)엔 3종이 있으나 출력 템플릿엔 없음. official-doc 슬라이스처럼 3종이 정당하게 무관한 corpus 에서 확정 차단 | 동일 | | `wiki-diagram-reviewer.md:195` | `NEEDS_FIX`(60≤점수<95, hard-stop 0) → `verdict: not-ready` + `blocking: 0` 인데 훅은 `not-ready ∧ blocking<1` 을 모순으로 차단 (`wiki_rules.py:245-246`) | **가장 흔한 채점 등급에서 결정론적 오차단** | | 게이트 전체 | `agent_type` 무시 → 위키와 무관한 범용 에이전트도 `Verdict: COMPLETE` 한 마디에 차단 (§1 재현) | 무관 작업의 이탈 | | 전 에이전트 공통 | `wiki-verdict`/`wiki-stats` 기계 블록이 출력 템플릿 바깥(부록 위치)에 정의됨 + 훅은 마커 부재 시 통과(presence-conditional) → 템플릿만 충실히 재현하면 블록 누락 = 게이트 silent never-fire | 미검증 통과 | | 전 에이전트 공통 | `verdict: blocked` 경로 미정의 (입력 불량 시 즉흥 대응) + 예시 블록이 happy-path 리터럴 값(anchor-copy 위험) | 스키마 이탈 | ### RC2 — 진입점 라우팅 공백 (게이트 우회의 구조적 원인) `SKILL.md` dispatch tree 가: - 10개 에이전트 중 4개를 모름 (`wiki-diagram-reviewer`, `branch-depth-auditor`, `coverage-auditor`, `project-readiness-auditor`) - `/branch-spec`·`/depth`·`/coverage`·`/project-spec` 게이트 파이프라인으로 라우팅하지 않음 - **파생 산출물(/interviewize·/blogify·/explain·portfolio) 분기가 아예 없음** → 자연어 요청이 "메인 에이전트 직접 응답"으로 폴스루 = status 게이트 미적용 - dispatch 시 필수 입력 3개 에이전트분 과소 전달 (adversarial-reviewer corpus path, doc-author mode/claim-evidence, source-summarizer source_type/정당화 결정) → `BLOCKED`/`NEEDS_CONTEXT` 왕복이 "flaky"처럼 보임 ### RC3 — main agent 는 무검증 지대 - **Stop 훅 없음** — `/ingest`·`/lint`·`/branch-spec` 등 main agent 인라인 명령의 최종 보고(`## Stats` funnel, 종합 판정)는 어떤 훅도 검증 안 함. `validate_stats_block` 검증기가 있는데 subagent 에만 배선 - `/lint` 가 `wiki_structure_lint.py --all` 을 한 번도 호출하지 않고 깨진 링크·frontmatter 검사를 LLM 수기 재연 (`lint.md:44-53`) - `wiki_quorum.py` 는 어느 명령도 호출하지 않는 dead tooling (유일 참조: adversarial-reviewer N=3 고위험 경로, 기본 N=1) ### RC4 — 결정론 게이트의 경로 공백 `CLAIM_REQUIREMENTS`(`wiki_rules.py:152-171`) 커버 prefix 는 5개뿐: | 미커버 경로 | 위험 | |---|---| | `wiki/projects/` | canonical 절반이 증거 등급 구조 무게이트 — interview/portfolio 가 인용해야 할 바로 그 층 | | `wiki/interview/`·`wiki/blog/`·`wiki/portfolio/`·`wiki/explainer/` | §11 최대 금지(canonical 우회·status 미달 파생)가 주 1회 LLM lint 에만 의존. 쓰기 시점 차단 가능한데 안 함 | | `raw/invest-daily/`·`raw/invest-ledger/`·`wiki/invest-plan/` | **실제 돈 경로**가 narrative 신뢰 + LLM 산술로 운영. 환각 수치가 모든 훅 통과 | | branch-note 파일명 | numbered-hierarchy 금지(§11)가 결정론 검사 없음 | ### RC5 — SSOT drift (복붙 재진술 엔진) - `CLAUDE.md` 인벤토리: `/coverage`·`/migrate-claims` 누락, `/explain` "예정" 표기(실존+3플랫폼 미러 완료) - `depth.md:2` description "2차 LLM 의미 게이트는 P2" — 본문은 이미 2차 dispatch 함 (stale) - drift 실증 2건: `/ingest` source_type 어휘(daily-task 특수 절차 부재), `blogify.md:36` 인라인 섹션 리스트 vs 템플릿 - `migrate-claims.md:92` **`rg -L` 버그** — ripgrep `-L`은 `--follow`(symlink)이지 files-without-match 가 아님. 유일한 결정론 검증 단계가 거짓 데이터 산출 - 명령 22개 전부 `allowed-tools`/`model` frontmatter 부재 — 판정 명령(/depth /coverage /query)과 실돈 명령(/invest-decide)이 전권 보유 - Claude 본판 에이전트에 Antigravity 포트의 G1(Pre-Read Proof)·G3(`{{ }}` placeholder 스키마)·G4(STOP 조건 열거) 하드 게이트 부재 — 본판이 포트보다 약한 역전 상태 ## §3. 우선순위 수정안 ### P0 — 오차단 제거 (증상의 직접 원인) 1. SubagentStop 게이트에 `agent_type` 스코핑 — 위키 에이전트 10종 외 즉시 allow 2. `wiki-diagram-reviewer.md:195` blocking 재정의 — blocking = 95점 미만 다이어그램 수(NEEDS_FIX 시 최소 1), hard-stop 수는 prose 로 3. COMPLETE 어휘 에이전트 2개(adversarial-reviewer, research-lane)에 `## Claim Traceability Check` 고정 섹션 — 3문자열을 "none found" 라도 항상 literal 출력 4. 기계 블록을 출력 템플릿 안으로 이동 + `verdict: blocked` 경로 + 예시 값 `{{ }}` placeholder 화 5. SKILL.md dispatch tree 보강 (누락 4 에이전트 + 게이트 파이프라인 + 파생 분기 + Required Inputs) 6. `migrate-claims.md` `rg -L` → `rg --files-without-match` (3 copies) ### P1 — 결정론 커버리지 확장 7. `CLAIM_REQUIREMENTS` 확장 (+6 엔트리): `wiki/projects/` · 파생 4종(`## Sources` 에 canonical wikilink 요구, portfolio 는 projects 필수) · `raw/invest-daily/`(수치 행 URL+날짜 토큰) 8. 파생 status 게이트 결정론화 — `check_markdown_write` 에서 Sources 의 canonical 링크 frontmatter `status:` 검사 (explainer 면제) 9. Stop 훅 추가 — main agent 최종 메시지의 wiki-stats/Verdict 를 동일 validator 로 검증 10. `/lint` 1단계 = `wiki_structure_lint.py --all` 실행 + §15.5 "(예정)" 3검사 구현 11. `/coverage` 1차 기계화 (`--coverage-pre` 모드) + branch-note 파일명 regex 검사 12. branch-spec 루프 천장 2회 (project-spec 과 정렬) + 최종 보고 wiki-stats funnel 13. PreToolUse claim_gate matcher 를 `Bash|Write|Edit|MultiEdit|NotebookEdit` 로 축소 (성능) 14. `allowed-tools` frontmatter 도입 (판정 명령 read-only, /invest-decide 최소권한) 15. CLAUDE.md 인벤토리 동기화 + `depth.md` description 갱신 ### P2 — 구조 개선 16. G1/G3/G4 하드 게이트 Claude 본판 역이식 17. invest 경화: `invest_ledger_check.py`(근거 링크 실존·staleness·주간 거래 수·row 스키마·P&L 재계산) + quorum 검증 invest 수치 opt-out 기본값 반전 + 임계값 strategy.md 일원화 18. 복붙 재진술 제거 (명령 내 템플릿 섹션 리스트 → "템플릿 Read 가 SSOT", §6 등급표·명명 규칙 → 참조 1줄) 19. `wiki_quorum.py` 배선 (`/lint --fix-plan` CRITICAL ≥5건 시 adversarial N=3 + quorum) 또는 폐기 명시 20. 판정 에이전트 3종(adversarial/depth/readiness) 모델 상향 검토 (sonnet→opus) 21. `wiki-decision-researcher` 모순 해소 — "controller 에 dispatch 요청 방출"로 재서술 + `Write` 도구 제거 22. one-retry 완화 검토 — `stop_hook_active` 시 스키마 오류 재차단 허용 (Claude Code 자체 8회 연속 차단 cap 존재; 단 P0 1~4 선행 후) ## §4. 잘 되어 있는 것 (유지) - `/depth`·`/project-spec` 의 "1차 결정론 스크립트 → 2차 의미 감사" 파이프라인 — 22개 명령 중 모범 - `wiki_structure_lint.py` 의 C2 링크 검사(코드 스팬·fence·escaped pipe)와 projected-content 방식 - 완성-선언 시에만 C1/C3 를 켜는 `is_completeness_checkable` 설계 (false-positive 소음 차단) - Bash 직접 쓰기 차단 + Write/Edit 강제 경유 — 새 CLAIM_REQUIREMENTS 엔트리가 진짜로 우회 불가능해지는 토대 ## §5. Claim Traceability Check (본 감사의 추적성 자기검사) - **Claim ID / Claims Extracted 검사**: 본 감사는 raw source 를 신규 생성하지 않음 — `Claims Extracted` 표 생성 의무 해당 없음. 근거는 전부 hooks/agents/commands 파일의 file:line 인용으로 추적 가능. - **Decision Evidence Map 검사**: branch-note 를 생성/수정하지 않음 — 해당 없음. (게이트 자체의 `Decision Evidence Map` 요구 로직은 `wiki_rules.py:157-160` 에서 검증함.) - **UNSUPPORTED_DECISION 검사**: 본 보고의 권고 중 외부 근거 없이 사용자 trade-off 로 결정해야 하는 항목 — P2-20(모델 상향: 비용 증가 vs 판정 신뢰), P2-22(one-retry 완화: 루프 위험 vs 집행 강도) — 은 측정 근거가 아니라 설계 판단이며, 채택 전 사용자 결정 필요. - **실측 증거**: §1 표의 6개 항목은 2026-06-10 라이브 세션에서 직접 재현·관측한 1차 증거 (probe agent transcript + 이벤트 덤프). ## §6. P0 구현 추적 | # | 항목 | 상태 (2026-06-10) | |---|---|---| | P0-1 | SubagentStop agent_type 스코핑 (`WIKI_AGENT_TYPES` SSOT in `wiki_rules.py` + `subagent_stop_gate` 분기) | ✅ 완료 — 테스트 5건 추가, 4개 suite 전부 OK | | P0-2 | diagram-reviewer blocking 재정의 (= 95점 미만 다이어그램 수, hard-stop 수는 prose) | ✅ 완료 | | P0-3 | Claim Traceability Check 고정 섹션 (adversarial-reviewer · research-lane) + bare-token/공백금지/BLOCKED 무방출 규칙 | ✅ 완료 | | P0-4 | 기계 블록 템플릿 내장(4-backtick 외곽 fence) + `verdict: blocked` 경로 + `{{ }}` placeholder — 7개 에이전트 | ✅ 완료 | | P0-5 | SKILL.md dispatch tree 보강 (4 에이전트 + 게이트 파이프라인 + 파생 분기 + Required Inputs + STOP 14항) | ✅ 완료 | | P0-6 | migrate-claims `rg -L` → `rg --files-without-match` (3 copies) | ✅ 완료 | | 후속 | 3-플랫폼 미러 동기화: SSOT `.agents/plugins/wiki-superpowers/agents/` 6 + Antigravity `agent.json` 6 (JSON 검증 OK) + Codex `.md`/`.toml` 12 (TOML 검증 OK, body 패리티 확인). platform-aware — Codex/Antigravity 에 SubagentStop 문구 미도입, 기존 G3/hard-gate 어휘 사용 | ✅ 완료 | 검증: `test_wiki_claim_gate`·`test_wiki_rules`·`test_wiki_structure_lint`·`test_wiki_quorum` 전부 OK / 편집된 에이전트 7파일 4-backtick fence 짝 균형 / 본 보고서 `wiki_structure_lint --file` PASS. ## §7. P1 구현 추적 (2026-06-10) | # | 항목 | 상태 | |---|---|---| | P1-7 | `CLAIM_REQUIREMENTS` +5 엔트리: `wiki/projects/`(실제 구현 내용+Sources, named-hub 면제) · `wiki/interview\|blog\|explainer`(Sources+canonical 링크 `content_regex`) · `wiki/portfolio/`(projects 링크 필수) · `raw/invest-daily/`(고정 체크리스트+출처 섹션) + 수치행 출처/조사시점 정책(`invest_daily_numeric_failures`) | ✅ 기존 파일 전수 dry-run — 오차단 1건(2026-06-06 invest-daily, 템플릿 도입 전)은 light-touch 마이그레이션으로 해소 | | P1-8 | 파생 status 게이트 결정론화: `derived_source_status_failures` — `## Sources` 의 canonical 링크 frontmatter `status` 전부 ∈ {reviewed, verified, published-ready} 필요 (explainer 면제) | ✅ | | P1-9 | main agent `Stop` 훅 (`--main-stop` 플래그): fenced `wiki-stats` 만 검증 — COMPLETE trap/wiki-verdict 는 메타 대화 오차단 위험으로 제외. Antigravity native `Stop`(subagent 의미) 라우팅과 플래그로 분리 | ✅ (신규 세션부터 활성 — 훅 설정은 세션 시작 시 스냅샷) | | P1-10 | `/lint` 개정: 절차 1단계 `--all`·2단계 `--stale`(신규 린터 모드) 결정론 선행 + §A1(§15.5 3검사) + C/D군 린터 출력 SSOT 화 + E군 write-time backstop 주석 | ✅ | | P1-11 | 린터 `--coverage-pre`(0 PASS/1 FAIL/3 EXEMPT) + `NAMING_VIOLATION`(신규 생성만 차단, 기존 파일 편집 허용) + `/coverage` 1차 스크립트화 | ✅ 기존 branch-note 파일명 위반 0건 사전 확인 | | P1-12 | `/branch-spec` 루프 천장 2회(§8c) + §9 `wiki-stats` funnel(Stop 훅 검증) + §8b `--coverage-pre` 연결 | ✅ | | P1-13 | PreToolUse claim_gate matcher `*` → `Bash\|Write\|Edit\|MultiEdit\|NotebookEdit` (동작 동일, 프로세스 스폰 감소) | ✅ | | P1-14 | `disallowed-tools`: depth/query(Write·Edit·NotebookEdit 금지) · coverage/lint(NotebookEdit·WebSearch·WebFetch — 정당한 쓰기 경로 보존) · invest-decide(WebSearch·WebFetch — 결정 시점 즉흥 조사 차단) | ✅ /coverage·/lint 전면 쓰기 금지는 §Coverage 기록·--fix-plan 적용을 깨뜨려 제외 | | P1-15 | CLAUDE.md 동기화(§1 흐름·§2 인벤토리·branch-spec 항목·§15 /explain 해제·§15.5 "(예정)" 해제) + depth description 갱신 + **depth.md 의 환각된 `--fix --apply` 플래그 참조 제거** (덤 발견) | ✅ | | 후속 | 명령 미러 동기화: lint·coverage·branch-spec·depth × Codex skill + Antigravity workflow (8파일, platform-aware — Stop 훅 문구 일반화, disallowed-tools 미전파, invest 절 미전파) | ✅ | 검증: 4개 test suite 전부 OK (123 tests, 신규 ~30 포함) / `settings.json` JSON valid / `--coverage-pre`·`--stale` 실데이터 스모크 PASS / 신규 게이트 전수 dry-run 오차단 0건. ## §8. P2 구현 추적 (2026-06-10 — 22개 권고 전체 완료) | # | 항목 | 상태 | |---|---|---| | P2-16 | G1 Pre-Read Proof(10/10) + G4 STOP 조건 열거(10/10, 기존 blocked 규칙 참조 통합) + G2(쓰기 2종 Post-Write Validation, read-only 판정자 self-grep 증거 규칙) Claude 본판 역이식 — 에이전트당 ≤40줄, G3 는 P0-4 기완료 | ✅ | | P2-17 | `invest_ledger_check.py` 신규(--check: 11열 스키마·근거 실존·staleness 24h/90d·주간 거래 수 / --report: P&L 기계 재계산) + 테스트 8건 + `/invest-decide` §5 배선·인라인 임계값 제거(strategy.md ①~⑤ SSOT) + `/invest-review` §3 배선 + ledger CLAIM_REQUIREMENTS 엔트리 + **quorum 기본값 반전**: invest-daily/research 고위험 수치 = read-only 검증 subagent ×3 + `wiki_quorum.py` 합산이 기본(opt-out 명시제, Workflow 는 상위 옵션 유지) | ✅ | | P2-18 | 재진술 제거 15파일(blogify·interviewize·explain·projectize·branch × SSOT+미러 2): 템플릿 섹션 리스트 → "템플릿 Read 가 SSOT", §6 등급 열거 → 참조, 명명 규칙 → 1줄+린터 위임. drift 실증 문자열 잔존 0건 grep 확인 | ✅ | | P2-19 | `wiki_quorum.py` 배선 — `/lint --fix-plan` CRITICAL ≥5건 시 adversarial N=3 + `/tmp/lint-vote-*` + 결정론 합산(KILL 제외/UNVERIFIED 보류/DOWNGRADE 하향). dead tooling 해소 (+미러 2) | ✅ | | P2-20 | 판정 3종(adversarial/depth/readiness) `model: opus` 상향 — **사용자 승인** | ✅ | | P2-21 | decision-researcher 모순 해소: description "dispatch 요청 방출(실 dispatch 는 controller)" + `Write` 제거 + SKILL.md/CLAUDE.md 정렬 + 변형 4벌(plugin SSOT·agent.json toolNames·codex toml sandbox read-only·codex md) 동기화 | ✅ | | P2-22 | one-retry 폐지(위키 에이전트 한정) — `stop_hook_active` 무검증 통과 제거, Claude Code 8회 cap 이 무한루프 방지. main-stop 은 one-retry 유지 — **사용자 승인** | ✅ | 최종 검증: **5개 test suite 전부 OK** (test_invest_ledger_check 신규 포함) / G1 Pre-Read Proof 10/10 / 4-backtick fence 균형 / 본 보고서 lint PASS. **잔여 follow-up (P0~P2 범위 밖, 기록만)**: ① Stop 훅·재차단 정책은 신규 세션부터 활성(훅 설정 세션 스냅샷) ② strategy ③ 주간 거래상한 N 미정 — 사용자가 정하면 `/invest-decide` 의 `--weekly-cap` 에 반영 ③ Bash claim gate 의 명령 문자열 path-매칭 false-positive(작업 중 2회 재현)는 redirect 타깃 기반 검사로 정밀화 후보 ④ concept source_type drift(메모리 2a) 별도 마이그레이션. **Stats**: 분석 대상 45 파일 / 병렬 lane 4 / 실측 검증 3건 / findings 60+ → 권고 22건 (P0 6 · P1 9 · P2 7)