chore: 이전 세션이 남긴 변경을 커밋한다

이번 파이프라인 작업과 무관하게 작업 트리에 남아 있던 것을 그대로 올린다.
사용자가 「전부 커밋」으로 정했고, 이번 작업과 섞이지 않게 커밋만 나눴다.

대부분은 clean-architecture-backend-template 의 그림 정본 재배치다 —
final/assets/diagrams/<이름>/ 에 있던 것이 CLAUDE.md 가 적은 배치인
final/assets/<이름>/ 로 옮겨졌고 .techviz/<이름>/ 이 함께 들어왔다.
삽입 줄의 대부분(3.15M)이 그 .techviz context.json 이다.

그 밖에 ca-tmpl·document-haness 의 정리, .claude/agents/ 열한 개,
writing-practitioner-guides 스킬, .playwright-mcp 세션 산출물,
scripts/check-ssot-facts.py 와 그 시험이 들어 있다.

이 커밋의 내용은 내가 만든 것이 아니라 이전 세션이 남긴 것이고 검증하지 않았다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
DongHyeonka
2026-09-17 11:02:02 +09:00
co-authored by Claude Opus 5
parent 2109f726fe
commit ab59130196
1524 changed files with 3160026 additions and 8369 deletions
+117 -18
View File
@@ -15,6 +15,9 @@
| Studio 에 넣고 저장한다 (Playwright MCP, 게시하지 않는다) | `publishing-tech-log-to-studio` |
| 분석에서 리팩터링 작업 항목을 뽑는다 | `refactoring-from-analysis` |
**스킬을 돌릴 에이전트는 `.claude/agents/` 에 있다.** 단계마다 맡을 것이 정해져 있고 그때그때
새로 만들지 않는다 — 배정은 「한 줄기로 실행할 때」의 표가 적고, 원장의 `runBy` 가 그 이름을 담는다.
구조가 갖춰졌는지는 `python3 scripts/verify-pipeline.py`가 검사한다.
## 실행 순서
@@ -25,9 +28,9 @@
→ 후보 처분 PROMOTE · MERGE_INTO · KEEP_IN_SSOT · NEEDS_EVIDENCE · NEEDS_DECISION
→ 분해 계약 tech-log-tree.json — PROMOTE 이고 CONFIRMED 인 것만 올린다. 주제마다 독자 질문 한 줄
→ 색인 생성 build-tech-log-tree.py · verify-tech-log-tree.py (error 0)
→ 종류 선택 Case · Concept · Reference · Question · Decision
→ 종류 선택 Case · Concept · Setup · Reference · Question · Decision
→ 칸 채우기 종류마다 칸이 다르다
→ 본문 작성 Case · Concept. 코드·표·다이어그램·이미지
→ 본문 작성 Case · Concept · Setup. 코드·표·다이어그램·이미지
→ 다이어그램 technical-visualizer 스킬. 손으로 SVG 를 그리지 않는다
→ 파서 검사 check_body.mjs
→ 문장 검사 check_prose.mjs (error 0) · style_profile.mjs
@@ -35,10 +38,14 @@
→ Studio 저장 → 게시 → 공개 화면 확인
```
**코드·표·다이어그램·이미지는 본문에만 들어간다. 본문이 있는 종류는 CaseConcept이다.**
Reference·Question·Decision의 칸은 평문으로 렌더링된다. 그런 자료가 필요하면 Case나 Concept
**코드·표·다이어그램·이미지는 본문에만 들어간다. 본문이 있는 종류는 Case·Concept·Setup 셋이다.**
Reference·Question·Decision의 칸은 평문으로 렌더링된다. 그런 자료가 필요하면 본문이 있는 종류
담고 `관계`로 가리킨다.
**Setup(환경 구성)만 끝난 일을 적지 않는다.** 나머지 다섯은 이미 일어난 일을 적고, Setup 은 읽는
사람이 자기 기계에서 실행할 순서를 적는다. 그래서 명령이 본문에 들어가고 버전만 본문 밖의
`pinnedVersions` 에 남는다. 검증일 칸이 없고, 프로젝트가 필수이며 주제는 비워도 된다.
## 한 줄기로 실행할 때
위 실행 순서를 사람이 손으로 잇지 않고 한 번에 돌리려면 `running-tech-log-pipeline` 을 쓴다.
@@ -46,15 +53,33 @@ Reference·Question·Decision의 칸은 평문으로 렌더링된다. 그런 자
앞 단계의 문맥이 새어 들어 스킬을 안 읽고도 그럴듯한 결과가 나오고, 그러면 스킬이 적용됐는지
확인할 방법이 없어진다.
| # | 단계 | 스킬 |
**그 에이전트를 그때그때 만들지 않는다.** 단계마다 맡을 에이전트가 `.claude/agents/` 에 있고,
`Agent` 도구의 `subagent_type` 에 그 이름을 준다. 프롬프트만 새로 써서 일반 에이전트를 띄우면
**어떤 규칙으로 일했는지가 어디에도 안 남는다** — 스킬을 열었다는 영수증은 남지만 연 사람이
누구인지는 안 남는다.
| # | 단계 | 스킬 | 에이전트 |
|---|---|---|---|
| S1 | 코드베이스 → SSOT | `analyzing-codebase-for-tech-log` | `ssot-analyst` |
| S2 | SSOT → 분해 계약 | `deriving-tech-log-root-tree` | `tree-deriver` |
| S3 | 글감 → 기록 | `writing-tech-log-records` | `record-writer` |
| S4 | 기록 → 그림 | `technical-visualizer` | `diagram-maker` |
| S5 | AI 티 제거 | `rewriting-technical-prose-naturally` | `prose-rewriter` |
| S6 | 일한 사람의 목소리 | `writing-as-the-person-who-did-it` | `voice-writer` |
| S7 | Studio 저장 | `publishing-tech-log-to-studio` | `studio-validator` |
**이 배정의 정본은 `scripts/verify-pipeline-run.py` 의 `STAGES` 다.** 원장의 `runBy` 가 그
이름을 담고, 검사기가 계약과 대조한 뒤 `.claude/agents/<이름>.md` 가 실재하는지까지 본다.
**단계가 아닌 에이전트가 넷 더 있다.** 기록 한 편을 놓고 역할을 가른 것이라 아무 단계에도
붙지 않고, 부를지는 사람이 정한다.
| 에이전트 | 언제 | 안 하는 일 |
|---|---|---|
| S1 | 코드베이스 → SSOT | `analyzing-codebase-for-tech-log` |
| S2 | SSOT → 분해 계약 | `deriving-tech-log-root-tree` |
| S3 | 글감 → 기록 | `writing-tech-log-records` |
| S4 | 기록 → 그림 | `technical-visualizer` |
| S5 | AI 티 제거 | `rewriting-technical-prose-naturally` |
| S6 | 일한 사람의 목소리 | `writing-as-the-person-who-did-it` |
| S7 | Studio 저장 | `publishing-tech-log-to-studio` |
| `source-auditor` | S3 앞. 원본의 주장을 `관측`·`추론`·`미검증`으로 가른 표를 만든다 | 기록을 안 쓴다 |
| `fact-reviewer` | 쓴 뒤. 결과 문장을 원문과 한 글자씩 역대조한다 | 파일을 안 고친다 |
| `reader-reviewer` | 쓴 뒤. 제목·요약·목차만 보고 30초 안에 읽히는지 본다 | 본문을 안 연다 |
| `setup-runner` | Setup 을 쓴 뒤. 손으로 끝까지 칠 수 있는지 읽는다 | 실제로 치지는 않는다 |
**S4 의 입력은 둘이다.** 무엇을 그릴지는 방금 쓴 기록 본문이 정하고, 그림의 사실은 그 기록의
`source` 앵커가 가리키는 SSOT 절이 댄다. 기록 `.md``techviz prepare` 에 넣지 않는다.
@@ -65,8 +90,8 @@ Reference·Question·Decision의 칸은 평문으로 렌더링된다. 그런 자
**S7 은 저장까지다.** 한 번이라도 게시한 문서는 게시를 취소해도 삭제가 409 로 거절된다.
한 런이 남기는 것은 산출물과 **런 원장** 둘이다. 원장은 단계마다 어떤 스킬을 실제로 열었고
(`skillEcho` — 그 SKILL.md 의 문장을 원문 그대로 옮긴 것) 어떤 관문을 어떤 종료 코드로
지났는지를 적는다.
(`skillEcho` — 그 SKILL.md 의 문장을 원문 그대로 옮긴 것) **누가 열었고**(`runBy` — 그 단계를
맡은 에이전트 이름) 어떤 관문을 어떤 종료 코드로 지났는지를 적는다.
```bash
python3 scripts/verify-pipeline-run.py --init runs/<프로젝트>/<runId>/run.json \
@@ -78,6 +103,49 @@ python3 scripts/verify-pipeline-run.py runs/<프로젝트>/<runId>/run.json
스킬의 실제 문장인지, 관문이 돌았고 종료 코드가 0 이었는지, 적어 낸 산출물이 디스크에 있는지.
건너뛴 단계도 사유를 적어야 한다. **S3·S5·S6 은 건너뛸 수 없다.**
**스킬을 고치면 그 전에 돈 런의 영수증이 현재 SKILL.md 에서 사라진다.** 그 영수증은 사실이다 —
그때 그 문장이 거기 있었다. 원장을 고쳐 쓰는 것은 영수증 위조이고 틀린 문장을 스킬에 되살리는
것은 검사기에 답하는 것이라, 둘 다 하지 않고 검사기가 git 으로 가른다.
| 영수증이 | 종료 | 문구 |
|---|---|---|
| 현재 SKILL.md 에 있다 | 통과 | (아무 말도 안 한다) |
| 그 스킬의 과거 커밋에만 있다 | **warn** | `그 뒤에 스킬이 고쳐져 영수증을 대조할 수 없다` — 어느 커밋에 있었는지 적는다 |
| 어느 판에도 없다 | **error** | `스킬 영수증이 그 스킬의 문장이 아니다` |
| 과거를 못 봤다 (git 없음 · 이력 상한 200) | **warn** | `스킬의 과거 본문을 못 봐서 영수증을 대조하지 못했다` |
**관문도 같다.** 검사기에 관문을 더하면 그 전에 돈 런이 전부 「관문이 빠졌다」가 된다. 그 런은
그때 요구되지 않은 것을 안 돌렸을 뿐이다. 원장에 없던 관문을 적어 넣는 것도, 요구를 빼는 것도
하지 않고 **검사기가 git 으로 가른다** — 그 관문을 요구하기 시작한 커밋이 런이 끝난 날보다
뒤면 warn 이고, 어느 커밋을 요구했는지 적는다. 런의 시각을 못 읽으면 봐주지 않고 error 다.
**`runBy` 도 같은 자리인데 가르는 기준이 다르다.** 여기서는 git 이 아니라 **원장이 스스로 밝힌
판**(`schemaVersion`)으로 가른다. git 은 작업 트리를 못 봐서, 요구를 더한 커밋이 아직 안 들어갔으면
`git log -S` 가 빈손으로 돌아오고 지난 런이 전부 error 로 뒤집힌다. 원장이 어느 계약으로 쓰였는지를
읽으면 커밋 전후로 판정이 흔들리지 않는다.
| `runBy` 가 | 종료 | 문구 |
|---|---|---|
| 그 단계의 계약 에이전트다 | 통과 | (아무 말도 안 한다) |
| `schemaVersion` 1 의 `"subagent"` | **warn** | `옛 판의 원장이라 누가 돌렸는지 적혀 있지 않다` |
| `schemaVersion` 2 인데 다른 이름이다 | **error** | `단계를 맡은 에이전트가 계약과 다르다` |
| 계약대로인데 그 `.md` 가 없다 | **error** | `그 에이전트의 정의가 없다` |
요약 줄이 「대조 못 한 영수증」과 **「누가 돌렸는지 모르는 단계」를 따로** 센다. 둘 다 warn 이지
통과가 아니고, 고치는 방법이 달라서 칸을 나눴다 — 스킬을 열었다는 증거가 없는 것과, 증거는
있는데 연 사람이 안 적힌 것은 다른 일이다.
```text
PIPELINE RUN: PASS — 런 5 · error 0 · warn 40 · 대조 못 한 영수증 5 · 누가 돌렸는지 모르는 단계 35
```
**옛 원장의 `runBy` 를 에이전트 이름으로 고쳐 쓰지 않는다.** 그때는 그 칸이 상수였고, 그렇게
적은 것이 사실이다. 되찾는 길은 하나뿐이다 — **다음에 여는 런부터 이름이 적힌다.**
새 원장은 단계마다 `skillRevision` (그 시점 스킬의 커밋)을 적어서 이력을 안 훑고 그 커밋
하나로 대조하게 한다. 작업 트리가 커밋과 다르면 `null` 이고, 칸이 없는 옛 원장은 이력 훑기로
떨어진다.
원장은 `runs/<프로젝트>/<runId>/` 에 둔다. 프로젝트 폴더 안에 두지 않는다 — 거기는
`final/``tech-log-studio/` 뿐이다.
@@ -151,7 +219,7 @@ docs/<프로젝트>/
└── tech-log-studio/ Studio 에 올릴 글만
├── tech-log-tree.json 분해 계약이자 색인. 이 프로젝트의 글감 전부다
└── <주제 slug>/
├── case/ concept/ reference/ question/ decision/
├── case/ concept/ setup/ reference/ question/ decision/
```
**분석하거나 반입하는 동안에만 있는 것이 따로 있다.**
@@ -276,7 +344,7 @@ evidence:
```
주제 폴더 이름은 Studio 주제의 slug 를 쓴다 — `jpa-feed-query-performance`,
`oauth-oidc-auth-boundary`. Studio 가 주제별로 섯 종류를 나눠 보여 주므로 폴더도 같은 모양이다.
`oauth-oidc-auth-boundary`. Studio 가 주제별로 섯 종류를 나눠 보여 주므로 폴더도 같은 모양이다.
Redis 20편은 한 글을 나눠 쓴 것이라 `docs/clean-architecture-backend-template/final/document.md`
하나로 합쳐 두었다. SSOT 는 프로젝트마다 `final/document.md` 하나다.
@@ -310,19 +378,19 @@ Redis 20편은 한 글을 나눠 쓴 것이라 `docs/clean-architecture-backend-
|---|---|
| `clean-architecture-backend-template` | `desktop-server-git/clean-architecture-backend-template` @ `21234e38` |
| `n+1liner` | `github-project/ca-tmpl` @ `761384d` — 저장소 HEAD 는 다른 브랜치다 |
| `ca-tmpl` | `github-project/ca-tmpl` — 같은 저장소의 아키텍처 경계 쪽 |
| `keycloak` | `keycloak-pattern` — 패턴 넷이 `develop-keycloak-pattern1`~`4` 브랜치에 나뉘어 있어 `revisions` 로 tip 넷을 적는다 |
| `keycloak-session-store` | `keycloak-pattern` @ `cdac9b8` — 같은 저장소의 실험 26건 |
| `TechLog` | `desktop-server-git/tech-log-frontend` · `tech-log-backend` |
| `virtualization` | 분석한 저장소가 없다 — 출발점이 반입한 문서 한 편이라 제1~4부는 `revision: null` 이고, 실험대인 제5~6부만 `keycloak-pattern` @ `9465582b` 로 고정한다 |
| 런 또는 파일 | 문서 |
|---|---|
| `ca-tmpl` | 실행 가능한 클린 아키텍처 — 선언이 아니라 빌드가 지키는 경계 |
| `keycloak` | 브라우저 토큰에서 엣지 세션까지: Keycloak 인증 패턴 네 가지의 경계 설계 |
| `keycloak-session-store` | 세션은 어디에 있는가 — Keycloak 다중 노드 실험 26건의 기록. `keycloak` 이 남긴 열린 질문 네 개에 측정으로 답한다 |
| `n+1liner` | 하이라이트 피드 조회 성능 — N+1 진단과 조회 전략의 진화 |
| `TechLog` | 계약이 먼저인 시스템에서 값이 사라지는 자리들 — TechLog를 만들며 만난 결함의 전수 기록 |
| `clean-architecture-backend-template` | 62개 leaf를 23편으로 읽은 통합 분석 · 모듈 분석 65편을 제2부에 합쳐 46,437줄 · 기록 949건 (선별 재판정 대기) |
| `virtualization` | CPU·메모리·네트워크·스토리지 가상화와 실험대 구축 — 반입한 개념 문서에 실험대 기록을 이어 붙였다 |
## 검사
@@ -342,6 +410,24 @@ python3 scripts/verify-pipeline.py # 위 셋을 모든 프로
python3 -m unittest discover -s scripts/tests # 파서·검사기·생성기
```
**기록 한 편에 런 원장 하나.** 원장의 `record` 칸이 그 런이 만든 기록을 가리킨다.
`verify-pipeline.py``RUN COVERAGE` 줄이 기록과 원장을 짝지어 센다.
```text
RUN COVERAGE: 기록 341 · 원장이 덮은 기록 5 · 원장 없는 기록 336
```
**덮이지 않은 것은 error 가 아니다.** 파이프라인을 거치지 않고 손으로 쓴 기록이 있는 것
자체는 잘못이 아니고, **지나간 일에 원장을 소급해 만드는 것은 영수증 위조다.** 다만 초록으로
보이면 안 된다 — 원장이 전부 통과했다는 것과 기록이 전부 원장을 지났다는 것은 다른 말이고,
이 줄이 없으면 앞의 것이 뒤의 것으로 읽힌다. 되찾는 길은 하나뿐이다: **다음에 쓰는 기록부터
한 편당 하나씩 연다.**
```bash
python3 scripts/verify-pipeline-run.py --init runs/<프로젝트>/<runId>/run.json \
--project <프로젝트> --record <기록 경로>
```
**검사기는 「볼 것이 없어서 통과」를 「문제 없음」이라고 쓰지 않는다.** 셋을 가른다.
| 상태 | 종료 코드 | 문구 |
@@ -401,6 +487,19 @@ python3 scripts/check-figure-overlap.py <프로젝트> # 상자와 라벨이
때문이다. 실측 예: 글자를 60자로 늘렸는데 배경은 131.9px 그대로였고 `check-figure-overlap`
은 통과시켰다. 그런 SVG 는 눈으로 본다.
**그래서 검사기가 못 본 그림을 따로 센다.** 상자를 알아보는 근거는 techviz 렌더러가 붙인
`class` 하나뿐이라, 손그림에서는 상자가 0개로 읽히고 겹칠 짝이 없어 겹침도 0 이 된다.
고치기 전에는 그것이 `그림 182 · 겹친 그림 0` 으로 찍혔는데 **실제로 본 것은 18장**이었다.
지금은 요약 줄이 갈라 적는다.
```text
FIGURE OVERLAP: PASS — 그림 182 · 본 그림 18 · 겹친 그림 0 · 못 본 그림 164
```
못 본 것은 결함이 아니다 — 손그림이 있는 것 자체는 잘못이 아니다. 다만 **초록으로 보이면
안 된다.** 숫자를 되찾으려면 그 그림을 techviz 로 다시 만들어야 하고,
`verify-project-layout.py` 의 「techviz 정본이 없는 그림」이 같은 모집단을 센다.
**그래도 마지막에는 눈으로 본다.** 글자가 상자 밖으로 조금 나가거나 화살표가 라벨을 지나는
것은 좌표로 안 잡힌다.