- H-158 state:Block → state:Apply(blocker), Blocker:__apply 메소드형(호출 규약 명시) - H-159 사용자 제안 _rerunRequired 홀드: fire=Update→Rerun, rawRerun이 실행 불가 상태의 요청을 홀드, _installed 폐기, Observer 대칭(전파 루프 else + bind/subscribe 1회 발화, 생성자 순서 fn→_subs) - H-160 홀드로 정정 + "error 나면 그 Effect는 죽는다" 계약 / H-161 Claim M5 스코프 / H-162 Void.luau 잎 모듈 - 감사 7→6→1→0, /code-review high 10건 중 8 반영, 둘(H-163 Slot 내부 Observer×홀드, H-164 emitFrom nil)은 문항으로 Co-authored-by: qwreey <me@qwreey.moe> Claude-Session: https://claude.ai/code/session_01546hjsYNLSMZdHdPyTZaGb
41 KiB
지금 할 일 (우선순위순)
루트 CLAUDE.md가 @import 하는 파일. 가장 자주 바뀜 — 해소된 항목은
미루지 말고 그 자리에서 지우고, 개수·목록은 여기 적지 말고 소스를 가리킬 것
(.claude/question.md, luau-test/STATUS.md 등).
- ⭐⭐⭐ [2026-08-26] 8라운드까지 전부 처리 완료 — M2 착수 게이트가 0이다.
8라운드(
qa-request/pre-implementation-handtrace-round8.md, 7라운드 반영분을 서로 겹쳐 재트레이싱 + 실측, 3개 패스, 발견 17건H-107Q10을 사용자와 대화형으로 처리해H-123)의 결정 문항 Q1base/에 전량 반영했다. 결정의 소스는qa-request/pre-implementation-handtrace-round8-followup.md(개수·개별 항목은 여기서 세지 않는다).question.md최우선 절은 비어 있다.
- 역전 없음 — 7라운드 확정 중 뒤집힌 건 하나도 없고, 고친 건 전부
7라운드가
base/에 내려앉을 때 생긴 누락·충돌이다(하루 차로 확정된 결정들이 서로를 못 본 자리). - 계약이 바뀐 것 넷:
Ref콜백이fn(value, ref)(2번째가 곧 출처Epoch) / Observerfn이 세 자리fn(targetState, self, emitFrom)+observer._state강참조 /WeakSubscribe도.Subscribed = true를 세움 / 예약 키 진단 타입 함수가T가 아니라 **keyof<T>**를 받음(이름도CheckReserved→CheckReservedKeys;T를 통째로 넘기는 배선은 실사용T에서 아예 안 돈다 — 실측). - ⭐ 사용자가 전제를 정정한 것 둘: (1)
Ref콜백과 Observer 콜백은 이질적 개념이라 애초에 통합 대상이 아니다("observer 에는 epoch 란게 존재하지 않음 … ref 는 그 자체로 epoch임") →Effect는 dep 종류별로 클로저 둘. (2)H-118은 소유권 문제가 아니라gate-plan5번의 문장이 틀린 것(🟡→🟢 강등). - M3 쪽 둘: splice 무효화가
j→j - 1(커서 위치 splice가 "변경 없음"과 구분이 안 됐다), 명시recompute호출도 재진입 게이트를 탄다(Add는 안전한데Remove가 깨져 있었다). - 새로 생긴 구현 항목: Store 생성자의
defaultsisSource화이트리스트 검증(errorlevel 2),isModifier가드를Source생성자로 이동. - 문서화 대상 등록: quad 두 벌 공존 시
Brand/None/Subscribed가 사본마다 분리된다는 사실(research/documentation-content-map.md§4). - ⭐ [2026-08-27] 9라운드를 돌렸고 Q1~Q10·
H-138·H-139·H-142전량 확정·반영했다. 발견은qa-request/pre-implementation-handtrace-round9.md(H-124Q8·Q10(H-141, 🔴 둘 다 실측 재현), 결정의 소스는-round9-followup.md(진행 표가 상태의 소스). 반영된 셋:recompute되감기 판정을lengthList[i]읽기 앞으로 /Offset·_baseObserver를 Slot 생성자로 +materializeSlotTree순서 +_destroyed/element → index를bk.indexOfElement하나로(사용자가 정한 적 없는token폐기). 같은 날 후속으로 Q4EffectHandle네 진입점 의사코드 / M2에Ref최소형 /WeakUnsubscribe관대 / 폐기 블록archive//InstanceChildHandler부기 /reconcile배치 Blocker)과H-138(숏핸드 우선순위)·H-139(New/drive파이프라인 의사코드 — 거기서H-142Parent순서 발견 → props에Parent금지로 확정)까지 반영. Q9는 문항 전제가 틀린 것(Tween 절 스케치 한 줄 복사 오류)으로 닫힘. [2026-08-27 기준] 감사 8라운드·/code-review high까지 돌렸다 — 리뷰 10건 중 여섯은 반영, 넷(H-143H-146, 새 메커니즘)은session/2026-08-27-03-handtrace-round9-h143-h146.md에서 사용자 결정으로 전부 권고 (a) 확정·반영(Rerun꼬리 즉시 소진 / 재구독 꼬리(진입점은EffectHandle자기 것) /bk.indexOfElementweak-key / 루트 부착은 금지 범위 밖). [2026-08-28] 그 반영분에/code-review high가 또 셋(H-147H-149)을 냈고, 사용자 판단으로 10라운드 문항지(qa-request/pre-implementation-handtrace-round10.md)로 올려 신선한 탐사자의 광범위 탐사(지시서-round10-brief.md, 발견H-150H-157) 와 함께 같은 날 대화형으로 전량 결정·반영(소스-round10-followup.md). 어제 결정 중 뒤집힌 것 셋:fn/cleanup은 자기 구독을 못 바꾼다(H-147,H-143소멸) / 재구독·재바인드의Refresh캐치업 폐기(H-151) / 루트는 밖에서.Parent =가 아니라 quad가Claim으로 소유(H-148,research/existing-mount-plan.md). 같은 날 후속H-158H-162(:Block폐기 →state:Apply(blocker)/_rerunRequired홀드 플래그가_installed를 흡수 /ClaimM5 스코프 /Voidexport)도 확정·반영. 남은 미결은question.md최우선 절의Claim갈래(특히 §5-7 다중 스크립트) 하나 — 게이트 아님. 남은 액션: M2 착수. 아래는 돌리기 전(2026-08-26) 서술: 지시서는qa-request/pre-implementation-handtrace-round9-brief.md. 스코프는 커밋9dd8213하나의 델타다 — 8라운드 결정 반영과 그 뒤/code-review high7패스의 수정이 전부 그 커밋에 들어 있고 아무도 트레이싱한 적이 없다(7차 수정분은 리뷰조차 안 됐다). 근거: 그 7패스의 HIGH 추이가1→1→0→1→0→3→0이라 직전 패스가 조용한 것이 수렴의 증거가 아님이 같은 세션에 반증됐다(5차 HIGH 0 → 6차 HIGH 3, 전부 5차 수정이 만든 것). 반대로 전수 재트레이싱은 수율이 낮다는 것도 실측됐다 — 8라운드 3차 패스가base/를 완독하고 🔴 0건이었다. M2 착수 게이트는 아니다(위 머리말대로 게이트는 0). 돌릴지 말지는 비용 판단이고, 돌린다면 그게 마지막 종이 라운드여야 한다는 게 이 지시서의 전제다 — 이후로는 M2 구현 자체가 더 나은 감사 도구다. 아래는 8라운드 이전(2026-08-25) 시점 서술:
[2026-08-25] 7라운드까지 전부 처리 완료 — 당시 question.md 최우선
절이 비었고 M2 착수 게이트가 0이었다. 7라운드(손 트레이싱, 6패스,
발견 52건 H-55~H-106)와 그 검증 패스를 사용자와 대화형으로 처리해
base/에 전량 반영했다. 결정의 소스는
qa-request/pre-implementation-handtrace-round7-followup.md(발견 원문은
qa-request/pre-implementation-handtrace-round7.md, 판정은
qa-request/pre-implementation-handtrace-round7-verification.md — 개수·개별 항목은 여기서
세지 않는다).
- 구조가 바뀐 것: Store — 명시적 초기화(옛 eager/lazy 이중 모델
폐기,
defaults가 곧 선언 키 집합) +WrapStore/ProcessStoreType폐기(타입 함수를 안 쓰고 타입 인자에Source<T>를 직접) + 동적 키를store:Of<<T>>(name)하나로(옛GetDynamic흡수),Ref가Epoch로 승격,Weak*등록 표면 신설(Ref:WeakCallback/Observer:WeakSubscribe),Effect의 강한 dep 맵 +Blocker억제, 전파 루프 의사코드 확정,rawInvalid→ 캐시 카운터 쌍,recompute재진입 차단 + 되감기,emit(commit) -> boolean,EpochMap:Peek,_hold불변식. - ⚠️ 같은 날 한 번 크게 되돌렸다: 오전에 "
store.key가 값,store:Of(k)가 프리미티브,index<>/keyof<>+ 팬텀 필드,store.key = v부활"이라는 Store 재설계를 넣었다가 같은 날 철회했다 — 살아남은 것은 명시적 초기화 하나다. 철회 이유와 원문은archive/store-value-field-redesign-withdrawn.md, 거기서 나온 원칙 ("타입 함수는 진단까지만")이base/typing-limits.md§0으로 승격됐다. - 역전 없음 —
store.key = value폐기(2026-08-06)는 유지된다. - 툴체인 하나:
luauCLI가 심볼릭 링크를 못 탄다는 게 밝혀져scripts/relink.sh+scripts/test.sh신설 — 그 전엔 스모크 2개가 안 돌고luau-analyze가 거짓 클린을 줬다. - 새 error 계약:
level이분(사용자 입력 2 / 내부 불변식 1), 메시지는 영어, 예외는pcall로 안 감싼다 (base/architecture.md의 두 신설 절).
[2026-08-21] 1~5라운드 전부 base/
반영 완료. ⭐ 같은 날 마지막에 Gate와 State 에포크까지 확정되면서
M2 착수를 막는 설계 항목은 더 이상 없다. Gate는
state:Gate(setup) + GateNode로(base/gate-plan.md), State의
재계산/전파 판정은 Epoch 리비전 비교 채택으로(base/state-epoch-plan.md
— [2026-08-24 재정정] 둘 다 M2다: 2026-08-22엔 EpochMap/Epoch
인터페이스만 디스패치 쪽으로 앞당겨 갈라져 있었으나, 마일스톤 순서
교체로 되돌아와 State 본체와 같은 마일스톤이 됐다) 닫혔다. 두 문서 모두 research/가 아니라 **base/**에 있다.
[2026-08-21 후속] Epoch/EpochMap/Brand 승격도 같은 날 완료 —
부기가 재사용 가능한 EpochMap으로 떨어져 나오고, 판정 인터페이스가
Source에서 Epoch로 일반화되고, Brand가 인스턴스 브랜드로 재작성됐다
(근거 기록은 reference/epoch-brand-composition.md, 옛 Brand 표면은
archive/brand-shared-registry-reversed.md). 그 부수로 effect-plan.md의
다중 의존성 중복 발화 미해결 항목도 닫혔다. [같은 날] 마지막 미정이던
리비전 증가 방식도 bit32 랩으로 확정 — Epoch/EpochMap/Brand에
열린 설계 항목은 하나도 없다(base/state-epoch-plan.md §2).
[2026-08-21 경위] 같은 날 /code-review high가 "게이트가 유보했다
내보내는 emit이 어느 출처를 싣는지"가 안 정해진 걸 잡아 한때 M3 항목으로
되돌아갔으나, 사용자가 그 자리에서 흡수 집합 스냅샷으로
확정했다(setup 시그니처는 안 바뀜 — base/gate-plan.md 4번.
[2026-08-22 표기 정정] 여기 emit(self) + 흡수 집합이라 적혀
있었으나 그건 Epoch 일반화 이전 표기다 — 게이트 노드 자신은
페이로드에 안 싣는다). 같이
제기됐던 에포크 쪽 세 자리도 전량 확정됐다(재계산 시 리비전 전부 갱신 /
새 노드는 emitEpochMap은 비우고 valueEpochMap은 실제 리비전으로 채운 뒤
rawInvalid = true / 그래서 :With 병합 규칙은 불필요) —
base/state-epoch-plan.md §4. [같은 날 두 번째 /code-review high]
7건이 더 나왔고 전부 유효했는데(재진입 시 빈 배치가 새어 변경이 증발하던
것, OffWithoutEmit이 흡수 집합을 안 비우던 것 등), 그중 사용자 판단으로
올라갔던 둘도 같은 날 닫혔다 — "재진입 계약"은 애초에 잘못 옮긴
서술이었고, "빈 배치 emit"은 아무것도 안 하는 것으로 확정(그 따름정리로
Effect의 설치 구간 억제가 Gate 소비자에서 빠지며 effect-plan.md의
순서 제약도 사라짐). 다시, M2 착수를 막는 설계 항목은 없다.
✅ [2026-08-24 해소] 설계가 아니라 순서가 막던 것도 닫혔다.
2026-08-22 ROADMAP.md 전반 점검에서 옛 M2(디스패치)와 옛 M3(반응형)의
의존이 양방향인 게 드러났었는데, 사용자가 (a) 순서 교체를 선택해
같은 날 전량 반영됐다 — 이제 M2가 반응형 코어, M3가 디스패치 엔진
이고 역방향 의존이 없다. 결정·근거·기각된 선택지는
archive/question-resolved.md의 "마일스톤 경계" 절이 소스, 새 마일스톤
구성은 ROADMAP.md의 M2 배너 — 여기서 반복하지 않는다. 부수로
Brand/Relate/LifetimeHandle 인터페이스가 M2 앞머리 "공통 기반"
절로 왔고, 2026-08-22에 디스패치로 앞당겼던
EpochMap/GateNode/Blocker는 M2로 되돌아왔으며, Observer/Effect
동적 경로 가드 등록과 ObserverEffectLeafHandler는 M3로 갔다.
⚠️ 2026-08-24 이전에 쓰인 session/·archive/·qa-request/의
M2/M3는 옛 의미(M2=디스패치, M3=반응형)로 읽을 것.
같은 2026-08-22 점검에서 Dispatch.drive가 두 패스가 아니라 단일 일반화
for라는 F-4-1 정정과 물리 조작 주입 op 이름 native* 확정도
ROADMAP.md/dispatch-core-plan.md에 반영됐고, M0 체크박스가 검증했던
스파이크 중 재작성 대기인 것들도 ROADMAP.md의 "재검증 대기" 절로
모았다(현황의 소스는 여전히 luau-test/STATUS.md).
그 외 남은 것은 판단이 아니라 구현 시 정할 것 하나 — 스파이크 05
재작성(luau-test/STATUS.md).
[2026-08-24 해소, 6라운드 H-49] 여기 Gate의 "생명주기·재진입 계약"을
같이 나열했었는데 두 항목 다 부정확했다 — 재진입은 이미
[2026-08-21 정리 — 열린 항목 아님]으로 닫혀 있었고, 생명주기는 "판단이
아니라 구현 시 정할 것"이 아니라 그 항목이 사는 절 제목이 정확히
"사용자 판단 필요"였다. 그 안의 *"Gate 자체에 Flush/Cancel 같은
표면을 둘지"*가 H-33이 걸린 바로 그 자리였고, 2026-08-24에
blocker:Policy(emit) 노출 + Debounce/Throttle이 자기 Blocker를
조종하는 구조로 확정되며 닫혔다(base/gate-plan.md 5번).
⭐⭐ 6라운드(손 트레이싱) — [2026-08-24] 회신·반영 완료.
4개 패스에 걸친 발견 보고(H-1~H-54)를 사용자와 대화형으로 하나씩
처리하고 base/에 전량 반영했다. 발견 원문은
qa-request/pre-implementation-handtrace-round6.md, 결정과 근거는
-followup.md가 소스(개수·심각도·개별 항목은 여기서 세지 않는다).
M2/M3에 직접 걸리던 것들이 전부 닫혔다 — 말단 핸들러 4종의
setLength/setOffsetSource 미등록(H-39), New(): Quad가 닫힌 타입이라
quad.Dispatch가 타입에러인 것(H-25, M3 체크리스트에 항목 신설),
Effect의 leaf 사망 cleanup 배선 부재(H-11), :List의 인덱스/좌표계
결함 둘(H-1/H-2).
구조가 바뀐 것 넷 — (1) slot._elemIndex(물리 요소 → 인덱스; [2026-08-27] 9라운드 Q3로 bk.indexOfElement에 통합됨) 신설로
:List의 keyIndex가 단순 키 집합으로 강등, (2) _mounted가 "물리
인스턴스 유무"만 뜻하게 좁혀지고 slot._physicalTarget이 신설되어 부기는
실체화 시점부터 항상 수행, (3) Ref.Callbacks가 해시맵 셋 + 해제 경로
(:Uncallback), (4) blocker:Policy(emit) 노출로 Debounce/Throttle이
자기 Blocker를 조종하는 정책이 됨. 요소 타입 검증도 블랙리스트에서
isInst 주입 술어 기반 화이트리스트로 뒤집혔다(H-40).
백로그로 넘긴 것 하나 — Fallback/Traceback 중 생성된 부분 트리의
회수(H-26, base/fallback-plan.md의 ⚠️ 절). 그 둘이 슈가라 구현 시점에
같이 다룬다.
4라운드 — [2026-08-21] 종결. 문항지는
.claude/qa-request/pre-implementation-qa-round4.md, 사용자 회신 원문은
-response.md, 처리 결과 전량은 -followup.md가 소스(여기서 목록을
세지 않음 — 마지막 H절이 최신). 4차 처리로 F-3이 전량 확인되며
Detach 보존 주체(userdata → slot._detached), KeyGone 센티널,
Owned 설치 플래그, 그리고 attachSlot 분해
(materializeSlotTree + mountSlotTree, 근거는
reference/slot-attach-decomposition.md)가 전부 확정·반영됐다.
[2026-08-21 정정] 5라운드 문항지를 만들었다 — 4라운드 처리 때는 사용자
지시("이후 stale 만 잡는것으로 끝낼 수 있어보임")로 안 만들기로 했으나, 같은
날 사용자가 5라운드를 요청("4차에서 예로 넘어갔던건 스킵하고, 새로운
부분들이나 다른 깊은 부분")해 qa-request/pre-implementation-qa-round5.md를
신설했다(회신 대기). 범위는 셋 — (1) 4라운드에 문항이 아예 없던 영역
(base/project-setup-plan.md/base/quad-types-plan.md, 그리고 문서가 아니라
실제 커밋된 M1 코드), (2) 4라운드 회신 이후 새로 확정된 것
(Detach/_detached/KeyGone/Owned/attachSlot 분해), (3) 큰 문서의 심화.
문항 수와 분포는 그 문서 자신이 소스.
[2026-08-21 후속] 5라운드 회신 도착·처리 완료(라운드 수는 여기서 안 셈) — 회신 원문은
-round5-response.md, 처리 결과의 소스는 -round5-followup.md.
즉시 반영된 것은 slot._detached lazy화, KeyGone에 새 값 반환도 error,
Owned = false에서 Detach는 _detached에 안 들어감, 조상 파괴 시
unowned 요소도 같이 죽는다는 계약 신설, groupClaimKeys 키 확정
((inst, groupValue) → k), Tween<T>:Mapped 이름 확정, 4라운드가 반영을
빠뜨렸던 E-10 dedup 대칭 결론 실반영, 그리고 "게이팅 먼저"(당시엔 디스패치 마일스톤으로 앞당기는 형태였으나 [2026-08-24] 순서 교체로 반응형이 먼저가 되며 그 앞당김은 불필요해짐).
아직 회신 대기인 것은 그 followup의 C절(rawAdd 의사코드 승인,
rawAdd의 Length:Set 제거, updateFn이 State를 반환할 때의 래핑/prev,
setLength 앵커를 물리 target으로 되돌리기, Gate 이름·표면, Effect
다중 의존성) — [2026-08-21 전량 처리 완료], 소스는 그 파일의 마지막
절(A~L). 대화 마지막 라운드에서 native* 물리 조작 계층이 확정되며
4라운드 C-7("부기가 물리보다 먼저")이 역전됐다. Gate 설계는 한때
다음 세션으로 미뤄졌으나("고칠것이 많으므로 Gate 는 다음 세션에
다루겠음") [2026-08-21 같은 날 확정] 사용자가 이어서 표면을 정해
base/gate-plan.md가 research/를 떠났다 — 위 00번 머리말이 소스.
아래는 4라운드 회신 전 서술:
(원 서술) 4라운드 문항지 작성 경위. 사용자 요청("모든 확정 부분에 있어서 예가 되어야하는 질문들을
계속 … 표면적 타입계약부터, 실제 내부 구현 계획과 동작 원리 등")으로
base/ 전 문서를 한 맥락에서 읽으며 확정 주장을 전수 문항화한 것.
아직 아무것도 정정하지 않았음 — 사용자가 "아니오"인 항목을 회신하면
그때 base/에 반영하고 그 문서를 1라운드처럼 근거 기록으로 재편한다.
문항 수/분포/읽는 순서는 그 문서 자신이 소스(여기서 세지 않음).
1~3라운드(완료): 1라운드는 사용자가 base/ 확정 문서 전체를
문항으로 재심사한 결과(원본 문답과 사용자 답변 원문은
.claude/qa-request/pre-implementation-qa-round1.md가 소스), 확정으로
적혀 있는데 실제로는 틀린 항목이 여러 건 나왔고 같은 날 전부 정정
반영됐다(개수는 그 문서가 소스, 여기서 세지 않음). 그대로 구현하면
반대로 돌던 두 건(canBound 게이트 방향, gcconn/gchold 강/약)도 닫혔다.
2라운드는 :List의 reconcile/recompute 같은 확정 의사코드를 실제로
손으로 실행해보는 작업(원본과 진행 로그는
.claude/qa-request/pre-implementation-qa-round2.md가 소스) — recompute
트레이싱에서 Frame{A,B}처럼 정적 자식 2개짜리도 첫 마운트에 크래시하는
경로(RC-1)를 찾았고, 같은 날 후속 대화에서 사용자가 직접 제시한
Blocker 재사용 게이팅 설계로 해결·반영까지 완료됐다
(archive/question-resolved.md의 RC-1 절).
3라운드(완료, .claude/qa-request/pre-implementation-qa-round3.md가
소스) — RC-1 해법이 실제로 attachSlot에 반영된 걸 트레이싱하다
새 문제 발견, 같은 세션에 전부 해결·반영까지 완료. 처음엔 activateList가
자기 Slot의 Blocker가 켜지기 전에 실행돼 :List 초기 population이
문제(RC-3/RC-4)를 낸다고 봤고, recompute가 의존하는 bk.N(순회
상한)의 수명주기도 문서에 없어 "고정값/그때그때 실제 개수 둘 다 각기
다른 방식으로 깨진다"고 판단했으나 — 사용자가 이 분석 자체를
정정했다: Blocker 게이팅은 bk.N이 아니라 blocker:IsOn()만 보므로
"그때그때 실제 개수" 모델이 배치 크래시를 되돌린다는 결론은 틀렸었다
(bk.N = 그때그때 실제 개수로 확정). RC-3/RC-4도 사용자가 더
단순한 해법을 직접 제시 — flush 루프를 분기하는 대신 attachSlot의
slot._mounted = true를 activateList 호출 뒤로 옮기는 것 하나로
둘 다 닫힘. 부수로 spliceArraysDown이 밀어야 할 배열에
bk.observers가 빠져 있던 것도 발견·반영, ROADMAP.md M3(디스패치)가
M2의 Blocker.luau에 구조적으로 의존하게 된 것도 각주로 반영
([2026-08-24] 그때 열어뒀던 마일스톤 재편 여부가 순서 교체로
닫혔다 — 위 00번 머리말).
✅ [2026-08-25 해소] 아래 둘은 전부 닫혔다 — question.md 최우선
절은 지금 비어 있다. 중간 State GC는 _hold 불변식(하류 → 상류
강함, 상류 → 하류 weak)으로 사용자가 확정했고, 동적 키 표면(옛 GetDynamic) 위치는
콜론 유지 + 예약 키 진단 타입 함수로 닫혔다([2026-08-26] 그 함수는
8라운드 H-112로 CheckReservedKeys<keyof<T>>가 됐다 — T를 통째로
넘기는 옛 배선은 실사용 T에서 안 돈다. 애초에 그 항목이 섰던
근거인 lazy __index 충돌 자체가 Store 재설계로 소멸). 남은 건 실측
스파이크 하나뿐이고 착수 게이트가 아니다(luau-test/STATUS.md의
"만들어야 할 스파이크" 절). 아래는 해소 전 서술:
⚠️⚠️ [2026-08-24 승격, 2026-08-25 해소됨] 아래 둘은 이제 바로 다음 마일스톤의
게이트다. 순서 교체 전엔 반응형이 M3라 "한 마일스톤 뒤"의 일이었는데,
반응형이 M2가 되면서 지금 착수 직전에 결론이 필요한 항목이 됐다
(위 00번이 "M2 착수를 막는 설계 항목은 없다"고 하는 것과 모순되지
않는다 — 하나는 실측 미완, 하나는 표면 위치 선택이라 성격이 다르지만,
어느 쪽이든 M2를 짜기 전에 답이 있어야 한다). 둘 다
question.md의 최우선 절로 올라가 있고(2026-08-24에 낮은 우선순위
절에서 승격), 각 base/ 문서에도 ⚠️로 표시돼 있다. [2026-08-21 정리] 여기 쌓여 있던 [해소] 항목들
(Blocker.luau 마일스톤 순서, 그룹 Attribute 위치 claim 키,
SetAndDispose, PopOnly→Detach, KeyGone 처분, Store 미선언 키
타입 에러, dedup 경로 대칭)은 전부 archive/question-resolved.md와
각 base/ 문서로 옮겼다 — 목록이 절반 넘게 해소 항목으로 차 있어
"지금 할 일"로 읽히지 않던 것을 걷어낸 것.
- 중간 State GC 미검증(
base/source-state-plan.md) — 상류 strong / 하류 weak 불변식을 명문화할지 +luau-test실측. M2 착수 전 필요. store:GetDynamic을 콜론 메소드로 둘지 탑레벨 함수로 둘지 (base/store-plan.md) — 콜론이면GetDynamic이 모든 Store의 예약 키가 됨(lazy__index와 충돌). M2/M4 착수 전 필요.
-
⭐ M0 착수를 막는 결정은 이제 없음 (2026-08-14 열한 번째 세션 기준).
question.md의 최우선 항목이 전부 비었음 —0-Y(:Computelazy 핸들 계약)는 13차 세션에,0-Z(Attribute 이름 소유권)와0-A(재디스패치 하강 diff)는 14차 세션에,0-B(dispose시그니처/범위)는 2026-08-14 열 번째 세션에 확정·base/반영 완료.0-W(같은Ref이중 배치, M8 구현 세부만 막던 항목)도 2026-08-14 열한 번째 세션에 해소 — 선택지 (a) 채택(즉시 error), 메커니즘은 새Relate없이bindLifetime/unbindLifetime재사용(base/ref-plan.md"이중 배치 방지" 절). 부수 결정으로canBound가canExecute와 별도 진입점으로 재도입됨(2026-08-14 다섯 번째 세션에 하나로 합쳤던 걸 부분적으로 되짚음 — "이미 묶여 있는가"(bound 문맥)와 "지금 발화해도 되는가" (execute 문맥)는 판정 로직은 공유해도 호출부의 질문이 다르다는 사용자 지적,base/lifecycle-pattern.md의 "canBoundvscanExecute" 절. [정정, 2026-08-18] 두 predicate는 값이 같은 게 아니라 서로의 부정이고 게이트는 항상if not canBound(v) then error(...)모양이다 — 그 문서의 같은 절이 소스).question.md엔 이제 "결정 대기" 절 자체가 없음(비어서 헤딩째로 삭제).M0 착수 전 반드시 읽을 것 — 이 두 개는 "결정"이 아니라 "구현 규약"이라 여전히 유효:
base/typing-limits.md(0-Y의 산물) — 핵심은 "파생 State를 만드는 자리마다 결과 타입을 명시 주석으로 바인딩" + 7번 설계 체크리스트. 재귀 제네릭이 자기를 다른 타입 인자로 반환하면 Luau가 타입 안전성을 에러 없이 조용히 잃는 상위 한계라 quad 쪽에서 우회하지 않기로 확정(RFCrelax-recursive-type-restriction수혜 대기, 추적luau-lang/luau#2380). 실측 근거는audit/type-recursion-issue/.base/dispatch-core-plan.md(0-A/0-Z의 산물, 14차 세션에bind-system-plan.md에서 분리 신설) — 재디스패치가 "철거 후 재구축"이 아니라 하강 diff임,retractFrom은 3-인자, 클로저 인자는nil이거나 같은 핸들러가 처리할 값(타입 보장),HANDLER_PRIORITY_FALLBACK, "base가 소유하는 핸들러와 주입되는 엔진 op"(addTag/removeTag/setAttribute). Handler 작성 체크리스트(개수는 그 문서가 소스)를 새 핸들러 짜기 전에 훑을 것 — 지난 세션들에서 실제로 반복된 실수 목록임.
해소 전 원문은
archive/question-resolved.md(0-Y/0-Z/0-A 절), 뒤집힌 옛 재디스패치 모델 전문은archive/dispatch-hintvalue-model-reversed.md. -
구현 시작 — 루트
ROADMAP.md의 M0부터. 설계 단계는 2026-08-04 로드맵 인수인계 라운드로 종료.research/pre-implementation-audit.md우선순위1은 2026-08-12 열일곱 번째 세션에 마지막 넷(1-3/1-4/1-10/1-11)까지 전부 해소되어 전원 완료(항목 수는 그 문서가 소스). [14차 세션 기준] 0-Y/0-Z/0-A까지 전부 해소돼 설계 게이트는 남아있지 않음 — 착수 전 읽을 것은 위 0번의 두 문서(typing-limits.md/dispatch-core-plan.md)뿐이고, 스파이크 상태는 아래 그대로:.claude/luau-test/(2026-08-09 신설) 스파이크 결과 — [2026-08-13 여섯 번째 세션에 첫 실측 완료, 대부분 닫힘]. 상태의 소스는 항상.claude/luau-test/STATUS.md(pass / 사람 결정 필요 / 스파이크 깨짐 / 미실행, 폴더 구조 자체가 상태) — 총 몇 개인지도, 지금 몇 개가 어느 폴더에 있는지도 여기서 세거나 나열 안 함(04/05/10/13/15/16/19가 여러 세션에 걸쳐 재설계로rewrite-required/에 들고나며 이 문단의 나열이 매번 stale해지는 패턴이 반복됐음, 최근엔 8차 세션의 "emit은 항상 전파" 정정으로05도 합류). 실행 결과 상세는.claude/audit/luau-test-first-run-2026-08-13.md. 첫 실측 요지만 (역사적 사실 — 이후 변동은 위처럼STATUS.md가 소스):- 런타임 12개 전원 통과(01~07/11/17/18/19/20, crash 0 / FAIL 0) —
특히
07이 연쇄 GC를,18이 두-Relate상호 순환 미해제를 실측 확정해 GC-native 아키텍처의 핵심 전제가 검증됨.04는 같은 세션 감사가 찾은chains:SetStrong순서 버그를 음성 대조군으로 재현. - 타입 쪽에서 하나가 걸렸었음 → 그게 구 0-Y, [13차 세션]
해소(Luau 현 한계로 확정,
base/typing-limits.md). 나머지 타입 스파이크는 판정 완료(08/09통과,12는 실패지만 문서가 이미 fallback으로 예비해둔 결과라 설계 영향 없음,14는 부분). 지금 M0 착수를 막는 설계 결정은 없고, 0-Y/0-A가 남긴 규약 (base/typing-limits.md/base/dispatch-core-plan.md)은 착수 전 필독.
- 런타임 12개 전원 통과(01~07/11/17/18/19/20, crash 0 / FAIL 0) —
특히
-
용어 정리 — 1차 제안 이후 대부분 확정, 소수만 남음. 최신 소스는
.claude/question.md1번(개수 반복 안 함, 항목 추가/해소될 때마다 여기가 stale해지는 패턴이 반복됐어서). [2026-08-13 정정]State는 2026-08-12 스무 번째 세션에 현재 이름 그대로 유지로 이미 확정됐음(이 목록이 "위험도 높음, 1순위 open"으로 stale하게 남아있던 걸 발견해 수정) — [2026-08-21] 여기 있던 이름 나열은 지웠다. 바로 위 문장이 이미 "question.md1번이 최신 소스"라고 선언해놓고 다음 줄에서 목록을 다시 나열하고 있었고, 예고대로 실제로 갈라졌다(2026-08-21에 추가된Owned와 그 전부터 있던hintValue가 둘 다 빠져 있었음 — 감사가 발견). 열린 항목이 뭔지는question.md1번을 열어볼 것. -
[2026-08-14 세션에 해소] 오래 열려 있던 "이미 생성된 인스턴스 재바인드"는 기각되어
archive/existing-instance-bind-rejected.md로 이전됨 — 더 이상 상의할 스코프 항목이 아님. -
[백로그] 범용 렌더 디버깅 도구
quad-mock(Tween mock 등 동적 동작 지원, M0 mock 테스트 하네스와는 별개), 런타임 디버깅 플러그인quad-debug(Studio 플러그인, 실물 Instance→코드 위치 역추적 — 채널 실현 가능성은 실측 검증 완료, 세부 API 이름만 남음), 문서 사이트 전체 구조(초심자/api/심화/quadnomicon4축 + 콘텐츠 맵),Operator콤비네이터 슈가(Sum/Product/Not/비트연산 등:Compute/:Apply용 — 메커니즘은 확정, 네임스페이스 이름만 미정, 구현은 순수 슈가라 맨 마지막), 컴포넌트 에러 격리 유틸Fallback/Traceback([2026-08-14 세션, 설계 확정 —research/에서base/fallback-plan.md로 승격]pcall기반Fallback과xpcall+debug.traceback기반Traceback으로 분리,err: any확정, 패키지·이름 전부 확정 — 설계만 끝났을 뿐 구현 우선순위는 그대로 맨 뒤), 생명주기 훅OnCreated/OnRendered/OnDestroyed([2026-08-14 아홉 번째 세션,research/에서base/lifecycle-hooks-plan.md로 승격] 각각PreRef/PostRef/Effect를 반환하는 순수 팩토리 함수 슈가 —OnRendered도 채택 확정, 그게 얹히는PostRef프리미티브 자체는 슈가가 아니라 디스패치 코어라 ROADMAP M8에서PreRef와 같이 구현됨 (백로그가 아님,base/ref-plan.md의 "PostRef" 절). 훅 슈가 셋만 후순위) — 전부 "quad 개발 상당 부분 끝난 뒤"로 사용자가 못박은 후순위. 상세는.claude/README.md의base/표(fallback-plan.md/lifecycle-hooks-plan.md)와research/표 (debug-tooling-plan.md/documentation-plan.md/documentation-content-map.md/framework-comparison-findings.md/operator-sugar-plan.md). [2026-08-14 추가, 2026-08-19 설계 전부 해소 후base/로 승격] 시간 기반 전파 게이트Debounce/Throttle(base/debounce-throttle-plan.md)도 백로그이지만 위 항목들과는 발단이 다름 — 사용자가 직접 요청한 실제 기능 갭에서 시작됨(그 문서 13절). 다만 제어 핸들 설계까지 닫히고 나니 실제로 quad-base에 새 코어 메커니즘을 추가하지 않는 순수 슈가로 확인돼(같은 절), 위 항목들과 우선순위는 다시 같아짐 — M0/M2를 막지 않고, 그 게이티드 노드는 [2026-08-21]state:Gate로 확정돼 M2에서 만들어진다(base/gate-plan.md) —Debounce/Throttle은 그 위의 정책으로 얹으면 되고, 같은 설계를 두 번 할 일은 없어졌다. 주입 op 2개(setTimeout/clearTimeout)가 백엔드 팩토리 표면에 추가될 예정이라는 것도 M1 설계 시 인지. 남은 열린 질문 없음(구question.md낮은 우선순위 절, 전량 해소로 항목 자체가 빠짐). [2026-08-18 추가] 사용자 아이디어 메모 두 건도 같은 성격의 백로그로 신설 — 스크롤 최적화 외부 유틸quad-roblox-fastscroll(research/fastscroll-plan.md, 선행으로Visible=false일 때AbsoluteSize/AbsolutePosition갱신 여부 실측 필요)과 스프링 물리 기반 지속 업데이트 프리미티브quad-spring(research/spring-plan.md, 참고 구현qwreey/spring.lua사용 가능성 확인 필요) — 둘 다 설계 논의 전 아이디어 단계이고 사용자가 직접 "아주 나중"으로 후순위 지정, M0/설계 게이트와 무관. [2026-08-19 추가]quad-roblox-types(가칭,quad-types와 같은 패턴으로quad-roblox전체 대신 그 타입만 필요한 모듈을 위한 패키지)도 같은 성격의 백로그로 신설 — 사용자가 지금 만들 필요는 없다고 명시적으로 후순위 지정, 상세는base/quad-types-plan.md의 "남은 것" 절. -
자율 작업 루프/스케줄 설정 여부는 사용자 결정 대기 중 (
HUMAN_TODO.md2번 항목). -
[신규 백로그, 2026-08-14 열네 번째 세션] 문서 stale 감소용 include 도구
doc-include.py(가칭,doc-check.py와 짝) —research/ doc-include-plan.md참고(상태의 소스는 그 문서). [2026-08-16 기준] 같은 날 CLAUDE.md 분할로 파일럿이 "session-summary.md를 통째로 생성"하는 단방향 설계로 단순화돼 플랜이 갱신됨(목적지 마커 불필요). 여전히 구현 착수 전. M0/설계 게이트와 무관. -
[2026-08-16 신설, (a)~(d) 전부 닫힘 — 다만 아래 두 건이 미해결로 남음] 감사 툴링 검증. (a)
@import3개(conventions.md/project-context.md/todos.md) 실제 로드 — 확인됨, (b)quad-doc-auditor레지스트리 등록 — 확인됨(첫 실측 때 전원agentType not found였던 건.claude/agents/가 세션 도중 생긴 디렉토리였기 때문, 재시작으로 해소), (c) frontmattermodel: sonnet반영 — 확인됨(서브에이전트 트랜스크립트에claude-sonnet-5기록), (d) 해소 — 읽기 전용인데 Write/Edit이 주어지던 원인은memory: project가 맞았음(근거는.claude/agents/quad-doc-auditor.md상단 배너). 다만tools:필드가 그대로 반영되지 않는 건 여전히 미해결이라, 읽기 전용은 도구 유무가 아니라 프롬프트의 행동 규약으로 계속 지킨다.[2026-08-16] 이번 세션의 감사 루프는 4라운드에서 사용자 결정으로 중단 — 수렴 조건(무발견 2연속)은 못 채웠다. 라운드별 새 발견은 6→5→2→2로 줄었고, 3·4라운드에 나온 것은 이 세션 변경의 stale이 아니라 코퍼스에 오래 있던 일반 부채(개수 하드코딩, 날짜 없는 시한부 주장)라 계속 돌리면 수렴이 아니라 옛 부채를 끝없이 캐는 쪽이 된다는 판단. 이 세션 변경분 자체는 안정적(4라운드 설계 코퍼스 각도에서 확실 발견 0건). 다음 세션이 중대 변경을 하면 그때 평소대로 감사 루프를 돌리면 되고, 이번 미수렴 때문에 따로 이어서 돌릴 필요는 없다.
미해결 1 — 정의 파일이 언제 반영되는지 모른다. 감사자가 실제로 받은 정의 텍스트가 실행마다 달랐다: 세션 시작 상태 → 그 시점 HEAD 커밋 → 어느 커밋과도 일치하지 않는 중간 워킹트리 상태(커밋된 적 없음,
git log -S로 확인). 이 세션이 "세션 시작 스냅샷", 이어서 "커밋된 HEAD에서 읽힌다"로 두 번 결론을 냈다가 두 번 다 반증됐으니 세 번째 가설을 세우지 말 것. 실무 규칙은 하나 — 정의를 고쳐도 반영됐다고 가정하지 말고, 중요하면 마커 문구를 넣어 감사자에게 물어 확인할 것. 상세 관측표는.claude/agents/quad-doc-auditor.md상단 배너가 소스. (워크플로 쪽은Workflow({scriptPath})가 디스크에서 실시간으로 읽는 게 확인돼 있으나, 지금 워크플로를 안 쓰므로 당장 쓸 일은 없음.)미해결 2 —
tools:필드가 그대로 반영되지 않는다: frontmatter에 적힌 Grep/Glob이 안 주어지고, 적지 않은advisor가 주어진다. 그래서 감사자의 읽기 전용은 도구 유무가 아니라 프롬프트의 행동 규약으로 지킨다.[2026-08-16 닫힘] 재감사 안 됐던 수정 6건은 확인 완료 — 첫 실동이 수렴 못 하고 끊겨 마지막 라운드분이 재감사 없이 커밋됐었는데, 새 절차의 첫 라운드(감사 2개 병렬)가 그 셋(spikes 개수 단일화,
slot-plan.md재역전 배너,doc-check.pydocstring)을 다시 훑어 회귀 없음으로 확인했다. 한 패스는 구세대 트리(8aeec76)와 현재본의 WARN 목록을 직접 diff해서 대조했고, 그 구간에 오히려 절 참조 오류 2건이 해소된 것도 확인됨. M0/설계 게이트와 무관. -
[2026-08-16 신설, 이미 닫힘 — 다음 세션이 알아야 할 규약] 절 인용 규약이 생겼다. 이제
`<파일>.md`의 "절 제목"형태로 인용할 땐 의역하지 말고 원문에서 잘라 쓸 것(#헤딩은 부분문자열,**볼드**절은 줄머리 + 앞부분일치). 규칙 본문은.claude/conventions.md의 "절 인용 규약"이 소스 — 여기서 반복하지 않음. 지키지 않으면doc-check.py가 ERROR로 잡아 커밋 게이트에 걸린다(WARN이 아님 — 절 참조 불일치를 78→0으로 정리한 뒤 승격했음). 경위는session/2026-08-16-03-doc-check-section-convention.md. -
[2026-08-16 신설, 이월 — 급하지 않음] 이번 절 인용 규약 작업에서 의도적으로 안 한 것 둘. 둘 다 다음 세션이 알아야 이중 조사를 안 한다.
#헤딩 검사가 부분문자열이라 느슨하다."확정"같은 짧은 인용은 같은 파일의 무관한 헤딩에 걸려 통과한다(base/slot-plan.md엔 "확정"이 든 헤딩이 여러 개). 커밋 전 감사가 실제 오매칭 사례를 하나도 못 찾았고,conventions.md의 "드문 오용이나 가상의 미래 요구까지 방어/최적화하려고 구조를 복잡하게 만들지 않는다" 원칙에 따라 지금은 안 고치기로 사용자와 합의. 실제로 물리면 그때 좁힐 것(길이 하한, 후보 2개 이상이면 WARN 등).- ⚠️ 감사자에게
git stash를 쓰지 말라고 프롬프트에도 매번 적을 것. 커밋 안 된 작업 트리에서 감사자가 HEAD 대조하려고 stash를 걸어 메인 세션의 스테이지가 반복적으로 풀렸다(2026-08-16 실동, 유실은 없었음). 금지 규약을.claude/agents/quad-doc-auditor.md에 넣어두긴 했지만 정의 파일이 언제 반영되는지 모른다는 게 위 7번의 미해결 1번이라, 정의에만 의존하지 말고 감사자를 띄우는 프롬프트에서 직접 금지할 것. 대안은git show HEAD:<경로>/git diff HEAD -- <경로>.