Files
llm-wiki/docs/superpowers/specs/2026-06-10-claude-harness-audit-report.md
T

19 KiB
Raw Blame History

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 에만 배선
  • /lintwiki_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 -Lrg --files-without-match (3 copies)

P1 — 결정론 커버리지 확장

  1. CLAIM_REQUIREMENTS 확장 (+6 엔트리): wiki/projects/ · 파생 4종(## Sources 에 canonical wikilink 요구, portfolio 는 projects 필수) · raw/invest-daily/(수치 행 URL+날짜 토큰)
  2. 파생 status 게이트 결정론화 — check_markdown_write 에서 Sources 의 canonical 링크 frontmatter status: 검사 (explainer 면제)
  3. Stop 훅 추가 — main agent 최종 메시지의 wiki-stats/Verdict 를 동일 validator 로 검증
  4. /lint 1단계 = wiki_structure_lint.py --all 실행 + §15.5 "(예정)" 3검사 구현
  5. /coverage 1차 기계화 (--coverage-pre 모드) + branch-note 파일명 regex 검사
  6. branch-spec 루프 천장 2회 (project-spec 과 정렬) + 최종 보고 wiki-stats funnel
  7. PreToolUse claim_gate matcher 를 Bash|Write|Edit|MultiEdit|NotebookEdit 로 축소 (성능)
  8. allowed-tools frontmatter 도입 (판정 명령 read-only, /invest-decide 최소권한)
  9. CLAUDE.md 인벤토리 동기화 + depth.md description 갱신

P2 — 구조 개선

  1. G1/G3/G4 하드 게이트 Claude 본판 역이식
  2. invest 경화: invest_ledger_check.py(근거 링크 실존·staleness·주간 거래 수·row 스키마·P&L 재계산) + quorum 검증 invest 수치 opt-out 기본값 반전 + 임계값 strategy.md 일원화
  3. 복붙 재진술 제거 (명령 내 템플릿 섹션 리스트 → "템플릿 Read 가 SSOT", §6 등급표·명명 규칙 → 참조 1줄)
  4. wiki_quorum.py 배선 (/lint --fix-plan CRITICAL ≥5건 시 adversarial N=3 + quorum) 또는 폐기 명시
  5. 판정 에이전트 3종(adversarial/depth/readiness) 모델 상향 검토 (sonnet→opus)
  6. wiki-decision-researcher 모순 해소 — "controller 에 dispatch 요청 방출"로 재서술 + Write 도구 제거
  7. 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 -Lrg --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)