Files
llm-wiki/rules/consistency-contract.md
T

88 lines
8.8 KiB
Markdown

# rules/consistency-contract — 문서 간 일관성 계약 (Single-Owner + Reference-Only)
> `rules/` 의 방법론 규칙. 문서 간 **모순의 근원은 재진술(복제)** 이다 — 같은 정책이 두 곳에 적혀 있으면 owner 쪽만 갱신될 때 모순이 *생산*된다. 본 계약은 재진술을 금지하고, 참조를 기계 검증하며, owner 변경을 역참조에 전파한다.
> 집행 3층: ① 결정론 검사기 `.claude/hooks/wiki_consistency_check.py` (Layer 1) ② `wiki-consistency-auditor` 의미 대조 (Layer 2) ③ `/sync` 수거 명령 (Layer 3).
## 원칙
| 원칙 | 내용 |
|---|---|
| **Single-Owner** | 모든 결정·관심사는 **정확히 1개의 owner 문서**를 가진다 — branch-note 의 Decision Evidence Map `D<n>` 행, 또는 project-note 의 `§<n>` 섹션. 같은 관심사를 두 branch 가 `covered-here` 주장하면 `DUAL_OWNERSHIP`. |
| **Reference-Only** | 타 문서는 owner 를 **포인터 + 1줄 요약**으로만 인용한다: `[[raw/branch-notes/<owner>]] D<n> — <1줄 요약>`. 정책 세부(임계값·메커니즘·예외 목록)의 재진술 금지 — 재진술은 owner 진화 시 낡은 복제본이 된다 (`RESTATED_FOREIGN_DECISION`). |
Project contract v2 에서는 project-note 의 Project Decision Registry 가 project-wide 결정 owner 다. ID 는 `DEC-<PROJECT>-<DOMAIN>-NNN`, revision 은 양의 정수이며 branch 참조는 항상 `DEC-...@revision` 으로 pin 한다. `<PROJECT>`·`<DOMAIN>` 은 uppercase kebab-case 다.
## 참조 형식 표준 (검사기 파싱 규약)
| 대상 | 형식 | 금지 |
|---|---|---|
| branch 결정 | `[[raw/branch-notes/<slug>]] D<n>` — wikilink **종료 후 같은 줄 100자 이내**에 `D<n>` | bare 슬러그 + D<n> (예: `feature-x-contract D7`) → `BARE_DECISION_REF` |
| project 섹션 | `[[raw/project-notes/<slug>]] §<n>` — 같은 줄 100자 이내 | 부재하는 § 번호 → `DANGLING_SECTION_REF` |
| Coverage delegated owner | owner 셀에 wikilink 필수 | bare 이름 → `BARE_OWNER_REF` |
| project 결정 | `DEC-<PROJECT>-<DOMAIN>-NNN@<positive-revision>` + `[[raw/project-notes/<slug>]]` | revision 없는 ID, 결정 상세 복제 |
| project Work Item | `WI-<PROJECT>-NNN` | branch slug 만으로 project handoff 식별 |
- `D<n>` 토큰이 wikilink 에서 같은 줄 100자를 넘으면 검사기가 참조 엣지로 인식하지 못한다 — 링크 직후에 쓴다.
- fenced code block 내부는 검사 대상 아님 (예시/템플릿 허용).
## 명명된 실패 모드
| 코드 | 층 | 의미 |
|---|---|---|
| `DANGLING_DECISION_REF` | 결정론 (`wiki_consistency_check.py`) | `[[feature-B]] D17` 인데 B 의 결정 표에 D17 부재 (B 실존 시 — 노트 부재는 `BROKEN_LINK` 몫) |
| `BARE_DECISION_REF` | 결정론 | wikilink 없는 bare 슬러그 + `D<n>` — 기계 추적 불가 |
| `BARE_OWNER_REF` | 결정론 | Coverage delegated 행의 owner 셀에 wikilink 없음 |
| `DUAL_OWNERSHIP` | 결정론 | 같은 관심사(정규화 exact)를 두 branch 가 `covered-here` 주장 |
| `DANGLING_SECTION_REF` | 결정론 | `[[project-note]] §34` 인데 해당 § 헤더 부재 |
| `STALE_SUMMARY` | 의미 (`wiki-consistency-auditor`) | 참조의 1줄 요약이 owner D-row 의 현재 내용과 어긋남 (owner 진화 후 무통보 낡음) |
| `CONTRADICTION` | 의미 | 두 문서가 같은 사안에 대해 양립 불가한 진술 |
| `RESTATED_FOREIGN_DECISION` | 의미 | 타 owner 의 결정 세부를 포인터 없이/포인터와 함께 본문에 재진술 (복제) |
| `MISSING_PROJECT_BINDING` | 결정론 | `project-work-item`의 slug가 WI row와 다르거나, `branch-child`의 parent·project·work_item 상속이 누락/불일치/순환임 |
| `MISSING_INHERITED_DECISION` | 결정론 | Work Item `Applies Decisions` 의 pinned ref 가 branch `inherits` 또는 Contract Packet 에 없음 |
| `STALE_INHERITANCE_REVISION` | 결정론 | branch 의 pinned revision 이 project registry 의 현재 decision revision 과 다르고 migration/override 로 설명되지 않음 |
| `CONFLICTS_WITH_PROJECT_DECISION` | 의미 | branch-local 결정·적용 요약이 inherited project decision 과 양립 불가하며 유효한 override 도 없음 |
| `UNDECLARED_OVERRIDE` | 결정론 + 의미 | project 결정과 다른 동작을 취하면서 `overrides` 와 Declared Overrides 표에 같은 pinned ref·이유·승인을 선언하지 않음 |
| `MISSING_EXPECTED_EDGE` | 결정론 | project→Work Item→branch, Work Item dependency, decision→branch inheritance 중 registry 가 기대하는 edge 가 없음 |
| `DUPLICATE_DECISION_OWNER` | 결정론 + 의미 | 같은 stable Decision ID 또는 같은 정규화 관심사를 둘 이상의 project/branch owner 가 소유함 |
| `DUPLICATE_BRANCH_ID` | 결정론 | 같은 stable Branch ID를 둘 이상의 v2 branch가 선언함 |
## Project → Work Item → Branch 상속 계약
1. project-note 가 `project_revision`, Project Decision Registry, Work Item Registry 를 소유한다.
2. Work Item row 는 적용 결정을 `DEC-...@revision` 으로 pin 하고 dependency 를 `WI-...` 로 가리킨다.
3. project 직접 자식 branch 는 `/branch-from-project` 로 만들며 frontmatter `project`·`work_item`·`inherits`·`depends_on``## Branch Contract Packet` 을 가진다.
4. branch 는 inherited 결정의 상세를 복제하지 않는다. project wikilink + pinned ref + project summary + branch application 만 기록한다.
5. branch-local 결정은 `D<n>` owner row 로 유지한다. project 결정을 refine 하면 `refines`, 다르게 적용하면 `overrides` 와 Declared Overrides row 를 함께 기록한다.
6. `kind: project-work-item`은 자기 slug가 Work Item Registry의 `branch slug`와 exact match여야 한다.
7. `kind: branch-child``parent_branch`가 필수이며 parent가 실존하고 cycle이 없어야 한다. child는 parent와 같은 `project`·`work_item`을 상속하고, Work Item row의 `branch slug`는 child가 아니라 parent `project-work-item` slug와 match한다.
8. `branch-child.inherits`는 parent inheritance + Work Item `Applies Decisions`의 superset이어야 한다. 제외는 같은 pinned ref가 frontmatter `overrides`와 승인된 Declared Overrides row 양쪽에 선언된 경우만 허용한다.
9. 직접 branch의 `id`는 Work Item ID의 `WI-``BR-`로 바꾼 값이다. child는 `BR-<PROJECT>-CHILD-<SHA256(slug) 앞 8자리>`를 사용하며 rename 뒤에도 ID를 재사용한다.
10. `planned`·`backlog`·`proposed`·`documented-only` Work Item은 branch 파일이 아직 없어도 expected-edge 실패로 보지 않는다. `in-progress` 이상 상태에서만 branch 실존을 요구한다.
archive로 격리한 문서는 active graph 검사에서 제외한다. active project/branch는 v2 계약을 적용하며 legacy 문서가 발견되면 `LEGACY_GRAPH_CONTRACT`로 이관 대상임을 보고한다.
## 전파
owner 노트의 D-row (결정 표) 가 변경되면:
1. **PostToolUse 훅이 역참조 목록을 비차단 알림** — 쓰기는 이미 완료, 모델에 "이 결정을 참조하는 문서 N개" 정보만 전달.
2. **같은 세션에서 참조 요약 갱신을 권장.** 변경이 D-row 의 의미를 바꿨다면 참조 측 1줄 요약이 낡았을 가능성이 높다.
3. 같은 세션에서 못 갱신한 항목은 **`/sync` 가 수거** (Layer 2 의미 대조 → fix-plan).
신규 참조 작성 시에는 PreToolUse 가 `DANGLING_DECISION_REF`/`DANGLING_SECTION_REF`**쓰기 차단** — owner 의 실제 Decision ID 를 확인하거나, 결정이 아직 없으면 owner 노트에 먼저 기록한다.
## 충돌 해소 우선순위
1. **owner 문서 우선** — 위임한 쪽(참조자)이 요약을 갱신한다. owner 본문을 참조자에 맞춰 고치지 않는다.
2. **hub(project-note) vs branch 충돌은 자동 적용 금지** — fix-plan 으로 사용자 판정. 보통 branch 가 더 최신·구체이므로 "project-note 갱신 제안" 형태가 기본이지만, 어느 쪽이 옳은지는 사용자가 정한다.
3. **적용은 항상 승인 후** — 어떤 해소도 사용자 확인 없이 본문을 바꾸지 않는다.
## retro 정책
- 기존 재진술·bare 참조는 **`/sync` 의 fix-plan 으로 점진 수거** — 일괄 자동 수정 금지. (2026-06 전수 dry-run: findings 190건 = `BARE_DECISION_REF` 129 · `BARE_OWNER_REF` 60 · 실제 `DANGLING_DECISION_REF` 1건 — D14 오귀속.)
- **신규 작성은 본 규약 준수** — 작성 시 참조 형식 가이드는 capture 계열(`/branch-spec` 등)이 본 문서를 참조한다.
## 한계 — 귀속 모호성
검사기는 외부 링크 후방 윈도의 `D<n>` 이 **인용자 자신의 DEM 에도 존재하면 침묵**한다 — 자기-결정 언급일 수 있기 때문 (실코퍼스: "X 에 의존 — 우회(D13)" 의 D13 이 인용자 자신의 D13). 따라서 결정론 층은 이런 케이스의 오귀속을 잡지 못하며, **의미 귀속 판정은 Layer 2 `wiki-consistency-auditor` 의 몫**이다.