docs: 감사 툴링 재시작 검증 + 핸드오버 감사 첫 실동(수렴 실패), 인용 3건 정정

전 세션이 "재시작해야만 확인 가능"으로 남긴 3건을 전부 닫음:
- @import 3개(conventions/project-context/todos) 실제 로드 확인
- quad-doc-auditor 레지스트리 등록 확인(전 세션 전멸은 .claude/agents/가
  세션 도중 생긴 디렉토리였던 탓)
- frontmatter model: sonnet 반영 확인(트랜스크립트에 claude-sonnet-5 기록,
  워크플로에 opts.model 명시 불필요)

정의 파일은 세션 시작 시점 스냅샷으로 고정된다는 것을 1차 증거로 확정 —
quad-handover-audit이 실제 실행한 스크립트가 세션 시작 시점 상태와 바이트
단위로 동일했고 같은 세션의 편집은 반영 0. 에이전트 정의도 동일.
정의를 고쳤으면 재시작 뒤에 감사를 돌릴 것(안 그러면 거짓 초록불).
전 세션 감사가 남긴 긴 가설 배너(80줄)를 검증된 것만 남겨 압축.

quad-handover-audit 첫 실동: 에이전트 67개/6라운드, 수렴 실패
(새 발견 28→15→16→7→11→6, 라운드5에서 되레 증가). MAX_ROUNDS와
"연속 dry 2회" 조건 재검토 필요 — 결과 자체는 위 스냅샷 문제로 옛
스크립트가 돈 것이라 재시작 후 재실동 대상.

감사가 잡은 것 반영: slot-plan.md 정정 배너가 그 뒤 재역전(retract=언마운트)을
놓치고 있던 것, "spikes 44개"(실제 48개) 류 하드코딩 개수의 단일 소스화,
doc-check.py docstring이 검사 심각도를 실제 코드와 다르게 서술하던 것 등.

인용 출처 3건 재분류 — 2건은 인용 대상만 틀린 것이라 실제 소스로 재조준
(v1-compat-plan.md→component-composition-plan.md+store-plan.md,
pre-implementation-audit.md→ROADMAP.md). 진짜 출처가 없는 1건
(modifier-plan.md:536)만 question.md 3번으로 올려 사용자 판단 대기.

워크플로 개선: 반환값에 findings 추가(커밋 전 diff 리뷰 근거),
totalFindingsFixed→findingsSentToFix 개명(과대계상), 반영 에이전트 sonnet 명시.

.claude/agent-memory/는 의도적으로 커밋 제외(추적 여부는 사용자 판단).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
qwreey 2026-08-16 03:02:33 +09:00
parent 8aeec7644f
commit 298dac2510
Signed by: qwreey
GPG key ID: D28DB79297A214BD
22 changed files with 356 additions and 94 deletions

View file

@ -6,15 +6,15 @@
**[2026-08-16 재구조화]** `CLAUDE.md`가 1537줄까지 불어나 사람이 검토할 수 **[2026-08-16 재구조화]** `CLAUDE.md`가 1537줄까지 불어나 사람이 검토할 수
없고 지침 준수도도 떨어져서, 주제별로 쪼개고 `@import`로 다시 합침. 지금 없고 지침 준수도도 떨어져서, 주제별로 쪼개고 `@import`로 다시 합침. 지금
`CLAUDE.md`39줄짜리 진입점이고 실제 내용은 아래 세 파일에 있음(전부 매 `CLAUDE.md`짧은 진입점일 뿐이고 실제 내용은 아래 파일들에 있음(앞 셋은
세션 자동 로드됨): 매 세션 자동 로드, `session-summary.md`/`question.md`는 온디맨드):
| 파일 | 무엇이 들어있나 | | 파일 | 무엇이 들어있나 |
|---|---| |---|---|
| `conventions.md` | 언어/모델 관례 + **작업 방식**(핸드오버 체크리스트, `doc-check.py`, `quad-doc-auditor`, SAFETY 준수 등 에이전트가 따라야 할 절차 전부) | | `conventions.md` | 언어/모델 관례 + **작업 방식**(핸드오버 체크리스트, `doc-check.py`, `quad-doc-auditor`, SAFETY 준수 등 에이전트가 따라야 할 절차 전부) |
| `project-context.md` | 이 프로젝트가 뭔지 + 계획 문서 구조(폴더별 성격 요약 — 상세 색인은 이 README가 소스) | | `project-context.md` | 이 프로젝트가 뭔지 + 계획 문서 구조(폴더별 성격 요약 — 상세 색인은 이 README가 소스) |
| `todos.md` | 지금 할 일(우선순위순). 가장 자주 바뀜 | | `todos.md` | 지금 할 일(우선순위순). 가장 자주 바뀜 |
| `session-summary.md` | 세션별 2~4줄 요약 색인. **`@import` 안 됨(의도적)** — 1231줄을 매 세션 올릴 이유가 없어 온디맨드로 둠, 선행 맥락이 필요할 때 grep해서 열 것. 자동생성 전환 예정(`research/doc-include-plan.md`) | | `session-summary.md` | 세션별 2~4줄 요약 색인. **`@import` 안 됨(의도적)** — 이만한 분량을 매 세션 컨텍스트에 올릴 이유가 없어 온디맨드로 둠, 선행 맥락이 필요할 때 grep해서 열 것. 자동생성 전환 예정(`research/doc-include-plan.md`) |
| `question.md` | 사용자가 답해야 할 열린 질문(우선순위순) | | `question.md` | 사용자가 답해야 할 열린 질문(우선순위순) |
## 폴더 기준 ## 폴더 기준
@ -25,14 +25,15 @@
| `reference/` | **[2026-08-07 신설]** 결정 자체가 아니라 다른 문서가 근거로 인용하는 온디맨드 참고 자료(v1 스냅샷, 프레임워크 비교 리서치) — "완료" 개념 없는 건 `base/`와 같지만, 항상 읽을 필요는 없고 해당 문서가 인용될 때만 열어보면 됨. `quadnomicon` 소재 후보가 많음 | | `reference/` | **[2026-08-07 신설]** 결정 자체가 아니라 다른 문서가 근거로 인용하는 온디맨드 참고 자료(v1 스냅샷, 프레임워크 비교 리서치) — "완료" 개념 없는 건 `base/`와 같지만, 항상 읽을 필요는 없고 해당 문서가 인용될 때만 열어보면 됨. `quadnomicon` 소재 후보가 많음 |
| `research/` | 아직 착수 전, 사용자와 스코프/설계를 더 상의해야 함 | | `research/` | 아직 착수 전, 사용자와 스코프/설계를 더 상의해야 함 |
| `qa-request/` | 구현 완료(코드/에이전트 검증까지 끝남) + 사용자 본인의 실기기(Roblox Studio) QA만 남음 — 지금은 구현 자체가 시작 전이라 비어있음 | | `qa-request/` | 구현 완료(코드/에이전트 검증까지 끝남) + 사용자 본인의 실기기(Roblox Studio) QA만 남음 — 지금은 구현 자체가 시작 전이라 비어있음 |
| `archive/` | 완료 + 사용자가 실사용/실기기로 직접 검증까지 마침 (구현 대상). **[2026-08-06 확장]** 완전히 뒤집힌 설계 결정을 원문+역전 이유+diff와 함께 보존하는 용도로도 사용(제목 `[역전됨]` — 한 번 확정했다가 뒤집힌 것) — 더 이상 능동적으로 참고 안 해도 되지만(토큰 낭비 방지 위해 `base/`/`research/`에서 뺌) `quadnomicon` 소재로는 나중에 쓸 수 있음. **[2026-08-07 확장]** 후보였다가 채택 안 된 것(확정한 적 없이 검토 후 기각)도 같은 방식으로 보존, 제목은 구분을 위해 `[기각됨]``[역전됨]`과 의미가 다르므로 혼동하지 말 것. **[2026-08-07 세 번째 확장]** 설계 반전/기각과 별개로, 에이전트가 문서 작성 중 스스로 낸 개념 혼동을 정정한 이력은 `[에이전트 실수]` 태그로 `agent-mistake.md` 하나에 모음(CLAUDE.md 세션 로그 중복 방지) | | `archive/` | 완료 + 사용자가 실사용/실기기로 직접 검증까지 마침 (구현 대상). **[2026-08-06 확장]** 완전히 뒤집힌 설계 결정을 원문+역전 이유+diff와 함께 보존하는 용도로도 사용(제목 `[역전됨]` — 한 번 확정했다가 뒤집힌 것) — 더 이상 능동적으로 참고 안 해도 되지만(토큰 낭비 방지 위해 `base/`/`research/`에서 뺌) `quadnomicon` 소재로는 나중에 쓸 수 있음. **[2026-08-07 확장]** 후보였다가 채택 안 된 것(확정한 적 없이 검토 후 기각)도 같은 방식으로 보존, 제목은 구분을 위해 `[기각됨]``[역전됨]`과 의미가 다르므로 혼동하지 말 것. **[2026-08-07 세 번째 확장]** 설계 반전/기각과 별개로, 에이전트가 문서 작성 중 스스로 낸 개념 혼동을 정정한 이력은 `[에이전트 실수]` 태그로 `agent-mistake.md` 하나에 모음(`.claude/session-summary.md`/`session/` 로그와의 중복 방지) |
| `feedback/` | 실사용 피드백을 정리한 긴 로그 — 지금은 비어있음(구현 시작 전) | | `feedback/` | 실사용 피드백을 정리한 긴 로그 — **[2026-08-16 기준] 폴더 자체가 아직 없음**(구현 시작 전, 첫 피드백이 생길 때 만들면 됨). `qa-request/`는 빈 폴더로 존재하지만 여긴 그것도 아직 아님 |
| `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` | | `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<T>` 레코드 필드 합성) 복구도 이 조사 중 완료 — 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<<T,U>>(fn)`)는 leaf 호출에선 sound하게 성립하지만(spurious 진단 원인도 규명 — read-only/read-write 가변성 불일치) 매 호출 T/U 전부 명시 필요 + 중첩 self 호출 여전히 실패라 순손해로 채택 안 함) | | `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/`(개수는 폴더가 소스). 다른 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<T>` 레코드 필드 합성) 복구도 이 조사 중 완료 — API 버전 드리프트였을 뿐 설계 문제 아니었음, `typing-limits.md` §5 승격), **`type-recursive-issue-try-callback/`**(**[2026-08-15 신설]** 콜백 파라미터 무주석 추론을 뚫을 방법이 정말 없는지 type function/메타테이블/오버로드/제네릭 디폴트 등 전방위로 재시도 — `REPORT.md` + `spikes/`(개수는 폴더가 소스 — 최초 라운드 + `/code-review high`가 이중 꺾쇠 명시적 제네릭 인스턴스화를 안 시도했음을 지적해 추가된 후속 조사 라운드로 구성). 결론: quad의 `state:Compute(fn)` 단일 호출 모양을 유지한 채로는 여전히 안 됨. 발견 셋 — (1) 근본 원인이 재귀 자기참조가 아니라 "제네릭 콜백 인자 전반에 컨텍스트 타입 전파가 안 됨"이라는 게 더 정확함(재귀 없는 최소 사례로도 재현), (2) `T`를 명시 중간 변수로 먼저 고정하거나 재사용 가능한 monomorphize 헬퍼를 거치면 실제로 추론이 살아나지만 둘 다 단일 콜론 호출을 2단계 체인으로 바꿔야만 해서 §0 대전제로 채택 안 함, (3) 이중 꺾쇠 명시 인스턴스화(`Compute<<T,U>>(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은 판단 대상 | | `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/`의 기계 점검과 짝을 이루는 의미론적 점검 계층 | | `agents/` | **[2026-08-16 신설]** 프로젝트 서브에이전트 정의(`.claude/agents/*.md`, Claude Code 표준 위치). 현재 `quad-doc-auditor.md` 하나 — `doc-check.py`가 못 잡는 의미론적 stale/모순(본문 문장이 뒤집힌 결정을 여전히 서술, 개수/목록 이중 소스 드리프트 등)을 신선한 맥락에서 찾는 읽기 전용 감사자. 중대 변경 커밋 전에 위임하는 게 기본(`.claude/conventions.md` "작업 방식" 참고). `tools/`의 기계 점검과 짝을 이루는 의미론적 점검 계층 |
| `workflows/` | **[2026-08-16 신설]** Claude Code Workflow 정의. 현재 `quad-handover-audit.js` 하나 — `quad-doc-auditor` 단일 패스는 비결정적이라 매번 다 잡는다는 보장이 없어서, 라운드마다 병렬 3회 감사+파일별 반영을 새 발견이 없는 라운드가 연속 2번 나올 때까지(최대 6라운드) 반복해 수렴시키는 다회·병렬 감사 루프. "핸드오버 준비하고 커밋해" 류 요청 시 자동으로 먼저 돌림(`CLAUDE.md` "작업 방식" 참고), 실제 `git commit`은 워크플로 밖 메인 세션이 함 | | `agent-memory/` | **[2026-08-16 신설]** 서브에이전트가 라운드를 넘겨 유지하는 영속 메모리(`agent-memory/<에이전트 이름>/MEMORY.md`가 색인). 지금은 `quad-doc-auditor/` 하나 — 코퍼스 구조, 반복되는 실패 패턴 등을 기억해 감사 라운드마다 처음부터 파악하지 않게 함. **사람이 손으로 채우는 문서가 아니라 에이전트가 스스로 쓰는 것**이지만, `.gitignore` 대상이 아니라 커밋하면 코퍼스 일부가 되고 `doc-check.py` 검사 대상에도 들어감(감사 대상이기도 하다는 뜻 — 여기 적힌 주장도 stale해질 수 있음). **[2026-08-16 기준] 아직 커밋 안 됨(untracked)** — 추적할지 `.gitignore`로 뺄지는 사용자 판단 |
| `session/` | **[2026-08-11 신설]** 세션별 상세 로그 원문(시행착오·정정 전 서술 포함, `quadnomicon` 개발로그 소재용) — 루트 `CLAUDE.md`가 3196줄까지 불어나 성능 저하를 유발해서 분리함. 파일명 `YYYY-MM-DD-NN-slug.md`, CLAUDE.md의 "세션 히스토리" 절에서 각 항목이 여기로 링크. 항상 읽을 필요 없음 — 결정의 논의 과정이 궁금할 때만 | | `workflows/` | **[2026-08-16 신설]** Claude Code Workflow 정의. 현재 `quad-handover-audit.js` 하나 — `quad-doc-auditor` 단일 패스는 비결정적이라 매번 다 잡는다는 보장이 없어서, 라운드마다 병렬로 여러 번 감사+파일별 반영을 새 발견이 없는 라운드가 연속으로 나올 때까지 반복해 수렴시키는 다회·병렬 감사 루프(라운드당 패스 수·수렴 조건·최대 라운드는 튜닝 대상 상수라 여기 숫자를 적지 않음 — 소스는 `quad-handover-audit.js` 상단). "핸드오버 준비하고 커밋해" 류 요청 시 자동으로 먼저 돌림(`.claude/conventions.md` "작업 방식" 참고), 실제 `git commit`은 워크플로 밖 메인 세션이 함 |
| `session/` | **[2026-08-11 신설]** 세션별 상세 로그 원문(시행착오·정정 전 서술 포함, `quadnomicon` 개발로그 소재용) — 루트 `CLAUDE.md`가 3196줄까지 불어나 성능 저하를 유발해서 분리함. 파일명 `YYYY-MM-DD-NN-slug.md`, `.claude/session-summary.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`) — 읽기 전용 리서치 소스, 여기 내용을 옮기지 말고 항상 원본 그대로 유지 | | `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`) — 읽기 전용 리서치 소스, 여기 내용을 옮기지 말고 항상 원본 그대로 유지 |
`research/`의 문서가 설계 확정되면 `base/`로 승격(또는 구현 착수 시 `research/`의 문서가 설계 확정되면 `base/`로 승격(또는 구현 착수 시
@ -44,7 +45,7 @@
| 문서 | 내용 | | 문서 | 내용 |
|---|---| |---|---|
| `architecture.md` | quad-v2 전체 아키텍처 확정 사항 요약(제일 먼저 볼 문서). **[2026-08-12 세션 신설, 같은 날 후속 세션에서 강화]** "코드 스타일 — Luau 문법 관례" 절 신설 — `if-then-else`가 공식 Luau 문법임을 명문화(환각/오타로 오인해 `and`/`or`로 되돌리는 회귀 방지), `A and B or C` 삼항 관용구는 항상-truthy 예외도 없이 전면 금지로 강화(`bind-system-plan.md`의 `retractUnder` falsy-값 버그가 실사례). `const` 바인딩은 공식 문법이나 툴링 미성숙으로 지금은 채택 보류 | | `architecture.md` | quad-v2 전체 아키텍처 확정 사항 요약(제일 먼저 볼 문서). **[2026-08-12 세션 신설, 같은 날 후속 세션에서 강화]** "코드 스타일 — Luau 문법 관례" 절 신설 — `if-then-else`가 공식 Luau 문법임을 명문화(환각/오타로 오인해 `and`/`or`로 되돌리는 회귀 방지), `A and B or C` 삼항 관용구는 항상-truthy 예외도 없이 전면 금지로 강화(`bind-system-plan.md`의 `retractUnder` falsy-값 버그가 실사례). `const` 바인딩은 공식 문법이나 툴링 미성숙으로 지금은 채택 보류 |
| `typing-limits.md` | **[2026-08-13 열세 번째 세션 신설]** Luau 타입 시스템이 quad 설계에 대해 **못 해주는 것**을 한 군데 모은 확정 문서 — 여러 `base/` 문서에 캐비엇으로 흩어져 있던 걸 통합. 대전제는 "**Luau의 한계를 우회하려고 타입/API를 비틀지 않는다**"(비틀면 나중에 Luau가 고쳐줘도 자동 수혜를 못 받고 되돌리는 마이그레이션이 생김). 1번 항목이 가장 큼 — **재귀 제네릭이 다른 타입 인자로 자기를 반환하면(`Compute<U>(self: State<T>,...) -> State<U>`) 타입 안전성이 에러 없이 조용히 사라짐**(구 `question.md` 0-Y, 스파이크 44개로 확정). 대응은 두 개: (a) 타입 선언을 "데이터부/메소드부"로 쪼개 콜백 파라미터 추론을 살리고, (b) **파생 State를 만드는 자리마다 결과 타입을 명시 주석으로 바인딩**(그 한 줄만 검증 안 되고 다운스트림 전체는 정상 체크됨). Luau RFC `relax-recursive-type-restriction``Promise<T>.andThen`으로 예시 든 바로 그 패턴이라 **지금 선언 그대로 두면 Luau 쪽 수정만으로 코드 변경 없이 풀림**(추적: `luau-lang/luau#2380`). **[2026-08-15 추가]** ③ 인라인 대신 이름 붙은 함수 + `typeof`로 선언하면 콜백 파라미터 주석은 여전히 필요하지만 LHS 명시 없이도 다운스트림이 안전해짐(①을 대체하지 않음, 보강). 그 외 Modifier `Overridden` 서브타입/Attribute 제네릭 키 narrowing/nilable default 오버로드도 여기 통합, `store.key` type function 한계는 **검증 완료로 승격**(§5), 7번에 **새 타입·API 설계 시 체크리스트**. 실측 근거는 `audit/type-recursion-issue/` + `audit/type-recursive-issue-with-typeof/` | | `typing-limits.md` | **[2026-08-13 열세 번째 세션 신설]** Luau 타입 시스템이 quad 설계에 대해 **못 해주는 것**을 한 군데 모은 확정 문서 — 여러 `base/` 문서에 캐비엇으로 흩어져 있던 걸 통합. 대전제는 "**Luau의 한계를 우회하려고 타입/API를 비틀지 않는다**"(비틀면 나중에 Luau가 고쳐줘도 자동 수혜를 못 받고 되돌리는 마이그레이션이 생김). 1번 항목이 가장 큼 — **재귀 제네릭이 다른 타입 인자로 자기를 반환하면(`Compute<U>(self: State<T>,...) -> State<U>`) 타입 안전성이 에러 없이 조용히 사라짐**(구 `question.md` 0-Y, 스파이크 다수로 확정 — 근거·개수는 `audit/type-recursion-issue/`). 대응은 두 개: (a) 타입 선언을 "데이터부/메소드부"로 쪼개 콜백 파라미터 추론을 살리고, (b) **파생 State를 만드는 자리마다 결과 타입을 명시 주석으로 바인딩**(그 한 줄만 검증 안 되고 다운스트림 전체는 정상 체크됨). Luau RFC `relax-recursive-type-restriction``Promise<T>.andThen`으로 예시 든 바로 그 패턴이라 **지금 선언 그대로 두면 Luau 쪽 수정만으로 코드 변경 없이 풀림**(추적: `luau-lang/luau#2380`). **[2026-08-15 추가]** ③ 인라인 대신 이름 붙은 함수 + `typeof`로 선언하면 콜백 파라미터 주석은 여전히 필요하지만 LHS 명시 없이도 다운스트림이 안전해짐(①을 대체하지 않음, 보강). 그 외 Modifier `Overridden` 서브타입/Attribute 제네릭 키 narrowing/nilable default 오버로드도 여기 통합, `store.key` type function 한계는 **검증 완료로 승격**(§5), 7번에 **새 타입·API 설계 시 체크리스트**. 실측 근거는 `audit/type-recursion-issue/` + `audit/type-recursive-issue-with-typeof/` |
| `lifecycle-pattern.md` | rbvm의 `Connected`+GC 관용구를 quad-v2가 채택하는 방식. **[2026-08-14 다섯 번째 세션, 시그니처 정정]** `bindLifetime(inst,value)`/`unbindLifetime(value)`/`canExecute(value)` — 뒤의 둘은 `inst`를 안 받음(`bindLifetime`이 바인딩 시점에 gcconn 참조를 `value``Relate`로 복사해두므로 `value` 하나로 생존을 물을 수 있고, 실제 호출부인 State 전파 루프엔 애초에 `inst`가 없음). `.Subscribed`는 전역 `:Subscribe()` 전용 필드로 분리(`bindLifetime`은 읽지도 쓰지도 않음), gcconn/gchold는 lazy가 아니라 **Instance 생성 시점**에 만들고 클로저가 `gchold`와 `inst`를 둘 다 캡처(userdata 포인터 동일성 = `inst`-키 `Relate` 전체의 전제). 옛 2-인자 모델은 `archive/canexecute-inst-arg-reversed.md`. **[2026-08-14 열한 번째 세션]** 별도 `canBound`가 다시 도입됨 — `bindLifetime`/`Observer:Subscribe()`의 이중 바인딩 가드는 `canBound`, State emit 전파 게이팅만 `canExecute`(판정 로직은 비공개 헬퍼 `isBoundAlive` 하나를 공유) | | `lifecycle-pattern.md` | rbvm의 `Connected`+GC 관용구를 quad-v2가 채택하는 방식. **[2026-08-14 다섯 번째 세션, 시그니처 정정]** `bindLifetime(inst,value)`/`unbindLifetime(value)`/`canExecute(value)` — 뒤의 둘은 `inst`를 안 받음(`bindLifetime`이 바인딩 시점에 gcconn 참조를 `value``Relate`로 복사해두므로 `value` 하나로 생존을 물을 수 있고, 실제 호출부인 State 전파 루프엔 애초에 `inst`가 없음). `.Subscribed`는 전역 `:Subscribe()` 전용 필드로 분리(`bindLifetime`은 읽지도 쓰지도 않음), gcconn/gchold는 lazy가 아니라 **Instance 생성 시점**에 만들고 클로저가 `gchold`와 `inst`를 둘 다 캡처(userdata 포인터 동일성 = `inst`-키 `Relate` 전체의 전제). 옛 2-인자 모델은 `archive/canexecute-inst-arg-reversed.md`. **[2026-08-14 열한 번째 세션]** 별도 `canBound`가 다시 도입됨 — `bindLifetime`/`Observer:Subscribe()`의 이중 바인딩 가드는 `canBound`, State emit 전파 게이팅만 `canExecute`(판정 로직은 비공개 헬퍼 `isBoundAlive` 하나를 공유) |
| `store-plan.md` | **[2026-08-14 신설 — `bind-system-plan.md` 3단계 분할 + 구 store-semantics.md 흡수]** Store = **이름 붙은 Source 모음, 그 이상 아님** — Store 부작용 허용이 기본 디자인(국소적 vs 경계를 넘는 부작용), `defaults`는 선택적 초기값 템플릿(원본을 나중에 mutate해도 UB 아님)이고 **eager 생성과 lazy 생성이 둘 다 필요**(Luau 타입은 런타임에 강제 안 되므로), `table.clone` 기반 eager 생성 스케치, `store.key`(dot-access)가 1급 경로이고 `store "key"` 문자열 커링은 동적 키용 미타입 폴백, 레코드 필드 타이핑은 Luau `type function`으로 해결 확인, `store.key = value` 폐기 → `store.key:Set(value)`(타입 대칭성+lazy 정직성), "Store가 Store를 저장 가능한가"는 **그런 경우를 안 만듦**으로 확정(`State<State<T>>`와는 다른 축) | | `store-plan.md` | **[2026-08-14 신설 — `bind-system-plan.md` 3단계 분할 + 구 store-semantics.md 흡수]** Store = **이름 붙은 Source 모음, 그 이상 아님** — Store 부작용 허용이 기본 디자인(국소적 vs 경계를 넘는 부작용), `defaults`는 선택적 초기값 템플릿(원본을 나중에 mutate해도 UB 아님)이고 **eager 생성과 lazy 생성이 둘 다 필요**(Luau 타입은 런타임에 강제 안 되므로), `table.clone` 기반 eager 생성 스케치, `store.key`(dot-access)가 1급 경로이고 `store "key"` 문자열 커링은 동적 키용 미타입 폴백, 레코드 필드 타이핑은 Luau `type function`으로 해결 확인, `store.key = value` 폐기 → `store.key:Set(value)`(타입 대칭성+lazy 정직성), "Store가 Store를 저장 가능한가"는 **그런 경우를 안 만듦**으로 확정(`State<State<T>>`와는 다른 축) |
| `source-state-plan.md` | **[2026-08-14 신설 — `bind-system-plan.md` 3단계 분할 + 구 store-semantics.md 흡수]** 반응형 코어: `Source`⊇`State` 구조적 서브타입(`RefSource` 폐기, 단방향 의존으로 Luau 솔버 회피 — 스파이크 `08` 통과), **push-invalidate/pull-recompute** 전파 모델과 "관측해야 실체화된다" 전역 원칙, State 체인 플래튼 기각(캐싱이 State의 존재 이유), `:With`도 매번 새 노드(clone 계열인 `Tag`/`Modifier`와 혼동 주의), `:Compute`의 lazy 핸들 계약(`:Get()` 누락이 반복되는 실수)·trailing args sugar·`fn(self, previous?, ...deps)` 순서·`previous`, `:Apply`, `:Emit()`(Source 원천 전용 하드 경계)과 `Store<T>`/`Source<T>`의 `T`가 Modifier일 수 없는 따름정리, `state:Observer(fn)`, `:Subscribe()`/`:Unsubscribe()`, **이중 바인딩 금지 게이트**(`canBound`, State emit 전파 게이팅은 `canExecute``base/lifecycle-pattern.md`의 "`canBound` vs `canExecute`" 절이 소스), PA님 코드 교차검증. **[2026-08-14 열두 번째 세션]** 새 절 "Observer/Effect Leaf dedup" — `RefLeafHandler`와 같은 `old ~= v` dedup(성능 최적화, correctness엔 불필요) | | `source-state-plan.md` | **[2026-08-14 신설 — `bind-system-plan.md` 3단계 분할 + 구 store-semantics.md 흡수]** 반응형 코어: `Source`⊇`State` 구조적 서브타입(`RefSource` 폐기, 단방향 의존으로 Luau 솔버 회피 — 스파이크 `08` 통과), **push-invalidate/pull-recompute** 전파 모델과 "관측해야 실체화된다" 전역 원칙, State 체인 플래튼 기각(캐싱이 State의 존재 이유), `:With`도 매번 새 노드(clone 계열인 `Tag`/`Modifier`와 혼동 주의), `:Compute`의 lazy 핸들 계약(`:Get()` 누락이 반복되는 실수)·trailing args sugar·`fn(self, previous?, ...deps)` 순서·`previous`, `:Apply`, `:Emit()`(Source 원천 전용 하드 경계)과 `Store<T>`/`Source<T>`의 `T`가 Modifier일 수 없는 따름정리, `state:Observer(fn)`, `:Subscribe()`/`:Unsubscribe()`, **이중 바인딩 금지 게이트**(`canBound`, State emit 전파 게이팅은 `canExecute``base/lifecycle-pattern.md`의 "`canBound` vs `canExecute`" 절이 소스), PA님 코드 교차검증. **[2026-08-14 열두 번째 세션]** 새 절 "Observer/Effect Leaf dedup" — `RefLeafHandler`와 같은 `old ~= v` dedup(성능 최적화, correctness엔 불필요) |
@ -91,7 +92,7 @@
| `debounce-throttle-plan.md` | **[2026-08-14 신설]** 시간 기반 전파 게이트 `Debounce`/`Throttle` — 사용자 요청("`Blocker`와 유사하게")으로 신설. 요지: (1) `Blocker`가 이미 쓰는 게이트 노드의 **릴리스 트리거만 타이머로 바꾼 것**이라 새 전파 메커니즘이 아님 — `Blocker` 구현(M3) 시점에 게이트를 공용으로 빼두는 게 쌈, (2) 무효화 채널만 만지므로 laziness 안 깨짐, (3) **Debounce/Throttle의 차이는 "신호가 창 타이머를 리셋하는가" 한 비트뿐** — 공개 생성자는 둘, 구현은 하나(초안의 lodash식 `maxWait` 공식엔 trailing 통과 직후 이중 발화 버그가 있었음), (4) 알고리즘은 quad-base + 주입 op 2개 `setTimeout(func, delay) -> Timeout`/`clearTimeout`(Roblox `task.delay`/`task.cancel`로 배선 — **인자 순서 반대라 주의**). `os.clock()`은 Luau 표준 라이브러리라 주입 대상 아님(단 절대 시각이 아니라 **diff 전용**), 취소 없는 엔진도 래핑+유효 플래그로 대응 가능, `Timeout``{ __type_timeout: true, _native: any }`. **부수 성과**: 이 설계 중 `source-state-plan.md`의 무효화 dedup 서술이 `Observer` 계약과 모순되는 게 발견돼 base 전면 정정(`archive/invalidate-dedup-propagation-reversed.md`) | 하 — M0 안 막음(코어 계약 변경 없음), 다만 순수 슈가가 아니라 실제 기능 갭이라 `operator-sugar-plan.md`보다는 위. 의존은 M3(State)+백엔드 주입. 남은 열린 질문: 이름(Roblox 관용 debounce와 충돌)/값 지연 의미론/제어 핸들 `Flush`/`Time=0` 허용 | | `debounce-throttle-plan.md` | **[2026-08-14 신설]** 시간 기반 전파 게이트 `Debounce`/`Throttle` — 사용자 요청("`Blocker`와 유사하게")으로 신설. 요지: (1) `Blocker`가 이미 쓰는 게이트 노드의 **릴리스 트리거만 타이머로 바꾼 것**이라 새 전파 메커니즘이 아님 — `Blocker` 구현(M3) 시점에 게이트를 공용으로 빼두는 게 쌈, (2) 무효화 채널만 만지므로 laziness 안 깨짐, (3) **Debounce/Throttle의 차이는 "신호가 창 타이머를 리셋하는가" 한 비트뿐** — 공개 생성자는 둘, 구현은 하나(초안의 lodash식 `maxWait` 공식엔 trailing 통과 직후 이중 발화 버그가 있었음), (4) 알고리즘은 quad-base + 주입 op 2개 `setTimeout(func, delay) -> Timeout`/`clearTimeout`(Roblox `task.delay`/`task.cancel`로 배선 — **인자 순서 반대라 주의**). `os.clock()`은 Luau 표준 라이브러리라 주입 대상 아님(단 절대 시각이 아니라 **diff 전용**), 취소 없는 엔진도 래핑+유효 플래그로 대응 가능, `Timeout``{ __type_timeout: true, _native: any }`. **부수 성과**: 이 설계 중 `source-state-plan.md`의 무효화 dedup 서술이 `Observer` 계약과 모순되는 게 발견돼 base 전면 정정(`archive/invalidate-dedup-propagation-reversed.md`) | 하 — M0 안 막음(코어 계약 변경 없음), 다만 순수 슈가가 아니라 실제 기능 갭이라 `operator-sugar-plan.md`보다는 위. 의존은 M3(State)+백엔드 주입. 남은 열린 질문: 이름(Roblox 관용 debounce와 충돌)/값 지연 의미론/제어 핸들 `Flush`/`Time=0` 허용 |
| `quad-recursive-acronym.md` | **[2026-08-14 신설]** GNU/WINE류로 `Quad`를 재귀 약어화하는 카피 브레인스토밍 — 설계 결정도 착수 게이팅도 아니고 나중에 README.md 헤딩 등에 쓸 캐치프레이즈 후보 모음. 자학 개그 방향(기각)과 지연평가/재귀·커링/펑터/클로저를 자랑하는 방향(채택 후보, 미확정) 정리 | 하 — 카피 소재, 설계 상의 필요 없음. 사용자가 최종 문구 고르면 반영 | | `quad-recursive-acronym.md` | **[2026-08-14 신설]** GNU/WINE류로 `Quad`를 재귀 약어화하는 카피 브레인스토밍 — 설계 결정도 착수 게이팅도 아니고 나중에 README.md 헤딩 등에 쓸 캐치프레이즈 후보 모음. 자학 개그 방향(기각)과 지연평가/재귀·커링/펑터/클로저를 자랑하는 방향(채택 후보, 미확정) 정리 | 하 — 카피 소재, 설계 상의 필요 없음. 사용자가 최종 문구 고르면 반영 |
| `v1-compat-plan.md` | v1 하위호환(compat) 레이어 — `quad-roblox-v1-compat` 패키지, v2→v1 단방향 브리지(`state:Observer()`+v1 프로퍼티 재대입), v2-in-v1/v1-in-v2 두 임베딩 방향의 기술 규칙까지 확정. quad2-try의 `quad-compat`은 빈 폴더로 실제 시도된 적 없었음을 확인 | 하 — Slot이 foreign Instance를 어떻게 다루는지만 Slot 코어 구현 시점까지 미결 | | `v1-compat-plan.md` | v1 하위호환(compat) 레이어 — `quad-roblox-v1-compat` 패키지, v2→v1 단방향 브리지(`state:Observer()`+v1 프로퍼티 재대입), v2-in-v1/v1-in-v2 두 임베딩 방향의 기술 규칙까지 확정. quad2-try의 `quad-compat`은 빈 폴더로 실제 시도된 적 없었음을 확인 | 하 — Slot이 foreign Instance를 어떻게 다루는지만 Slot 코어 구현 시점까지 미결 |
| `doc-include-plan.md` | **[2026-08-14 신설]** 문서 stale 감소용 include 도구 `doc-include.py`(가칭) — 원본 파일에 `<!--#summary-->` 류 마커로 요약 구간을 표시해두면 인용하는 문서가 그 구간을 기계적으로 추출해 붙여넣게 하는 도구. `doc-check.py`(사후 탐지)와 짝을 이루는 사전 차단 장치. AsciiDoc tagged include/markdown-magic이 선례, build vs buy 검토 후 Python 표준 라이브러리로 직접 제작(~100줄) 채택. 파일럿은 `CLAUDE.md` 세션 히스토리 ← `.claude/session/*.md` 요약 마커부터(부작용 최소) | 하 — M0/설계 게이트와 무관한 메타 도구, 플랜만 초안, 사용자가 내일 다듬을 예정 | | `doc-include-plan.md` | **[2026-08-14 신설]** 문서 stale 감소용 include 도구 `doc-include.py`(가칭) — 원본 파일에 `<!--#summary-->` 류 마커로 요약 구간을 표시해두면 인용하는 문서가 그 구간을 기계적으로 추출해 붙여넣게 하는 도구. `doc-check.py`(사후 탐지)와 짝을 이루는 사전 차단 장치. AsciiDoc tagged include/markdown-magic이 선례, build vs buy 검토 후 Python 표준 라이브러리로 직접 제작(~100줄) 채택. 파일럿은 `.claude/session-summary.md` ← `.claude/session/*.md` 요약 마커부터(CLAUDE.md 분할로 목적지가 "통째로 생성되는 파일"이 돼 단방향 생성으로 단순화됨) | 하 — M0/설계 게이트와 무관한 메타 도구. **[2026-08-16 기준]** 플랜 초안 단계, 열린 질문 미해소(소스: 이 문서의 "열린 질문" 절) |
## `archive/` — 완료됐거나 완전히 뒤집힌 것, 능동 참고 불필요 ## `archive/` — 완료됐거나 완전히 뒤집힌 것, 능동 참고 불필요

View file

@ -3,7 +3,6 @@ name: quad-doc-auditor
description: quad 프로젝트의 `.claude/` 설계 문서 코퍼스(base/research/reference/archive, README.md, question.md, conventions.md, project-context.md, todos.md, 루트 CLAUDE.md/ROADMAP.md/HUMAN_TODO.md)에서 `doc-check.py`가 못 잡는 의미론적 stale/모순을 찾는다. 설계 결정이 뒤집히거나 확정되는 등 이 코퍼스에 중대한 변경이 있은 뒤, 특히 그런 변경을 커밋하기 전에 사용. 읽기 전용 — 문제를 리포트만 하고 직접 고치지 않는다. description: quad 프로젝트의 `.claude/` 설계 문서 코퍼스(base/research/reference/archive, README.md, question.md, conventions.md, project-context.md, todos.md, 루트 CLAUDE.md/ROADMAP.md/HUMAN_TODO.md)에서 `doc-check.py`가 못 잡는 의미론적 stale/모순을 찾는다. 설계 결정이 뒤집히거나 확정되는 등 이 코퍼스에 중대한 변경이 있은 뒤, 특히 그런 변경을 커밋하기 전에 사용. 읽기 전용 — 문제를 리포트만 하고 직접 고치지 않는다.
tools: Read, Grep, Glob, Bash tools: Read, Grep, Glob, Bash
model: sonnet model: sonnet
memory: project
--- ---
너는 quad(Roblox 엔진용 DOMless UI 렌더러 재작성 프로젝트)의 `.claude/` 설계 너는 quad(Roblox 엔진용 DOMless UI 렌더러 재작성 프로젝트)의 `.claude/` 설계
@ -14,8 +13,29 @@ memory: project
자기가 뭘 안 건드렸는지는 모르기 때문이다. 너는 그 변경과 무관한 신선한 자기가 뭘 안 건드렸는지는 모르기 때문이다. 너는 그 변경과 무관한 신선한
맥락에서 코퍼스 전체를 다시 읽어 그 사각지대를 메우는 역할이다. 맥락에서 코퍼스 전체를 다시 읽어 그 사각지대를 메우는 역할이다.
너는 파일을 고치지 않는다(Edit/Write 도구가 없다). 발견한 것만 구조화해서 너는 파일을 고치지 않는다 — 발견한 것만 구조화해서 보고하고, 실제 반영은
보고하고, 실제 반영은 너를 호출한 세션이 한다. 너를 호출한 세션이 한다. 이 규칙은 도구 유무가 아니라 **행동 규약**이다 —
어떤 이유로 쓰기 도구가 주어지더라도 문서를 직접 고치지 마라.
> **[2026-08-16] 정의 파일은 세션 시작 시점 스냅샷으로 고정된다 — 고쳤으면
> 재시작한 뒤에 감사를 돌릴 것.** 이 배너는 같은 날 감사 라운드들이 남긴
> 긴 가설 서술을 검증된 것만 남겨 압축한 것이다(경위 원문은
> `.claude/session/2026-08-16-01-subagent-audit-and-claudemd-split.md`).
> 확인된 것:
> - **스냅샷 고정 — 1차 증거 있음.** `quad-handover-audit` 실행 시 실제로
> 돌아간 스크립트 파일이 세션 시작 시점 상태와 **바이트 단위로 동일**했고,
> 같은 세션에서 그 파일에 가한 편집은 전혀 반영되지 않았다. 에이전트
> 정의도 같아서, 감사 에이전트들이 받은 지시문엔 그 세션에 추가된 배너가
> 실려 있지 않았다. **워크플로·에이전트 정의 모두 해당.**
> - **`model: sonnet`은 반영된다** — 서브에이전트 트랜스크립트에서
> `claude-sonnet-5` 확인(자기 보고가 아니라 기록 기준).
> - **Write/Edit이 주어지는 원인은 미확정.** `memory: project`를 뺐지만
> 재시작 뒤 재확인은 아직 안 했다. 그래서 위 행동 규약이 유일한 보루다.
> - **"Grep/Glob이 안 주어졌다"는 두 소스가 어긋나는 미해결 불일치다** —
> 호출하는 세션이 보는 에이전트 등록 목록엔 Grep/Glob이 **포함돼 있는데**,
> 실행된 에이전트는 자기 도구를 Read/Bash/Write/Edit으로 보고했다. 어느
> 한쪽을 실측으로 확정하지 말고, (d)와 함께 재시작 직후 깨끗한 실행에서
> 같이 볼 것.
## 절차 ## 절차

View file

@ -10,8 +10,8 @@
오히려 더 중요해졌음** — `bindLifetime`/`canExecute`/`unbindLifetime` 오히려 더 중요해졌음** — `bindLifetime`/`canExecute`/`unbindLifetime`
재정정으로 `canExecute(value)`**`value` 쪽 릴레이션에 복사된 gcconn의 재정정으로 `canExecute(value)`**`value` 쪽 릴레이션에 복사된 gcconn의
`.Connected`를 직접 읽는 것**이 leaf 경로 생존 판정의 전부가 됐기 때문 `.Connected`를 직접 읽는 것**이 leaf 경로 생존 판정의 전부가 됐기 때문
(`base/lifecycle-pattern.md`의 "`bindLifetime`/`canExecute`/`unbindLifetime` (`base/lifecycle-pattern.md`의 "`bindLifetime`/`canBound`/`canExecute`/
— 확정" 절). **[재정정, 2026-08-14 열한 번째 세션] `canBound`는 폐기되지 `unbindLifetime` — 확정" 절). **[재정정, 2026-08-14 열한 번째 세션] `canBound`는 폐기되지
않고 별도 진입점으로 재도입됨** — 이중 바인딩 게이트(`bindLifetime`/ 않고 별도 진입점으로 재도입됨** — 이중 바인딩 게이트(`bindLifetime`/
`Observer:Subscribe()`)는 `canBound`, State emit 전파 게이팅만 `Observer:Subscribe()`)는 `canBound`, State emit 전파 게이팅만
`canExecute`(판정 로직은 비공개 헬퍼 하나를 공유, `base/lifecycle-pattern.md` `canExecute`(판정 로직은 비공개 헬퍼 하나를 공유, `base/lifecycle-pattern.md`

View file

@ -16,7 +16,7 @@
> 확정됐고, 콜백의 lazy 핸들 계약은 **그대로 유지**됩니다. > 확정됐고, 콜백의 lazy 핸들 계약은 **그대로 유지**됩니다.
> >
> - 지금 유효한 규약: **`base/typing-limits.md`** > - 지금 유효한 규약: **`base/typing-limits.md`**
> - 재실측 전문(스파이크 44개): **`audit/type-recursion-issue/`** > - 재실측 전문: **`audit/type-recursion-issue/`**(개수는 `spikes/` 폴더가 소스)
> >
> 아래 런타임 스파이크 결과(12개 통과, `04`/`07`/`18` 절)는 **그대로 > 아래 런타임 스파이크 결과(12개 통과, `04`/`07`/`18` 절)는 **그대로
> 유효**합니다 — 정정 대상은 타입 절뿐입니다. > 유효**합니다 — 정정 대상은 타입 절뿐입니다.

View file

@ -10,12 +10,14 @@
> > 될 때 해결될 이슈로써, 당장 우리가 할 수 있는 바 없다." > > 될 때 해결될 이슈로써, 당장 우리가 할 수 있는 바 없다."
> >
> **지금 유효한 설계 규약은 `base/typing-limits.md`가 소스** — 이 > **지금 유효한 설계 규약은 `base/typing-limits.md`가 소스** — 이
> 문서는 그 결론에 이른 실측 근거(실험 44개 + RFC/소스 대조)를 원문 > 문서는 그 결론에 이른 실측 근거(`spikes/` 폴더의 실험 전체 + RFC/소스 대조)를 원문
> 그대로 보존하는 audit 기록입니다. 규약만 필요하면 `typing-limits.md` > 그대로 보존하는 audit 기록입니다. 규약만 필요하면 `typing-limits.md`
> 보고, "왜 그렇게 정해졌나"가 궁금할 때만 이 문서를 여세요. > 보고, "왜 그렇게 정해졌나"가 궁금할 때만 이 문서를 여세요.
**이 폴더의 구성**: 이 `REPORT.md`(실측 서술) + `spikes/`(재현 스크립트 **이 폴더의 구성**: 이 `REPORT.md`(실측 서술) + `spikes/`(재현 스크립트
44개). `.claude/audit/`의 다른 기록과 달리 스크립트를 같이 두는 이유는 전체 — `00`~`43`에 `21b`~`21e` 같은 후속 변형이 더해짐, 정확한 개수는
폴더 자체가 소스라 여기서 세지 않음). `.claude/audit/`의 다른 기록과
달리 스크립트를 같이 두는 이유는
이 건의 근거가 "여러 formulation을 서로 대조한 것"이라 개별 파일을 이 건의 근거가 "여러 formulation을 서로 대조한 것"이라 개별 파일을
직접 돌려봐야 판정이 재현되기 때문입니다(`luau-analyze spikes/<파일>`, 직접 돌려봐야 판정이 재현되기 때문입니다(`luau-analyze spikes/<파일>`,
추론된 실제 타입까지 보려면 `luau-analyze --annotate spikes/<파일>`). 추론된 실제 타입까지 보려면 `luau-analyze --annotate spikes/<파일>`).
@ -444,7 +446,9 @@ type Promise<T> = {
## 7. 실험 파일 인덱스 ## 7. 실험 파일 인덱스
`00`~`25`(초안, 문제 A 중심)와 `26`~`35`(정정, 문제 B 발견)로 나뉩니다. `00`~`25`(초안, 문제 A 중심), `26`~`35`(정정, 문제 B 발견), `36`~`43`
(후속 — 명시 제네릭 인자/미래 대비)로 나뉩니다(`21b`~`21e`처럼 뒤에 끼워
넣은 변형은 원래 번호 옆에 붙어 있습니다).
자세한 개별 실험 설명은 각 파일 상단 주석 참고. 핵심만: 자세한 개별 실험 설명은 각 파일 상단 주석 참고. 핵심만:
| 파일 | 확인 내용 | 결과 | | 파일 | 확인 내용 | 결과 |

View file

@ -533,8 +533,16 @@ Modifier 값을 변수/모듈 상수로 만들어 재사용하는, 기존에도
**미검토로 남긴 것**: `Apply` 체인이 실측으로 병목이라고 확인되면 그때 **미검토로 남긴 것**: `Apply` 체인이 실측으로 병목이라고 확인되면 그때
"unsafe/fast-path mutable 빌더" 같은 별도 opt-in을 검토할 수 있으나, 지금은 "unsafe/fast-path mutable 빌더" 같은 별도 opt-in을 검토할 수 있으나, 지금은
근거 없는 선제 최적화라 설계하지 않음 — CLAUDE.md의 "드문 오용/가상 미래 근거 없는 선제 최적화라 설계하지 않음 — "드문 오용/가상 미래 요구까지
요구까지 방어/최적화하려고 구조를 복잡하게 만들지 않는다" 원칙과 동일. 방어/최적화하려고 구조를 복잡하게 만들지 않는다" 원칙과 동일.
> **[2026-08-16] 위 인용의 출처가 코퍼스에 없음 — 사용자 판단 대기.**
> 원래 이 문장은 그 원칙을 `CLAUDE.md`의 것으로 인용했으나, 코퍼스 전체
> grep과 `git log -S`(CLAUDE.md 전 히스토리) 어디에도 그런 서술이 없음.
> 원칙을 `conventions.md`에 정식으로 명문화할지, 아니면 출처 없이 이
> 문서의 지역 논거로만 둘지는 사용자가 정할 것 — `question.md`
> "인용 출처 없는 원칙" 항목 참고. 이 문장이 지지하는 결론("지금은
> 설계하지 않음") 자체는 영향받지 않음.
### 9-2. `Overridden`가 서로 다른(그러나 상하위 관계인) Modifier 타입을 섞는 경우 — ### 9-2. `Overridden`가 서로 다른(그러나 상하위 관계인) Modifier 타입을 섞는 경우 —
타입 시그니처 미확정 (2026-08-07 다섯 번째 세션 후속) 타입 시그니처 미확정 (2026-08-07 다섯 번째 세션 후속)

View file

@ -218,10 +218,14 @@ Slot이 store 바인드로 들어오는 경우, pluggable 처리기에 `retract`
미리 수행하고 다시 `process`하면 되므로, 부모에게 위임(자식 slot 요소 자체가 미리 수행하고 다시 `process`하면 되므로, 부모에게 위임(자식 slot 요소 자체가
스스로 정리를 실행하는 게 아니라). 스스로 정리를 실행하는 게 아니라).
> **정정(2026-08-04 검증 라운드)**: 위 "부모 위임" 잠정안은 이후 **폐기** > **정정(2026-08-04 검증 라운드)**: 위 "부모 위임" 잠정안은 당시 **폐기**
> 쪽으로 정정됨 — 아래 "확정" 절과 `.claude/question.md`("Slot의 `retract` > 쪽으로 정정됐었음. **[재역전, 2026-08-13 여섯 번째 세션] 그 "폐기"마저
> 동작이 '부모 위임' 잠정안에서 '폐기(옮기지 않음)'로 확정") 참고. 이 문단은 > 다시 뒤집혀 지금 정본은 `retract`=언마운트**(파괴 아님) — 이 문서 맨 위
> 검토 과정의 히스토리로만 남겨둠, 현재 유효한 동작 아님. > 상태 배너, `archive/question-resolved.md` 맨 끝 확정 요약 표의
> `base/slot-plan.md` 행, 그리고 아래 "`State<Slot>` 교체는 파괴가 아니라
> 언마운트" 절 참고(역전된 "폐기" 원문·역전 근거는
> `archive/slot-discard-no-portal-reversed.md`). 이 문단은 검토 과정의
> 히스토리로만 남겨둠, 두 잠정안 모두 현재 유효한 동작 아님.
**[전면 정정, 2026-08-12 열한 번째 세션, 2026-08-13 다섯 번째/열네 번째 **[전면 정정, 2026-08-12 열한 번째 세션, 2026-08-13 다섯 번째/열네 번째
세션에 서술 갱신] 위 "핸들러 타입이 안 바뀌면 retract 없이 process가 diff 세션에 서술 갱신] 위 "핸들러 타입이 안 바뀌면 retract 없이 process가 diff
@ -480,8 +484,8 @@ nested `Slot`을 파괴 후 재사용하는 경로가 정확히 이 케이스).
- **같은 바인딩이면 완전히 무시하는 게 이 자리에선 효율 문제가 아니라 - **같은 바인딩이면 완전히 무시하는 게 이 자리에선 효율 문제가 아니라
정합성 문제** — 이 no-op 가드가 없으면 **[정정, 2026-08-13 4차 감사] 정합성 문제** — 이 no-op 가드가 없으면 **[정정, 2026-08-13 4차 감사]
재귀 재emit이 있을 때마다 마운트된 서브트리 전체가 언마운트됐다 다시 재귀 재emit이 있을 때마다 마운트된 서브트리 전체가 언마운트됐다 다시
마운트됨**(작성 당시엔 아직 destroy 모델이었음, 위 "확정" 절 언마운트 마운트됨**(작성 당시엔 아직 destroy 모델이었음, 아래 "`State<Slot>` 교체는
전환 참고 — 물리 트리 이탈+재마운트라 여전히 자식들이 들고 있던 스크롤 파괴가 아니라 언마운트" 절의 언마운트 전환 참고 — 물리 트리 이탈+재마운트라 여전히 자식들이 들고 있던 스크롤
위치/포커스/애니메이션 상태는 유실됨, 파괴가 아니라는 것만 정정) — 위치/포커스/애니메이션 상태는 유실됨, 파괴가 아니라는 것만 정정) —
Tag의 `Contains` 힌트가 막으려던 "깜빡임" 문제보다 훨씬 파급이 큰 버전. Tag의 `Contains` 힌트가 막으려던 "깜빡임" 문제보다 훨씬 파급이 큰 버전.
`store.key:Set(sameSlotAgain)`처럼 사용자가 실수로 같은 객체를 다시 `store.key:Set(sameSlotAgain)`처럼 사용자가 실수로 같은 객체를 다시

View file

@ -430,8 +430,9 @@ Tag/Modifier의 클론은 호출 즉시 결과가 확정되는 값이라 "-ed"(
> **[2026-08-13 열세 번째 세션, 해소 — 아래 계약은 그대로 확정]** > **[2026-08-13 열세 번째 세션, 해소 — 아래 계약은 그대로 확정]**
> 한때 이 계약이 Luau 추론과 충돌한다며 `question.md` 0-Y로 열려 있었고, > 한때 이 계약이 Luau 추론과 충돌한다며 `question.md` 0-Y로 열려 있었고,
> "콜백이 raw 값을 받으면 완전히 클린"이라는 1차 판정까지 붙어 있었음. > "콜백이 raw 값을 받으면 완전히 클린"이라는 1차 판정까지 붙어 있었음.
> **44개 스파이크 재실측 결과 그 1차 판정이 뒤집혔음** — raw 값 계약도 > **스파이크 재실측 결과 그 1차 판정이 뒤집혔음**(스파이크 개수·구성은
> 똑같이 불안전했고, 진짜 문제는 콜백 계약이 아니라 **`Compute` > 여기서 세지 않음 — 소스는 아래 `audit/type-recursion-issue/` 폴더) —
> raw 값 계약도 똑같이 불안전했고, 진짜 문제는 콜백 계약이 아니라 **`Compute`
> `State<U>`(자기 이름을 다른 타입 인자로 감싼 타입)를 반환한다는 것 > `State<U>`(자기 이름을 다른 타입 인자로 감싼 타입)를 반환한다는 것
> 자체**였음(Luau의 현 한계, RFC가 `Promise<T>.andThen`으로 예시 든 바로 > 자체**였음(Luau의 현 한계, RFC가 `Promise<T>.andThen`으로 예시 든 바로
> 그 패턴). **따라서 아래 lazy 핸들 계약은 바꿀 이유가 없고 그대로 > 그 패턴). **따라서 아래 lazy 핸들 계약은 바꿀 이유가 없고 그대로

View file

@ -49,8 +49,9 @@
## 1. ⭐ 재귀 제네릭이 다른 타입 인자로 자기를 반환하면 타입 안전성이 조용히 사라짐 ## 1. ⭐ 재귀 제네릭이 다른 타입 인자로 자기를 반환하면 타입 안전성이 조용히 사라짐
**실측 근거: `audit/type-recursion-issue/`**(REPORT.md + 재현 스파이크 **실측 근거: `audit/type-recursion-issue/`**(REPORT.md + `spikes/`의 재현
44개). 이게 이 문서에서 가장 크고, 가장 넓게 영향을 주는 항목입니다. 스파이크 — 개수는 폴더가 소스). 이게 이 문서에서 가장 크고, 가장 넓게
영향을 주는 항목입니다.
### 무엇이 안 되는가 ### 무엇이 안 되는가

View file

@ -83,9 +83,11 @@ haiku, 일반 작업은 sonnet. 특히 소스코드를 많이 읽어야 하는
`.claude/workflows/quad-handover-audit.js`(Workflow 이름 `.claude/workflows/quad-handover-audit.js`(Workflow 이름
`quad-handover-audit`)를 먼저 돌릴 것.** 단일 `quad-doc-auditor` 패스는 `quad-handover-audit`)를 먼저 돌릴 것.** 단일 `quad-doc-auditor` 패스는
비결정적이라 매번 다 잡는다는 보장이 없다는 게 사용자 지적 — 이 워크플로는 비결정적이라 매번 다 잡는다는 보장이 없다는 게 사용자 지적 — 이 워크플로는
라운드마다 `quad-doc-auditor`를 병렬로 3회 돌리고 새 발견을 파일별로 라운드마다 `quad-doc-auditor`를 병렬로 여러 번 돌리고 새 발견을 파일별로
즉시 반영한 뒤, **새 발견이 없는 라운드가 연속 2번 나올 때까지**(최대 즉시 반영한 뒤, **새 발견이 없는 라운드가 연속으로 나올 때까지** 반복해
6라운드) 반복해 수렴시킨다. 사용자가 정확성을 시간보다 우선한다고 수렴시킨다(라운드당 패스 수·수렴 조건·최대 라운드는 튜닝 대상 상수라
여기 숫자를 적지 않음 — 소스는 `.claude/workflows/quad-handover-audit.js`
상단). 사용자가 정확성을 시간보다 우선한다고
명시했으므로 기본 워크플로 크기 가이드라인(15 에이전트 이하)을 의도적으로 명시했으므로 기본 워크플로 크기 가이드라인(15 에이전트 이하)을 의도적으로
넘을 수 있음 — 이 워크플로 자체가 그 예외 대상. Workflow는 백그라운드로 넘을 수 있음 — 이 워크플로 자체가 그 예외 대상. Workflow는 백그라운드로
돌고 완료 시 알림이 오므로, 호출 직후 대화를 막지 말고 진행 상황만 돌고 완료 시 알림이 오므로, 호출 직후 대화를 막지 말고 진행 상황만

View file

@ -43,7 +43,8 @@
인라이닝" 방향은 **채택 안 함**. 인라이닝" 방향은 **채택 안 함**.
- 지금 유효한 규약: **`base/typing-limits.md`** - 지금 유효한 규약: **`base/typing-limits.md`**
- 실측 근거 전문(스파이크 44개 포함): `audit/type-recursion-issue/` - 실측 근거 전문(스파이크 다수 포함 — 개수는 `spikes/` 폴더가 소스):
`audit/type-recursion-issue/`
`15`도 같은 계약을 다루지만 **스파이크 자체가 파싱 실패**라 `15`도 같은 계약을 다루지만 **스파이크 자체가 파싱 실패**라
`rewrite-required/`에 그대로 둠 — 재작성 대상이지 사람 결정 대상이 `rewrite-required/`에 그대로 둠 — 재작성 대상이지 사람 결정 대상이

View file

@ -10,7 +10,9 @@ Roblox 엔진에서 동작하는 DOMless UI 렌더러 **quad**를 처음부터
지속 가능성 — 빠른 이터레이션보다 정확성/설계 정합성이 우선. 작업 기간은 지속 가능성 — 빠른 이터레이션보다 정확성/설계 정합성이 우선. 작업 기간은
길게 잡음. 길게 잡음.
**지금은 설계/계획 단계이고 구현은 아직 시작 전** — 저장소 루트에 실제 소스 **[2026-08-16 기준] 지금은 설계/계획 단계이고 구현은 아직 시작 전**(M0에
착수하면 루트 `CLAUDE.md` 머리말도 같이 고칠 것 — 같은 상태를 두 곳이
서술하고 있음) — 저장소 루트에 실제 소스
코드(`src/` 등)가 없음. 핵심 아키텍처(Store 책임 분리, `process`/`retract` 코드(`src/` 등)가 없음. 핵심 아키텍처(Store 책임 분리, `process`/`retract`
디스패치 모델, Store/State/Source 온톨로지, 소스 트리 구조, Modifier 메커니즘, 디스패치 모델, Store/State/Source 온톨로지, 소스 트리 구조, Modifier 메커니즘,
컴포넌트=플레인 함수, 컴포넌트 경계 modifier/Ref 전달)는 전부 `.claude/base/` 컴포넌트=플레인 함수, 컴포넌트 경계 modifier/Ref 전달)는 전부 `.claude/base/`
@ -18,7 +20,7 @@ Roblox 엔진에서 동작하는 DOMless UI 렌더러 **quad**를 처음부터
직접 "지금 quad에서 가장 문제되는 부분"으로 지목했던 컴포넌트화(특히 직접 "지금 quad에서 가장 문제되는 부분"으로 지목했던 컴포넌트화(특히
modifier/Ref의 컴포넌트 경계 통과 방식) 논의도 2026-08-04 세션에서 수렴 modifier/Ref의 컴포넌트 경계 통과 방식) 논의도 2026-08-04 세션에서 수렴
완료(`base/component-composition-plan.md`) — 남은 핵심 설계 질문은 없고, 완료(`base/component-composition-plan.md`) — 남은 핵심 설계 질문은 없고,
용어 정리(진행 중)와 실제 스캐폴딩만 남음, 아래 "지금 할 일" 참고. 용어 정리(진행 중)와 실제 스캐폴딩만 남음, `.claude/todos.md` 참고.
이전에 시도했다 폐기한 v2 재작성 시도(`.claude/initreq/quad2-try`)도 리서치 이전에 시도했다 폐기한 v2 재작성 시도(`.claude/initreq/quad2-try`)도 리서치
완료 — OOP 상속/커스텀 파서/Slot 스텁/`Pipe` copy-on-write 절충안은 확인된 완료 — OOP 상속/커스텀 파서/Slot 스텁/`Pipe` copy-on-write 절충안은 확인된
@ -27,7 +29,7 @@ modifier/Ref의 컴포넌트 경계 통과 방식) 논의도 2026-08-04 세션
## 계획 문서 구조 ## 계획 문서 구조
`.claude/README.md`가 색인. 요약: `.claude/README.md`가 색인. 요약:
- **[2026-08-16]** 루트 `CLAUDE.md`39줄짜리 진입점일 뿐이고, 실제 내용은 - **[2026-08-16]** 루트 `CLAUDE.md`짧은 진입점일 뿐이고, 실제 내용은
`.claude/conventions.md`(관례·작업 방식) / 이 문서 / `.claude/todos.md` `.claude/conventions.md`(관례·작업 방식) / 이 문서 / `.claude/todos.md`
(지금 할 일)로 쪼개져 `@import`로 다시 합쳐짐. `.claude/session-summary.md` (지금 할 일)로 쪼개져 `@import`로 다시 합쳐짐. `.claude/session-summary.md`
(세션 요약 색인)만 **import 안 됨** — 필요할 때 직접 열 것. (세션 요약 색인)만 **import 안 됨** — 필요할 때 직접 열 것.
@ -36,27 +38,25 @@ modifier/Ref의 컴포넌트 경계 통과 방식) 논의도 2026-08-04 세션
- `.claude/reference/`**[2026-08-07 신설]** base처럼 확정된 건 아니지만 - `.claude/reference/`**[2026-08-07 신설]** base처럼 확정된 건 아니지만
base 문서가 근거로 인용하는 온디맨드 참고 자료(v1 내부 동작 스냅샷, base 문서가 근거로 인용하는 온디맨드 참고 자료(v1 내부 동작 스냅샷,
Fusion/Vide 비교 리서치) — 항상 읽을 필요는 없고 인용될 때만 열어볼 것. Fusion/Vide 비교 리서치) — 항상 읽을 필요는 없고 인용될 때만 열어볼 것.
- `.claude/research/` — 아직 착수 전, 사용자와 상의 필요한 설계 논의. - `.claude/research/` — 아직 착수 전, 사용자와 상의 필요한 설계 논의. 전부
`debug-tooling-plan.md`/ 후순위. **어떤 문서가 있는지·우선순위가 뭔지는 여기서 세지도 나열하지도
`documentation-plan.md`/`documentation-content-map.md`/ 않고 `.claude/README.md``research/` 표로 미룸**(개수뿐 아니라 파일명
`framework-comparison-findings.md`/`additional-primitives-plan.md`(2026-08-09 나열 자체가 새 문서가 추가될 때마다 stale해지는 패턴이 실제로 반복됐음 —
세 번째 세션에 마지막 열린 항목까지 전부 해소, 이제 배경 자료용)/ 과거엔 "두 개뿐"이라 적어놨다가, 2026-08-16엔 7개짜리 나열이 실제 11개와
`pre-implementation-audit.md`/`v1-compat-plan.md` 어긋난 걸 감사가 발견. 아래 luau-test/audit 문단과 같은 처리로 통일).
— 전부 후순위(`tween-plan.md`는 2026-08-12 세션에 마지막 열린 항목까지 `research/`를 떠난 것만 짚으면: `tween-plan.md`는 2026-08-12 세션에 마지막
전부 해소돼 `base/`로 승격, 이미 생성된 인스턴스 재바인드는 열린 항목까지 전부 해소돼 `base/`로 승격, 이미 생성된 인스턴스 재바인드는
2026-08-14 세션에 기각돼 `archive/existing-instance-bind-rejected.md`로 이전, 더 이상 여기 없음). 최신 목록·우선순위는 2026-08-14 세션에 기각돼 `archive/existing-instance-bind-rejected.md`
`.claude/README.md`가 소스, 여기서 개수 반복 안 함(과거에 "두 개뿐"이라 이전 — 둘 다 더 이상 여기 없음.
적어놨다가 새 문서 추가될 때마다 안 갱신되는 패턴이 반복돼서 아예 안
세기로 함).
- `.claude/luau-test/`**[2026-08-09 신설]** "추론만으로 확정하고 실제 - `.claude/luau-test/`**[2026-08-09 신설]** "추론만으로 확정하고 실제
Luau로 부딪혀본 적 없는 것"을 미리 검증하는 독립 실행 스파이크 20개 Luau로 부딪혀본 적 없는 것"을 미리 검증하는 독립 실행 스파이크 모음
(`luau <파일>` / `luau-analyze <파일>`). **상태의 소스는 항상 `STATUS.md`** (`luau <파일>` / `luau-analyze <파일>`). **상태의 소스는 항상 `STATUS.md`**
(pass / 사람 결정 필요 / 스파이크 깨짐 / 미실행, 폴더 구조 자체가 상태), (pass / 사람 결정 필요 / 스파이크 깨짐 / 미실행, 폴더 구조 자체가 상태),
각 파일이 뭘 왜 검증하는지는 `README.md`. 2026-08-13에 첫 실측 완료(당시 각 파일이 뭘 왜 검증하는지는 `README.md`. 2026-08-13에 첫 실측 완료(당시
런타임 12개 전원 통과) — 이후 여러 세션에 걸쳐 재설계로 몇 건이 추가로 런타임 12개 전원 통과) — 이후 여러 세션에 걸쳐 재설계로 몇 건이 추가로
`rewrite-required/`에 합류했으니 **지금 몇 개가 어디 있는지는 여기서 `rewrite-required/`에 합류했으니 **총 몇 개인지도, 지금 몇 개가 어디
나열 안 하고 `STATUS.md`로 미룸**(나열하다 stale해지는 패턴이 실제로 있는지도 여기서 세지 않고 `STATUS.md`로 미룸**(세거나 나열하다 stale해지는
반복됐음, 아래 "지금 할 일" 0번 참고). 패턴이 실제로 반복됐음, `.claude/todos.md`의 luau-test 스파이크 항목 참고).
- `.claude/audit/`**[2026-08-13 신설]** 스파이크를 실제로 돌린 **실측 - `.claude/audit/`**[2026-08-13 신설]** 스파이크를 실제로 돌린 **실측
결과** 기록(계획 아님). 부분 확인도 있는 그대로 남김 — **지금 몇 개가 결과** 기록(계획 아님). 부분 확인도 있는 그대로 남김 — **지금 몇 개가
있는지·각각 뭘 확인했는지는 여기서 나열 안 하고 `.claude/README.md` 있는지·각각 뭘 확인했는지는 여기서 나열 안 하고 `.claude/README.md`
@ -64,13 +64,14 @@ modifier/Ref의 컴포넌트 경계 통과 방식) 논의도 2026-08-04 세션
추가될 때마다 stale해지는 패턴이 실제로 반복됐음, 가장 최근엔 추가될 때마다 stale해지는 패턴이 실제로 반복됐음, 가장 최근엔
2026-08-15에 이 목록이 3개에서 멈춰 있는 걸 `/code-review`가 발견). 2026-08-15에 이 목록이 3개에서 멈춰 있는 걸 `/code-review`가 발견).
`type-recursion-issue/`만 참고로 짚으면: **[13차 세션]** 0-Y 재실측 `type-recursion-issue/`만 참고로 짚으면: **[13차 세션]** 0-Y 재실측
전체 — `REPORT.md` + `spikes/` 44개, **스크립트를 같이 두는** 예외적 전체 — `REPORT.md` + `spikes/`(개수는 폴더가 소스), **스크립트를 같이 두는** 예외적
구성(판정이 "여러 formulation 대조"라 개별 파일을 직접 돌려야 재현됨), 구성(판정이 "여러 formulation 대조"라 개별 파일을 직접 돌려야 재현됨),
결론은 `base/typing-limits.md`로 승격 — 이후 신설된 폴더들도 같은 결론은 `base/typing-limits.md`로 승격 — 이후 신설된 폴더들도 같은
구성 관례를 따름(`type-recursive-issue-with-typeof/`, 구성 관례를 따름(`type-recursive-issue-with-typeof/`,
`type-recursive-issue-try-callback/` 등). `type-recursive-issue-try-callback/` 등).
- `.claude/qa-request/`, `.claude/feedback/` — 구현 시작되면 쓰기 시작함, - `.claude/qa-request/`, `.claude/feedback/` — 구현 시작되면 쓰기 시작함,
지금은 비어있음. `.claude/archive/`는 원래 같은 취급이었으나 **[2026-08-16 기준] 아직 비어 있음**(`feedback/`은 폴더 자체가 아직
없음). `.claude/archive/`는 원래 같은 취급이었으나
2026-08-06 세 번째 세션부터 **완전히 뒤집힌 설계 결정을 원문+역전 2026-08-06 세 번째 세션부터 **완전히 뒤집힌 설계 결정을 원문+역전
이유+diff와 함께 보존하는 용도로도 사용 시작**(구현 완료 대상만이 이유+diff와 함께 보존하는 용도로도 사용 시작**(구현 완료 대상만이
아님) — `archive/store-source-proxy-reversed.md`가 첫 사례, 나중 아님) — `archive/store-source-proxy-reversed.md`가 첫 사례, 나중

View file

@ -31,11 +31,14 @@
사용자 원 메모: "quad는 register라던가 좀 부정확하거나 느낌이 바로 와닿지 사용자 원 메모: "quad는 register라던가 좀 부정확하거나 느낌이 바로 와닿지
않던 용어들이 많음 — 전체적 용어를 보고 생각해볼래? 제안을 줘, 나도 같이 않던 용어들이 많음 — 전체적 용어를 보고 생각해볼래? 제안을 줘, 나도 같이
볼게." **이미 확정된 이름**(`State`/`Relate`/`List`/`Ref`/ 볼게." **이미 확정된 이름**(`State`/`Relate`/`List`/`canBound`/`Ref`/
`PreRef`/`Peek`/`isState`/`None`/`NoneHandler`/`Handler`)의 근거는 `PreRef`/`Peek`/`isState`/`None`/`NoneHandler`/`Handler`)의 근거는
`archive/question-resolved.md`. (`canBound`는 2026-08-14 다섯 번째 세션에 `archive/question-resolved.md`. (`canBound`는 2026-08-14 다섯 번째 세션에
**폐기**되어 이 목록에서 빠짐 — `canExecute` 하나로 통합됐음, 폐기돼 `canExecute`로 통합됐다가 **같은 날 열한 번째 세션에 별도 진입점으로
`archive/canexecute-inst-arg-reversed.md`.) 재도입**되어 여전히 이 목록에 있음 — 이중 바인딩 가드 전용이고 `canExecute`
(emit 게이팅 전용)와는 판정 로직만 공유. 아래 3번 `canExecute` 항목과
`base/lifecycle-pattern.md`의 "`canBound` vs `canExecute`" 절,
`archive/canexecute-inst-arg-reversed.md` 하단 addendum 참고.)
- **`DI`(Declarative Instance, 1순위)**: "Dependency Injection"의 업계 - **`DI`(Declarative Instance, 1순위)**: "Dependency Injection"의 업계
표준 축약어와 완전히 겹침 — 4차 라운드에서 이미 한 번 실제로 오해가 표준 축약어와 완전히 겹침 — 4차 라운드에서 이미 한 번 실제로 오해가
@ -110,6 +113,23 @@
## 3. 낮은 우선순위 — 열려 있지만 급하지 않음 ## 3. 낮은 우선순위 — 열려 있지만 급하지 않음
- **인용 출처 없는 원칙 — "드문 오용/가상 미래 요구까지 방어/최적화하려고
구조를 복잡하게 만들지 않는다"(2026-08-16 신설)** —
`base/modifier-plan.md`의 "미검토로 남긴 것" 문단이 이 원칙을 `CLAUDE.md`
것으로 인용해왔으나, **코퍼스 전체 grep과 `git log -S`(CLAUDE.md 전
히스토리) 어디에도 그런 서술이 없음** — 즉 존재한 적 없는 출처였음(같이
발견된 다른 두 건은 인용 대상만 틀린 것이라 실제 소스로 재조준 완료:
`research/v1-compat-plan.md`→`base/component-composition-plan.md`+
`base/store-plan.md`, `research/pre-implementation-audit.md`→`ROADMAP.md` +
`question.md`(이 문서)).
선택지는 (a) 이 원칙을 `.claude/conventions.md`에 정식 명문화 —
실제로 여러 설계 결정이 이 취지로 내려졌으니 한 번 적어두면 앞으로도
인용 가능, (b) 명문화하지 않고 `modifier-plan.md`의 지역 논거로만 둠
(이 경우 그 문단의 정정 배너를 지우고 문장만 남기면 됨).
**어느 쪽이든 그 문단의 결론("지금은 fast-path 빌더를 설계하지 않음")은
영향받지 않음** — 순수하게 "이 원칙을 프로젝트 공식 관례로 승격할
것인가"만 묻는 질문.
- **`Operator` 콤비네이터 슈가 네임스페이스 이름+포함 범위(2026-08-12 신설, - **`Operator` 콤비네이터 슈가 네임스페이스 이름+포함 범위(2026-08-12 신설,
같은 날 후속으로 외부 리서치 완료)** — `Sum`/`Product`/`Not`/비트연산 등 같은 날 후속으로 외부 리서치 완료)** — `Sum`/`Product`/`Not`/비트연산 등
`:Compute`/`:Apply`용 슈가 함수 모음의 이름. 흔한 단어라 top-level `:Compute`/`:Apply`용 슈가 함수 모음의 이름. 흔한 단어라 top-level

View file

@ -97,7 +97,8 @@ ERROR, `doc-check.py` 파이프라인에 편입) 두 모드.
1. 마커 문법 자체(위 초안 확정 여부, id 네이밍 규칙 — 날짜+세션번호로 1. 마커 문법 자체(위 초안 확정 여부, id 네이밍 규칙 — 날짜+세션번호로
충분한지). 충분한지).
2. 기존 세션 항목 전부(13개+)에 마커를 소급 삽입할지, 아니면 다음 2. 기존 세션 항목 전부(`.claude/session/` 폴더에 지금까지 쌓인 파일
전부 — 개수는 여기 안 적음, 폴더가 소스)에 마커를 소급 삽입할지, 아니면 다음
세션부터 신규 항목에만 적용하고 과거분은 그대로 둘지. 세션부터 신규 항목에만 적용하고 과거분은 그대로 둘지.
3. `--write` 실행 시점 — 수동(세션 마무리 시 사람이 실행) vs 커밋 훅. 3. `--write` 실행 시점 — 수동(세션 마무리 시 사람이 실행) vs 커밋 훅.
이 레포는 지금 CI가 없고 사람이 `doc-check.py`도 수동으로 돌리는 이 레포는 지금 CI가 없고 사람이 `doc-check.py`도 수동으로 돌리는

View file

@ -431,9 +431,14 @@ State<T>` 조합조차 M0 스파이크 대상(솔버가 죽을 수 있음)으로
"역시 얇은 래퍼가 필요하다"로 뒤집히면, 이미 "그냥 함수" 규약으로 짜인 "역시 얇은 래퍼가 필요하다"로 뒤집히면, 이미 "그냥 함수" 규약으로 짜인
기존 컴포넌트 전체를 마이그레이션해야 하는 연쇄가 발생. 기존 컴포넌트 전체를 마이그레이션해야 하는 연쇄가 발생.
**제안**: `CLAUDE.md`가 이미 M2/M3/M5에서 quad-debug 훅 확장 지점을 **제안**: 루트 `ROADMAP.md``quad-debug` 백로그 항목("M2/M3/M5 구현 시
고려하라고 명시해뒀으니, 그 시점에 이 질문도 같이 열어 "래퍼 없음"이 훅 확장 지점만 고려해두면 이 항목 자체는 지금 착수 불필요")과
구조적으로도 최종 확정인지 한 번 더 확인할 것. M1 스캐폴딩 전에. `question.md`의 같은 서술이 이미 그 시점을 지목해뒀으니, 그때 이 질문도
같이 열어 "래퍼 없음"이 구조적으로도 최종 확정인지 한 번 더 확인할 것.
M1 스캐폴딩 전에. (**[2026-08-16 인용 정정]** 원래 이 근거를 `CLAUDE.md`
명시해뒀다고 적혀 있었으나 CLAUDE.md엔 그런 서술이 없었음 — 실제 소스는
위 두 곳. 다만 `research/debug-tooling-plan.md` 쪽 서술은 더 약한
"훅 확장 지점 존재 가능성만 인지해두는 정도"라는 점에 유의.)
### 2-4. existing-instance-bind가 Slot의 "엄격한 단일 마운트 소유권" 불변식과 근본적으로 긴장 — **[해소됨, 2026-08-14 세션: 기능 자체가 기각]** ### 2-4. existing-instance-bind가 Slot의 "엄격한 단일 마운트 소유권" 불변식과 근본적으로 긴장 — **[해소됨, 2026-08-14 세션: 기능 자체가 기각]**

View file

@ -47,8 +47,14 @@ v1(`.claude/initreq/quad/src`) 조사 결과, API는 성격이 다른 두 계층
- 인스턴스화 시 생성자 인자를 자동으로 store로 감싸고(`class.lua:367`), - 인스턴스화 시 생성자 인자를 자동으로 store로 감싸고(`class.lua:367`),
이후 `comp.Text = "hi"`처럼 프로퍼티를 재대입하면 `__newindex`가 자동으로 이후 `comp.Text = "hi"`처럼 프로퍼티를 재대입하면 `__newindex`가 자동으로
내부 store에 위임 + `UpdateTriggers`에 걸리면 자동 재렌더까지 발생 내부 store에 위임 + `UpdateTriggers`에 걸리면 자동 재렌더까지 발생
(`class.lua:524-566`) — CLAUDE.md에 이미 "이 자동 위임/재렌더 매직은 (`class.lua:524-566`) — v2에서 폐기하기로 확정된 바로 그 메커니즘
v2에서 폐기하기로 확정"이라 기록된 바로 그 메커니즘. (**[2026-08-16 인용 정정]** 원래 "CLAUDE.md에 기록됨"이라 적혀 있었으나
CLAUDE.md에 그런 서술은 없었음. 실제 소스는
`base/component-composition-plan.md`의 "1. 컴포넌트 = 그냥 함수, "자기
store 자동 소유" 매직은 폐기" 절(자동 흡수/자동 store 생성 매직 폐기,
사용자 확정)과 `base/store-plan.md`의 "Store 값 설정 문법 —
`myStore.key = value` 폐기, `source:Set(value)`로 전환" 절(`__newindex`
자동 위임 폐기)).
## 3. 계층별 실현 가능성 ## 3. 계층별 실현 가능성

View file

@ -1,8 +1,8 @@
# 세션 히스토리 (요약 색인) # 세션 히스토리 (요약 색인)
루트 `CLAUDE.md``@import` 하지 **않음 — 의도적**. 1231줄을 매 세션 루트 `CLAUDE.md``@import` 하지 **않음 — 의도적**. 세션마다 계속 자라는
컨텍스트에 올릴 이유가 없다는 판단(2026-08-16). 선행 맥락이 필요할 때만 히스토리 문서라 통째로 매 세션 컨텍스트에 올릴 이유가 없다는
grep해서 읽는 온디맨드 자료. 판단(2026-08-16). 선행 맥락이 필요할 때만 grep해서 읽는 온디맨드 자료.
**[2026-08-16 기준] 이 파일은 아직 손으로 관리 중이지만, 곧 전체 자동생성으로 **[2026-08-16 기준] 이 파일은 아직 손으로 관리 중이지만, 곧 전체 자동생성으로
전환 예정** — 각 `.claude/session/*.md`가 자기 요약을 마커 블록으로 들고 있고 전환 예정** — 각 `.claude/session/*.md`가 자기 요약을 마커 블록으로 들고 있고
@ -1247,10 +1247,19 @@ type-recursive-issue-try-callback/`, spikes 35개) — **결론은 그대로
사용자가 "핸드오버 전/커밋 전에 code-review 같은 걸 스스로 돌게 만들 수 사용자가 "핸드오버 전/커밋 전에 code-review 같은 걸 스스로 돌게 만들 수
있나"에서 출발 — hook은 셸 명령만 실행해 스킬/서브에이전트를 직접 못 있나"에서 출발 — hook은 셸 명령만 실행해 스킬/서브에이전트를 직접 못
부르므로, **읽기 전용 감사자 `.claude/agents/quad-doc-auditor.md`**(발견만 부르므로, **읽기 전용 감사자 `.claude/agents/quad-doc-auditor.md`**(발견만
리포트, `memory: project`)와 **다회·병렬 수렴 루프 리포트 — 처음엔 `memory: project`를 켰으나, 그게 켜져 있으면 에이전트 등록
목록에 Write/Edit이 같이 딸려오는 것으로 보여 같은 세션 후속 작업에서 다시
뺐음. **[2026-08-16 기준] 옵션을 뺀 뒤에도 Write/Edit이 그대로 주어져 원인
진단은 미확정**. **[2026-08-16 정정]** 한때 `.claude/agent-memory/quad-doc-auditor/`
"아무도 로드하지 않는 잔여물"로 적어뒀으나, 옵션을 뺀(02:03) 뒤 돌린 감사에서도
그 디렉토리에 새 기록이 쌓이는 게 실측돼(02:11) 반증됨 — 메모리는 여전히
로드·기록되고 있으니 잔여물로 취급하지 말 것. 최신 상태는
`.claude/agents/quad-doc-auditor.md` 상단 배너가 소스. 어느 쪽이든 읽기
전용은 도구 유무가 아니라 프롬프트의 행동 규약으로 못박음)와 **다회·병렬 수렴 루프
`.claude/workflows/quad-handover-audit.js`**(라운드당 병렬 3회 감사 + `.claude/workflows/quad-handover-audit.js`**(라운드당 병렬 3회 감사 +
파일별 즉시 반영을, 새 발견 없는 라운드가 연속 2번 나올 때까지 최대 파일별 즉시 반영을, 새 발견 없는 라운드가 연속 2번 나올 때까지 최대
6라운드)로 나눠 구성. 첫 실측은 `.claude/agents/`가 세션 도중 생긴 6라운드 — 이 상수들은 튜닝 대상이라 소스는 `quad-handover-audit.js` 상단,
여기 숫자는 도입 당시 값)로 나눠 구성. 첫 실측은 `.claude/agents/`가 세션 도중 생긴
디렉토리라 6개 전원 `agentType not found`로 실패 — **더 중요한 건 그 디렉토리라 6개 전원 `agentType not found`로 실패 — **더 중요한 건 그
실패가 `converged:true`로 보고된 것**(감사 패스가 전멸해도 `fresh`가 비어 실패가 `converged:true`로 보고된 것**(감사 패스가 전멸해도 `fresh`가 비어
"깨끗한 라운드"와 구분이 안 됐음). 감사 도구 최악의 실패 모드라 즉시 "깨끗한 라운드"와 구분이 안 됐음). 감사 도구 최악의 실패 모드라 즉시
@ -1258,9 +1267,10 @@ type-recursive-issue-try-callback/`, spikes 35개) — **결론은 그대로
빼 다음 라운드가 재시도). 이어 사용자 지적으로 **루트 `CLAUDE.md` 빼 다음 라운드가 재시도). 이어 사용자 지적으로 **루트 `CLAUDE.md`
1537줄을 4분할** — `conventions.md`(관례+작업 방식) / 1537줄을 4분할** — `conventions.md`(관례+작업 방식) /
`project-context.md` / `todos.md``@import`하고, `project-context.md` / `todos.md``@import`하고,
**`session-summary.md`(1231줄, 전체의 80%)는 의도적으로 import 안 함** **`session-summary.md`(분할 전 `CLAUDE.md`의 80%)는 의도적으로 import 안 함**
(그 문서 스스로 "항상 읽을 필요 없음, `base/`가 소스"라고 명시해왔음) — (그 문서 스스로 "항상 읽을 필요 없음, `base/`가 소스"라고 명시해왔음) —
매 세션 로드가 1537→354줄. 부수 수확: 공식 문서에서 (a) 권장치가 파일당 매 세션 로드가 분할 전 `CLAUDE.md` 분량의 극히 일부로 줄었음(구체적인 줄
수는 계속 바뀌니 여기 안 적음 — 궁금하면 그때 `wc -l`). 부수 수확: 공식 문서에서 (a) 권장치가 파일당
200줄이고 초과 시 **지침 준수도 자체가 떨어진다**는 것, (b) `@import` 200줄이고 초과 시 **지침 준수도 자체가 떨어진다**는 것, (b) `@import`
컨텍스트를 **안 줄인다**는 것, (c) CLAUDE.md 계열의 블록 HTML 주석은 컨텍스트를 **안 줄인다**는 것, (c) CLAUDE.md 계열의 블록 HTML 주석은
주입 전 제거돼 **에이전트가 못 본다**는 것을 확인(자기 변경에서 실제로 주입 전 제거돼 **에이전트가 못 본다**는 것을 확인(자기 변경에서 실제로
@ -1274,3 +1284,27 @@ stale")가 틀렸음**을 잡아냄(실제로는 `initreq/tbox/CLAUDE.md`를 가
`research/doc-include-plan.md`는 이 분할로 **설계 절반이 불필요해져** `research/doc-include-plan.md`는 이 분할로 **설계 절반이 불필요해져**
양방향 마커 → 단방향 생성으로 단순화(목적지가 통째로 생성되는 파일이라 양방향 마커 → 단방향 생성으로 단순화(목적지가 통째로 생성되는 파일이라
`<!--#include-->` 마커 자체가 필요 없어짐). `<!--#include-->` 마커 자체가 필요 없어짐).
**2026-08-16 두 번째 세션 — 감사 툴링 재시작 검증, 핸드오버 감사 첫 실동(수렴 실패)**
(`session/2026-08-16-02-audit-tooling-verification-and-first-real-run.md`)
전 세션이 남긴 재시작 검증 3건을 전부 닫음 — `@import` 로드 ✅,
`quad-doc-auditor` 등록 ✅, frontmatter `model: sonnet` 반영 ✅(트랜스크립트
기록 기준). **가장 큰 수확은 "정의 파일은 세션 시작 시점 스냅샷으로
고정된다"를 1차 증거로 확정한 것** — 워크플로가 실제 실행한 스크립트가 세션
시작 시점 상태와 바이트 단위로 같았고 같은 세션의 편집은 반영 0이었음(에이전트
정의도 동일). **정의를 고쳤으면 재시작 뒤에 감사를 돌릴 것.** 전 세션 감사가
남긴 "Grep/Glob 미지급"은 **두 소스가 어긋나는 미해결 불일치**로 정리(호출
세션이 보는 등록 목록엔 포함돼 있는데 실행된 에이전트는 자기 도구에 없다고
보고) — 어느 쪽도 확정하지 말고 재시작 직후 실행에서 볼 것. 전 세션이
"존재하지 않는 원칙 인용" 3건으로 넘긴 것은 재분류돼 **2건이 인용 대상
오류**로 판명(`v1-compat-plan.md`→`component-composition-plan.md`+
`store-plan.md`, `pre-implementation-audit.md`→`ROADMAP.md`), 진짜 출처 없는
1건(`modifier-plan.md:536`)만 `question.md` 3번으로 올려 사용자 판단 대기.
`quad-handover-audit` 첫 실동은 에이전트 67개/6라운드에 **수렴 실패**(새 발견
28→15→16→7→11→6, 라운드5에서 되레 증가) — 단조 감소 전제와 `MAX_ROUNDS`
재검토 필요. 수정 품질 자체는 높았음: `slot-plan.md`의 정정 배너가 그 뒤
재역전된 걸 놓치고 있던 것, `spikes 44개`(실제 48개) 류 하드코딩 개수의
단일 소스화, `doc-check.py` docstring이 검사 심각도를 실제 코드와 다르게
서술하던 것 등을 잡음. 워크플로도 개선 — 반환값에 `findings` 추가(커밋 전
diff 리뷰 근거), `totalFindingsFixed`→`findingsSentToFix` 개명(과대계상),
반영 에이전트 `model: 'sonnet'` 명시.

View file

@ -0,0 +1,105 @@
# 2026-08-16 두 번째 세션 — 감사 툴링 재시작 검증 + 핸드오버 감사 첫 실동
전 세션(`2026-08-16-01-subagent-audit-and-claudemd-split.md`)이 남긴
"재시작해야만 확인 가능한 것 3개"를 닫고, `quad-handover-audit` 워크플로를
처음으로 **실제로 감사가 도는 상태**에서 돌린 세션.
## 1. 재시작 검증 3건 — 전부 확인
| 항목 | 결과 | 근거 |
|---|---|---|
| `@import` 3개 로드 | ✅ | `conventions.md`/`project-context.md`/`todos.md` 내용이 실제 컨텍스트에 들어옴 |
| `quad-doc-auditor` 등록 | ✅ | 에이전트 목록에 잡힘. 전 세션 전멸(`agentType not found`)은 `.claude/agents/`가 세션 도중 생긴 디렉토리였던 탓 |
| frontmatter `model: sonnet` 반영 | ✅ | 서브에이전트 트랜스크립트에 `"model":"claude-sonnet-5"` 기록. 워크플로에 `opts.model` 명시 불필요 |
모델 확인은 처음에 "네 모델과 도구를 보고해라"는 프로브 에이전트로 시도했다가
**에이전트가 프롬프트 인젝션으로 판단해 거부**했다(원래 과업인 감사를 버리고
시스템 프롬프트를 덤프하라는 지시였으니 정당한 거부). 자기 보고 대신
트랜스크립트 파일을 직접 grep하는 쪽이 1차 증거라 더 낫다.
## 2. ⭐ 정의 파일은 세션 시작 시점 스냅샷으로 고정된다 (에이전트·워크플로 공통)
전 세션 감사 라운드들이 "캐시냐 frontmatter 무시냐"로 길게 갈라놨던 것을
결정적으로 닫는 증거가 이 세션에서 나왔다.
- 이 세션에서 `.claude/workflows/quad-handover-audit.js`를 편집한 뒤
`Workflow({name: 'quad-handover-audit'})`를 돌렸는데, 런타임이 실제로
실행한 스크립트 파일이 **세션 시작 시점 상태(= 당시 HEAD, 작업트리가
깨끗했음)와 바이트 단위로 동일**했다. 내 편집은 하나도 안 실렸다.
- 같은 현상이 에이전트 정의에서도 관측됐다(감사 에이전트들이 받은 지시문에
그 세션에 추가된 배너가 없었음).
**실무 규칙: 정의 파일(`.claude/agents/*.md`, `.claude/workflows/*.js`)을
고쳤으면 세션을 재시작한 뒤에 감사를 돌릴 것.** 안 그러면 옛 정의로 돌면서
새 정의로 돈 것처럼 보인다 — 감사 도구에선 이게 조용한 거짓 초록불이다.
미해소로 남은 건 **읽기 전용인데 Write/Edit이 주어지는 원인** 하나.
`memory: project`를 뺐지만 그 뒤 재시작 없이 관찰한 것뿐이라 진단 미확정.
전 세션 감사가 남긴 **"Grep/Glob이 안 주어졌다"는 서술은 두 소스가 어긋나는
미해결 불일치**다 — 호출 세션이 보는 에이전트 등록 목록엔 Grep/Glob이
포함돼 있는데, 실행된 에이전트는 자기 도구를 Read/Bash/Write/Edit으로
보고했다. (처음엔 "자기 보고라 근거가 약하다"고 깎으려 했으나, 에이전트는
자기 함수 목록을 직접 볼 수 있으므로 그건 과한 판단이었다.) 어느 쪽도
확정하지 말고 Write/Edit 원인과 함께 재시작 직후 실행에서 볼 것.
## 3. "존재하지 않는 원칙 인용" 3건 — 재분류 결과 2건은 인용 오류였음
전 세션은 셋 다 같은 성격(가짜 원칙)으로 넘겼는데, 코퍼스 grep +
`git log -S`로 다시 보니 갈렸다.
- **`research/v1-compat-plan.md:50`** — 원칙 자체는 실재. 실제 소스는
`base/component-composition-plan.md` §1(자동 store 생성/자동 흡수 매직
폐기, 사용자 확정)과 `base/store-plan.md` "Store 값 설정 문법" 절
(`__newindex` 자동 위임 폐기). → 재조준.
- **`research/pre-implementation-audit.md:434`** — 역시 실재. 실제 소스는
루트 `ROADMAP.md`의 quad-debug 백로그 항목 + `question.md`. 다만
`research/debug-tooling-plan.md` 쪽은 더 약한 표현("존재 가능성만
인지")이라 그 온도차도 같이 적었다. → 재조준.
- **`base/modifier-plan.md:536`** — 이것만 **진짜로 출처가 없다.** 코퍼스
전체에도, `git log -S`로 본 `CLAUDE.md` 전 히스토리에도 그런 서술이
존재한 적 없다. 임의로 정하지 않고 날짜 붙인 대기 배너 + `question.md`
3번 항목(선택지 (a) `conventions.md`에 명문화 / (b) 지역 논거로만 유지)로
올려 **사용자 판단 대기**.
## 4. `quad-handover-audit` 첫 실동 — 6라운드, **수렴 실패**
에이전트 67개 / 라운드별 새 발견 **28 → 15 → 16 → 7 → 11 → 6**. 최대
라운드(6)를 소진할 때까지 새 발견이 마르지 않아 `converged:false`로 끝났다.
과거 수동 감사가 4~6라운드에 수렴했던 것과 다른 양상.
- 라운드 5에서 발견이 7→11로 **다시 늘었다** — 감사가 코퍼스를 훑는 순서/
관점이 라운드마다 달라서 생기는 것으로 보이고, 단조 감소를 전제한
`MAX_ROUNDS=6`이 이 코퍼스엔 부족하다는 신호.
- 이번 실행은 **위 2번 때문에 옛 스크립트로 돌았다** — 즉 이 결과 자체가
"정의를 고치고 재시작 없이 돌린" 사례다. 다음 실동은 재시작 뒤에.
수정 품질 자체는 높았다. 실제로 잡힌 것 중 값진 것:
- `base/slot-plan.md:218`의 정정 배너가 "폐기로 정정됨"에서 멈춰 있었는데,
그 "폐기"가 2026-08-13에 **다시 뒤집혀** 지금 정본은 `retract`=언마운트다.
배너만 보고 지나가면 구현자가 옛 결론을 믿을 자리였다.
- `spikes 44개`류 하드코딩 개수가 여러 문서에 흩어져 있었는데 실제로는
48개(`00`~`43` + `21b`~`21e`)였다. 전부 "폴더가 소스"로 바꿈 —
`conventions.md`의 "개수·목록·상태는 소스를 하나만" 규칙 적용.
- `tools/doc-check.py` docstring이 1·2번 검사 심각도를 **실제 코드와 다르게**
적어놨던 것(둘 다 ERROR라 했지만 코드는 그렇게 동작한 적 없음). 검사
로직은 안 건드리고 서술만 정정.
## 5. 워크플로 스크립트 개선(다음 실행부터 적용됨)
- **반환값에 `findings` 배열 추가.** 기존엔 `roundLog`에 파일명·개수만 있어
커밋 전 diff 리뷰 때 "이 수정이 왜 들어갔는지"를 알 방법이
`journal.jsonl` 고고학뿐이었다.
- `totalFindingsFixed``findingsSentToFix`로 개명. "의심"으로 표시돼
반영 에이전트가 확인 후 건드리지 않은 것도 "고쳐짐"으로 세던 과대계상.
- 반영 에이전트에 `model: 'sonnet'` 명시(감사 패스는 frontmatter로 이미
sonnet, 반영 쪽만 메인 모델을 상속하고 있었음).
## 남은 것
- **`MAX_ROUNDS` 재검토** — 수렴 실패가 재현되는지 재시작 후 실동으로 확인.
단조 감소 전제가 안 맞으니 "연속 dry 2회" 조건 자체도 같이 볼 것.
- **(d) Write/Edit 원인** — 다음 세션 시작 직후 확인.
- **`.claude/agent-memory/`** — 감사 에이전트가 스스로 쓰는 영속 메모리가
생겼고 지금 untracked. 커밋할지 `.gitignore`로 뺄지는 사용자 판단.
- **`modifier-plan.md:536` 원칙** — `question.md` 3번, 사용자 판단 대기.

View file

@ -46,11 +46,12 @@
해소돼 설계 게이트는 남아있지 않음** — 착수 전 읽을 것은 위 0번의 두 해소돼 설계 게이트는 남아있지 않음** — 착수 전 읽을 것은 위 0번의 두
문서(`typing-limits.md`/`dispatch-core-plan.md`)뿐이고, 스파이크 상태는 문서(`typing-limits.md`/`dispatch-core-plan.md`)뿐이고, 스파이크 상태는
아래 그대로: 아래 그대로:
- **`.claude/luau-test/`(2026-08-09 신설, 2026-08-13 기준 20개) 스파이크 - **`.claude/luau-test/`(2026-08-09 신설) 스파이크 결과 — [2026-08-13
결과 — [2026-08-13 여섯 번째 세션에 첫 실측 완료, 대부분 닫힘].** 여섯 번째 세션에 첫 실측 완료, 대부분 닫힘].**
**상태의 소스는 항상 `.claude/luau-test/STATUS.md`**(pass / 사람 결정 **상태의 소스는 항상 `.claude/luau-test/STATUS.md`**(pass / 사람 결정
필요 / 스파이크 깨짐 / 미실행, 폴더 구조 자체가 상태) — 몇 개가 지금 필요 / 스파이크 깨짐 / 미실행, 폴더 구조 자체가 상태) — 총 몇 개인지도,
어느 폴더에 있는지는 여기서 나열 안 함(04/05/10/13/15/16/19가 여러 지금 몇 개가 어느 폴더에 있는지도 여기서 세거나 나열 안
함(04/05/10/13/15/16/19가 여러
세션에 걸쳐 재설계로 `rewrite-required/`에 들고나며 이 문단의 나열이 세션에 걸쳐 재설계로 `rewrite-required/`에 들고나며 이 문단의 나열이
매번 stale해지는 패턴이 반복됐음, 최근엔 8차 세션의 "emit은 항상 매번 stale해지는 패턴이 반복됐음, 최근엔 8차 세션의 "emit은 항상
전파" 정정으로 `05`도 합류). 실행 결과 상세는 전파" 정정으로 `05`도 합류). 실행 결과 상세는
@ -116,6 +117,27 @@
(`HUMAN_TODO.md` 2번 항목). (`HUMAN_TODO.md` 2번 항목).
6. **[신규 백로그, 2026-08-14 열네 번째 세션]** 문서 stale 감소용 include 6. **[신규 백로그, 2026-08-14 열네 번째 세션]** 문서 stale 감소용 include
도구 `doc-include.py`(가칭, `doc-check.py`와 짝) — `research/ 도구 `doc-include.py`(가칭, `doc-check.py`와 짝) — `research/
doc-include-plan.md` 참고. 플랜만 초안, **사용자가 내일 다듬을 doc-include-plan.md` 참고(상태의 소스는 그 문서). **[2026-08-16 기준]**
예정**. M0/설계 게이트와 무관. 같은 날 CLAUDE.md 분할로 파일럿이 "`session-summary.md`를 통째로
생성"하는 **단방향** 설계로 단순화돼 플랜이 갱신됨(목적지 마커 불필요).
여전히 **구현 착수 전**. M0/설계 게이트와 무관.
7. **[2026-08-16 신설, 대부분 닫힘 — 남은 건 (d) 하나]** 감사 툴링 검증.
(a) `@import` 3개(`conventions.md`/`project-context.md`/`todos.md`)
실제 로드 — **확인됨**, (b) `quad-doc-auditor` 레지스트리 등록 —
**확인됨**(첫 실측 때 전원 `agentType not found`였던 건 `.claude/agents/`
세션 도중 생긴 디렉토리였기 때문, 재시작으로 해소), (c) frontmatter
`model: sonnet` 반영 — **확인됨**(서브에이전트 트랜스크립트에
`claude-sonnet-5` 기록), (d) **미해소** — 읽기 전용인데 Write/Edit이
주어지는 원인. `memory: project`를 뺐지만 그 뒤 재시작 없이 돌린
관찰뿐이라 진단 미확정이고, **다음 세션 시작 직후에 한 번 확인하면 됨**.
결론 날 때까지 읽기 전용은 도구 유무가 아니라 프롬프트의 행동 규약으로
지킨다.
**부수 확정 — 정의 파일은 세션 시작 시점 스냅샷으로 고정된다**(에이전트·
워크플로 정의 모두): `quad-handover-audit`이 실제로 돌린 스크립트가 세션
시작 시점 상태와 바이트 단위로 같았고 같은 세션의 편집은 반영 0이었음.
**정의를 고쳤으면 재시작한 뒤에 감사를 돌릴 것** — 안 그러면 옛 정의로
돌면서 새 정의로 돈 것처럼 보인다. 상세는
`.claude/agents/quad-doc-auditor.md` 상단 배너가 소스. M0/설계 게이트와
무관.

View file

@ -11,17 +11,24 @@
python3 .claude/tools/doc-check.py --quiet # 실패한 검사만 python3 .claude/tools/doc-check.py --quiet # 실패한 검사만
종료코드: 오류(ERROR) 하나라도 있으면 1, 경고만 있으면 0. 종료코드: 오류(ERROR) 하나라도 있으면 1, 경고만 있으면 0.
검사 항목 검사 항목 ([2026-08-16 정정] 1·2번의 심각도를 실제 코드에 맞춰 고침
1. [ERROR] 깨진 파일 참조 라이브 문서가 가리키는 .md/.luau가 실제로 없음 예전엔 [ERROR]라고 적어놨지만 코드는 그렇게 동작한 적이 없음)
2. [ERROR] 깨진 참조 `foo.md` "절 제목" 파일에 없음 1. [ERROR/WARN] 깨진 파일 참조 라이브 문서가 가리키는 .md/.luau가 실제로
(문서를 쪼개거나 헤딩을 고칠 가장 깨지는 아홉 번째 세션에 없음. 파일명이 레포의 명명 관례(`OURS`) 걸리면 ERROR, 아니면
bind-system-plan.md를 분할하며 20곳이 여기 걸렸음) 외부 문서명일 있어 WARN.
2. [WARN] 깨진 참조 `foo.md` "절 제목" 파일에 없음
(문서를 쪼개거나 헤딩을 고칠 가장 걸리는 아홉 번째 세션에
bind-system-plan.md를 분할하며 20곳이 여기 걸렸음. 제목을 의역해
인용하는 관례가 있어 오탐이 섞이므로 ERROR가 아니라 WARN)
3. [ERROR] 색인 누락 base/research/archive/reference 파일이 README에 없음 3. [ERROR] 색인 누락 base/research/archive/reference 파일이 README에 없음
4. [WARN] 날짜 없는 시한부 주장 "아직 안 돌려봄", "열린 질문 없음" 4. [WARN] 날짜 없는 시한부 주장 "아직 안 돌려봄", "열린 질문 없음"
시간이 지나면 거짓이 되는데 언제 기준인지 적힌 문장 시간이 지나면 거짓이 되는데 언제 기준인지 적힌 문장
5. [WARN] 미반영 배너를 파일 vs 반영 목록 일치 여부 5. [WARN] 미반영 배너를 파일 vs 반영 목록 일치 여부
`session/`(원문 보존), `initreq/`(읽기 전용 클론) 검사 대상에서 제외. 검사 대상에서 제외되는 폴더는 `SKIP_DIRS` 소스 `session/`(원문 보존),
`initreq/`(읽기 전용 클론), `worktrees/`, `tools/`( 스크립트 자신이 여기
있으므로 **doc-check.py는 자기 자신을 검사하지 않음**, docstring의 주장은
사람이 손으로 확인해야 ).
`archive/` `.claude/session-summary.md` 검사 대상이되 **히스토리 문서** `archive/` `.claude/session-summary.md` 검사 대상이되 **히스토리 문서**
참조/시한부 주장 검사는 면제(`is_history()` 참고). 참조/시한부 주장 검사는 면제(`is_history()` 참고).
""" """
@ -245,8 +252,11 @@ def main():
check_temporal(docs) check_temporal(docs)
check_banner(docs) check_banner(docs)
# 제외 목록은 SKIP_DIRS 하나만 소스로 두고 여기서 다시 적지 않음
# ([2026-08-16] 예전엔 "session/·initreq/ 제외"라고 하드코딩돼 있어
# worktrees/·tools/가 빠진 채 stale했음)
print(f"검사 대상 라이브 문서 {len(docs)}" print(f"검사 대상 라이브 문서 {len(docs)}"
f"(session/·initreq/ 제외)\n") f"({'·'.join(d + '/' for d in SKIP_DIRS)} 제외)\n")
if errors: if errors:
print(f"■ ERROR {len(errors)}건 — 고쳐야 함") print(f"■ ERROR {len(errors)}건 — 고쳐야 함")
for e in errors: for e in errors:

View file

@ -60,6 +60,10 @@ function fixPrompt(file, items) {
const seen = new Set() const seen = new Set()
const roundLog = [] const roundLog = []
// 실제 발견 내용 자체를 누적한다 — 카운트만 돌려주면 호출한 세션이
// 커밋 전 diff 리뷰(관례상 필수)를 할 때 "이 수정이 왜 들어갔는지"를
// 알 길이 없어서 journal.jsonl을 뒤져야 한다(2026-08-16 지적).
const appliedFindings = []
let dry = 0 let dry = 0
let round = 0 let round = 0
@ -127,6 +131,10 @@ while (dry < DRY_ROUNDS_TO_CONVERGE && round < MAX_ROUNDS) {
label: `fix:${file}`, label: `fix:${file}`,
phase: 'Fix', phase: 'Fix',
agentType: 'general-purpose', agentType: 'general-purpose',
// 토큰 관례(.claude/conventions.md "일반 작업은 sonnet") — 감사
// 패스는 frontmatter로 이미 sonnet, 반영 쪽만 메인 모델(Opus)을
// 상속하고 있어서 맞춤.
model: 'sonnet',
}) })
) )
) )
@ -136,10 +144,12 @@ while (dry < DRY_ROUNDS_TO_CONVERGE && round < MAX_ROUNDS) {
// 사라지고, 안 고쳐진 채로 수렴 판정이 난다(위와 같은 클래스의 버그). // 사라지고, 안 고쳐진 채로 수렴 판정이 난다(위와 같은 클래스의 버그).
const failedFiles = [] const failedFiles = []
fixed.forEach((r, i) => { fixed.forEach((r, i) => {
const [file, items] = fileEntries[i]
if (r === null) { if (r === null) {
const [file, items] = fileEntries[i]
failedFiles.push(file) failedFiles.push(file)
items.forEach((f) => seen.delete(keyOf(f))) items.forEach((f) => seen.delete(keyOf(f)))
} else {
items.forEach((f) => appliedFindings.push({ round, ...f }))
} }
}) })
if (failedFiles.length) { if (failedFiles.length) {
@ -162,6 +172,10 @@ if (!converged) {
return { return {
converged, converged,
rounds: round, rounds: round,
totalFindingsFixed: seen.size, // ⚠️ "반영 에이전트에게 넘긴 발견"의 수이지 "실제로 고쳐진" 수가 아니다
// — "의심"으로 표시된 항목은 반영 에이전트가 확인 후 건드리지 않고
// 넘어갈 수 있다. 실제 반영 여부는 항상 `git diff`로 확인할 것.
findingsSentToFix: appliedFindings.length,
findings: appliedFindings,
roundLog, roundLog,
} }

View file

@ -1,7 +1,9 @@
# CLAUDE.md # CLAUDE.md
Roblox 엔진용 DOMless UI 렌더러 **quad**를 처음부터 다시 짜는 프로젝트. Roblox 엔진용 DOMless UI 렌더러 **quad**를 처음부터 다시 짜는 프로젝트.
지금은 설계/계획 단계이고 구현은 아직 시작 전. **[2026-08-16 기준] 지금은 설계/계획 단계이고 구현은 아직 시작 전** — 같은
상태를 `.claude/project-context.md`도 서술하니 M0에 착수하면 두 곳을 같이
고칠 것.
<!-- [2026-08-16 재구조화] 이 파일은 1537줄까지 불어나 (a) 사람이 검토 불가, <!-- [2026-08-16 재구조화] 이 파일은 1537줄까지 불어나 (a) 사람이 검토 불가,
(b) 공식 권장치(파일당 200줄) 7.7배 초과로 지침 준수도 저하, (c) 에이전트가 (b) 공식 권장치(파일당 200줄) 7.7배 초과로 지침 준수도 저하, (c) 에이전트가
@ -10,7 +12,7 @@ Roblox 엔진용 DOMless UI 렌더러 **quad**를 처음부터 다시 짜는 프
편집 정확도, 그리고 파일 단위 자동생성 가능성을 산다. 편집 정확도, 그리고 파일 단위 자동생성 가능성을 산다.
※ 이 주석은 컨텍스트 주입 전에 제거되므로 사람용 메모만 넣을 것. --> ※ 이 주석은 컨텍스트 주입 전에 제거되므로 사람용 메모만 넣을 것. -->
**이 파일에 내용을 직접 쌓지 말 것** — 39줄짜리 진입점으로 유지한다. 새 **이 파일에 내용을 직접 쌓지 말 것** — 짧은 진입점으로 유지한다. 새
서술은 아래 import된 파일 중 맞는 곳에 넣을 것(어디에도 안 맞으면 그건 서술은 아래 import된 파일 중 맞는 곳에 넣을 것(어디에도 안 맞으면 그건
매 세션 로드될 내용이 아닐 가능성이 높음 — `.claude/` 아래 해당 문서로). 매 세션 로드될 내용이 아닐 가능성이 높음 — `.claude/` 아래 해당 문서로).
@ -31,13 +33,13 @@ Roblox 엔진용 DOMless UI 렌더러 **quad**를 처음부터 다시 짜는 프
| 사용자가 답해야 할 열린 질문 | `.claude/question.md` | | 사용자가 답해야 할 열린 질문 | `.claude/question.md` |
| 구현 순서 / 마일스톤 | 루트 `ROADMAP.md` | | 구현 순서 / 마일스톤 | 루트 `ROADMAP.md` |
| 사람만 할 수 있는 일 | 루트 `HUMAN_TODO.md` | | 사람만 할 수 있는 일 | 루트 `HUMAN_TODO.md` |
| **어떤 결정이 왜 그렇게 됐나 / 전에 뒤집힌 적 있나** | `.claude/session-summary.md`를 grep (세션별 2~4줄 요약 색인, 91개) | | **어떤 결정이 왜 그렇게 됐나 / 전에 뒤집힌 적 있나** | `.claude/session-summary.md`를 grep (세션별 2~4줄 요약 색인) |
| 그 결정의 논쟁 과정 원문 | `.claude/session/YYYY-MM-DD-NN-slug.md` | | 그 결정의 논쟁 과정 원문 | `.claude/session/YYYY-MM-DD-NN-slug.md` |
| 뒤집히거나 기각된 설계의 원문 | `.claude/archive/` | | 뒤집히거나 기각된 설계의 원문 | `.claude/archive/` |
**주의**: `session-summary.md`는 의도적으로 `@import` 안 함 — 1231줄을 매 세션 **주의**: `session-summary.md`는 의도적으로 `@import` 안 함 — 계속 자라는
컨텍스트에 올릴 이유가 없다고 판단(그 문서 스스로 "항상 읽을 필요 없음, 지금 히스토리 문서라 통째로 올릴 이유가 없음(그 문서 스스로 "항상 읽을 필요 없음,
유효한 설계는 `base/`가 소스"라고 명시). 선행 맥락이 필요해지면 그때 가서 열 것. 지금 유효한 설계는 `base/`가 소스"라고 명시). 필요해지면 그때 가서 열 것.
**충돌 시 우선순위**: `.claude/base/` > 여기 요약이나 `session-summary.md`. **충돌 시 우선순위**: `.claude/base/` > 여기 요약이나 `session-summary.md`.
후자들은 과거 시점 서술이라 더 최근 결정이 안 반영돼 있을 수 있음. 후자들은 과거 시점 서술이라 더 최근 결정이 안 반영돼 있을 수 있음.