Files
llm-wiki/docs/superpowers/specs/2026-06-01-wiki-structure-lint-design.md

7.3 KiB

Design: wiki-structure-lint — 결정론적 문서 구조 린터

  • 날짜: 2026-06-01
  • 대상: .claude/hooks/wiki_structure_lint.py (신규), /depth 연동, (2차) PostToolUse hook
  • 목적: 위키 문서가 자기 source_type 템플릿의 양식을 따르는지 결정론적으로(파이썬) 검증. "templates대로 안 된 문서"를 코퍼스 전수로 색출하고, P3(옵시디언 링크 문법)와 depth 게이트의 기계적 사전체크를 한 도구로 묶는다.

0. 배경 / 왜 결정론적 레이어인가

branch-depth-gate(LLM 의미 게이트, 별도 스펙)를 설계하다, 검증을 결정론(파이썬) vs 의미(LLM)로 나누는 게 자연스럽다는 결론. 파이썬은 틀·양식 + 기계적으로 판별 가능한 것(섹션 존재, 링크 문법, 앵커 실재)만 보고, 의미(claim 깊이 L0/L1, 조건의 진위)는 LLM 감사기가 본다.

여기에 사용자 관찰이 더해짐: "지금 문서들이 templates대로 안 되어 있는 게 매우 많다." → 결정론 레이어를 먼저 짓는 게 즉시 가치(비적합 문서 색출) + 싼 게이트 우선.

기존 자산과의 경계:

  • wiki_claim_gate.py (PreToolUse hook, 유지): 특정 표(Claims Extracted 등) 존재를 write 시점에 강제. 본 린터는 이를 일반화(전 source_type · 전 섹션).
  • /lint (LLM, 유지): 의미 품질(과장·canonical 우회 등). 본 린터는 결정론 구조만.

1. 검증 3군 (전부 이진 PASS/FAIL — 심각도 단계 없음)

문서당 결과는 PASS 또는 FAIL + 사유 목록. 사용자 결정: "양식대로 안 되어있으면 불통."

C1. 템플릿 적합성

문서는 자기 source_type 템플릿의 필수 + 무마커 섹션 전부 + frontmatter 키 전부를 가져야 PASS.

  • (있다면)·(있을 때)·(전용)·(infra 전용)optional 마커 섹션은 없어도 PASS.
  • 무마커 섹션 = 필수로 간주(양식이므로).
  • 템플릿에 없는 추가 섹션은 허용(불통 아님).
  • source_type이 어느 템플릿과도 매칭 안 되면 → 불통(UNMAPPED_SOURCE_TYPE).

C2. 옵시디언 링크 문법 (= P3 흡수)

  • `[[...]]` 인라인 코드/백틱에 싸인 위키링크 → 불통(옵시디언이 링크로 렌더 안 함).
  • [[경로]] 타깃 파일 부재 → 불통(BROKEN_LINK).
  • [[파일#앵커]] 의 앵커가 대상에 부재 → 불통(DANGLING_ANCHOR, best-effort: 헤딩 또는 Claim ID 토큰 검색).
  • fenced code block(```) 내부의 [[...]] 는 예시이므로 스킵(false positive 방지). 인라인 백틱은 검출.

C3. depth 구조 사전체크 (branch-note 만)

  • Decision Evidence Map 의 선택 조건 셀 비어 있음 → 불통.
  • ## 엣지·실패·의존 섹션 없음/내용 없음 → 불통.
  • (신규 템플릿 적용 브랜치에 발동. 기존 80개는 C1에서 "섹션 없음"으로 먼저 걸림.)

2. source_type → 템플릿 매핑 (거의 자동 도출)

해석 순서 (2026-06-01 정리 후 — 모든 템플릿이 frontmatter source_type 를 직접 선언, fallback 제거됨):

  1. 각 템플릿 frontmatter source_type: 파싱. 다중값은 |/, 구분raw-source-template: official-doc | company-tech-blog | personal-blog.
  2. daily-task 는 문서 frontmatter track:(develop/infra)으로 분기.
  3. (보조) ## source_type 허용값 섹션 파싱은 backward 호환용으로 유지.
  4. 위 어디에도 안 걸리는 source_type → UNMAPPED_SOURCE_TYPE 불통.

명시 결과 (빈 source_type 4종 해소): concept-template ← llm-generated, raw-source-template ← official-doc|company-tech-blog|personal-blog, interview-template ← interview, source-summary-template ← source-summary(둘 다 wiki/concepts 층이라 구분 필수). 매핑 SSOT 가 전부 템플릿 frontmatter 안에 있음(스크립트 상수 fallback 0).

nav/hub/meta 제외: layer 최상위 직속 파일(wiki/llm-wiki.md·wiki/log.md) + README.md/log.md/index.md 는 템플릿 콘텐츠가 아니므로 린트 스킵. frontmatter 없는 스텁은 섹션 누락 도배 대신 NO_FRONTMATTER 1건으로 표면화.

3. 헤더 정규화 매칭

번역·괄호주석·순서 차이를 흡수:

  • ## Parent / 부모 (필수) → 선두 ## 제거 → 괄호 (...) 제거 → / 분리 → 각 토큰 strip+소문자 → {parent, 부모}.
  • 문서 헤더도 같게 정규화. 순서 무관 집합 비교. 한쪽(한글/영문)만 있어도 매칭.
  • optional 판정: 원본 헤더에 optional 마커 정규식(있다면|있을 때|있으면|전용|optional) 포함 여부.

4. CLI / 출력 / 통합

  • 표준 라이브러리만 (claim_gate.py 스타일, 의존성 0). frontmatter 는 라인 파싱(^key:).
  • 호출:
    • python3 .claude/hooks/wiki_structure_lint.py --file <path> — 단일. /depth 사전체크·hook용.
    • python3 .claude/hooks/wiki_structure_lint.py --allraw/·wiki/ 전수 스윕.
  • 출력: 문서별 PASS / FAIL + 사유(rule code · line · 설명). --all 은 끝에 요약(전체 N, FAIL M, source_type별 집계).
  • exit code: FAIL 있으면 ≠ 0 (hook/CI 게이트용).
  • /depth 연동: 먼저 --file 결정론 검사 → 구조 불통이면 그것부터 보고, 통과 시 LLM branch-depth-auditor 로.
  • (2차) PostToolUse hook: 저장 시 C2 자동 검출(P3 목적). 1차는 CLI만.

5. 검증 / 수용 기준

  • --all 이 정상 종료하고 source_type별 집계를 출력.
  • 알려진 비적합(personal-blog·meta·error source_type)이 UNMAPPED_SOURCE_TYPE 로 잡힘.
  • 의도적으로 백틱 래핑한 테스트 링크가 C2 로 잡힘.
  • 잘 정비된 문서 1개(예: 최근 branch-note)가 PASS.
  • false positive 점검: fenced code block 내 예시 [[...]] 가 BROKEN 으로 안 잡힘.

6. 자동수정(autofix) — 백틱 래핑만

사용자 결정으로 안전한 한 종류만 자동수정 도입: 순수 `[[...]]` 래핑 → [[...]].

  • --fix (기본 dry-run, 변경 미리보기) / --fix --apply (실제 기록).
  • fenced code block 내부·혼합 코드 스팬(`foo [[x]] bar`)은 건드리지 않음(보수적).
  • git 미사용 환경이므로 --apply폴더 백업 필수.
  • 2026-06-01 1회 실행 결과: 388파일/3117곳 수정, 백업 llm-wiki-backup-20260601-214319.

비목표:

  • 그 외 autofix 없음(누락 섹션·frontmatter 는 내용 생성 불가 → 마이그레이션 영역).
  • 의미 품질 판정 없음 — LLM /lint·branch-depth-auditor 담당.
  • 멀티 CLI 전파(Codex/Gemini) 범위 밖.

6.1 알려진 한계 (구현 중 보정)

  • 링크 타깃 해석: [[x.md]].md suffix 허용, templates/ 도 유효 타깃으로 인덱싱(초기 FP 2종 수정 완료).
  • placeholder 링크([[X]]·[[URL]]·[[double bracket]] 등 예시 텍스트)가 BROKEN_LINK 로 잡힘 — 향후 예시 라인 스킵 규칙으로 보정 여지.
  • 템플릿 드리프트(MISSING_SECTION 571·MISSING_FRONTMATTER 89)는 본 린터의 검출 대상이되, 해소는 문서→템플릿 마이그레이션(별도 사이클). 린터가 그 진척도 측정기 역할.

7. 산출물

파일 작업
.claude/hooks/wiki_structure_lint.py 신규 (C1+C2+C3, CLI 2모드)
/depth (depth 게이트 구현 시) 사전체크로 본 린터 호출
(2차) .claude/settings.json PostToolUse hook 등록 (C2 자동)