`question.md`에 열려 있던 마지막 항목(마일스톤 경계)을 사용자가 **(a) 순서 교체**로 닫았다 — 이제 **M2 = 반응형 코어(Source/State/Store), M3 = 디스패치 엔진**이다. 결정과 기각된 선택지는 `archive/question-resolved.md`의 "마일스톤 경계" 절, 경위와 시행착오는 `session/2026-08-24-02-milestone-order-swap.md`. ## 왜 (a)인가 의존이 양방향처럼 보였지만 실제로는 한 방향이었다 — 디스패치→반응형은 *본체* 의존(`setLength`가 `State<number>`를, `setOffsetSource`가 `Source<number>`를 받고 `recompute`가 `offset:Set()`을 부름)이라 우회 불가고, 반대는 *등록 표면* 의존(핸들러 셋)이라 미루면 그만이다. 옛 순서로는 디스패치 마일스톤의 `mock 대상 테스트` 체크박스조차 State 없이 불가능했고, 반응형 코어는 순수 Lua라 `luau`만으로 단독 테스트가 된다. (b) 분할은 기존 `M2` 참조 전부를 "M2a인가 M2b인가"로 만들어 오히려 비싸고, (c) 유지는 "순서의 소스는 `ROADMAP.md`"라는 원칙을 스스로 무효화한다. ## 그냥 맞바꾸기로는 안 끝났다 - **`Brand`/`Relate`/`LifetimeHandle`(인터페이스)이 M2 앞머리 `### 공통 기반` 절로** — 반응형이 이 셋을 먼저 요구한다(`Source`가 `SourceBrand`+`EpochBrand`에 등록되고, State 전파 루프가 매 발화마다 `canExecute`를 부르며, 그 판정이 `Relate` 위에 얹힌다). 셋 다 State-free 이자 dispatch-free라 어느 쪽에도 안 걸린다. - **2026-08-22에 디스패치로 앞당겼던 `EpochMap`/`GateNode`/`Blocker`가 M2로 복귀** — 앞당길 이유 자체가 순서 교체로 사라졌다. "게이팅 먼저"는 그대로 지켜진다(게이팅이 디스패치보다 먼저 지어진다). - **Observer/Effect 동적 경로 가드 등록과 `ObserverEffectLeafHandler`는 M3로** — 둘 다 "핸들러를 등록한다"뿐이라 본체와 잘라내기 쉽다. 이것이 M2가 M3에 개념상 지던 유일한 의존이고, 미뤘으므로 빌드 순서엔 역방향 간선이 없다. - **`EpochMap`이 State 본체보다 앞으로**(감사 5라운드 발견) — State가 `valueEpochMap`/`emitEpochMap` 둘을 컴포지션하므로 옛 배치로는 `State.luau`를 못 짠다. 문서 자신이 *"아래 `Source.luau`/`State.luau`가 이걸 전제로"*라 쓰면서 그 둘이 위에 있는 형태로 증거를 남기고 있었다. ## 대가 하나 — 게이트 둘이 "바로 다음"으로 올라왔다 `question.md` 낮은 우선순위에 있던 **중간 State GC 미검증**과 **`store:GetDynamic` 위치**가 원래 반응형(옛 M3)의 게이트였는데, 반응형이 M2가 되면서 착수 직전 항목이 됐다 — 최우선 절로 승격했다. 순수 *설계* 결정 대기는 여전히 0건이다(하나는 실측 미완, 하나는 표면 위치 선택). ## 번호 재부여의 경계 라이브 문서의 `M2`/`M3` 참조 248건은 전량 새 번호로 맞췄다(코퍼스의 참조가 거의 전부 "그 내용이 사는 마일스톤"을 가리켜 기계적 맞교환으로 의미가 보존됨). **`session/`·`archive/`·`qa-request/`는 히스토리라 소급 수정하지 않았다** — 그 문서들의 `M2`/`M3`는 옛 의미(M2=디스패치, M3=반응형)이고, 이 경고를 인덱스 다섯 곳에 박아뒀다. 일괄 치환에 `\bM([23])\b`를 썼다가 Python `\w`가 유니코드라 한글이 붙은 93건(`M2는`/`M2로`)이 안 바뀌는 실수를 냈고, `git show HEAD:<경로>`로 되돌린 뒤 ASCII 경계 lookaround로 재실행했다. 그 부수로 `Relate`/ `LifetimeHandle` 참조들은 구 M2 → 신 M2로 두 번 옮겨져 **번호가 우연히 보존**됐다는 것도 드러났다(치환하면 안 되는 자리 — 감사가 잡아 되돌렸다). ## 검증 `quad-doc-auditor` 루프가 라운드마다 각도를 바꿔 **7라운드에서 새 발견 0건으로 수렴**(10→8→1→1→2→2→0). 가장 값이 큰 건 5라운드(구현 순서 시뮬레이션)로, 위 `EpochMap` 배치 오류를 잡았고 **순서 교체의 전제 자체도 검증**했다(새 M2 전체를 디스패치 심볼로 훑어 "가드 등록 둘 말고는 없음"). **수렴 뒤 사용자가 돌린 `/code-review high`가 5건을 더 잡았고 전부 유효** — 넷이 *"라벨은 치환됐는데 그 라벨을 설명하던 산문이 안 고쳐진"* 종류였고, 그중 하나는 `research/` 안의 **히스토리 블록**이 치환을 맞아 원래 논거가 문장 그대로 거짓이 된 것이었다(소급 수정 제외 대상을 세 폴더로만 잡은 게 샜다). `conventions.md`의 *"`/code-review`는 감사자를 대체하지 않는다"*가 또 재확인됐다. `doc-check.py` ERROR 0. Co-authored-by: qwreey <me@qwreey.moe> Claude-Session: https://claude.ai/code/session_01Jjrec9xAS7TZstMx5gi3cm
8.8 KiB
프로젝트 컨텍스트
루트 CLAUDE.md가 @import 하는 파일. 폴더별 상세 색인은
.claude/README.md가 소스 — 여기선 중복 서술하지 말고 가리키기만 할 것.
이 프로젝트가 뭔지
Roblox 엔진에서 동작하는 DOMless UI 렌더러 quad를 처음부터 다시 짜는 프로젝트. 목표는 개별 프로덕트가 아니라 라이브러리로서의 코드 퀄리티와 지속 가능성 — 빠른 이터레이션보다 정확성/설계 정합성이 우선. 작업 기간은 길게 잡음.
[2026-08-24 기준] M0(스파이크 검증)/M1(스캐폴딩) 완료, 다음은 M2(반응형
코어 — Source/State/Store)(마일스톤이 넘어갈 때 루트 CLAUDE.md 머리말도
같이 고칠 것 — 같은 상태를 두 곳이 서술하고 있음). ⚠️ [2026-08-24] M2와
M3의 번호·순서가 맞바뀌었다 — 열려 있던 마일스톤 순서 문제가 (a) 순서
교체로 닫힌 결과다(경위는 archive/question-resolved.md의 "마일스톤 경계"
절, 새 구성은 ROADMAP.md의 M2 배너). 2026-08-24 이전에 쓰인
session/·archive/·qa-request/의 M2/M3는 옛 의미(M2=디스패치,
M3=반응형)다. 그 교체의 부작용으로 M2 착수 전에 답이 필요한 항목이
question.md 최우선 절로 올라왔다(무엇이 몇 개인지는 그 절이 소스 —
여기서 세지 않는다. 설계 게이트가 아니라 실측·표면 선택이라, 설계 게이트가
없다는 아래와 todos.md의 서술과 모순되지 않음). 저장소 루트에
quad-base/src/(New()/RunInit/AddPlugin/Relate/Debug)/
quad-types/src//type-version-check/src/가 실제로 존재(quad-roblox/src는
아직 빈 폴더 — M5에서 채워짐), 자세한 진행 상황은 루트 ROADMAP.md가
소스. 핵심 아키텍처(Store 책임 분리, process/retract
디스패치 모델, Store/State/Source 온톨로지, 소스 트리 구조, Modifier 메커니즘,
컴포넌트=플레인 함수, 컴포넌트 경계 modifier/Ref 전달)는 전부 .claude/base/에
문서로 확정돼 있음 — 먼저 .claude/base/architecture.md를 읽을 것. 사용자가
직접 "지금 quad에서 가장 문제되는 부분"으로 지목했던 컴포넌트화(특히
modifier/Ref의 컴포넌트 경계 통과 방식) 논의도 2026-08-04 세션에서 수렴
완료(base/component-composition-plan.md) — 남은 핵심 설계 질문은 없고,
용어 정리(진행 중)와 실제 스캐폴딩만 남음, .claude/todos.md 참고.
이전에 시도했다 폐기한 v2 재작성 시도(.claude/initreq/quad2-try)도 리서치
완료 — OOP 상속/커스텀 파서/Slot 스텁/Pipe copy-on-write 절충안은 확인된
죽은 접근이라 반복 조사 금지(base/bind-system-plan.md "확정된 것" 절 참고).
계획 문서 구조
.claude/README.md가 색인. 요약:
- [2026-08-16] 루트
CLAUDE.md는 짧은 진입점일 뿐이고, 실제 내용은.claude/conventions.md(관례·작업 방식) / 이 문서 /.claude/todos.md(지금 할 일)로 쪼개져@import로 다시 합쳐짐..claude/session-summary.md(세션 요약 색인)만 import 안 됨 — 필요할 때 직접 열 것. .claude/base/— 확정된 아키텍처/컨텍스트, plan/done 개념 없음. 먼저.claude/base/architecture.md를 읽을 것..claude/reference/— [2026-08-07 신설] base처럼 확정된 건 아니지만 base 문서가 근거로 인용하는 온디맨드 참고 자료(v1 내부 동작 스냅샷, Fusion/Vide 비교 리서치) — 항상 읽을 필요는 없고 인용될 때만 열어볼 것. [2026-08-21 확장] 확정된 결정의 근거 기록(그 결정이 왜 그렇게 났는지)도 여기 둠 —research/를 떠났지만archive/대상은 아닌 것들. 어떤 문서가 있는지는.claude/README.md가 소스..claude/research/— 아직 착수 전, 사용자와 상의 필요한 설계 논의. 전부 후순위. 어떤 문서가 있는지·우선순위가 뭔지는 여기서 세지도 나열하지도 않고.claude/README.md의research/표로 미룸(개수뿐 아니라 파일명 나열 자체가 새 문서가 추가될 때마다 stale해지는 패턴이 실제로 반복됐음 — 과거엔 "두 개뿐"이라 적어놨다가, 2026-08-16엔 7개짜리 나열이 실제 11개와 어긋난 걸 감사가 발견. 아래 luau-test/audit 문단과 같은 처리로 통일).research/를 떠난 것만 짚으면:tween-plan.md는 2026-08-12 세션에 마지막 열린 항목까지 전부 해소돼base/로 승격, 이미 생성된 인스턴스 재바인드는 2026-08-14 세션에 기각돼archive/existing-instance-bind-rejected.md로 이전 — 둘 다 더 이상 여기 없음..claude/luau-test/— [2026-08-09 신설] "추론만으로 확정하고 실제 Luau로 부딪혀본 적 없는 것"을 미리 검증하는 독립 실행 스파이크 모음 (luau <파일>/luau-analyze <파일>). 상태의 소스는 항상STATUS.md(pass / 사람 결정 필요 / 스파이크 깨짐 / 미실행, 폴더 구조 자체가 상태), 각 파일이 뭘 왜 검증하는지는README.md. 2026-08-13에 첫 실측 완료(당시 런타임 12개 전원 통과) — 이후 여러 세션에 걸쳐 재설계로 몇 건이 추가로rewrite-required/에 합류했으니 총 몇 개인지도, 지금 몇 개가 어디 있는지도 여기서 세지 않고STATUS.md로 미룸(세거나 나열하다 stale해지는 패턴이 실제로 반복됐음,.claude/todos.md의 luau-test 스파이크 항목 참고)..claude/audit/— [2026-08-13 신설] 스파이크를 실제로 돌린 실측 결과 기록(계획 아님). 부분 확인도 있는 그대로 남김 — 지금 몇 개가 있는지·각각 뭘 확인했는지는 여기서 나열 안 하고.claude/README.md의audit/행으로 미룸(luau-test와 같은 이유 — 나열하다 새 폴더가 추가될 때마다 stale해지는 패턴이 실제로 반복됐음, 가장 최근엔 2026-08-15에 이 목록이 3개에서 멈춰 있는 걸/code-review가 발견).type-recursion-issue/만 참고로 짚으면: [13차 세션] 0-Y 재실측 전체 —REPORT.md+spikes/(개수는 폴더가 소스), 스크립트를 같이 두는 예외적 구성(판정이 "여러 formulation 대조"라 개별 파일을 직접 돌려야 재현됨), 결론은base/typing-limits.md로 승격 — 이후 신설된 폴더들도 같은 구성 관례를 따름(type-recursive-issue-with-typeof/,type-recursive-issue-try-callback/등)..claude/qa-request/— 원래는 "구현이 끝나고 사용자 실기기 QA만 남은 것"을 담는 폴더였으나, [2026-08-18] 구현 전 사용자 심사 라운드의 산출물도 여기 둠(pre-implementation-qa-round1.md/pre-implementation-qa-round2.md/pre-implementation-qa-round3.md전부 완료 — 라운드마다 새 파일, 상태의 소스는 각 파일 자신)..claude/feedback/— 실사용 피드백용(M0/M1 스캐폴딩이 아니라 실제로 렌더링해보고 쓰는 단계부터), [2026-08-19 기준] 폴더 자체가 아직 없음 — 첫 피드백이 생길 때 만들면 됨..claude/archive/는 원래 같은 취급이었으나 2026-08-06 세 번째 세션부터 완전히 뒤집힌 설계 결정을 원문+역전 이유+diff와 함께 보존하는 용도로도 사용 시작(구현 완료 대상만이 아님) —archive/store-source-proxy-reversed.md가 첫 사례, 나중quadnomicon콘텐츠 소재로 재사용 예정..claude/session/— [2026-08-11 신설] 세션별 상세 로그 원문(시행착오· 정정 전 서술 포함,quadnomicon개발로그 소재용) — 루트CLAUDE.md가 3000줄 넘게 불어나 성능 저하를 유발해서 분리함..claude/session-summary.md의 각 항목이 여기로 링크. 항상 읽을 필요 없음 — 특정 결정의 논의 과정/시행착오가 궁금할 때만 열어볼 것, 지금 유효한 설계는 항상base/가 소스..claude/initreq/— 클론해둔 참고 레포(quad v1, Fusion, Vide, rbvm, tbox, code-docker) + PA님 실 코드(artworks/) + 원본 요청. 읽기 전용,.gitignore로 커밋 제외됨 — 내용을 다른 곳으로 옮기지 말고 항상 원본 그대로 둘 것. 리서치가 더 필요하면 이 폴더를 다시 파고들 것..claude/question.md— 사용자가 답해야 할 질문 전체 취합(우선순위순).- 루트
ROADMAP.md— 설계 단계 종료 후 실제 구현 순서(M0, M1, ... 마일스톤 + todo 체크박스). "무엇을 확정했는가"는.claude/base/가 소스, "어떤 순서로 만드는가"는 이 문서가 소스 — 헷갈리지 말 것. - 루트
HUMAN_TODO.md— 사람만 할 수 있는 일(로컬 GUI 조작, 스케줄/루프 설정 등).