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
+46 -1
View File
@@ -11,6 +11,7 @@ import collections
import hashlib
import json
import os
import re
@@ -64,11 +65,55 @@ def check_targets(projects, root: str, needs: str = "") -> int | None:
return None
KINDS = ["case", "concept", "reference", "question", "decision"]
# ── 종류 ─────────────────────────────────────────────────────────────────────
# **한 곳에서 정하고 나머지가 여기를 쓴다.** 손으로 나열한 목록에 새 종류를 빠뜨리는 일이
# 반복됐다 — 프론트엔드가 같은 실패를 먼저 적어 두었다(`application/ports/studio-gateway.ts:8-12`):
# 「여기 손으로 적어 두었던 동안 개념과 환경 구성이 빠져 있었고, 작업본 목록의 종류 필터는
# 그 둘을 아예 고를 수 없었다」. 계약의 `RecordKind` 는 여섯이다
# (`studio-api.openapi.yaml:838-840` · tech-log-frontend @ 9e5642c).
KINDS = ["case", "concept", "reference", "question", "decision", "setup"]
# 폴더 이름 → frontmatter 의 `kind`. 하나만 다르다 — `decision/` 의 kind 는 PROJECT_DECISION 이다
KIND_OF_DIR = {"case": "CASE", "concept": "CONCEPT", "reference": "REFERENCE",
"question": "QUESTION", "decision": "PROJECT_DECISION", "setup": "SETUP"}
DIR_OF_KIND = {v: k for k, v in KIND_OF_DIR.items()}
# 본문(`bodyMarkdown`)을 갖는 종류. **셋이다** — 환경 구성의 본문도 Case 와 같은 파서를 탄다
# (`SetupInput.required` 에 `bodyMarkdown` 이 있다 · `setup-document-page.tsx:11`).
# 나머지 셋(Reference·Question·Decision)의 칸은 평문으로 렌더링된다
BODY_KINDS = {"case", "concept", "setup"}
BODY_KIND_CODES = {KIND_OF_DIR[k] for k in BODY_KINDS}
READINESS = ["READY", "OPEN", "NEEDS_EVIDENCE", "NEEDS_DECISION", "BLOCKED"]
DISPOSITIONS = ["PROMOTE", "MERGE_INTO", "KEEP_IN_SSOT",
"NEEDS_EVIDENCE", "NEEDS_DECISION", "BLOCKED"]
def front_matter_block(text: str, key: str) -> str:
"""frontmatter 의 `key:` 아래 들여쓴 블록. 없으면 빈 문자열.
이 저장소의 frontmatter 파서들은 `^키: 값$` 한 줄만 읽는다. 그래서 값이 아래 줄에 있는
칸(`source:` · `assets:` · `pinnedVersions:`)은 **빈 값으로 읽힌다.** 스칼라 칸만
요구하는 동안에는 드러나지 않았는데, 환경 구성의 `pinnedVersions` 는 목록이면서
그 기록의 유효 범위라 「비었다」와 「채웠다」를 갈라야 한다 — 그 칸만 따로 읽는다.
"""
if not text.startswith("---"):
return ""
end = text.find("\n---", 3)
if end < 0:
return ""
lines = text[3:end].splitlines()
for i, line in enumerate(lines):
if not re.match(rf"^{re.escape(key)}:\s*$", line):
continue
block = []
for nxt in lines[i + 1:]:
if nxt.strip() and not nxt[:1].isspace():
break # 들여쓰기가 끝났다 — 다음 칸이다
block.append(nxt)
return "\n".join(block).strip("\n")
return ""
def sha256_of(path: str) -> str | None:
if not os.path.exists(path):
return None