pipeline: make tech-log-tree.json the one decomposition contract and enforce it

리뷰 두 건을 반영했다.

계약
- tech-log-tree.json 하나가 분해 계약이자 색인이다. 사람이 읽는 트리·Node Specification·
  후보 대장은 없어졌고, 문서에 남아 있던 그 개념을 걷어냈다
- candidateScope — 후보를 찾는 SSOT 범위. 접어 넣은 제2부·제3부는 근거이지 후보가 아니다
- sourceRepository — 분석한 저장소의 경로·리비전·판단 근거. 리비전을 모르면 null 로 두고
  지어내지 않는다. 갈래가 여럿이면 revisions
- 검사기: 계약 미채택·PENDING·PROMOTE↔글감 양방향·candidateScope·sourceRepository 를
  error/warn 으로 센다. 옛 스키마도 검사를 피하지 못한다. 테스트 22 → 31

기록 쓰기
- 템플릿 5종에 source·sourceRevision·topicName, Question 에 닫는 조건, 본문 없는 종류에서
  assets 제거. 고정 절 개수 삭제
- check_evidence.mjs — 인용한 코드가 SSOT 에 있는지, 앵커가 SSOT 를 가리키는지, 제목이
  계약과 같은지, 리비전이 저장소에 있는지. 게시된 기록에서 SSOT 와 다른 URL 을 잡았다

문체
- 문체 규칙의 정본을 ai-tells.md 로. explaining.md 의 질문체 제목·절 끝 대조 반복·그림 예고
  규칙을 삭제해 충돌을 없앴다. 첫 절 「설명 뒤에 평가를 붙이지 않는다」에 지우는 사례 네 유형
- voice 스킬의 「독자 쪽을 본다」를 자료에 오독 기록이 있을 때로 좁히고, 평가만 더한 예시를 교체
- check_prose: 안내 문장을 요구하던 경고 제거, 문장이 끝나지 않은 채 문단이 끝나는 조각 검사 추가

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
DongHyeonka
2026-09-07 12:39:20 +09:00
co-authored by Claude Fable 5.1
parent 73026cada6
commit 9d2a3725c5
54 changed files with 3583 additions and 871 deletions
@@ -30,30 +30,67 @@ Concept 에 담고 `관계`로 가리킨다. `references/record-kinds.md`
## 필수 절차
0. **글감 나누기** — 긴 글(SSOT)에서 옮겨 오는 것이면 먼저 나눈다. 기준`tech-log-tree.json`
형식은 `references/from-ssot-to-records.md`. 나눈 뒤 글을 쓴다.
0. **글감 나누기** — 긴 글(SSOT)에서 옮겨 오는 것이면 먼저 나눈다. 기준
`references/from-ssot-to-records.md`, 계약은 `references/tech-log-tree-contract.md`.
**`tech-log-tree.json` 에 노드가 없는 글은 쓰지 않는다** — 트리에 먼저 올리고, 그 노드의
후보가 `PROMOTE` 이면서 `dispositionReview: CONFIRMED` 인지 확인한 뒤에 쓴다. `PENDING`
사람이 다시 읽지 않았다는 뜻이라, 그 위에 쓴 글은 과분류를 그대로 물려받는다. 계약 밖에서 쓴
기록은 색인에 `unlisted` 로 남는다.
1. **종류 선택** — 위 표. 애매하면 "재현했나"를 묻는다.
2. **칸 채우기** — 칸과 게시 조건은 `references/record-kinds.md`.
3. **본문 작성**(Case·Concept) — **종류마다 무엇을 어떤 순서로 쓰는지는
`references/writing-each-kind.md`.** 문법은 `references/body-syntax.md`, 표·코드·그림은
`references/code-tables-diagrams.md`. **문장은 `references/explaining.md`.**
**문서군 전체의 리듬은 `references/ai-tells.md`.**
그림이 필요하면 손으로 그리지 말고 `technical-visualizer` 스킬로 만든다.
이미 쓴 문장이 AI가 쓴 것처럼 읽히면 `rewriting-technical-prose-naturally` 로 다시 쓴다.
4. **검사** — 둘 다 돌린다. 파서와 문장은 다른 것을 본다.
**문서군 전체의 리듬은 `references/ai-tells.md`.** 이 둘은 첫 초안부터 적용한다 — AI 티를
남겨 두고 나중에 걷어내는 순서가 아니다. **문체를 손보기 전에 문장을 고른다** — 설명이 끝난
뒤에 붙은 평가·예고·되풀이·독자 오해 가정을 먼저 뺀다(`ai-tells.md` 첫 절). 문체 규칙의
정본은 `ai-tells.md` 다.
순서·경계·상태 전이처럼 문장만으로 따라가기 어려운 관계가 있으면 그때
`technical-visualizer` 로 그림을 만든다. 손으로 SVG 를 그리지 않고, 모든 글에 그림을 만들지도
않는다.
4. **검사** — 셋 다 돌린다. 파서와 문장과 증빙은 각각 다른 것을 본다.
- `scripts/check_body.mjs` — Case 본문이 Studio 파서를 통과하는지. 같은 파서를 그대로 부른다.
- `rewriting-technical-prose-naturally/scripts/check_prose.mjs` — 문장 규범. **error 0 이 될 때까지 고친다.**
칸 하나나 한 절만 고쳤으면 `--doc` 없이 부른다. 이어서 `style_profile.mjs` 로 문체 수치를 본다.
- `scripts/check_evidence.mjs <프로젝트> --repo`**인용한 것이 실재하는지.** 본문 코드블록의
각 줄이 SSOT 안에 있는지, `source` 앵커가 SSOT 를 가리키는지, 제목이 계약과 같은지,
`sourceRepository` 의 리비전이 그 저장소에 있는지를 본다.
5. **관계 연결** — Decision은 근거가 **1개 이상** 없으면 게시가 거절된다.
6. **Studio에서 확인** — 넣고 **저장까지만** 한 뒤 미리보기로 읽는다.
절차는 `references/studio-draft-review.md`. **게시하지 않는다.**
7. **게시**고칠 것이 없을 때만. 못 채운 칸은 그 칸 아래에 표시된다.
7. **색인 갱신**기록을 쓰거나 지웠으면 다시 만들고 검사한다.
`python3 scripts/build-tech-log-tree.py <프로젝트>` ·
`python3 scripts/verify-tech-log-tree.py <프로젝트>` — error 0 이어야 한다.
8. **게시** — 고칠 것이 없을 때만. 못 채운 칸은 그 칸 아래에 표시된다.
## 어느 스킬이 무엇을 하나
이 스킬이 첫 초안을 만든다. 나머지는 초안이 나온 뒤에 각각 다른 것을 고친다.
| 스킬 | 하는 일 | 하지 않는 일 |
|---|---|---|
| `deriving-tech-log-root-tree` | 후보에 처분을 매기고 `PROMOTE` 를 글감으로 올린다 | 글을 쓰지 않는다 |
| `writing-tech-log-records` | 종류를 고르고 칸과 본문을 쓴다. `explaining.md`·`ai-tells.md` 를 처음부터 적용한다 | — |
| `technical-visualizer` | 문장으로 따라가기 어려운 관계를 그림으로 만든다 | 모든 글에 그림을 붙이지 않는다 |
| `rewriting-technical-prose-naturally` | 사실과 구조가 이미 맞는 초안의 번역투·반복 문형·과한 대구를 고친다 | 분류가 틀렸거나 근거가 모자란 것은 못 고친다 |
| `writing-as-the-person-who-did-it` | 자료에 남아 있는 선택·비교·어긋남·확인하지 못한 범위를 제자리에 놓는다 | 자료에 없는 「처음에는」·「고민 끝에」를 만들지 않는다 |
Reference·Question·Decision 은 그림을 렌더링할 자리가 없다. 그림이 필요한 내용은 짝이 되는
Case 나 Concept 에 담고 `관계`로 가리킨다.
## 보호 구간
수치, 날짜, 버전, 단위, 코드, 명령어, URL, 인용, 공식 명칭은 원문과 한 글자도 달라지면 안 된다.
측정하지 않은 값을 채우지 않는다 — 검증일은 실제로 확인한 날이다.
**옮겨 적었다고 확인한 것이 아니다.** 앞선 기록에서 코드를 가져오거나 기억으로 경로를 쓰면
SSOT 에 없는 인용이 생긴다. 실제로 그렇게 게시된 기록에 잘못된 redirect URI 가 네 곳 남아 있었고,
realm 설정이 와일드카드라 실행해도 드러나지 않았다. **인용한 줄은 SSOT 에서 찾아 대조한다.**
`check_evidence.mjs` 가 그 대조를 기계로 한 번 더 한다.
SSOT 에 없는데 필요한 인용이라면 순서가 반대다 — `final/document.md` 를 먼저 보강하고,
그것도 저장소에서 확인한 뒤에 한다. `sourceRepository.path` 가 그 저장소를 가리킨다.
## 쓰지 않는 것
- 자료가 뒷받침하지 않는 선택 이유. 썼다는 사실을 왜 골랐는지로 바꾸지 않는다.
@@ -81,5 +118,8 @@ Concept 에 담고 `관계`로 가리킨다. `references/record-kinds.md`
| `![](https://…외부)` | Asset으로 올려 `/api/v1/public/media/…` |
| Decision에 근거 없음 | 관계 1개 이상 연결 |
| 측정 안 한 검증일 | 비워 둔다 |
| 설명 직후에 「~증거다」「~가 아니다」로 평가 | 지운다. 앞 문장이 사실을 말했으면 거기서 끝낸다 |
| 「~로 읽기 쉽다. 그렇지 않다」 | 오해를 지어내지 않는다. 관측부터 적는다 |
| 「먼저 ~를 보고 …」 차례 예고 · 「~를 함께 적는다」 | 지운다. 다음 절이 바로 시작한다 |
작성 후 `references/review-checklist.md`로 대조한다.