사용자 제기 — doc-check.py가 정규식으로 결정론적 판정을 하는데 표기가 흔들리면 문제가 커지니, 정규식을 늘리기보다 "예상 가능 범위"를 컨벤션으로 좁히는 게 싸지 않냐. 실측해보니 날짜 표기는 이미 100% 균일해서 고칠 게 없었고(강제 장치 없이), 드리프트는 절 인용 쪽이었다 — WARN 86건 중 78건(91%)이 절 참조 불일치. 핵심은 그 78건이 코퍼스가 지저분한 게 아니라 **검사기가 못 읽는 것**이었다는 점이다. 이 코퍼스는 `**볼드**` 줄을 하위 절로 쓰는데 headings()가 `#`만 봤다. ## 동작 변화 (문서 정정으로만 보이지만 게이트가 바뀐다) - 절 참조 불일치가 **WARN → ERROR**. 이제 절 인용 오류가 커밋을 막는다. - 절 인식이 `#` 헤딩 + `**볼드**` 절로 확장. 단 볼드는 **빈 줄 다음이나 리스트 항목 머리**만 인정 — 문단이 줄바꿈되며 우연히 줄머리에 걸린 강조를 절로 오인하던 걸 커밋 전 감사가 잡아 조였다. - 인용 길이 상한 60→160자. 60자를 넘으면 매칭 자체가 안 걸려 검사에서 **조용히** 빠져나갔음(위양성보다 나쁜 구멍). - 비교를 공백 무시로(줄바꿈 인용 대응), 선두 장식·상태/날짜 태그 정규화, `initreq/` 대상 인용은 절 검사 면제(읽기 전용 외부 원본). ## 규약 `conventions.md`에 "문서 표기 규약" 절 신설 — 절 인용 규약(의역 금지, 헤딩은 부분문자열/볼드는 앞부분일치, 태그로 닫히는 볼드 캐비엇, blockquote 함정), 세션은 산문 서수 말고 파일 ID로 지칭. 날짜 마커 라벨 어휘 닫기는 사용자 판단 으로 기각(기계 검사 대상이 아니라 읽는 쪽 판단 재료). ## 결과 절 참조 불일치 78 → 0. 36건은 검사기 수정으로 사라졌고(애초에 위양성), 42건은 인용을 실제 절 제목으로 손으로 고쳤다. 마지막 15건은 서브에이전트 3개에 병렬 위임해 추적 — **설계 서술이 유실된 건은 0건**, 대부분 코드 주석·본문 산문· 주제명처럼 애초에 절이 아닌 걸 절로 인용해온 것이었다. 부수로 드러나 같이 고친 것: onchange-plan이 9차 분할 때 일부러 안 옮긴 절을 잘못된 파일로 가리키던 것, brand-plan이 이미 이행된 정정을 "정정 대상"이라 부르던 것, ROADMAP의 blockquote가 인용 줄바꿈 때문에 깨져 있던 것, pre-implementation-audit의 해소된 항목이 "아직 안 고침" 절에 남아 있던 것 (사용자 결정으로 "이미 고침"으로 이동). 커밋 전 감사 4라운드(에이전트 8개)를 돌렸고, 발견 추이는 2→2→1→0이다. 매 라운드 발견이 "직전 라운드 수정이 만든 새 결함"이었던 게 특징 — 규약을 세우는 커밋이 그 규약의 첫 위반자가 된다는 걸 실측으로 확인했다. 상세는 .claude/session/2026-08-16-03-doc-check-section-convention.md. 부수: __pycache__를 .gitignore에 추가하고 추적 해제(32e9db0에 실수로 딸려 들어가 있었음). quad-doc-auditor에 작업 트리를 바꾸는 git 명령 금지 규약 추가 — 감사자가 git stash를 걸어 메인 세션 스테이지가 반복적으로 풀렸다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011zk7XHkSfiBfdPLZUQHdZf
118 lines
7.3 KiB
Markdown
118 lines
7.3 KiB
Markdown
# 문서 stale 감소용 include 도구 — `doc-include.py` (가칭)
|
|
|
|
**상태**: research — 2026-08-14 세션에 아이디어 확정, **[2026-08-16 갱신]**
|
|
CLAUDE.md 분할로 파일럿 설계가 **단방향 생성으로 단순화**됨(아래 "파일럿
|
|
범위" 참고). 구현 착수 전.
|
|
|
|
> **[2026-08-16] 이 문서의 원 설계에서 절반이 불필요해졌음.** 원래는 원본에
|
|
> `<!--#summary-->`, 인용처에 `<!--#include-->` 두 종류 마커를 두는 **양방향**
|
|
> 설계였는데, 같은 날 CLAUDE.md를 분할하면서 세션 히스토리가 독립 파일
|
|
> (`.claude/session-summary.md`)이 됐음 — 목적지가 "손으로 쓴 파일 속 구간"이
|
|
> 아니라 **통째로 생성되는 파일**이 되면서 목적지 마커가 필요 없어졌다. 남는
|
|
> 건 원본 쪽 마커 + 단방향 생성기뿐. 아래 본문은 이 정정을 반영해 갱신했다.
|
|
|
|
## 배경
|
|
|
|
같은 날 진행된 코퍼스 전체 사실관계 감사(서브에이전트 4개 병렬)에서 실제
|
|
오류 20건을 찾아 고쳤는데, 대부분이 "같은 사실이 두 곳 이상에 적혀있다가
|
|
한쪽만 갱신됨" 패턴이었음(`bind-system-plan.md` 3단계 분할 후 다른 문서가
|
|
옛 줄번호를 가리키던 것 11곳 등). 이 프로젝트는 이미 `doc-check.py`(기계
|
|
검증기, ERROR/WARN 리포트)로 이 문제를 **사후 탐지**하고 있는데, 사용자가
|
|
**사전 차단**(애초에 중복 서술이 안 생기게)이 더 근본적이지 않겠냐고 제안 —
|
|
"summary" 같은 블록을 원본 파일에 마커로 표시해두고, 인용하는 쪽은 그 마커
|
|
구간을 기계적으로 추출해 붙여넣는 도구를 만들면 정보의 관리 주체가 자연히
|
|
한 파일로 모인다는 아이디어.
|
|
|
|
## 선례 (재발명 아님을 확인)
|
|
|
|
- **AsciiDoc tagged region include** — `// tag::x[]` ... `// end::x[]`로
|
|
구간 표시, `include::file.adoc[tag=x]`로 다른 문서가 그 구간만 당겨옴.
|
|
사용자가 제안한 `--#summary-start`/`--#summary-end` 아이디어의 원조 격.
|
|
- **markdown-magic**(JS) — HTML 주석 마커(`<!-- AUTO-GENERATED-CONTENT:START -->`)로
|
|
README 등에 다른 파일 내용을 주입, 재실행하면 갱신. Markdown 생태계에서
|
|
가장 가까운 기존 도구.
|
|
- **Obsidian/Roam/Logseq의 block transclusion**(`![[file#^blockid]]`) —
|
|
빌드 스텝 없이 렌더 시점에 라이브로 당겨옴. stale이 구조적으로 원천 차단되는
|
|
더 강한 버전이지만 이 프로젝트는 정적 `.md` 파일이 소스라 뷰어 종속적인
|
|
이 방식은 안 맞음.
|
|
|
|
## Build vs Buy 판단 — 직접 제작 채택
|
|
|
|
- 필요한 기능이 좁음: 마커 사이 텍스트를 원본에서 읽어 대상에 갱신 삽입 +
|
|
재실행해도 안정적(idempotent) + `--check` 모드로 어긋나면 실패. 정규식
|
|
몇 개 + 파일 I/O가 전부라 100줄 내외로 충분.
|
|
- 기존 도구(markdown-magic 등)를 쓰면 이 레포에 없던 Node/npm 툴체인이
|
|
새로 들어옴 — 지금 유일한 도구인 `doc-check.py`가 Python 표준 라이브러리만
|
|
쓰는 의존성 0 스크립트라는 관례와 어긋남. 프로젝트가 얻는 이득(TOC 생성,
|
|
배지 삽입 등 우리가 안 쓸 기능들)에 비해 대가가 큼.
|
|
- 마커 문법을 이 코퍼스 관례(한국어, `doc-check.py`의 ERROR/WARN 리포팅
|
|
스타일)에 맞춰 직접 정하고 싶으므로, 외부 도구 설정 파일로 끼워 맞추는
|
|
것보다 직접 짜는 쪽이 코드도 적고 통제도 쉬움.
|
|
|
|
**결론**: `.claude/tools/doc-check.py`와 짝을 이루는 `doc-include.py`를
|
|
Python 표준 라이브러리만으로 신설. `--write`(갱신 삽입)/`--check`(어긋나면
|
|
ERROR, `doc-check.py` 파이프라인에 편입) 두 모드.
|
|
|
|
## 파일럿 범위 — `.claude/session-summary.md` 전체 생성
|
|
|
|
사용자가 지목한 이유: 세션 히스토리 항목은 서로 독립적(과거 기록이라
|
|
다른 문서가 그 문장을 인용하는 경우가 거의 없음)이라 이 도구가 버그가
|
|
있어도 **부작용이 다른 곳으로 안 번짐** — 첫 적용 대상으로 가장 안전.
|
|
|
|
- **[2026-08-16 기준] 지금 구조**: `.claude/session/YYYY-MM-DD-NN-slug.md`에
|
|
세션 원문 전체가 있고, `.claude/session-summary.md`(CLAUDE.md 분할 전엔
|
|
분할 전 `CLAUDE.md`에서 `세션 히스토리` 절이었음)에 사람이 손으로 압축한 2~4줄
|
|
요약 + 링크가 **별도 텍스트로** 적혀있음 — 한쪽만 갱신되면 어긋날 수
|
|
있는 구조.
|
|
- **적용 후**: 각 세션 파일 안에 "이게 이 세션의 정본 요약"이라고 표시하는
|
|
마커 블록을 신설(**새로 요약을 쓸 필요 없음** — 지금 `session-summary.md`에
|
|
이미 있는 압축 요약을 그대로 그 블록 안으로 옮기면 됨). 생성기가 세션
|
|
파일들을 파일명 순으로 훑어 마커 블록을 모아 `session-summary.md`를
|
|
**통째로 다시 씀**. 그 시점부터 `session-summary.md`는 직접 편집 금지
|
|
대상이 되고(파일 상단에 그렇게 명시), 요약을 고치려면 세션 파일을 고침.
|
|
|
|
### 왜 목적지 마커가 필요 없어졌나
|
|
|
|
원안은 목적지(`CLAUDE.md`)가 손으로 관리되는 파일이라, 그 안의 특정
|
|
구간만 골라 갱신하려고 `<!--#include-->` 마커가 필요했음. 분할 후엔
|
|
목적지가 **파일 통째로 파생 데이터**라 "어디를 갱신할지"를 표시할 이유가
|
|
없음 — 파일 전체를 덮어쓰면 됨. 부품이 절반으로 줄고, "목적지 마커가
|
|
손실되면?" 같은 실패 모드도 같이 사라짐.
|
|
|
|
## 마커 문법 (초안 — 사용자가 확정할 것)
|
|
|
|
```
|
|
# 세션 파일(.claude/session/2026-08-14-14-....md) 안:
|
|
<!--#summary-->
|
|
**2026-08-14 열네 번째 세션 — ...** (`session/2026-08-14-14-....md`)
|
|
... 2~4줄 압축 요약 ...
|
|
<!--#/summary-->
|
|
```
|
|
|
|
`session-summary.md` 쪽엔 마커가 없음 — 생성기가 헤더 + 각 세션 블록을
|
|
파일명 순으로 이어 붙여 전체를 씀. id도 불필요해짐(파일명이 곧 순서이자
|
|
식별자).
|
|
|
|
## 열린 질문 (사용자가 다듬을 것)
|
|
|
|
1. 마커 문법 자체(위 초안 확정 여부, id 네이밍 규칙 — 날짜+세션번호로
|
|
충분한지).
|
|
2. 기존 세션 항목 전부(`.claude/session/` 폴더에 지금까지 쌓인 파일
|
|
전부 — 개수는 여기 안 적음, 폴더가 소스)에 마커를 소급 삽입할지, 아니면 다음
|
|
세션부터 신규 항목에만 적용하고 과거분은 그대로 둘지.
|
|
3. `--write` 실행 시점 — 수동(세션 마무리 시 사람이 실행) vs 커밋 훅.
|
|
이 레포는 지금 CI가 없고 사람이 `doc-check.py`도 수동으로 돌리는
|
|
관례라 같은 패턴(수동 + 커밋 전 확인)이 자연스러워 보이지만 확정은
|
|
사용자 몫.
|
|
4. `--check` 실패를 `doc-check.py`의 ERROR로 편입할지 별도 스크립트로
|
|
둘지.
|
|
5. 파일럿이 성공하면 다음 확대 후보 — `.claude/README.md` 표의 "상태"
|
|
요약을 각 `base/`/`research/` 문서 맨 위 `**상태**: ...` 줄에서
|
|
추출해오는 것(단, `luau-test/STATUS.md`처럼 이미 "폴더 구조 자체가
|
|
상태"인 곳은 include로 바꿀 필요 없음 — 그쪽은 이미 소스가 하나로
|
|
수렴된 상태라 적용 대상 아님).
|
|
|
|
## 우선순위
|
|
|
|
하 — M0/설계 게이트와 무관한 메타 도구. 사용자가 플랜을 다듬은 뒤 착수
|
|
시점 결정.
|