init: document-haness 하네스 설계

This commit is contained in:
DongHyeonka
2026-07-24 13:58:08 +09:00
parent d6f78f92a0
commit c39406bbdd
219 changed files with 7010 additions and 20052 deletions
+280 -149
View File
@@ -1,165 +1,296 @@
# Technical Document Flow
# ClariDoc Harness
기술 문서를 “정보가 많은 글”이 아니라 “독자가 한 단계씩 납득하는 글”로 만드는 작성 하네스입니다.
ClariDoc은 기술 블로그와 기술 문서를 **독자의 질문 순서가 드러나는 논리 구조**로 계획·작성·검토·수정하는 멀티 에이전트 하네스다. 단순 프롬프트 템플릿이 아니라 다음을 코드로 강제한다.
참조 문서`executable-clean-architecture.md`에서 다음 논증 흐름을 추출해 일반화했습니다.
- 문서 유형별 정보 구조 계약
- 독자·목표·선행지식·범위·비범위가 포함된 작성 브리프
- 출처별 사실 단위를 분리한 근거 팩
- Codex, Claude, Google Antigravity 제공자 어댑터
- 논리·독자·근거·운영 관점의 독립 리뷰
- Markdown 구조, 절차 안전성, 인용, 버전 맥락을 검사하는 결정적 린터
- 점수, blocker/error 한도, 수정 횟수를 포함한 품질 게이트
- 각 단계의 원문 응답, 보고서, 실행 이벤트, SHA-256 매니페스트
## 핵심 설계
```text
실패 장면
→ 진짜 원인
→ 설계 요구사항
→ 필요한 원리
→ 선택과 구현
→ 종단 동작
→ 자동 검증과 실패 실험
→ 비용·한계
→ 처음 질문에 대한 답
brief.json + sources.json
[문서 유형별 구조 계약]
│ planner: Codex
[질문 기반 outline.json]
│ writer: Claude
[draft.md]
├── 결정적 린터
├── 논리 리뷰: Codex
├── 독자 리뷰: Claude
├── 근거 리뷰: Antigravity
└── 운영 리뷰: Antigravity
[품질 게이트] ── 실패 ──> reviser: Claude ──> 재검사
│ 통과 또는 수정 한도 도달
final/document.md + quality-report.md + manifest.json
```
이 순서를 모든 문서에 억지로 씌우지는 않습니다. 설명문, 의사결정 문서, 사용 절차, 참조 문서마다 다른 흐름을 선택하되, 모든 절이 독자의 질문에 답하고 다음 절이 필요한 이유를 남기게 합니다.
모델이 자유롭게 목차부터 만들게 두지 않는다. 먼저 코드가 문서 유형별 필수 질문과 순서를 정하고, planner는 제목·전환·근거 배치를 정교화하되 필수 intent를 삭제하거나 재배열할 수 없다. 모델 출력이 구조 계약을 위반하면 planner 단계는 결정적 기본 구조로 폴백한다.
## 이 하네스가 막는 문제
## 지원 문서 유형
- 해결책부터 제시해 독자가 “왜 필요한가”를 놓치는 글
- 용어를 설명하지 않은 채 타입명·약어·제품명을 한꺼번에 쏟는 글
- 주장과 근거 사이가 비어 있는 글
- 앞 절과 다음 절이 연결되지 않는 목차
- 코드·표가 본문의 논증과 따로 노는 글
- 결론에서 본문에 없던 주장을 새로 만드는 글
- 자세하지만 대상 독자가 따라갈 수 없는 글
핵심 용어 정책은 단순합니다.
> 먼저 익숙한 말로 현상과 역할을 설명하고, 다시 쓸 가치가 있을 때만 정식 용어를 붙입니다.
기술적으로 정확한 이름을 없애지는 않습니다. 코드 식별자, 표준명, 제품명은 보존하고 첫 등장 설명·사용 이유·일관된 이름을 관리합니다.
## 빠른 시작
### 에이전트에서 사용
설치 후 다음처럼 요청합니다.
```text
$technical-doc-flow
이 설계 메모를 중급 백엔드 개발자가 이해할 수 있는 기술 문서로 작성해 줘.
핵심 독자 질문은 “왜 이 경계가 필요한가?”야.
참고 자료: docs/design-notes.md, src/build.gradle
```
기존 문서를 고칠 때도 같은 스킬을 사용합니다.
```text
$technical-doc-flow
draft.md의 논리 흐름과 전문용어 부담을 검토하고 고쳐 줘.
독자는 이 기술을 처음 쓰는 애플리케이션 개발자야.
```
Claude Code에서는 같은 이름의 스킬을, Gemini CLI에서는 `/technical-doc` 또는 `/technical-doc-review`를 사용할 수 있습니다.
### 결정적 검사만 실행
LLM 없이도 구조와 용어 계약을 검사할 수 있습니다.
```bash
python3 scripts/lint_document.py \
--document _workspace/2026-07-23-001/final.md \
--reader-contract _workspace/2026-07-23-001/02_reader_contract.json \
--logic-map _workspace/2026-07-23-001/04_logic_map.json \
--term-ledger _workspace/2026-07-23-001/05_term_ledger.json \
--draft-baseline _workspace/2026-07-23-001/07_draft.md \
--output _workspace/2026-07-23-001/08_lint.json
```
실행 전체를 검증하려면 다음 명령을 사용합니다.
```bash
python3 scripts/verify_run.py --run-dir _workspace/2026-07-23-001
```
## 세 경로
| 경로 | 적합한 작업 | 흐름 |
| `document_type` | 독자 요구 | 기본 논리 축 |
|---|---|---|
| `light` | 짧고 이미 구조가 선 초안 | 독자·논리 계약 → 집필 → lint |
| `standard` | 일반적인 신규 문서나 구조 수정 | 근거 정리 → 논리 설계집필독립 리뷰 2종 → 마무리 → lint |
| `deep` | 장문, 근거가 많거나 검증 기록이 필요한 문서 | standard + 장문 분할 + 엄격 gate |
| `technical_blog` | 문제와 설계 판단을 이해 | 결론 → 맥락/제약 → 멘털 모델 → 메커니즘 → 예시 → 검증 → 트레이드오프 → 행동 |
| `tutorial` | 안내를 따라 학습·완성 | 결과 → 준비 → 전체 경로단계체크포인트 → 최종 검증 → 다음 학습 |
| `how_to` | 특정 작업을 안전하게 완료 | 목표/적용 조건 → 사전 조건 → 절차 → 확인 → 롤백 → 문제 해결 |
| `explanation` | 개념과 원리를 이해 | 질문/답 → 익숙한 기준점 → 모델 → 인과 과정 → 예시 → 대안 → 한계 → 실무 의미 |
| `reference` | 정확한 사실을 빠르게 조회 | 범위/버전 → 구문 → 필드 → 동작 → 오류 → 최소 예시 → 관련 항목 |
| `troubleshooting` | 증상에서 원인과 복구로 이동 | 증상 → 영향 → 안전 → 최소 진단 → 원인 분기 → 조치 → 복구 확인 → 예방 |
| `design_doc` | 대안을 비교하고 결정을 승인 | 결정 요청 → 문제 → 목표/비목표 → 제약 → 대안 → 선택 → 아키텍처 → 실패 → 롤아웃 → 관측 → 위험 |
사용자가 경로를 지정하면 그 선택이 우선합니다. 지정하지 않으면 brief·기존 draft·모든 UTF-8 source를 합친 글자 수와 제목 수, source 수, 신규 작성 여부를 코드가 판정합니다. 계산값은 `00_run.json.route_metrics`에 남고 verifier가 원본으로 다시 계산합니다. 점수 산출에 실패하면 품질 단계를 생략하지 않고 `standard`로 내려갑니다.
상세 근거는 [`research/FOUNDATIONS.md`](research/FOUNDATIONS.md), 구현 규칙은 [`docs/LOGIC_MODEL.md`](docs/LOGIC_MODEL.md)에 정리되어 있다.
## 실행 산출물
## 빠른 실행: 외부 모델 없이 전체 흐름 검증
각 실행은 `_workspace/{YYYY-MM-DD-NNN}/`에 분리됩니다.
```text
00_run.json 실행 상태·경로 지표·입력/계약/규칙 해시
01_input.md 요청과 원문
01_sources.json 참고 자료 인벤토리
02_reader_contract.json 독자·목적·선수지식·비목표
03_evidence_map.json 주장과 근거, 관찰/추론/권고 구분
04_logic_map.json 절별 질문·답·연결·독자 상태
05_term_ledger.json 정식 용어·쉬운 설명·첫 등장·별칭
07_draft.md 초안
08_logic_review.json 논증 리뷰
08_reader_review.json 독자·용어 리뷰
08_lint.json 결정적 검사 결과
final.md 최종 문서
09_final_report.json 최종 판정과 남은 한계
```
`final.md`만 보아도 쓸 수 있지만, 나머지 파일은 왜 이런 구조와 표현을 택했는지 재현하는 감사 기록입니다.
경로상 생략 가능한 파일을 만들지 않았다면 `00_run.json.omissions`에 파일별 이유를 기록합니다. 최종 verifier는 필수 파일이나 이미 존재하는 파일을 생략했다고 선언하지 않았는지 확인하고, 검증된 목록을 `09_final_report.json`에 그대로 남깁니다.
최종 보고서의 `verdict`는 하네스 실행의 완전성, `document_verdict`는 문서 판정입니다. review 모드에서 결함을 정확히 찾아 `document_verdict: revise`가 나온 실행은 `verdict: pass`일 수 있으므로, 진단 성공을 문서 통과와 혼동하지 않습니다. 보고서에는 현재 문서·계약·규칙 SHA-256과 일치한 lint/review만 요약하며, lint의 error/warning 수·rule ID·fidelity·한계와 review별 finding 수·ID를 함께 남깁니다.
lint report는 입력 파일을 output으로 지정할 수 없고, 기존 파일은 같은 도구가 만든 report일 때만 다시 씁니다. verifier output은 run 안의 canonical `09_final_report.json`만 허용합니다. 상태 갱신과 검증은 crash-safe run lock을 공유하며, 일반 `update_run.py` 호출로 `verified`를 만들 수 없습니다. 각 상태 checkpoint도 단계별 파일/schema와 현재 review·lint hash를 직접 검사하므로 빈 파일이나 오래된 pass report로 진행 상태를 앞당길 수 없습니다. 실패 terminal 상태는 다른 상태로 다시 전이하지 않습니다.
write/revise의 `final.md`는 검토·확정한 `07_draft.md`의 byte-identical 게시 복사본입니다. 표현 하나라도 고칠 필요가 생기면 draft를 먼저 고치고 적용되는 두 리뷰를 다시 만든 뒤 복사합니다. 이 경계가 리뷰 뒤의 작은 부정어 변경 같은 의미 드리프트를 막습니다.
## 품질 원칙
1. **독자 먼저** — 대상 독자와 선수지식이 비어 있으면 집필을 시작하지 않습니다.
2. **한 문장 핵심 주장** — 문서가 끝까지 증명할 답을 앞부분에 둡니다.
3. **질문에서 답으로** — 각 절은 독자 질문, 답, 근거, 한계, 다음 연결을 가집니다.
4. **쉬운 설명 후 이름** — 현상·역할을 평이하게 설명한 뒤 필요한 정식 용어를 소개합니다.
5. **근거의 종류 공개** — 관찰한 사실, 거기서 도출한 추론, 저자의 권고를 섞지 않습니다.
6. **검증의 한계 공개** — 테스트가 증명하는 것과 증명하지 않는 것을 함께 적습니다.
7. **결론에서 새 주장 금지** — 처음 문제와 요구를 본문의 구현 또는 명시한 한계에 다시 연결합니다.
8. **코드는 객관적 gate** — 제목, 링크, 용어 첫 사용, 약어, 산출물 계약은 LLM의 자기평가를 믿지 않고 스크립트로 확인합니다.
## 디렉터리
```text
skills/technical-doc-flow/ 단일 오케스트레이터와 런타임 규칙
├─ config/ 품질 규칙 SSOT
├─ schemas/ 산출물 JSON Schema
└─ scripts/ 설치본에서도 동작하는 결정적 런타임
agents/ 좁은 역할의 작성·리뷰 에이전트
scripts/ 저장소 루트용 얇은 CLI 진입점
tests/ 단위·golden·offline E2E·선택적 live 평가
commands/ Gemini CLI 명령
.claude-plugin/ Claude 플러그인 메타데이터
```
구현 원리와 유지보수 규칙은 [CLAUDE.md](CLAUDE.md), 설치 방법은 [INSTALL.md](INSTALL.md), 테스트 철학은 [tests/README.md](tests/README.md)를 참고하세요.
## 지원 범위와 한계
- 현재 정본 출력은 Markdown입니다.
- 현재 하네스는 Markdown 텍스트 문서만 작성·검토합니다.
- 정적 검사는 논리의 의미를 완전히 판단하지 못합니다. 그래서 논리 리뷰와 독자 리뷰를 독립 단계로 둡니다.
- 새 용어의 첫 설명, 별칭 선행 사용, 문장·문단·절 예산, 미등록 영문·코드형 후보는 기본 gate로 막습니다. 소문자 영문은 설정에 열거한 기술어만 후보로 삼아 일반 영문 산문 전체를 오탐하지 않습니다. 다만 표준명이나 코드 식별자를 무작정 쉬운 말로 바꾸는 자동 치환기는 아닙니다.
- 외부 자료의 사실성은 제공된 근거 범위 안에서만 검증합니다. 운영 효과를 관찰하지 않았다면 그렇게 쓰지 않습니다.
## 개발
요구 사항은 Python 3.10 이상이다. 핵심 패키지는 외부 Python 의존성이 없다.
```bash
python3 -m pytest tests -q
python3 scripts/build_quick_rules.py --check
python3 scripts/check_release_sync.py
cd claridoc-harness
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -e .
claridoc run \
--brief examples/briefs/retry-policy-blog.json \
--sources examples/sources/retry-policy-sources.json \
--config config/pipeline.mock.json \
--output .run/retry-policy
```
라이브 LLM 평가는 기본 CI에서 실행하지 않으며, 명시적으로 켰을 때만 실행합니다. 자세한 조건은 [tests/README.md](tests/README.md)에 있습니다.
또는 저장소에서 바로 실행한다.
```bash
bash scripts/run-demo.sh
```
Mock 제공자는 **파이프라인·계약·린터·보고서 재현용**이다. 언어 모델 품질을 증명하지 않으며, 생성 점수도 외부 모델 평가값이 아니라 테스트용 결정적 값이다.
## Codex + Claude + Antigravity 실행
예제 역할 배치는 다음과 같다.
- Codex: 구조 planner와 논리 reviewer
- Claude: primary writer, reader reviewer, reviser
- Antigravity: evidence reviewer와 operations reviewer
먼저 각 도구를 설치하고 인증한 뒤 진단한다.
```bash
claridoc doctor --config config/pipeline.multi-agent.example.json
```
Antigravity SDK 어댑터를 사용할 때는 선택 의존성을 설치한다.
```bash
python -m pip install -e '.[antigravity]'
```
실행:
```bash
claridoc run \
--brief examples/briefs/retry-policy-blog.json \
--sources examples/sources/retry-policy-sources.json \
--config config/pipeline.multi-agent.example.json \
--output .run/retry-policy-live
```
기본 호출 방식은 다음과 같다.
| 제공자 | 기본 통합 | 안전 기본값 |
|---|---|---|
| Codex | `codex exec`에 프롬프트를 stdin으로 전달하고 마지막 메시지를 파일로 수집 | `--sandbox read-only`, Git 저장소 검사 생략 가능 |
| Claude | `claude -p --output-format text`와 piped task | 파일 변경을 요구하지 않는 출력 전용 프롬프트 |
| Antigravity | `google.antigravity.Agent` + `LocalAgentConfig` | SDK 설정을 명시적으로 전달; 하네스 자체는 도구 실행을 요청하지 않음 |
조직별 래퍼가 있으면 provider의 `options.command` 또는 `options.extra_args`를 사용한다. 자세한 내용은 [`docs/PROVIDERS.md`](docs/PROVIDERS.md)를 참조한다.
## 입력 계약
### `brief.json`
브리프는 문서 주제보다 **독자가 왜 읽는지**를 더 엄격하게 정의한다.
```json
{
"title": "API 재시도는 횟수가 아니라 부하 예산으로 설계한다",
"document_type": "technical_blog",
"language": "ko-KR",
"audience": {
"roles": ["백엔드 개발자"],
"prior_knowledge": ["HTTP와 타임아웃의 기본 개념"],
"needs": ["재시도 정책의 판단 기준"]
},
"reader_goal": "장애를 증폭하지 않는 재시도 정책을 설계한다",
"core_message": "재시도는 실패 중인 의존성에 보내는 추가 부하 예산이다.",
"scope": ["동기 HTTP 클라이언트 재시도"],
"non_scope": ["메시지 큐 전달 보장 전체"],
"prerequisites": ["로그와 지표를 조회할 수 있음"],
"required_topics": ["멱등성", "백오프", "지터", "한도", "검증"],
"constraints": {
"target_words": 1200,
"tone": "직접적이고 검증 가능한 문체",
"version_context": "HTTP 의미론은 RFC 9110, 2026-07-23 기준",
"max_heading_depth": 3,
"require_citations": true,
"allow_external_knowledge": false
},
"forbidden_claims": ["재시도는 항상 안전하다"],
"metadata": {"risk": "high"}
}
```
`allow_external_knowledge: false`일 때 모델은 근거 팩 밖의 외부 사실을 추가하지 않도록 지시받는다. 논리 설명과 명시적인 가상 예시는 가능하지만 측정값·버전·사건·API를 지어낼 수 없다.
### `sources.json`
근거 팩은 URL 목록이 아니라 **출처가 실제로 지지하는 사실의 최소 단위**를 제공한다.
```json
{
"sources": [
{
"id": "S1",
"title": "Authoritative source title",
"url": "https://example.com/source",
"publisher": "Publisher",
"accessed": "2026-07-23",
"facts": ["This source explicitly supports this fact."],
"notes": "Allowed use and limitations"
}
]
}
```
모델은 문서에서 `[S1]`처럼 인용한다. 린터는 존재하지 않는 ID, 근거 팩이 비었는데 인용이 필수인 경우, 출처가 있는데 하나도 사용하지 않은 경우를 검사한다. 하네스는 URL 내용을 자동으로 신뢰하거나 실행하지 않는다.
스키마는 [`schemas/`](schemas/)에 있다.
명시적인 pipeline JSON은 `planner`, `writer`, `reviewers`, `reviser`를 모두 포함해야 하며 reviewer는 최소 한 명이어야 한다. reviewer role은 중복될 수 없고, 모델 리뷰는 9개 고정 평가 차원과 허용된 severity만 반환해야 한다. 일부 역할에 Mock을 섞으면 합성 점수가 실제 모델 평가처럼 보이지 않도록 실행 경고가 자동으로 남는다.
## 명령어
```text
claridoc init [directory] [--force]
claridoc validate --brief BRIEF [--sources SOURCES]
claridoc outline --brief BRIEF [--sources SOURCES] [--output OUTLINE]
claridoc lint DOCUMENT --brief BRIEF [--sources SOURCES] [--json] [--output REPORT]
claridoc run --brief BRIEF [--sources SOURCES] [--config PIPELINE] --output RUN_DIR
claridoc doctor --config PIPELINE [--json]
```
`claridoc init`은 시작용 브리프, 근거 팩, Mock 설정을 만든다.
## 품질 게이트
기본 복합 점수는 다음과 같다.
```text
composite = deterministic_lint × 0.4 + model_review_mean × 0.6
```
점수만으로 통과시키지 않는다. 다음을 동시에 확인한다.
- 최소 복합 점수
- blocker 최대 개수
- error 최대 개수
- 최대 수정 라운드
결정적 린터의 주요 검사:
- H1 개수와 제목, heading level skip, 중복·일반적 제목
- 문서 유형 계약의 필수 H2 존재와 순서
- 오프닝의 독자 목표·핵심 메시지·비범위 노출
- 과도하게 긴 문단과 문장, 한 문단에 과도한 문장 수
- 절차 문서의 번호 단계·사전 조건·검증·롤백
- 기술 블로그/설명의 예시와 트레이드오프
- 닫히지 않은 코드 fence와 언어 태그
- 출처 ID, 인용 부재, 숫자·버전형 주장에 대한 근거 표식
- TODO/TBD/FIXME, 금지 주장
- 파괴적 명령 주변의 경고·백업·복구 경로
- 버전/날짜 맥락과 목표 길이
린터는 휴리스틱이다. 문장의 참·거짓과 실제 코드 동작을 보증하지 않는다. 이 부분은 출처 검증, 코드 테스트, 도메인 소유자 리뷰로 보완해야 한다.
## 산출물
```text
run-dir/
├── inputs/
│ ├── brief.normalized.json
│ ├── sources.normalized.json
│ └── pipeline.normalized.json
├── stages/
│ ├── 01-planner.raw.txt
│ ├── 02-outline.json
│ ├── 02-outline.md
│ └── 03-writer.raw.txt
├── rounds/
│ └── round-01/
│ ├── draft.md
│ ├── lint.json
│ ├── lint.md
│ ├── review-*.json
│ ├── review-*.raw.txt
│ └── quality-gate.json
├── final/
│ ├── document.md
│ └── quality-report.md
├── provider-events.jsonl
├── run.json
└── manifest.json
```
`manifest.json`은 자신을 제외한 산출물의 바이트 크기와 SHA-256을 기록한다. 모델 프롬프트에는 소스·브리프가 신뢰되지 않은 데이터라는 경계를 반복해서 넣으며, 원문 응답을 보존해 사후 감사를 가능하게 한다.
## 테스트와 재현 검증
```bash
bash scripts/test.sh
```
전체 배포 전 검증은 다음 한 명령으로 수행한다.
```bash
bash scripts/verify.sh
```
이 명령은 단위·통합 테스트, Python 3.10 문법 호환 파싱, JSON 구문, 로컬 Markdown 링크, 입력 계약, Mock 종단 간 실행, 합성 점수 경고, 산출물 SHA-256 매니페스트를 검사한다.
테스트 범위에는 계약 파싱, 7개 문서 유형 구조, 구조 병합 실패 조건, 리뷰 스키마 우회 차단, 필수 H2 중복, 임의 source ID, 파괴적 명령 안전 통제, reviewer artifact 경로 격리, Codex/Claude 가짜 실행 파일, Antigravity 가짜 SDK, 수정 한도, 전체 Mock 파이프라인, CLI 초기화가 포함된다. 실행 시점의 상세 결과와 실제 외부 provider 미검증 범위는 [`verification/TEST_REPORT.md`](verification/TEST_REPORT.md)에 기록한다.
## Agent Skills
저장소에는 동일한 작성 규칙을 에이전트가 직접 발견할 수 있도록 스킬을 포함한다.
- Codex / Antigravity: `.agents/skills/technical-document-author/SKILL.md`
- Claude Code: `.claude/skills/technical-document-author/SKILL.md`
- 저장소 전역 규칙: `AGENTS.md`, `CLAUDE.md`
스킬은 하네스를 우회해 자유 형식으로 글을 쓰지 않고, 브리프 → 근거 팩 → outline 계약 → 작성 → lint/review → gate 순서를 따르도록 지시한다.
## 보안과 한계
- 제공자 인증 토큰을 구성 파일에 저장하지 않는다. 각 CLI/SDK의 인증 메커니즘을 사용한다.
- `options.command`는 신뢰된 로컬 설정으로 취급한다. 외부 입력을 그대로 command에 넣지 않는다.
- Codex 기본 sandbox는 read-only다. 하네스 자체는 모델에게 shell 실행이나 파일 수정을 요구하지 않는다.
- 브리프·근거 팩·초안 내부의 지시문은 데이터로 취급하도록 모든 단계에서 명시한다. 다만 LLM prompt injection을 수학적으로 제거할 수는 없다.
- URL 접근, 사실 수집, 링크 상태 확인은 이 버전의 core pipeline에 포함하지 않는다. 입력 근거 팩의 진실성은 작성자가 책임진다.
- 실제 코드 예시, 명령, API, 보안·법률·의료·재무 내용은 해당 분야 검증을 별도로 거쳐야 한다.
- Mock PASS는 배선과 규칙이 동작했다는 의미이며 외부 모델이 좋은 문서를 작성했다는 증거가 아니다.
자세한 위협 모델은 [`docs/SECURITY.md`](docs/SECURITY.md)를 참조한다.