diff --git a/.claude/README.md b/.claude/README.md index 78f5bba..c21400c 100644 --- a/.claude/README.md +++ b/.claude/README.md @@ -18,6 +18,8 @@ | `luau-test/` | **[2026-08-09 신설]** `base/` 확정 사항 중 "추론만으로 확정하고 실제 Luau로 부딪혀본 적 없는 것"(M0 스파이크 대상)을 `luau`/`luau-analyze`/`luau-lsp`/Roblox Studio로 사용자가 직접 돌려볼 독립 실행 스크립트 모음. **[2026-08-13 여섯 번째 세션, 첫 실측]** `luau`/`luau-analyze` 바이너리가 생겨 처음으로 실제 실행 — **런타임 12개 전원 통과**, 타입 쪽에서 `:Compute(fn)` lazy 핸들 계약이 Luau 추론과 충돌하는 게 드러남(당시 `question.md` 0-Y). **[2026-08-13 열세 번째 세션]** 그 0-Y가 해소되며 `review-required/`가 **비었음** — 계약은 유지 확정, 남은 건 Luau 자체 한계라 `base/typing-limits.md`가 담당. **`STATUS.md`가 상태의 소스**(pass / 사람 결정 필요 / 스파이크 깨짐 / 미실행 분류 — 사람이 먼저 볼 것만 위에), `luau-test/README.md`는 각 파일의 검증 의도·배경, 실행 결과 상세는 `audit/luau-test-first-run-2026-08-13.md` | | `audit/` | **[2026-08-13 신설]** `luau-test/` 등 스파이크를 실제로 돌려본 뒤 "무엇이 확인됐고 무엇이 아직 안 됐는지"를 기록하는 곳 — 스크립트/계획 자체가 아니라 **실측 결과**만 다룸. base/luau-test와 달리 부분 확인(일부만 통과)도 있는 그대로 기록, 완전히 해소되면 관련 `base/`/`luau-test/README.md` 캐비엇을 지우고 이 문서는 근거로 남김. **현재 6개**: `luau-test-first-run-2026-08-13.md`(첫 실측 라운드 전체 — 런타임 12개 통과, 구 `question.md` 0-Y의 1차 근거. **단 이 문서의 "콜백이 raw 값을 받으면 완전 클린" 판정은 아래 `type-recursion-issue/`가 뒤집었음**), `gcconn-trick-verification.md`(사용자가 Studio에서 직접 돌린 gcconn 트릭 부분 확인 — `10`의 A 섹션 앞부분만. **[2026-08-14 다섯 번째 세션, 열한 번째 세션에 `canBound` 재도입 반영해 재갱신]** 실측된 사실 자체는 그대로 유효하고 `value` 단독 1-인자 재정정으로 오히려 더 중요해졌음 — 이중 바인딩 게이트(`canBound`)/emit 게이팅(`canExecute`)/재바인딩 허용/`value` 쪽 복사 gcconn 판정/Instance userdata 동일성/B/C가 미확인), **`type-recursion-issue/`**(**[2026-08-13 열세 번째 세션 신설]** 0-Y 재실측 전체 — `REPORT.md` + `spikes/` 44개. 다른 audit 기록과 달리 **스크립트를 같이 둠**: 이 건의 근거가 "여러 formulation을 서로 대조한 것"이라 개별 파일을 직접 돌려야 판정이 재현되기 때문. 결론은 `base/typing-limits.md`로 승격됨), `fallback-xpcall-verification.md`(**[2026-08-14 신설]** `base/fallback-plan.md`의 `Traceback` 메커니즘 전부 확인 — 클로저 업밸류 배선/중첩 스택 캡처/`err: any`/`error(msg)` 위치 접두 10개 검증 전부 통과. 스크립트 1개뿐이라 재현용으로 같이 둠: `fallback-xpcall-spike.luau`), **`type-recursive-issue-with-typeof/`**(**[2026-08-15 신설]** 사용자가 발견한 `typeof(named fn)` 간접참조가 0-Y(재귀 제네릭 반환 leak)를 실제로 우회하는지 실측 — `REPORT.md` + `spikes/`. 결론: 인라인 대신 이름 붙은 함수 + `typeof`로 선언하면 LHS 명시 없이도 다운스트림이 안전해짐(체이닝 50단·타입 변경·중첩 self 호출까지 확인), `typing-limits.md` §1 ③으로 승격. 부수적으로 `setmetatable` 확장 시도에서 quad와 무관한 Luau 0.733 솔버 버그(모순 진단 두 개 동시 발생) 발견, 채택 안 함. `luau-test/16`(type function으로 `Store` 레코드 필드 합성) 복구도 이 조사 중 완료 — API 버전 드리프트였을 뿐 설계 문제 아니었음, `typing-limits.md` §5 승격), **`type-recursive-issue-try-callback/`**(**[2026-08-15 신설]** 콜백 파라미터 무주석 추론을 뚫을 방법이 정말 없는지 type function/메타테이블/오버로드/제네릭 디폴트 등 전방위로 재시도 — `REPORT.md` + `spikes/` 35개(00~19는 최초 라운드, `/code-review high`가 이중 꺾쇠 명시적 제네릭 인스턴스화를 안 시도했음을 지적해 20~33(+21b) 후속 조사 추가). 결론: quad의 `state:Compute(fn)` 단일 호출 모양을 유지한 채로는 여전히 안 됨. 발견 셋 — (1) 근본 원인이 재귀 자기참조가 아니라 "제네릭 콜백 인자 전반에 컨텍스트 타입 전파가 안 됨"이라는 게 더 정확함(재귀 없는 최소 사례로도 재현), (2) `T`를 명시 중간 변수로 먼저 고정하거나 재사용 가능한 monomorphize 헬퍼를 거치면 실제로 추론이 살아나지만 둘 다 단일 콜론 호출을 2단계 체인으로 바꿔야만 해서 §0 대전제로 채택 안 함, (3) 이중 꺾쇠 명시 인스턴스화(`Compute<>(fn)`)는 leaf 호출에선 sound하게 성립하지만(spurious 진단 원인도 규명 — read-only/read-write 가변성 불일치) 매 호출 T/U 전부 명시 필요 + 중첩 self 호출 여전히 실패라 순손해로 채택 안 함) | | `tools/` | **[2026-08-13 아홉 번째 세션 신설]** 코퍼스 기계 점검 — `doc-check.py`가 깨진 파일/절 참조, README 색인 누락, 날짜 없는 시한부 주장("아직 안 돌려봄" 등), 미반영 ⚠️ 배너를 한 번에 훑음. **중대 변경 후 커밋 전에 돌릴 것**(`python3 .claude/tools/doc-check.py`) — 수동 감사에서 나온 발견의 대부분이 이 종류였고, 실제로 문서를 쪼개다 잘못 옮긴 참조를 이게 잡아냄. ERROR는 고치고 WARN은 판단 대상 | +| `agents/` | **[2026-08-16 신설]** 프로젝트 서브에이전트 정의(`.claude/agents/*.md`, Claude Code 표준 위치). 현재 `quad-doc-auditor.md` 하나 — `doc-check.py`가 못 잡는 의미론적 stale/모순(본문 문장이 뒤집힌 결정을 여전히 서술, 개수/목록 이중 소스 드리프트 등)을 신선한 맥락에서 찾는 읽기 전용 감사자. 중대 변경 커밋 전에 위임하는 게 기본(`CLAUDE.md` "작업 방식" 참고). `tools/`의 기계 점검과 짝을 이루는 의미론적 점검 계층 | +| `workflows/` | **[2026-08-16 신설]** Claude Code Workflow 정의. 현재 `quad-handover-audit.js` 하나 — `quad-doc-auditor` 단일 패스는 비결정적이라 매번 다 잡는다는 보장이 없어서, 라운드마다 병렬 3회 감사+파일별 반영을 새 발견이 없는 라운드가 연속 2번 나올 때까지(최대 6라운드) 반복해 수렴시키는 다회·병렬 감사 루프. "핸드오버 준비하고 커밋해" 류 요청 시 자동으로 먼저 돌림(`CLAUDE.md` "작업 방식" 참고), 실제 `git commit`은 워크플로 밖 메인 세션이 함 | | `session/` | **[2026-08-11 신설]** 세션별 상세 로그 원문(시행착오·정정 전 서술 포함, `quadnomicon` 개발로그 소재용) — 루트 `CLAUDE.md`가 3196줄까지 불어나 성능 저하를 유발해서 분리함. 파일명 `YYYY-MM-DD-NN-slug.md`, CLAUDE.md의 "세션 히스토리" 절에서 각 항목이 여기로 링크. 항상 읽을 필요 없음 — 결정의 논의 과정이 궁금할 때만 | | `initreq/` | 프로젝트 착수 시 클론해둔 참고 레포(quad v1, fusion, vide, rbvm, tbox, code-docker) + PA님 실 코드(`artworks/`, 4차 라운드 교차검증 근거) + 원본 요청(`req.md`, `raw-userinput.md`) + `quad2-try`(이전에 시도했다 폐기한 v2 재작성 시도 — 리서치 완료, 결론은 `base/bind-system-plan.md`) — 읽기 전용 리서치 소스, 여기 내용을 옮기지 말고 항상 원본 그대로 유지 | diff --git a/.claude/agents/quad-doc-auditor.md b/.claude/agents/quad-doc-auditor.md new file mode 100644 index 0000000..5cf0a21 --- /dev/null +++ b/.claude/agents/quad-doc-auditor.md @@ -0,0 +1,71 @@ +--- +name: quad-doc-auditor +description: quad 프로젝트의 `.claude/` 설계 문서 코퍼스(base/research/reference/archive, README.md, question.md, CLAUDE.md, 루트 ROADMAP.md/HUMAN_TODO.md)에서 `doc-check.py`가 못 잡는 의미론적 stale/모순을 찾는다. 설계 결정이 뒤집히거나 확정되는 등 이 코퍼스에 중대한 변경이 있은 뒤, 특히 그런 변경을 커밋하기 전에 사용. 읽기 전용 — 문제를 리포트만 하고 직접 고치지 않는다. +tools: Read, Grep, Glob, Bash +model: sonnet +memory: project +--- + +너는 quad(Roblox 엔진용 DOMless UI 렌더러 재작성 프로젝트)의 `.claude/` 설계 +문서 코퍼스를 감사하는 전담 에이전트다. 이 프로젝트는 설계 단계가 길고, +같은 사실이 여러 문서에 흩어져 서술되는 구조라 한 세션이 결정을 뒤집거나 +확정해도 다른 문서의 본문 문장이 안 따라오는 일이 반복돼왔다. **핵심 +전제: 방금 그 변경을 만든 세션 자신의 self-audit은 이걸 잘 못 잡는다** — +자기가 뭘 안 건드렸는지는 모르기 때문이다. 너는 그 변경과 무관한 신선한 +맥락에서 코퍼스 전체를 다시 읽어 그 사각지대를 메우는 역할이다. + +너는 파일을 고치지 않는다(Edit/Write 도구가 없다). 발견한 것만 구조화해서 +보고하고, 실제 반영은 너를 호출한 세션이 한다. + +## 절차 + +1. 먼저 `python3 .claude/tools/doc-check.py`를 돌려라. 깨진 파일/절 참조, + README 색인 누락, 날짜 없는 시한부 주장, 미반영 배너는 이미 기계가 + 잡는다 — 그 결과를 그대로 네 리포트 맨 위에 포함하고, **같은 종류의 + 문제를 네가 다시 손으로 찾으려 하지 마라**(중복 노력). +2. `git status`/`git diff`(스테이지 여부 상관없이)로 최근 변경, 그리고 + 대화 맥락(너를 호출한 프롬프트)으로 "이번에 뒤집히거나 새로 확정된 + 핵심 주장이 뭔지"를 먼저 파악해라. 없으면(예: 정기 점검 목적으로 + 호출된 경우) `.claude/session/`의 가장 최근 파일 1~2개를 훑어 최근 + 결정을 파악해라. +3. 그 주장의 핵심 키워드로 코퍼스 전체를 grep해서, **옛 주장을 여전히 + 확정된 것처럼 서술하는 본문 문장**이 남아있는지 확인해라. 가장 잦은 + 실패 유형: 헤더/배너에는 "[정정, ...]" 표시가 붙었는데 그 배너가 + 부정하는 *본문 bullet*은 안 고쳐진 경우 — 배너만 보고 넘어가지 말고 + 반드시 본문까지 읽어라. +4. 뒤집힌 결정의 원문이 `archive/`로 옮겨지지 않고 라이브 문서(`base/`, + `research/`, `reference/`, `README.md`, `CLAUDE.md`, `ROADMAP.md`)에 + "히스토리로만 보존" 같은 말과 함께 전체 서술로 남아있는지 확인해라. + 앞에서부터 읽는 구현자가 그걸 "확정"으로 오인할 여지가 있으면 문제다. +5. 이번 변경으로 개수·목록·상태 서술("N개 문서", "남은 항목은 이것뿐", + "전부 확정됨" 류)이 두 곳 이상에 나오게 됐는지 확인해라. 이런 서술은 반드시 + 소스가 하나여야 한다(예: 개수는 폴더 구조나 `STATUS.md` 하나만 소스로 + 삼고 나머지는 가리키기만 해야 함) — 두 곳 이상에 적혀 있으면 그 자체가 + 발견이다(값이 지금 일치하더라도, 구조적으로 갈라질 수 있으면 지적해라). +6. 인덱스 레이어 3개가 이번 변경을 반영했는지 확인해라: `.claude/README.md` + (색인), `.claude/question.md`(사용자가 답할 질문만), 루트 + `ROADMAP.md`/`HUMAN_TODO.md`. 설계가 바뀌었는데 이 중 하나만 갱신되고 + 나머지가 안 따라온 경우가 실제로 반복됐다. +7. 시간이 지나면 거짓이 될 수 있는 서술인데 날짜가 없는 것 — `doc-check.py`의 + 정규식 패턴(TEMPORAL)에 안 걸리는 자연어 변형(예: "지금은", "당분간")도 + 찾아라. 날짜/세션 번호를 붙이라고 권고해라. + +## 스코프 밖 + +- `.claude/session/`(세션 원문 보존용, stale 여부를 따질 대상이 아님), + `.claude/initreq/`(읽기 전용 클론), `.claude/worktrees/`는 감사 대상이 + 아니다. +- `archive/` 안의 문서 자체는 "뒤집힌 결정을 원문 그대로 보존"하는 게 + 목적이라 낡은 서술이 있어도 정상이다 — 문제는 **라이브 문서가 archive + 항목을 아직 유효한 것처럼 인용**하는 경우뿐이다. +- 설계 자체의 옳고 그름(quad 아키텍처가 맞는 선택인지)은 네 스코프가 + 아니다. 오직 "코퍼스가 스스로와 모순되지 않는가"만 본다. + +## 출력 형식 + +발견마다: `파일:줄` — 무슨 문장이 무엇과 모순/stale인지 한 문장 — 어떻게 +고치면 되는지 한 문장. **확실**(다른 문장과 직접 모순되거나 doc-check.py급 +확신)과 **의심**(사람 판단 필요, 애매한 경우)으로 나눠라. + +발견이 없으면 "발견 없음"이라고 그대로 보고해라. 그럴듯해 보이려고 사소한 +문체 지적을 지어내지 마라 — 이 감사의 가치는 정확도지 발견 개수가 아니다. diff --git a/.claude/workflows/quad-handover-audit.js b/.claude/workflows/quad-handover-audit.js new file mode 100644 index 0000000..b44f474 --- /dev/null +++ b/.claude/workflows/quad-handover-audit.js @@ -0,0 +1,125 @@ +export const meta = { + name: 'quad-handover-audit', + description: '커밋 전 .claude/ 코퍼스 정합성을 quad-doc-auditor 병렬·다회 감사로 수렴시킴', + whenToUse: '사용자가 "핸드오버 준비하고 커밋해" 류로 요청했을 때, 커밋 전에 자동으로 돌릴 것. 단일 감사 패스는 비결정적이라 놓치는 게 있을 수 있으므로, 라운드마다 독립된 감사를 병렬로 여러 번 돌리고, 새 발견이 없는 라운드가 연속으로 나올 때까지 반복해 수렴시킨다. 시간보다 정확성을 우선하는 사용자 요청에 따라 기본 워크플로 크기 가이드라인(15 에이전트 이하)을 의도적으로 초과할 수 있음.', + phases: [ + { title: 'Audit', detail: 'quad-doc-auditor 서브에이전트를 라운드당 병렬로 여러 번' }, + { title: 'Fix', detail: '라운드에서 나온 새 발견을 파일별로 반영' }, + ], +} + +// 실측 편의를 위해 조정 가능한 상수. 과거 세션의 수동 감사가 보통 +// 4~6라운드 안에 수렴했음(예: 8→7→11→9→4→0, 9→2→3→2→0→0) — MAX_ROUNDS는 +// 그보다 여유를 두되 무한루프는 막는 안전판. +const PASSES_PER_ROUND = 3 +const DRY_ROUNDS_TO_CONVERGE = 2 +const MAX_ROUNDS = 6 + +const FINDINGS_SCHEMA = { + type: 'object', + properties: { + findings: { + type: 'array', + items: { + type: 'object', + properties: { + file: { type: 'string', description: '레포 루트 기준 상대 경로' }, + line: { type: 'number', description: '해당 줄 번호(모르면 0)' }, + issue: { type: 'string', description: '무슨 문장이 무엇과 모순/stale인지 한 문장' }, + fix: { type: 'string', description: '어떻게 고치면 되는지 한 문장' }, + confidence: { type: 'string', enum: ['확실', '의심'] }, + }, + required: ['file', 'issue', 'fix', 'confidence'], + }, + }, + }, + required: ['findings'], +} + +const AUDIT_PROMPT = + '핸드오버 준비 감사 라운드다. 너의 정해진 절차대로 .claude/ 코퍼스를 ' + + '처음부터 독립적으로 감사해라. 다른 병렬 패스가 이미 뭘 찾았는지는 ' + + '모른다 — 그걸 의식하지 말고 빠짐없이 훑어라.' + +function keyOf(f) { + return `${f.file}:${f.line || 0}:${(f.issue || '').slice(0, 40)}` +} + +function fixPrompt(file, items) { + const lines = items + .map((f) => `- (줄 ${f.line || '?'}, ${f.confidence}) ${f.issue} → 제안: ${f.fix}`) + .join('\n') + return ( + `아래는 quad-doc-auditor가 "${file}"에서 찾은 stale/모순 서술이다. ` + + `이 파일을 읽고 CLAUDE.md의 관례(한국어 서술, 최소 수정, 뒤집힌 결정은 ` + + `archive/로 이전+포인터, 날짜 없는 시한부 주장엔 날짜 붙이기)에 맞춰 직접 ` + + `고쳐라. "의심"으로 표시된 항목은 실제로 문제인지 먼저 확인하고, 문제가 ` + + `아니면 건드리지 말고 넘어가라(억지로 고치지 말 것).\n\n${lines}` + ) +} + +const seen = new Set() +const roundLog = [] +let dry = 0 +let round = 0 + +while (dry < DRY_ROUNDS_TO_CONVERGE && round < MAX_ROUNDS) { + round++ + phase('Audit') + log(`라운드 ${round} — quad-doc-auditor 병렬 ${PASSES_PER_ROUND}회`) + + const passes = await parallel( + Array.from({ length: PASSES_PER_ROUND }, (_, i) => () => + agent(AUDIT_PROMPT, { + label: `audit-r${round}-${i}`, + phase: 'Audit', + agentType: 'quad-doc-auditor', + schema: FINDINGS_SCHEMA, + }) + ) + ) + + const all = passes.filter(Boolean).flatMap((p) => p.findings || []) + const fresh = all.filter((f) => !seen.has(keyOf(f))) + + if (!fresh.length) { + dry++ + log(`라운드 ${round}: 새 발견 없음 (연속 dry ${dry}/${DRY_ROUNDS_TO_CONVERGE})`) + roundLog.push({ round, fresh: 0, dry }) + continue + } + + dry = 0 + fresh.forEach((f) => seen.add(keyOf(f))) + log(`라운드 ${round}: 새 발견 ${fresh.length}건 — 파일별로 반영 시작`) + + const byFile = {} + for (const f of fresh) { + ;(byFile[f.file] ||= []).push(f) + } + + phase('Fix') + await parallel( + Object.entries(byFile).map(([file, items]) => () => + agent(fixPrompt(file, items), { + label: `fix:${file}`, + phase: 'Fix', + agentType: 'general-purpose', + }) + ) + ) + + roundLog.push({ round, fresh: fresh.length, files: Object.keys(byFile) }) +} + +const converged = dry >= DRY_ROUNDS_TO_CONVERGE +if (!converged) { + log(`${MAX_ROUNDS}라운드 안에 수렴 못 함 — 남은 문제는 사람이 볼 것`) +} + +return { + converged, + rounds: round, + totalFindingsFixed: seen.size, + roundLog, +} diff --git a/CLAUDE.md b/CLAUDE.md index 0e7a39a..c1ee436 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -120,7 +120,9 @@ modifier/Ref의 컴포넌트 경계 통과 방식) 논의도 2026-08-04 세션 줍지 말고 바꾸는 그 순간에 닫을 것: 1. **`python3 .claude/tools/doc-check.py`를 돌릴 것**(아래 항목 참고) — ERROR 0을 유지한 채로 커밋. 이게 규율 대부분을 기계가 대신함. - 2. **바꾼 주장을 부정당하는 *본문 문장*을 grep으로 전수 찾을 것.** + 2. **바꾼 주장을 부정당하는 *본문 문장*을 grep으로 전수 찾을 것**(또는 + `.claude/agents/quad-doc-auditor.md`로 위임 — 아래 항목 참고, 신선한 + 맥락에서 도는 서브에이전트가 이 항목을 실제로 더 잘 잡아왔음). 헤더에 정정 배너만 달고 본문 bullet을 안 고치는 게 가장 잦은 실패 — 실제로 `CLAUDE.md`가 "스파이크를 아직 안 돌려봄"이라고 서술한 채 한 라운드를 통과했음. **배너를 달았으면 그 배너가 부정하는 문장을 @@ -143,14 +145,38 @@ modifier/Ref의 컴포넌트 경계 통과 방식) 논의도 2026-08-04 세션 이걸로 잡히는 종류였고, 실제로 여덟 번째 세션에 문서를 쪼개면서 잘못 옮긴 참조를 이 스크립트가 잡아냈음. ERROR는 고치고, WARN은 판단이 필요한 것(절 제목을 의역해 인용한 관례 등)이라 늘 0일 필요는 없음. +- **[2026-08-16 도입] `.claude/agents/quad-doc-auditor.md` 서브에이전트 — + 위 체크리스트 2~4번(본문 문장 grep, archive 이전, 개수/목록 단일화)을 + 신선한 맥락에서 대신 수행.** 읽기 전용, 발견만 리포트(직접 수정 안 함). + **`.claude/base`/`.claude/research`/CLAUDE.md에 중대한 변경이 있은 뒤, + 특히 커밋 전에 돌리는 게 기본** — 지난 세션들에서 "변경한 세션 자신의 + self-audit은 자기가 뭘 안 건드렸는지 몰라서 놓친다"는 패턴이 반복 + 확인됐고(세션 히스토리 7·8·10·11차 등), 이걸 매번 즉흥적으로 프롬프트 + 짜는 대신 고정 정의로 옮긴 것. **아주 큰 변경**(설계 반전 규모)엔 이걸로 + 대체하지 말고 `/code-review`(diff 기반)와 사용자의 직접 diff 검토를 + 병행할 것 — 이 서브에이전트는 diff가 아니라 코퍼스 전체의 정합성만 봄. +- **[2026-08-16 도입] "핸드오버 준비하고 커밋해" 류 요청엔 되묻지 말고 + `.claude/workflows/quad-handover-audit.js`(Workflow 이름 + `quad-handover-audit`)를 먼저 돌릴 것.** 단일 `quad-doc-auditor` 패스는 + 비결정적이라 매번 다 잡는다는 보장이 없다는 게 사용자 지적 — 이 워크플로는 + 라운드마다 `quad-doc-auditor`를 병렬로 3회 돌리고 새 발견을 파일별로 + 즉시 반영한 뒤, **새 발견이 없는 라운드가 연속 2번 나올 때까지**(최대 + 6라운드) 반복해 수렴시킨다. 사용자가 정확성을 시간보다 우선한다고 + 명시했으므로 기본 워크플로 크기 가이드라인(15 에이전트 이하)을 의도적으로 + 넘을 수 있음 — 이 워크플로 자체가 그 예외 대상. Workflow는 백그라운드로 + 돌고 완료 시 알림이 오므로, 호출 직후 대화를 막지 말고 진행 상황만 + 알린 뒤 알림을 기다릴 것. 알림이 오면 `python3 .claude/tools/doc-check.py`로 + ERROR 0을 최종 확인한 뒤 평소 커밋 절차(git status/diff 검토, 메시지 작성)로 + 넘어갈 것 — **실제 `git commit`은 이 워크플로 안이 아니라 항상 메인 세션이 + 직접 함**(커밋 전 diff 재검토는 대화형 맥락이 필요해서 워크플로에 위임 안 함). - **문서가 쌓이면서 모순/중복/stale 마커가 생기기 쉬움 — 주기적으로 감사할 - 것.** 다만 위 체크리스트+`doc-check.py`가 자리잡으면 이 감사는 - "기계가 못 보는 것"(설계 자체의 자기모순, 의사코드 손 트레이싱)에만 - 집중하면 됨. 2026-08-04 세션에 실제로 전체 `.claude/` 코퍼스에서 이런 문제가 - 다수 발견되어 정리함(아래 "세션 히스토리" 참고) — 여러 라운드에 걸쳐 - 같은 문서를 계속 고치다 보면 "정정됨" 표시가 원래 문장에 안 반영되고 - 방치되는 패턴이 반복되니, 큰 방향 전환이 있을 때마다 관련 문서 전체를 - 훑어 확인할 것. + 것.** 다만 위 체크리스트+`doc-check.py`+`quad-doc-auditor`가 자리잡으면 + 이 감사는 "기계도 서브에이전트도 못 보는 것"(설계 자체의 자기모순, 의사코드 + 손 트레이싱)에만 집중하면 됨. 2026-08-04 세션에 실제로 전체 `.claude/` + 코퍼스에서 이런 문제가 다수 발견되어 정리함(아래 "세션 히스토리" 참고) — + 여러 라운드에 걸쳐 같은 문서를 계속 고치다 보면 "정정됨" 표시가 원래 + 문장에 안 반영되고 방치되는 패턴이 반복되니, 큰 방향 전환이 있을 때마다 + 관련 문서 전체를 훑어 확인할 것. - **Roblox Studio MCP 연결 시 주의**: Studio는 잘 죽는 편 — 죽었을 때 살리려고 위험한 명령을 반복 시도하지 말 것. 그런 상황이면 MCP 없이 할 수 있는 작업만 하거나 대기. 연결 방법은 `HUMAN_TODO.md` 1번 항목 참고(사용자가 Studio에서