9.0 KiB
title, source_type, status, confidence, tags, last_reviewed
| title | source_type | status | confidence | tags | last_reviewed | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Spec C — funnel stats + no-silent-truncation 계약 (G4) | llm-generated | draft | medium |
|
2026-06-06 |
Spec C — funnel stats + no-silent-truncation
상위 감사: 2026-06-06-harness-audit-report §3 G4. Spec B 다음 슬라이스. 확정 결정: Lean(계약+경량 funnel), 승인 완료.
1. 문제 (감사에서)
- G4 (P4): funnel stats 가 거의 어디에도 없다.
wiki_structure_lint.py의fail_by_type/fail_by_rule만 유일. 어떤 judge·command 도 deep-research funnel(후보→처리→탈락→확정)을 안 냄./ingest가 promotable 항목을 silent 누락했는지 알 수 없고,coverage-auditor가 관심사를 몇 개 열거했는지 보이지 않는다.
2. 핵심 원리 / 비목표
- B 와 동일 철학: 결정론 코어(파싱·검증)는
wiki_rules.py(단일 SSOT), enforcement 는 SubagentStop hook(Claude·Codex)·G3 in-prompt(Antigravity). dispatch/계수는 controller/agent(self-report). - self-report stats 는 완벽한 진실이 아니지만, funnel 균형 검증(found = processed + dropped)과 dropped_reason 필수가 "조용한 누락"을 보이게 만든다 — 그게 G4 의 목표(관측가능성), 정확한 회계가 아니다.
- 비목표: 모든 agent/command 에 stats 강제(YAGNI) → 핵심 4 agent + /ingest 만. branch-spec/project-spec Workflow → Spec D.
3. 설계 결정 (확정)
DD1 — Lean 범위
- 결정론 코어:
wiki_rules.validate_stats_block+claim_gateSubagentStop 검증(B 메커니즘 재사용). - 계약:
rules/reporting-standards.md에 no-silent-truncation 절. - funnel 방출: 핵심 4 agent(
coverage-auditor·branch-depth-auditor·wiki-decision-researcher·wiki-research-lane) +/ingest(command, advisory).
DD2 — funnel 균형이 teeth
found == processed + dropped 가 깨지면 오류. dropped>0 인데 dropped_reason 비면 오류. 이 두 검사가 "조용한 truncation" 을 차단한다.
4. 아키텍처
.claude/hooks/
wiki_rules.py ← MOD. validate_stats_block() + 상수
wiki_claim_gate.py ← MOD. subagent_stop_gate 가 wiki-stats 마커 시 검증
test_wiki_rules.py ← MOD. TestStatsBlock
rules/reporting-standards.md ← MOD. "No silent truncation" 계약 절
.claude/agents/{coverage-auditor,branch-depth-auditor,wiki-decision-researcher,wiki-research-lane}.md
← MOD. Output 에 ## Stats wiki-stats 블록
.claude/commands/ingest.md ← MOD. funnel(found→promoted→skipped+이유) 출력 계약
3-플랫폼 미러: 4 agent 의 Antigravity(.agents/plugins/.../*.md G3 통합) + Codex(.codex/agents/*.md+*.toml). (wiki-decision-researcher·wiki-research-lane 도 shared 9 agent 에 포함 → 미러 대상.)
4.1 wiki-stats 기계 블록
```wiki-stats
agent: coverage-auditor
found: 12
processed: 10
dropped: 2
dropped_reason: 2 out-of-scope (governing §4)
```
found= 후보로 식별한 총 항목(관심사/claim/후보/파일).processed= 실제 판정한 수 — 결과 무관. covered·delegated·missing·verified·promoted 등 어떤 판정이든 "다뤘으면" processed. (coverage 의 missing 은 drop 이 아니라 판정된 gap 이므로 processed 에 포함된다.)dropped= 판정하지 않고 의도적으로 제외한 수(범위 밖/bound 초과).dropped>0→dropped_reason필수.- 불변식:
found = processed + dropped. (모든 식별 항목은 판정됨 이거나 제외됨 — 제3의 침묵 누락이 없다.)
4.2 wiki_rules.py 추가
STATS_FENCE_RE = re.compile(r"```wiki-stats\s*\n(.*?)\n```", re.S)
def parse_stats_block(text):
m = STATS_FENCE_RE.search(text or "")
if not m:
return None
out = {"agent": None, "kv": {}}
for line in m.group(1).splitlines():
line = line.strip()
if not line:
continue
kv = re.match(r"([a-z_]+):\s*(.+)$", line)
if kv:
k, v = kv.group(1), kv.group(2).strip()
if k == "agent":
out["agent"] = v
else:
out["kv"][k] = v
return out
def validate_stats_block(text):
"""(parsed, errors). parsed None → 마커 없음(통과). errors → SubagentStop 차단."""
parsed = parse_stats_block(text)
if parsed is None:
return None, []
errors = []
if not parsed["agent"]:
errors.append("wiki-stats 블록에 `agent:` 누락")
nums = {}
for k in ("found", "processed", "dropped"):
try:
nums[k] = int(parsed["kv"].get(k, ""))
except ValueError:
errors.append(f"wiki-stats `{k}` 는 정수여야 함 (funnel 필수 필드)")
if len(nums) == 3:
if nums["found"] != nums["processed"] + nums["dropped"]:
errors.append(
f"funnel 불균형: found({nums['found']}) ≠ processed({nums['processed']}) "
f"+ dropped({nums['dropped']}) — 조용한 누락 의심"
)
if nums["dropped"] > 0 and not parsed["kv"].get("dropped_reason", "").strip():
errors.append("dropped>0 인데 `dropped_reason` 누락 (no-silent-truncation 위반)")
return parsed, errors
4.3 SubagentStop 강제 (wiki_claim_gate.subagent_stop_gate 확장)
verdict 검사 뒤에 추가(같은 패턴):
sparsed, serr = wiki_rules.validate_stats_block(message)
if sparsed is not None and serr and not event.get("stop_hook_active"):
emit_block("wiki-stats 블록 오류:\n- " + "\n- ".join(serr))
마커 없는 출력 영향 없음. settings.json 무변경.
4.4 rules/reporting-standards.md — No silent truncation 계약
새 절 추가:
No silent truncation. 출력이 캡/슬라이스/top-N/skip 으로 coverage 를 bound 하면 드롭한 수 + 이유를 반드시 보고한다. funnel 은 균형해야 한다:
found = processed + dropped. agent 출력은wiki-stats블록으로(SubagentStop 검증), command 는## Stats절로 보고한다. 침묵 누락은 "전부 다뤘다" 는 거짓 신호다.
4.5 agent .md 편집 (4, 3-플랫폼 미러)
각 Output 에 ## Stats 의 wiki-stats 블록 추가. funnel 의미 매핑:
- coverage-auditor: found=governing 관심사 수, processed=covered+delegated, dropped=명시 제외(있으면 이유).
- branch-depth-auditor: found=점검한 claim/결정 수, processed=판정 완료, dropped=범위 밖(이유).
- wiki-decision-researcher: found=식별 후보 수, processed=archive 한 수, dropped=bound 초과 제외(이유).
- wiki-research-lane: found=슬라이스 파일 수, processed=정독+추출, dropped=무관/제외(이유).
Antigravity 는 G3 Output Schema 에 {{ }} 스타일로 통합("형식 외 응답 금지").
4.6 /ingest 출력 계약 (advisory)
출력 끝에 ## Stats funnel: found promotable 항목 / promoted(canonical 경로별) / skipped(항목+이유). daily/branch 특수처리는 추출/미추출 카운트를 명시(이미 "추출 안 한 항목 raw 보존" 규칙 있음 — 카운트만 추가).
5. 위험
| 위험 | 완화 |
|---|---|
| agent 가 found/dropped 를 부정확 self-report | funnel 균형 검증이 내부 모순은 잡음(완벽한 회계는 아님 — 관측가능성이 목표). |
| SubagentStop 가 비-stats subagent 오차단 | parsed is None(마커 부재) 시 통과 — opt-in. |
| 3-플랫폼 미러 drift | B 와 동일 4 agent, grep-verify; 생성기 부재로 수기. |
| dropped_reason 강제가 noise | dropped==0 이면 reason 불요 — 실제 누락 시에만. |
6. 수용 기준 (검증 가능)
validate_stats_block: 균형 블록 → errors=[].found=12 processed=10 dropped=0→ 불균형 오류.dropped=2+ reason 없음 → 오류. 마커 부재 → (None, []).subagent_stop_gate: wiki-stats 불균형 마커 → exit 2. 균형 마커 → exit 0. 마커 없음 → exit 0.rules/reporting-standards.md에 "No silent truncation" 절 존재(grep).- 4 agent
.md각 Output 에wiki-stats블록 존재 + 3-플랫폼 미러(grep parity). /ingest.md에## Statsfunnel 계약 존재(grep).- 기존 4 스위트 + 신규 stats 테스트 전부 green.
7. 구현 순서 (writing-plans)
wiki_rules.pyparse_stats_block/validate_stats_block(TDD) +test_wiki_rulesTestStatsBlock.claim_gate.subagent_stop_gate확장 + subprocess 회귀(균형/불균형/마커없음).rules/reporting-standards.mdno-silent-truncation 절.- 4 agent
.md(Claude) ## Stats 블록. /ingest.mdfunnel 계약.- 3-플랫폼 미러(4 agent) + grep parity.
- 전체 스위트 + §6 스모크.
8. 메모
wiki_rules.py가 A(구조)·B(verdict)·C(stats) 의 공유 SSOT 로 계속 성장 — 전부 기계장치(스키마/검증), 정책은 agent.md+rules.- self-report 한계는 인정 — Spec C 는 "조용한 누락을 보이게" 가 목표(deep-research 의 결정론 funnel 은 Workflow=Spec D 에서만 가능).