19 KiB
2026-06-10 — .claude/ 문서관리 하네스 전수 감사 보고
- 의뢰: "하네스가 잘 동작하긴 하는데 한번씩 하네스대로 동작하지 않고 결과물을 내는 경우가 있다. agents·command·hooks·skills 를 하나씩 분석해 극한으로 동작시키기 위한 개선점을 찾아라."
- 범위:
.claude/agents/10 ·.claude/commands/22 ·.claude/hooks/8 ·settings*.json2 ·.claude/skills/wiki-workflow/SKILL.md1 (+ 교차참조: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 인라인 명령의 최종 보고(## Statsfunnel, 종합 판정)는 어떤 훅도 검증 안 함.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:2description "2차 LLM 의미 게이트는 P2" — 본문은 이미 2차 dispatch 함 (stale)- drift 실증 2건:
/ingestsource_type 어휘(daily-task 특수 절차 부재),blogify.md:36인라인 섹션 리스트 vs 템플릿 migrate-claims.md:92rg -L버그 — ripgrep-L은--follow(symlink)이지 files-without-match 가 아님. 유일한 결정론 검증 단계가 거짓 데이터 산출- 명령 22개 전부
allowed-tools/modelfrontmatter 부재 — 판정 명령(/depth /coverage /query)과 실돈 명령(/invest-decide)이 전권 보유 - Claude 본판 에이전트에 Antigravity 포트의 G1(Pre-Read Proof)·G3(
{{ }}placeholder 스키마)·G4(STOP 조건 열거) 하드 게이트 부재 — 본판이 포트보다 약한 역전 상태
§3. 우선순위 수정안
P0 — 오차단 제거 (증상의 직접 원인)
- SubagentStop 게이트에
agent_type스코핑 — 위키 에이전트 10종 외 즉시 allow wiki-diagram-reviewer.md:195blocking 재정의 — blocking = 95점 미만 다이어그램 수(NEEDS_FIX 시 최소 1), hard-stop 수는 prose 로- COMPLETE 어휘 에이전트 2개(adversarial-reviewer, research-lane)에
## Claim Traceability Check고정 섹션 — 3문자열을 "none found" 라도 항상 literal 출력 - 기계 블록을 출력 템플릿 안으로 이동 +
verdict: blocked경로 + 예시 값{{ }}placeholder 화 - SKILL.md dispatch tree 보강 (누락 4 에이전트 + 게이트 파이프라인 + 파생 분기 + Required Inputs)
migrate-claims.mdrg -L→rg --files-without-match(3 copies)
P1 — 결정론 커버리지 확장
CLAIM_REQUIREMENTS확장 (+6 엔트리):wiki/projects/· 파생 4종(## Sources에 canonical wikilink 요구, portfolio 는 projects 필수) ·raw/invest-daily/(수치 행 URL+날짜 토큰)- 파생 status 게이트 결정론화 —
check_markdown_write에서 Sources 의 canonical 링크 frontmatterstatus:검사 (explainer 면제) - Stop 훅 추가 — main agent 최종 메시지의 wiki-stats/Verdict 를 동일 validator 로 검증
/lint1단계 =wiki_structure_lint.py --all실행 + §15.5 "(예정)" 3검사 구현/coverage1차 기계화 (--coverage-pre모드) + branch-note 파일명 regex 검사- branch-spec 루프 천장 2회 (project-spec 과 정렬) + 최종 보고 wiki-stats funnel
- PreToolUse claim_gate matcher 를
Bash|Write|Edit|MultiEdit|NotebookEdit로 축소 (성능) allowed-toolsfrontmatter 도입 (판정 명령 read-only, /invest-decide 최소권한)- CLAUDE.md 인벤토리 동기화 +
depth.mddescription 갱신
P2 — 구조 개선
- G1/G3/G4 하드 게이트 Claude 본판 역이식
- invest 경화:
invest_ledger_check.py(근거 링크 실존·staleness·주간 거래 수·row 스키마·P&L 재계산) + quorum 검증 invest 수치 opt-out 기본값 반전 + 임계값 strategy.md 일원화 - 복붙 재진술 제거 (명령 내 템플릿 섹션 리스트 → "템플릿 Read 가 SSOT", §6 등급표·명명 규칙 → 참조 1줄)
wiki_quorum.py배선 (/lint --fix-planCRITICAL ≥5건 시 adversarial N=3 + quorum) 또는 폐기 명시- 판정 에이전트 3종(adversarial/depth/readiness) 모델 상향 검토 (sonnet→opus)
wiki-decision-researcher모순 해소 — "controller 에 dispatch 요청 방출"로 재서술 +Write도구 제거- 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)