# 정책 문서 단일화·뷰어 메타분석

> **번호 변경 2026-08-11**: 원래 `07-doc-viewer-meta-analysis.md` 였다. `docs-viewer` worktree 에만
> 있어 `main` 의 `07-domain-knowledge-gap.md` 와 번호가 충돌했고, worktree 통합 시 14 로 옮겼다.
> 내용은 무편집. 참조하는 두 파일(`insuniverse-docs-70-viewer.prd.md` · `docs/_meta/viewer-requests.md`)의
> 경로도 함께 고쳤다.
>
> 작성 2026-08-10 · 대상: 우산 PRD `insuniverse-policy-docs` 산출물(50문서)을 사람이 읽는 단일 표면으로 만드는 작업
> 판정 근거는 이 저장소 실측 + 타사 사례 + 논문. 링크는 §5.
> **이 문서는 분석이며 규약이 아니다.** 규약 정본은 `05-final-spec.md` / `.claude/templates/doc-kit/`.

---

## 0. 결론 먼저

| 질문 | 판정 |
|---|---|
| 지금 PRD 수준으로 뷰어 구현 가능한가 | **부분 가능.** 파서·데이터 계약의 70%는 이미 있다. 5개 필드가 없어서 핵심 기능 3개가 못 만들어진다 |
| 지금 착수해야 하는가 | **아니다.** 소비 문서 실측 0건. 첫 5문서(`20-foundation-access`) 나온 뒤 착수 |
| 지금 해야 하는 것 | **데이터 계약 5필드를 `template-config.yaml` 확정(M5) 때 같이 넣는 것.** 그 시점을 놓치면 50문서 전부 재작성 |
| 무엇을 만드나 | **단일 자립 HTML 1개.** SSG(MkDocs·Docusaurus) 도입 안 함. 사유 §4 |

핵심 발견 한 줄: **우산 제약 #1(기획/개발 2절 분리)이 이미 DITA 의 audience profiling 을 H2 레벨로 구현한 것**이다. 뷰어는 독자 분리를 새로 발명할 필요가 없고 렌더 시점에 lane 토글만 붙이면 된다. 이게 이 프로젝트에서 가장 값싸고 가장 효과 큰 기능이다.

---

## 1. 구현 가능한 근거 — 이미 있는 것

| 자산 | 실측 | 뷰어에서의 쓸모 |
|---|---|---|
| 3종 템플릿 프론트매터 | `policy-doc@1` · `ia-doc@1` · `flow-doc@1` | 문서 = 구조화 레코드. `doc_id`·`title`·`policies[].{id,status,evidence,anchors,unknown_reason,limitations}`·`last_verified` 전부 기계 필드 |
| `lint-docs.mjs` 920행 | 평탄 YAML 파서 · `parseDoc` · `sectionRange` · `h3Ranges` · `labelRanges` · `resolveRefItem`(문서간 참조 해석) | **뷰어 파서를 새로 쓰지 않는다.** 파서 부분을 모듈로 떼어내 재사용 |
| `template-config.yaml` 계약 | statuses 8 · evidence_grades 15 · actors 6 · services 3 · repos 3 · auth_layers 5 · status_precedence | 패싯(필터 축)이 공짜로 나온다. 뷰어가 자체 분류 체계를 만들 필요 없음 |
| 우산 제약 #1 | `## 정책 (기획)` / `## 강제 지점 (개발)` H2 고정 + 양쪽 `### <id>` 집합 일치를 lint 가 강제 | 독자별 lane 렌더의 전제조건이 이미 기계 검증된다 |
| 우산 제약 #7 | lint 가 유일 강제수단(CI 없음) | 뷰어 빌드가 두 번째 게이트가 될 수 있다 — 빌드 실패 = 형식 위반 |
| `extraction-manifest.yaml` | repo 3종 SHA 문자열 동결 | 앵커 rot 검사의 기준점. 코드가 움직였는지 판정 가능 |

즉 "마크다운 50개를 긁어 목차 붙이기" 수준이 아니라, **프론트매터가 곧 DB인 상태**다. 이건 대부분의 사내 문서화 프로젝트가 도달하지 못하는 지점이다.

---

## 2. 못 만드는 것 — 빠진 데이터 계약 5

각 항목: 무엇이 없는가 / 그래서 뷰어의 무엇이 죽는가 / 언제 넣어야 하는가.

### 2-1. `repos[].url_template` — 앵커가 링크가 안 된다 (심각도: 높음)

앵커 형식은 `insuniverse-server/apps/api/src/.../x.guard.ts#ClassName` 문자열이다. 저장소는 서브모듈이고 SHA 는 manifest 에 동결돼 있는데, **원격 호스트 URL 이 어디에도 없다.** 뷰어가 앵커를 클릭 가능한 링크로 못 만든다.

- 죽는 기능: "정책 → 코드로 1클릭" — 우산 제약 #4(역추적 가능)의 실사용 형태
- 필요: `template-config.yaml` 또는 manifest 에 `repos[].url_template: "<base>/blob/{sha}/{path}#L{line}"` + 앵커에 line 번호 또는 심볼 해석 규칙
- 넣을 시점: **M5(템플릿 고유값 채우기)**. 이후면 앵커 표기법 자체를 바꿔야 할 수 있다

### 2-2. status 메타데이터가 데이터가 아니다 (심각도: 높음)

`config.statuses` 는 이름 8개 나열뿐이다. "본문 수록 / 부록 격리 / `99-deprecated` 로" 라는 **처리 규칙과 심각도는 `05-final-spec.md` §3 산문 표에만 있다.**

- 죽는 기능: 상태 배지 색·정렬·"미판정만 보기" 필터 — 뷰어의 최대 가치인 *폐기 정책 오학습 차단*이 바로 이 필터다
- 필요: statuses 를 스칼라 리스트 → 매핑으로 승격. `active-prod: {label: "운영 반영", severity: 0, placement: body}` 형태. `status_precedence` 가 이미 존재하므로 severity 는 그 순서에서 파생 가능 → 실질 추가는 `label`·`placement` 2필드
- 주의: `lint-docs.mjs` 가 `statuses` 를 평탄 리스트로 읽으므로 스키마 변경은 lint 동반 수정. **M5 이전이면 비용 0, 이후면 lint + 전 문서 재검증**

### 2-3. 읽는 순서가 기계 형태로 없다 (심각도: 중)

`docs/00-index.md` 는 사람용 마크다운이고 **아직 미생성**(M7 pending). spec §4 의 트리는 산문이다.

- 죽는 기능: nav 트리, 이전/다음, "선행 개념 없이 읽히는 문서가 없도록"이라는 순서 원칙의 렌더
- 선택지 2개:
  - (a) 파일명 숫자 접두(`01-`, `02-`)를 정렬 계약으로 **선언**한다 → 추가 파일 0. 이미 전 경로가 그렇게 설계돼 있다
  - (b) `docs/_meta/nav.yaml` 신설 → 파일 1개 추가, 소유자 `00-protocol`
- 권장: **(a).** 이미 지켜지는 규칙을 계약으로 승격하는 게 가장 싸다. 단 `00-index.md` 에 "파일명 숫자가 읽는 순서다" 한 줄을 명시해야 계약이 된다

### 2-4. 연혁이 프론트매터 밖 자유 표다 (심각도: 중)

`## 연혁` 은 `릴리스 | 날짜 | SHA | 변경 요약` 마크다운 표다.

- 죽는 기능: **문서 횡단 타임라인** — "2026-03 에 어떤 정책들이 같이 바뀌었나". 우산 PRD 가 명시한 문제 (c)"왜 이렇게 되어 있는가에 답을 얻지 못한다"에 직접 대응하는 유일한 뷰
- 선택지: 표 파싱을 감수(형식 흔들리면 조용히 실패) / 프론트매터로 승격(작성 부담 증가) / **타임라인 포기, 문서 내 렌더만**
- 권장: 1차 뷰어는 표 파싱하되 **파싱 실패를 경고로 노출**한다. 조용히 빠뜨리는 것이 이 프로젝트에서 가장 위험한 실패 양식이다(§3 논문 근거)

### 2-5. 문서 ↔ `policy-candidates.*.jsonl` 연결 키 없음 (심각도: 낮음, 그러나 지표에 직결)

Success Metric #3(담당자 이해 일치)의 측정 단위는 문서 본문이 아니라 **`policy-candidates.*.jsonl` 행**이다. 그런데 `policies[].id` 와 candidate 행 id 를 잇는 필드가 정의돼 있지 않다.

- 죽는 기능: 리뷰 모드 — "이 정책은 어느 후보 행에서 왔나 / 후보 중 문서화 안 된 것은 무엇인가"
- 필요: `policies[].candidate_refs: [<jsonl id>]` 또는 candidate 쪽에 `documented_in`
- 지금 정할 필요는 없다. 단 인덱스 3종이 candidate 행에 **안정적 id 를 부여하고 있는지**는 지금 확인해야 한다. 없으면 나중에 만들 수 없다

### 부수 확인 사항 (계약 아님)

- `90-history/**` · `99-deprecated/**` 는 lint 예외이고 `template:` 이 없다 → 뷰어는 **비정형 문서 2등급 경로**를 반드시 가져야 한다. 5문서. 프론트매터 없는 마크다운으로 렌더하고 배지 없음 처리
- `ia-doc@1` 은 현재 소비 문서 0건 → 뷰어 1차는 `policy-doc@1` + `flow-doc@1` 2종만 지원해도 손실 없음
- 합본(단일 .md) 요구를 살리려면 H1 강등 + id 네임스페이싱이 필요하다(문서 50개 × H1 1개 = 앵커 충돌). 단일 HTML 로 가면 이 문제가 자동 소멸

---

## 3. 타사 사례 · 논문에서 가져올 것

### 3-1. 사례

| 사례 | 사실 | insuniverse 적용 |
|---|---|---|
| **GitLab Handbook** | handbook-first · SSoT · 개인은 월 1회, 팀은 분기 1회 자기 섹션 감사 스프린트. 2,700+ 페이지 | 채택: **재검증 주기.** `last_verified` 필드는 있는데 *갱신 의무*가 PRD 어디에도 없다. 뷰어가 `last_verified` ↔ 서브모듈 HEAD 격차를 배지로 노출하면 주기가 자동 가시화된다. 경계: 2,700 페이지는 반면교사 — 50문서 상한을 지켜라 |
| **Spotify Backstage TechDocs** | docs-like-code. 마크다운을 코드 옆에 두고 CI 가 MkDocs 로 빌드, 중앙 포털에서 렌더. Backstage 130+ 플러그인 중 트래픽 20% 를 TechDocs 가 차지 | 부분 채택: 중앙 렌더는 맞다. 단 **코드 옆에 두는 축은 뒤집는다** — 정책이 3저장소를 관통하므로(ANS 상태코드 59종) 문서는 4번째 저장소에 있는 게 맞다. 대신 stale 검출을 명시적으로 짜야 한다(그게 docs-like-code 가 공짜로 주던 것) |
| **Google / Twitter / Spotify 문서 문화** | 엔지니어가 꼽은 3위 문제가 "필요한 기술 문서를 못 찾음" | 채택: **검색이 부가기능이 아니라 1급 기능.** 50문서라도 마찬가지 |
| **Diátaxis** (Django · Canonical · Cloudflare · Gatsby) | 4분면 — tutorial / how-to / reference / explanation. 두 축: 행동↔지식, 학습↔업무 | 진단에 사용: 현 3종 매핑은 `policy-doc`=reference, `flow-doc`=how-to, `ia-doc`=reference. **explanation 사분면이 비어 있다.** 우산 PRD 가 스스로 문제 (c)로 적은 "왜"가 소유자 없는 상태다. `90-history/02-epics.md` 가 유일한 근접이고 그건 lint 예외 = 품질 미보증 |
| **DITA conditional profiling** | `@audience` `@platform` `@product` 속성 + DITAVAL 로 단일 소스에서 독자별 변형 출력 | **이미 저수준으로 구현돼 있다.** H2 2절 = audience 2값. 뷰어에서 lane 토글(기획 / 개발 / 통합)로 렌더하면 DITA 가 하는 일을 도구 없이 얻는다. `## 플랫폼 차이` 절은 `@platform` 대응 |
| **Living Documentation** (Martraire) / Specification by Example (Adzic) | 좋은 살아있는 문서 4원칙: reliable · low-effort · collaborative · insightful | 진단: 근거 2중화 + evidence 등급이 **reliable** 을 담당한다(강함). **low-effort 는 현재 0** — 50문서 전량 수작업. 자동 앵커 검증이 가장 싼 low-effort 레버 |
| **ADR** (Nygard, adr.github.io, MS Well-Architected) | 결정 1건 = 맥락 + 근거 + 귀결. 근거 없는 기록은 시간이 지나면 가치를 잃는다 | 갭: `## 연혁` 은 `릴리스\|날짜\|SHA\|변경 요약` 이며 **"왜"를 담는 칸이 없다.** 최소 조치 — 변경 요약 칸의 작성 규약에 "무엇이 바뀌었나 + 왜"를 명시하거나, 5열을 추가. 이걸 안 하면 문제 (c)는 형식적으로 해결 불가 |

### 3-2. 논문

| 근거 | 발견 | 적용 |
|---|---|---|
| Aghajani et al., **Software Documentation Issues Unveiled** (ICSE 2019) — 878 문서 관련 아티팩트를 메일링리스트·SO·이슈·PR 4소스에서 수집·분류 | 문서 문제의 최대 계열은 정보 내용의 정확성·완전성, 그리고 **outdatedness** | status 모델 + 5중 폐기 필터가 이 계열을 정면으로 겨냥한다. 설계가 문헌과 일치 — 이 부분은 바꾸지 마라 |
| Aghajani et al., **Software Documentation: The Practitioners' Perspective** (ICSE 2020) | 실무자 관점에서 문서 이슈의 상대 중요도·해결 가능성을 조사 | 지표에 커버리지 %를 안 쓰기로 한 판단을 지지 |
| **Detecting outdated code element references in software repository documentation** (EMSE 2023, 3,000+ GitHub 프로젝트) | **대부분의 프로젝트가 이력 중 한 번은 outdated code element reference 를 갖는다** — 소스에서 전부 지워졌는데 문서에 살아남은 참조 | **뷰어 최우선 기능의 근거.** 앵커(파일 경로 + 심볼)를 서브모듈 SHA 기준으로 기계 검증하고 rot 배지를 붙인다. 문헌상 "언젠가"가 아니라 "반드시" 발생한다 |
| Steinmacher et al., **Barriers faced by newcomers to OSS: a systematic review** — 5계열 58 배리어 | 문서 문제가 5계열 중 하나. **오래된 문서는 신입에게 도움이 아니라 장애물이 된다** | 우산 PRD Risk 표의 "이 실패는 문서가 없는 것보다 나쁘다"와 동일 결론. 이미 내면화됨 — 뷰어는 이 원칙을 시각적으로 강제해야 한다(미판정 항목을 본문과 같은 시각 무게로 렌더하지 말 것) |
| Traceability link recovery 계열 (Marcus & Maletic LSI, ICSE 2024 *Recovering Trace Links Between Software Documentation And Code*) | 문서↔코드 링크를 IR/임베딩으로 **복원**하는 연구 — 즉 대부분의 조직은 링크를 잃어버린 상태에서 시작한다 | **역으로 강점 확인**: 이 프로젝트는 앵커를 작성 시점에 명시하므로 복원 문제 자체가 없다. 대신 유지(rot 검출)에 자원을 쓰면 된다. IR 도입 불필요 |
| ADR 템플릿 비교 실증 (arXiv 2604.27333) — 이해도·사용성·도입 용이성 | 템플릿마다 이해도·도입 비용이 유의하게 다름 | "4번째 템플릿 타입을 만들지 않는다"는 결정을 지지. 타입 추가는 비용이 실증된 행위 |
| 온보딩 문서 인지부하 재구조화 (arXiv 2605.19174) | 온보딩 문서의 구조 자체가 인지 과부하를 만들며 재구조화가 효과 | 뷰어의 lane 토글·점진적 공개가 실측 근거를 갖는 개입임 |

---

## 4. 권장 구성

### 4-1. 무엇으로 만드나 — 단일 자립 HTML

사다리를 밟은 결과:

1. 필요한가 — 필요하다. 50문서 × 2 lane × 8 status 는 마크다운 합본으로 안 읽힌다
2. 이미 있는가 — `lint-docs.mjs` 의 파서. **재사용한다**
3. 표준 라이브러리 / 플랫폼 기능으로 되는가 — 검색은 `<details>` + `String.includes` 로 충분(전문 50문서 ≈ 400KB). **검색 인덱스 라이브러리 불필요**
4. 기성 도구는 — MkDocs Material 은 lunr 기반 클라이언트 검색 + offline 플러그인이 있으나 **한국어 토크나이징이 약하고**, Python 툴체인·플러그인·테마 의존이 붙는다. Docusaurus 는 Node + React 빌드 파이프라인. Antora 는 AsciiDoc 전제. **셋 다 얻는 것보다 도입 비용이 크다** — 상태 패싯·앵커 rot·lane 토글은 어차피 전부 커스텀 플러그인이 된다
5. 결론 — **`docs/_meta/build-viewer.mjs` 1파일이 `docs/viewer.html` 1파일을 뱉는다.** 의존성 0, `file://` 로 열림, 배포 = 파일 복사, 오프라인 동작, 사용자가 말한 "단일 문서 또는 viewer" 를 **동시에** 만족

한국어 검색은 형태소 분석 없이 부분문자열 매칭으로 간다. 50문서 규모에서 정밀도 손실보다 의존성 0 이 이득이다. (CJK 검색이 필요해지면 Pagefind 가 다음 단계 — 지금은 아니다)

### 4-2. 뷰어가 가져야 할 표면 7개 (우선순위 순)

| # | 표면 | 근거 | 데이터 계약 의존 |
|---|---|---|---|
| 1 | **상태 배지 + 미판정 격리 필터** | 최상위 Risk(폐기 정책 오학습)의 유일한 시각적 방어 | §2-2 필요 |
| 2 | **lane 토글 (기획 / 개발 / 통합)** | DITA profiling 등가. 우산 제약 #1 이 이미 보장 | 없음 — 지금 가능 |
| 3 | **앵커 rot 배지** | EMSE 2023 — outdated reference 는 반드시 발생 | §2-1 필요 |
| 4 | **전문 검색** | 문서 문제 3위가 "못 찾음" | 없음 |
| 5 | **actor × 서비스 역인덱스** | "대리점이 막히는 정책 전부" — 기획·운영 담당자의 실제 질문 형태. `## 적용 범위` 표가 이미 전 문서에 강제됨 | 없음 |
| 6 | **읽는 순서 nav** | spec §4 순서 원칙의 렌더 | §2-3 필요 |
| 7 | **연혁 통합 타임라인** | 문제 (c) "왜" 대응 | §2-4 필요 |

1·3 이 이 뷰어의 존재 이유다. 4·5 는 공짜에 가깝다. 7 은 계약이 안 되면 버려도 된다.

### 4-3. 착수 시점

```
지금            M5 에 데이터 계약 5필드 반영 결정만  ← 유일하게 시급한 것
                (M5 이후면 50문서 재작성 비용)
20-foundation-  첫 소비 문서 5건 산출
access 종료 후  → 실제 코퍼스로 뷰어 프로토타입. 이때 형식 결함이 드러난다
30~60 진행 중   문서가 늘어나며 뷰어를 두 번째 게이트로 승격
                (뷰어 빌드 실패 = 형식 위반, lint 와 이중화)
```

**지금 뷰어를 만들면 안 되는 이유**: 소비 문서 실측 0건. 예제 픽스처만 보고 만든 렌더러는 첫 실문서에서 전부 다시 짜게 된다. `doc-template-kit` M7 이 되돌린 판단(문서 5건을 위한 형식 신설)과 같은 부류의 실수다.

---

## 5. 열린 질문 (사용자 판단 필요)

- [ ] **status 메타데이터 승격을 M5 에 넣는가** — 넣으면 `lint-docs.mjs` 의 config 파서 수정 동반. 안 넣으면 뷰어 기능 1이 하드코딩 매핑으로 떨어진다(문서와 뷰어가 갈라질 표면 신설)
- [ ] **연혁 표에 "왜" 칸을 넣는가** — ADR 문헌 기준 근거 없는 결정 기록은 가치를 잃는다. 넣으면 작성 부담 +1열 × 50문서
- [ ] **explanation 사분면(왜 이 구조인가)의 소유자** — 현재 없음. `90-history/02-epics.md` 로 흡수할지, 문제 (c)를 연혁 칸으로만 처리할지
- [ ] **앵커에 line 번호를 넣는가** — 넣으면 링크 정밀도 상승, 코드 변경 시 rot 가속. 심볼(`#ClassName`)만 유지하면 rot 는 느리나 링크는 파일 단위

---

## 6. 참고 링크

**사례**
- [Diátaxis](https://diataxis.fr/) · [start-here](https://diataxis.fr/start-here/)
- [Announcing TechDocs: Spotify's docs-like-code plugin for Backstage](https://backstage.io/blog/2020/09/08/announcing-tech-docs/) · [TechDocs 문서](https://backstage.io/docs/features/techdocs/)
- [How Google, Twitter, and Spotify built a culture of documentation](https://www.doctave.com/blog/2021/09/07/how-google-twitter-and-spotify-build-culture-of-documentation)
- [GitLab: handbook-first](https://handbook.gitlab.com/handbook/company/culture/all-remote/handbook-first/) · [Shared Reality (SSoT 감사 주기)](https://handbook.gitlab.com/teamops/shared-reality/)
- [DITA conditional processing (profiling)](https://docs.oasis-open.org/dita/v1.2/os/spec/archSpec/condproc.html) · [DITA](https://dita-lang.org/)
- [Architectural Decision Records](https://adr.github.io/) · [MS Well-Architected: ADR](https://learn.microsoft.com/en-us/azure/well-architected/architect-role/architecture-decision-record)
- [Living Documentation (Martraire)](https://www.oreilly.com/library/view/living-documentation-continuous/9780134689418)
- [Material for MkDocs — 오프라인 빌드](https://squidfunk.github.io/mkdocs-material/setup/building-for-offline-usage/) · [검색 플러그인](https://squidfunk.github.io/mkdocs-material/plugins/search/)

**논문**
- [Software Documentation Issues Unveiled (ICSE 2019)](https://dl.acm.org/doi/abs/10.1109/ICSE.2019.00122) · [요약](https://neverworkintheory.org/2021/10/06/software-documentation-issues-unveiled.html)
- [Software Documentation: The Practitioners' Perspective (ICSE 2020)](https://dl.acm.org/doi/10.1145/3377811.3380405) · [PDF](https://homepages.dcc.ufmg.br/~figueiredo/disciplinas/papers/icse20aghajani.pdf)
- [Detecting outdated code element references in software repository documentation (EMSE 2023)](https://link.springer.com/article/10.1007/s10664-023-10397-6)
- [Barriers Faced by Newcomers to Open Source Projects: A Systematic Review](https://inria.hal.science/hal-01373086)
- [Software Solutions for Newcomers' Onboarding: SLR (2024)](https://arxiv.org/pdf/2408.15989)
- [Recovering Trace Links Between Software Documentation And Code (ICSE 2024)](https://dl.acm.org/doi/10.1145/3597503.3639130) · [Recovery of Traceability Links (LSI)](https://www.cs.kent.edu/~jmaletic/papers/IJSEKE05.pdf)
- [One Size Fits All? An Empirical Comparison of ADR Templates](https://arxiv.org/pdf/2604.27333)
- [Restructure This: Using AI to Restructure Onboarding Documents to Reduce Cognitive Overload](https://arxiv.org/pdf/2605.19174)
