# Implementation Report: `flow-doc@1` 신설 — 절차·권한 매뉴얼 형식

**Plan**: `.claude/PRPs/plans/completed/doc-template-kit-m7.plan.md`
**Branch**: `feat/doc-template-kit`
**Milestone**: `doc-template-kit` M7 (M1~M6 complete, M7 이 마지막)
**날짜**: 2026-08-05

## Summary

3번째 문서 타입 `flow-doc@1` 을 신설했다. **"목적을 가진 actor 가 무엇을 어떤 순서로, 어떤 권한으로"** 를 담는 절차 매뉴얼 형식이며, `50-domain` 의 흐름·콘솔 문서 10개(`docs/20-site/` 5 + `docs/30-admin/` 5)가 이 형식을 쓴다.

PRD 가 "재계획 시 확정한다" 로 남긴 미확정 3건을 전부 확정하고 구현했다 — 상호참조 방식 · flow 의 `status` 규칙 · lint 규칙 집합. 새 문서군도, 배타 소유 경로 변경도 없다.

## Assessment vs Reality

| Metric | Predicted (Plan) | Actual |
|---|---|---|
| Complexity | Medium | Medium — 예측대로 |
| lint 신규 규칙 | 4 | **3** (`id-crossref` 는 신규가 아니라 기존 규칙의 flow 분기) |
| lint 신규 헬퍼 | 2 (`h3Range` · 표 헬퍼 확장) | **4** (`h3Ranges` · `labelRanges` · `tableFirstColumnInRange` · `substantiveLines`) + `doc.fenced` |
| Files Changed | 17 | **17** (신규 8 · 갱신 9) |
| 예시 flow 건수 | ≥ 3 (콘솔 ≥ 1) | 3 (site 1 · 콘솔 2) |
| fixture | 5종 + 전용 config | 5종 + 전용 config |

## Tasks Completed

| # | Task | Status | Notes |
|---|---|---|---|
| 1 | config 키 2종 추가 | 완료 | `auth_layers` 5행 · `status_precedence` 8행. 각 값의 근거를 주석으로 |
| 2 | `flow-example.md` 초안 — 실물 3건으로 형식 역검증 | 완료 | 판정 3항목 통과 (아래 참조) |
| 3 | `flow-doc.template.md` | 완료 | 필수 절 3 + 선택 1. insuniverse 고유값 0 |
| 4 | `TEMPLATES` 등록 · `id-crossref` · `flow-block` | 완료 | |
| 5 | `auth-layers` (조건부 필수 포함) | 완료 | 권한 라벨 범위로 스코프 — "블록 첫 표" 보다 견고 |
| 6 | `flow-refs` + `--strict-refs` + 경고 채널 | 완료 | `lintFile` 반환형 변경 · 호출부 4곳 갱신 |
| 7 | fixture 5종 + selftest 배선 | 완료 | strict 양방향 + 코드펜스 케이스 추가 |
| 8 | README 갱신 | 완료 | 규칙 표 12 → 15 · 한계 6행 → 11행 |
| 9 | 상류 문서 정정 | 완료 | **Task 7 이후로 순서 고정** (Codex 흡수, 아래 참조) |

### Task 2 형식 역검증 판정 (Task 3 진입 게이트)

| 판정 | 결과 |
|---|---|
| (a) 한 블록 안에 4요소가 들어가는가 | 통과 — `전제`·`절차`·`권한`·`실패·이탈` 전부 `### <id>` 안 |
| (b) 목록 표만 보고 문서를 훑을 수 있는가 | 통과 — flow id · 목적 · actor · status 4열 |
| (c) 블록이 화면 스크롤 2개를 넘지 않는가 | 통과 — 42 / 38 / 52줄 |

D3 재설계 불필요. Task 3 이하 정상 진행.

## Validation Results

| Level | Status | Notes |
|---|---|---|
| Static Analysis | 통과 | `node --check lint-docs.mjs` OK. 이 저장소에 type-check/lint 인프라 없음 |
| Unit Tests | 통과 | `--selftest` 가 유일한 상시 검사 (`00-protocol` PRD 제약: 테스트 프레임워크 금지) |
| Build | N/A | 빌드 대상 아님 — Markdown + 의존성 0 Node 스크립트 |
| Integration | N/A | 서버 없음 |
| Edge Cases | 통과 | BOM+CRLF · 코드펜스 · strict 양방향 · 미지원 YAML 7종 |

```
selftest OK
  정상 3건 PASS  (policy-example · ia-example · flow-example)
  결함 10건이 지정 규칙으로 FAIL
  strict 양방향 (한 프로세스 안에서 두 모드)
  코드펜스 안의 표가 진짜 표로 읽히지 않음
  BOM + CRLF
  미지원 YAML 문법 7종 거부
```

| 명령 | exit | 기대 |
|---|---|---|
| `lint-docs.mjs --selftest` | 0 | 0 |
| `lint-docs.mjs examples/flow-example.md` | 0 + stderr notice 2건 | 0 |
| `lint-docs.mjs --strict-refs examples/flow-example.md` | 1 | 1 |
| `lint-docs.mjs examples/policy-example.md examples/ia-example.md` | 0 | 0 (회귀 없음) |
| `lint-docs.mjs --strict-refs` (policy · ia) | 0 | 0 |
| `lint-docs.mjs --bogus x.md` | 2 | 옵션 오타를 조용히 무시하지 않는다 |

`flow-example.md` 앵커 9개 전부 실재 파일임을 기계 확인했다.

### Design Grounding

N/A (no design trigger) — `impeccable-detect` 가 `skill_available=false` · `design_signal=false`.
산출물에 렌더링 표면(`.tsx/.css/.html`)이 0이다. Phase 3.6 DESIGN FINISH · Phase 3.7 GROUNDING VERIFY 둘 다 no-op.

## Files Changed

**신규 8**

| File | Lines |
|---|---|
| `.claude/templates/doc-kit/flow-doc.template.md` | +124 |
| `.claude/templates/doc-kit/examples/flow-example.md` | +215 |
| `.claude/templates/doc-kit/examples/fixtures/bad-flow-block.md` | +53 |
| `.claude/templates/doc-kit/examples/fixtures/bad-auth-layers.md` | +63 |
| `.claude/templates/doc-kit/examples/fixtures/bad-status-precedence.md` | +69 |
| `.claude/templates/doc-kit/examples/fixtures/bad-flow-config-missing.md` | +67 |
| `.claude/templates/doc-kit/examples/fixtures/config-no-flow-keys.yaml` | +19 |
| `.claude/templates/doc-kit/examples/fixtures/bad-flow-xref.md` | +66 |

**갱신 9**

| File | Lines |
|---|---|
| `.claude/templates/doc-kit/lint-docs.mjs` | +330 / −23 |
| `.claude/templates/doc-kit/README.md` | +87 / −26 |
| `.claude/templates/doc-kit/template-config.schema.md` | +48 / −7 |
| `.claude/templates/doc-kit/examples/template-config.insuniverse.yaml` | +24 |
| `.claude/prds/doc-template-kit.prd.md` | +69 / −3 |
| `.claude/prds/insuniverse-docs-50-domain.prd.md` | +22 / −1 |
| `.claude/prds/insuniverse-policy-docs.prd.md` | +20 / −4 |
| `.claude/meta/06-access-model-findings.md` | 열린 항목 1건 → 닫힌 항목으로 이동 |
| `.claude/plans/doc-template-kit-m7.plan.md` | Codex Implementation Review 섹션 주입 (게이트) |

## Deviations from Plan

| # | WHAT | WHY |
|---|---|---|
| 1 | 신규 규칙 **4 → 3** | `id-crossref` 의 flow 분기는 기존 규칙 이름에 `forTemplate("flow-doc@1")` 분기를 하나 더 다는 것이라 신규 규칙이 아니다. README 표는 15행(12 공통 + 3 flow 전용)으로 적었다 |
| 2 | `auth-layers` 스코프를 "블록 첫 표" 가 아니라 **`권한` 라벨 범위**로 | 계획 Task 5 문구는 "각 H3 블록의 첫 표" 였으나, `전제` 에 표를 쓰면 그게 첫 표가 된다. `flow-block` 이 이미 계산하는 라벨 범위를 재사용하는 편이 견고하고 코드도 짧다 |
| 3 | 헬퍼 2개 → **4개 + `doc.fenced`** | Codex 가 지적한 코드펜스 미인지를 흡수했다. 예시로 적어 둔 표가 진짜 표로 읽히는 오탐을 막는다. `tableFirstColumn` 도 이 혜택을 받는다(기존 두 타입 회귀 없음 확인) |
| 4 | `--strict-refs` 를 모듈 전역 상수가 아니라 **`lintFile(file, {strictRefs})` 인자로** | Codex next_steps #2 흡수. 전역이면 selftest 가 한 프로세스에서 두 모드를 돌 수 없어 양방향 검사가 성립하지 않는다 |
| 5 | 예시 flow **4건 계획 → 3건** | sales 콘솔 진입 flow 는 정직하게 해결 가능한 `refs` 대상이 없었다(대응 IA·정책 문서 미작성). 없는 참조를 지어내는 대신 뺐다. `50-domain` 의 `03-sales-console.md` 착수 시 자연히 생긴다. 비차단 메뉴 노출 층의 통찰은 남은 3건의 `권한` 표가 전부 담고 있다 |
| 6 | Task 9 를 **Task 7 이후로 순서 고정** | Codex F1 흡수. 상류 문서가 "산출 완료" 라고 선언하는 시점이 selftest 통과 시점보다 앞서면, 명세만 머지되고 강제는 없는 상태가 만들어진다 |
| 7 | 상류 `mnu_url` 100% 문구에 **정정 배너 추가** | 계획에 없던 발견. `doc-template-kit.prd.md` M7 배경의 "100% 일치" 는 findings §4 재측정(80/82, 98%)에 의해 이미 낡았다. 원문을 지우지 않고 배너를 얹었다 |

## Issues Encountered

| # | 문제 | 해결 |
|---|---|---|
| 1 | 게이트가 지시한 plan 편집(`## Codex Implementation Review` 주입)이 상류 `mccp-plan-codex` receipt 의 `plan_hash` 를 무효화 → `validate` exit 2 | 동일한 결과값(`codex_verdict=divergent` · `impeccable_skipped`)으로 재스탬프하고 **의미 diff 가 비어 있음을 기계 대조**했다. 해시·타임스탬프 외 변경 0 |
| 2 | `AdminLayout.tsx` corp 분기가 findings §1 기록(`filterMenusByAuthority(corpMenus, corpCode)`)과 달라져 있었다 — 지금은 `getCorpMenuCodes(corpCode, agcRole, agcAnalysisView)` 를 거친다 | 계획 Risk "예시 앵커가 findings 시점 코드와 어긋남" 이 실제로 발동했다. 앵커는 전부 **파일을 직접 열어 확인한 실물**만 썼다 |
| 3 | 코드펜스 인지 로직을 넣었으나 어떤 예시도 펜스를 쓰지 않아 **검증되지 않는 코드**가 됨 | selftest 에 주입 케이스 추가 + 펜스 없는 음성 대조로 **판별력이 있음을 확인**했다 (펜스 없으면 `auth-layers` FAIL) |

## Tests Written

프레임워크 없음 (`00-protocol` PRD 제약). `--selftest` 가 전부다.

| 검사 | 건수 | 대상 |
|---|---|---|
| 정상 PASS | 3 | policy · ia · **flow** 예시 |
| 결함 FAIL (지정 규칙 단언) | 10 | 기존 5 + **신규 5** |
| strict 양방향 | 1 | 같은 문서 · 같은 프로세스 · 두 모드 |
| 코드펜스 | 1 | 펜스 안 표가 진짜 표로 읽히지 않는가 |
| BOM + CRLF | 1 | Windows 작성 환경 |
| 미지원 YAML 거부 | 7 | 조용히 넘기지 않는가 |

## 남는 한계 (README 한계표에 기재)

- **참조 대상 부재** — `--strict-refs` 를 돌리지 않으면 dangling ref 가 살아남는다. 이 저장소에 CI 가 없어 강제는 우산 제약 #7 이 유일하다
- **`status` 승계의 완결성** — 미해결 참조가 있으면 지배 요소 판정은 부분 검증이다
- **문서 밖 구성 요소** — 코드만 있는 단계는 `refs` 가 없어 지배 순서 계산에 들어오지 않는다
- **`status_precedence` 순서 자체** — 프로젝트가 선언한 순서가 옳은지는 lint 가 판정하지 못한다
- **`권한` 표 내용의 진위** — 첫 열 집합만 본다. `해당 없음` 이 정말 해당 없는지는 리뷰어 몫

## Next Steps

- [ ] `/mccp:pr` — PR 생성 (PR-Codex 게이트가 산출된 diff 를 실제로 리뷰한다)
- [ ] `50-domain` 흐름·콘솔 문서 10개 착수 가능 — 착수 전 `docs/_meta/template-config.yaml` 에 `auth_layers` · `status_precedence` 추가 필요
