사용자가 research/state-epoch-validation.md를 직접 읽고 기제 서술 세 건을
정정. 채택 여부 자체는 여전히 미정(M3 전 결론 필요).
- sourceList 순회 조건이 반대였다: rawInvalid == false일 때만 돈다.
true면 재계산이 이미 확정이라 훑을 이유가 없고, 순회의 목적은 오직
"못 받은 emit(게이트에 막혔던 것)을 여기서 먼저 받는 것".
- emit은 (source, count)가 아니라 발행 source만 싣는다 — 받는 쪽이
source의 count 필드를 그냥 읽으면 된다.
- 에이전트가 요구했던 seen/computedAt 두 카운트 분리는 철회. count 갱신과
rawInvalid = true가 같은 스텝이라 캐시 오인 경로가 없다.
- emit 수신 규약 확정형: 같으면 삼킴 / 다르면 count 먼저 갱신 →
rawInvalid = true → 그 다음 뒤로 emit. 다른 소스 항목은 안 건드림.
- 부수로 열린 것: 순회가 발견한 변경을 뒤로 emit 할 것인가. 다이아몬드
쪽은 사용자가 스스로 안전으로 정정(D도 count를 갱신해 중복을 삼킴),
게이트 쪽만 "해제 emit이 source = nil을 싣고 받는 쪽이 전체 확인"
규약으로 남음 — 게이트는 보통 최종단이라 채택을 막지 않는다는 판단.
- 비용 서술도 뒤집었고(훑는 쪽이 흔한 경로), question.md에 남아 있던
이미 뒤집힌 옛 결론("중복 통지는 안 고쳐짐 / UB 명문화 필요")도 정정.
처리 기록은 round5-followup.md M절. doc-check.py ERROR 0.
Co-authored-by: qwreey <me@qwreey.moe>
Claude-Session: https://claude.ai/code/session_01TiW21rnti9SbLgF6twtn6D
30 KiB
확인/결정 필요 목록
이 문서는 사용자가 답해야 할 것만 담습니다. 이미 결정이 끝난 항목은
2026-08-13 아홉 번째 세션에 archive/question-resolved.md로 옮겼음 —
"해결된 게 너무 많아 필요한 부분만 읽기 어렵다"는 사용자 지적에 따른 것.
결정 내용은 안 바뀌었고 읽는 자리만 옮겼으니, 어떤 항목이 왜 그렇게
정해졌는지 되짚고 싶으면 그 문서를 볼 것(지금 유효한 설계 자체는 항상
base/가 소스).
항목을 해소하면: 여기서 지우고 archive/question-resolved.md에
근거와 함께 옮길 것 — 다시 쌓이면 같은 문제가 반복됨.
⭐ 최우선 — 없음 (2026-08-14 열한 번째 세션 기준)
M0 착수를 막던 항목이 전부 해소됐습니다.
0-Y(:Compute(fn)의 lazy 핸들 계약)는 열세 번째 세션에,0-Z(Attribute 이름 소유권)와0-A(재디스패치 하강 diff)는 열네 번째 세션에,0-W(Ref이중 배치 방지)는 2026-08-14 열한 번째 세션에 확정·base/반영 완료 — 그래서 이 문서엔 이제 "결정 대기" 절 자체가 없음(비어서 헤딩째로 삭제). 해소 전 원문과 결론은archive/question-resolved.md, 뒤집힌 옛 재디스패치 모델은archive/dispatch-hintvalue-model-reversed.md.M0 착수 전 읽을 것:
base/typing-limits.md(0-Y가 남긴 구현 규약),base/dispatch-core-plan.md(0-A/0-Z가 반영된 디스패치 코어 — 열네 번째 세션에bind-system-plan.md에서 분리 신설).
1. 용어 정리 — 아직 안 정해진 것만 (사용자 요청, 진행 중)
사용자 원 메모: "quad는 register라던가 좀 부정확하거나 느낌이 바로 와닿지
않던 용어들이 많음 — 전체적 용어를 보고 생각해볼래? 제안을 줘, 나도 같이
볼게." 이미 확정된 이름(State/Relate/List/canBound/Ref/
PreRef/Peek/isState/None/NoneHandler/Handler)의 근거는
archive/question-resolved.md. (canBound는 2026-08-14 다섯 번째 세션에
폐기돼 canExecute로 통합됐다가 같은 날 열한 번째 세션에 별도 진입점으로
재도입되어 여전히 이 목록에 있음 — 이중 바인딩 가드 전용이고 canExecute
(emit 게이팅 전용)와는 판정 로직만 공유. 아래 3번 canExecute 항목과
base/lifecycle-pattern.md의 "canBound vs canExecute" 절,
archive/canexecute-inst-arg-reversed.md 하단 addendum 참고.)
- [해소됨, 2026-08-18]
DI→D(Declarative) 확정 — 원문과 근거는archive/question-resolved.md. 요지:DI가 "Dependency Injection"과 완전히 겹쳐 실제 오해 전례가 있었고,D는 Instance 전용이 아닌 declare 요소 전반으로 확장 가능하며D.FrameModifier류 타입 프리픽스도 짧게 유지된다. 미뤄뒀던 유일한 사유(한 글자 식별자의 검색성/자기설명력)는 "문서에서 처음 나올 때 항상D(Declarative)로 풀어쓴다"는 표기 규약으로 보완하기로 같이 확정. 코퍼스 반영 완료 —base/bind-system-plan.md의 "인스턴스 생성 / 이벤트 네이밍 인체공학" 절. - [해소됨, 2026-08-19]
PopOnly→Detach확정 — 원문과 근거는archive/question-resolved.md. 요지: 이미 있는Extract(호출자가 직접 부르는 명령형 추출)와 동사가 겹치면 헷갈리는데,Detach는 "화면(부모 계층)에서만 떼어낼 뿐 관리 주체는 여전히 reconcile"이라는 뜻이라Extract의 "소유권을 통째로 넘긴다"와 자연스럽게 구분되고,nil(파괴)과의 대비도 더 직접적으로 드러남. 공개 표면 위치도 같이 확정 —Slot이 함수(팩토리)라Slot.Detach처럼 붙이려면 callable-table+메타테이블이 새로 필요해서 과함,None과 같은 선례를 따라 패키지 최상위 export로. 코퍼스 반영 완료 —base/slot-plan.md의 "nil리턴은 파괴가 기본" 절. Gate(2순위, 2026-08-21 신설):Blocker/Debounce/Throttle아래의 공용 게이트 노드 이름. 사용자 지적 — "프리미티브 명을 Gater? 뭔가 이상하게 들어간다는게 약간의 문제" — 코퍼스가Blocker/Modifier/Observer처럼-er를 많이 쓰는데Gater는 영어로 어색하다. 에이전트 권고는Gate그대로(gate는 이미 행위자가 아니라 장치를 가리키는 명사라-er가 불필요 —Source/Ref/Slot/Tween도 같은 계열), 대안 후보는Valve/Relay. 설계 자체가 다음 세션으로 미뤄졌으므로 이름도 그때 같이 — 3번 절의Gate항목과research/gate-primitive.md가 소스.Slot(2순위): Vue의 "slot"(콘텐츠 주입 지점)과 이름은 같지만 의미가 다름(quad의 Slot은 자식 배열 재조정 프리미티브) — Vue 배경 있는 사람이 헷갈릴 수 있음.Owned(3순위, 2026-08-21 신설)::List/:Single의 설치 시점 플래그(기본true,false면 어떤 경로로도 파괴 안 함).elementOwner/claimOwner/releaseOwner와 같은 뿌리라 골랐지만 잠정 이름이다 — 형용사라 옵션 테이블 키로는 자연스러운데, 실제로 묻는 건 "이 Slot이 요소의 수명을 책임지는가"라서OwnsElements처럼 주어를 드러내는 쪽이 나을 수도 있음.base/slot-plan.md의 "소유권은 설치 시점에 정해진다" 절.canExecute(3순위, 사소함): 실제로 "이 값이 아직 살아있나" 확인인데 이름이 범용 권한 체크처럼 들림 —isAlive쪽이 더 직접적이라는 제안이 있었으나, (2026-08-08 재검토)isAlive는 top-levelisX계열 (isState/isRef/isPreRef/isModifier/isObserver류 — 전부 타입 판별자)과 접두어가 겹쳐 "이것도 타입 체크인가" 오해를 유발할 수 있다는 점이 지적됨.canExecute는 타입이 아니라 liveness(생존 여부)를 묻는 질문이라is보다can계열 접두를 유지하는 쪽이 낫다는 방향으로 사용자가 기욺 — 여전히 미확정, 다음에can으로 시작하는 구체 대안(예:canRun)을 같이 검토할 것. [2026-08-14 다섯 번째 세션] 시그니처는canExecute(value): boolean1-인자로 확정(옛(inst, value)2-인자는 폐기,base/lifecycle-pattern.md,archive/canexecute-inst-arg-reversed.md). [2026-08-14 열한 번째 세션 정정] 당시엔canBound가 폐기돼canExecute하나가 두 역할을 겸했으나, 이후canBound가 별도 진입점으로 재도입되며 다시 갈라짐(같은 문서의 "canBoundvscanExecute" 절) — 이 이름 정리 항목은 이제canExecute(emit 게이팅 전용)에만 적용되고,canBound(이중 바인딩 가드 전용)는 별개 이름으로 유지됨. 둘 다 판정 로직은 비공개 헬퍼 하나를 공유.- 클로저 인자 이름
hintValue(3순위, 사소함, 2026-08-13 열네 번째 세션 신설): 하강 diff 재디스패치에서 이 인자는 더 이상 "힌트"가 아니라nil이거나 같은 핸들러가 곧 처리할 새 값임이 계약으로 보장됨(base/dispatch-core-plan.md) — 이름이 옛 모델의 잔재라nextValue류가 더 정확함. 코퍼스에 이미 널리 쓰인 이름이라 이번엔 안 바꾸고 대기열에만 올림(의사코드는 새로 쓰는 자리부터nextValue를 쓰기 시작했음). Brand(3순위, 사소함, 2026-08-07 여덟 번째 세션 추가): 런타임 nominal 타입 판별 통합 메커니즘(Brand.set/Brand.get,isState를 branded 타입 전부로 일반화) —brand-plan.md의Brand절에서 동작/구현 방식은 확정, "OOP 인스턴스의 클래스명을 얻는 느낌"을 전달할 더 나은 이름이 있는지가 열린 질문(사용자가 직접 제기) —Tag는 이미 quad-roblox의CollectionService래퍼로 쓰여서 이름 충돌, 후보로 "type namespace"류를 사용자가 검토했으나 미확정. (2026-08-08 재확인) 사용자가 다시 짚었지만 여전히 미정.Tag/Added/Removed/Merged(3순위, 사소함, 2026-08-08 세 번째 세션 array-part 값 객체 재설계 때 확정된 API 표면):base/tag-plan.md가 "열린 질문 없음, 값 모양/메커니즘/retract/패키지 배치 전부 확정, 이름 자체만 용어 정리 대상"이라고 명시해뒀으나 이 목록에 반영이 안 돼 있던 누락 — 이번에 추가.Tag는 RobloxCollectionService가 쓰는 용어와 1:1 대응이라 그 자체로는 무난해 보이지만, 위Brand항목(97-99행)에서 "Tag가 이미 이 뜻으로 쓰이고 있어서 충돌"이라는 이유로Brand의 대안 이름 후보에서 제외됐다는 점은 참고할 것 — 두 이름이 같은 코퍼스 안에서 공존 가능한지도 같이 검토 대상.Attribute/AttributeKey(3순위, 사소함, 2026-08-11 아홉 번째 세션 추가): 여러 Store를 한 번에 attribute로 묶는 그룹 프리미티브 (Attribute(store1, store2, ...),Tag와 동형)가 신설되면서, 기존 단일 키 생성자Attribute<<T>>("name")를 이름 충돌 방지를 위해AttributeKey<<T>>로 잠정 리네임함(OnChange/OnChangeKey처럼 함수 이름과 반환 타입 이름이 분리된 기존 전례와 대칭) — 해석 모호성 자체는 이미 없앴으니 급하지 않지만, 최종 이름은 여전히 이 목록의 다른 가칭들과 함께 검토 대상.base/attribute-plan.md"그룹Attribute(...)" 절 참고.- 참고 — 이미 지나간 사례:
register(v1) →State(v2) 리네임은 "모호함"은 풀었지만 "다른 뜻으로 이미 쓰이는 단어"라는 새 문제를 만든 셈 — 이번 정리에서 같은 패턴을 조심할 것. Store/Source/Modifier/process/retract/isHandlable은 업계 선례와 잘 맞거나 이미 신중하게 결정된 이름들이라 특별한 문제 없음.
3. 낮은 우선순위 — 열려 있지만 급하지 않음
- [해소, 2026-08-21 구현 전 QA 5라운드
CR-3] M2가 M3의Blocker.luau에 구조적으로 의존하던 순서 문제 — "게이팅 먼저"로 결정. 사용자 판정: "게이팅 먼저. 게이팅을 base 에 만들 준비를 해야한다. 실질적 모양 정의가 필요함." 즉 로드맵 순서를 유지하지 않고 게이팅을 M2로 앞당긴다. 다만 앞당기는 대상이Blocker그 자체가 아니라 그 아래의 공용Gate노드로 바뀌었고(같은 라운드DT-4), 그 표면/이름이 미정이라 새 열린 항목으로 이어진다 — 바로 아래Gate항목. 아래는 해소 전 서술: 이대로 각주만 두고 로드맵 순서를 유지할지,Blocker.luau(또는 최소 표면On/Off/IsOn/OffWithoutEmit)를 M2로 앞당길지, M2/M3 경계 자체를 재검토할지.**RC-1의 Blocker 게이팅 해법 때문에ROADMAP.mdM2의Dispatch.setLength/setOffsetSource체크박스가getBlocker/:On()/:IsOn()/:OffWithoutEmit()을 호출하는데, 정작Blocker.luau자체는 M3 체크박스에 있다 — 로드맵 순서대로면 M2가 아직 없는 걸 참조하게 된다. 지금은 M2 체크박스에 이 사실만 각주로 남겨둔 임시 조치(가장 보수적인 선택, 마일스톤 재편은 안 함) — M2 착수 전 필요. 상세는qa-request/pre-implementation-qa-round3.md의 "ROADMAP.md 마일스톤 정합성" 절. - [해소, 2026-08-21 구현 전 QA 5라운드 H절]
mountInst의 삽입 위치 + 중첩 offset 결함 —Dispatch.getOffsetAt(ownerKey, i)신설로 확정.setOffsetSource(None)은 얼리 리턴하고, 숫자가 필요한 쪽이getOffsetAt을 직접 부른다(사용자안 — 병렬 배열을 안 늘리는 pull 방식). 베이스는isSlot분기의 정체가 "베이스가 있나"임을 명확히 했고(베이스는 따로 저장하지 않고 Slot의.Offset을 그대로 읽는다 — 최상위 물리 inst는 항상 0), 중첩 Slot은 자기Offset을 관측해 깊은 전파를 한다. 반영하다 재마운트가OffsetSource를 새로 만들던 결함도 같이 잡았다(identity 재사용). 상세는qa-request/pre-implementation-qa-round5-followup.md의 H절. 아래는 열려 있던 시점의 서술: 둘이 한 덩어리다: (a)setOffsetSource의None이 "아무것도 안 차지함"과 "발행 채널 없음" 두 뜻을 겸하고 있어 plain 요소의 offset 숫자가 계산조차 안 된다(그래서 DOM류 백엔드가 삽입 위치를 알 방법이 없다 — 사용자 지적), (b)recompute가sum = 0에서 시작해ownerKey.Offset을 안 읽으므로 depth ≥ 2에서 중첩 Slot의 자식 offset이 부모 베이스만큼 어긋난다(이번에 발견, 지금까지 depth 1만 써서 안 드러났음). 제안은bk.offsetList신설(항상 숫자 계산) +mountInst(target, element, index)+recompute의base시드 + 중첩 Slot이 자기Offset을 관측해 재계산하는 구독 하나 —qa-request/pre-implementation-qa-round5-followup.md의 G절이 소스. - [해소, 2026-08-21] offset이 바뀌면 이미 배치된 물리 노드를 옮겨야 하는가 —
아니오. 사용자 확정: "애초에 offset 바뀌여도 상관 없는게 위에서 넣고
빼면 insert 같은거로 일어나서 뒤로 밀린다는거였긴함" — DOM류는 삽입/삭제
자체가 뒤 형제를 물리적으로 밀고 당기므로, 이미 놓인 노드를 다시 옮길 일이
없다. offset 숫자는 그 자리가 다음에 insert/remove할 때 쓰는 것뿐이라는
기존 서술이 그대로 맞다. 이게 성립하려면 백엔드 op이 아토믹한 최소 단위
(
mountInst/unmountInst/reposition)여야 한다는 게 같이 확인된 요구사항. 아래는 열려 있던 시점의 서술:mountInst(target, element, index)가 삽입 시점의 위치만 받는 일회성 호출이라, 이미 마운트된 요소의 물리 위치는 offset이 바뀌어도 갱신되지 않는다. Roblox는LayoutOrder가 프로퍼티라updateFn이 반응형으로 처리하면 되지만 DOM은 물리 순서 자체가 배치다.dispatch-core-plan.md는 "quad-web의 offset 핸들러는 no-op이고 숫자는 다음에 스스로 insert/remove할 때만 쓴다"고 적어뒀는데, 앞 형제의 길이가 변해 뒤 형제들의 offset이 밀리는 흔한 경우에 이미 놓인 노드를 옮길지가 그 서술만 으론 안 갈린다. 선택지는 (a) 옮긴다(백엔드가 offset 변경을 관측해 재배치), (b) 안 옮긴다(그러면 DOM에선 순서가 실제로 어긋남), (c):List가 재조정 때 필요한 것만 명시적으로 다시mountInst. quad-web이 실제로 생길 때까지 미룰 수 있으나, 계약을 지금 정해두지 않으면 M6 구현이 (b)를 전제로 굳는다. - [해소, 2026-08-21]
:List재조정의getOffsetAt비용 — 접두합 캐시로. 사용자 제안 채택: "getOffsetAt 은 compute 된걸 캐시해도 될듯. length 변경되는 뒤는 캐시가 무효화되도록 shouldRecomputeAfter 등을 둬서 특정 인덱스 초과부는 offset 다시 계산하고, 해당 값 위치 자체는 유효하므로 그것을 통해 더 length 를 이어붙이면 될듯." →bk.offsetCache+bk.invalidAfter("여기까지는 유효")로 반영 (base/dispatch-core-plan.md). 무효화 규칙은 하나 —invalidAfter = min(invalidAfter, i)(setLength도 splice도 자기 인덱스까지, 베이스 변경만0).recompute도 이 캐시 위에 얹혀 O(N)이라 "캐시를 누가 채우나"라는 갈래가 없어졌다(사용자 정정: 함수를 나눌 이유가 없다). 아래는 열려 있던 시점의 서술:settle이 키마다rawAdd/rawReplace를 부르고 그 각각이getOffsetAt(O(i))을 부르므로, 이미 마운트된 리스트의 데이터가 통째로 바뀌면 **O(N²)**다(최초 마운트는_mounted == false라 얼리 리턴이 막아준다).DC-9에서setOffsetSource의 즉시 계산이 O(N²)인 걸 "배치 등록 1회니 감수"로 판단했지만 이건 매 reconcile이라 빈도가 다르다. 해법은 있다 — reconcile이pos처럼 절대 offset도 러닝 누적으로 들고 다니면 O(n)(그게mountSlotTree가 이미 하는 방식). 그렇게 할지, 아니면 실측 전엔 그냥 둘지 판단 필요. - ⭐ [신설, 2026-08-21 구현 전 QA 5라운드] 공용
Gate노드의 이름과 표면 — M2 착수 전 필요. 위 항목의 결정("게이팅 먼저")에 따라 base에 만들 것이Blocker가 아니라 상류 emit을 가로채 정책이 통과 여부를 정하는 공용 게이트 노드로 확정됐다(Blocker/Debounce/Throttle이 그 위의 정책). 사용자 스케치는Gate(function(emit) return function() ... end end)2단 구조이고, 공개 API로 낸다(사용자: "이 API가 비공개일 이유는 없어보인다"). 남은 것 — (a) 이름(사용자: "프리미티브 명을 Gater? 뭔가 이상하게 들어간다는게 약간의 문제", 에이전트 권고는Gate그대로 —gate는 이미 장치를 가리키는 명사), (b):Apply팩토리인지 독립 생성자인지, (c)Blocker가 그 위에 어떻게 얹히는지, (d) M2에Gate만 넣을지Blocker까지 넣을지. 상세는research/gate-primitive.md. - ⭐ [신설, 2026-08-21 구현 전 QA 5라운드] State 재계산 판정을 "소스 에포크
비교"로 바꿀지 — M3 착수 전 필요. 사용자 제안: 각 State가 자기 상류 루트
Source들의 카운트를 들고 있다가Get()때 비교해 재계산 여부를 정한다. 동기는 성능이 아니라 정확성 — DFS 전파 도중 Observer가Get()을 부르면 아직 신호를 못 받은 다른 가지의 옛 캐시가 섞여 들어가는 glitch가 지금 모델에 실재한다. 에이전트 분석 결과 진단·방향 모두 타당하고 선례도 있다 (MobX/Adapton류 버전 검증). [2026-08-21 갱신 — 여기 있던 "중복 통지는 안 고쳐지고 선언 안 된 의존성을 UB로 명문화해야 한다"는 서술은 같은 날 둘 다 뒤집혔다]: 중복 통지도 같은 장치로 접고, UB 조항은 사용자 기각으로 빠졌다. 이어진 3차 정정으로 기제도 확정형에 가까워졌다 —sourceList순회는rawInvalid가 false일 때만 돌고(목적은 "못 받은 emit 받기"), emit은 count 없이 발행 source만 싣고, 카운트는 하나면 충분하다. 사용자 정리: "그냥 지금 순수 count 와 source 를 ref해두는 구현은 문제가 없어보인다." 남은 판단은 (a) 채택 여부 자체와 (b) 게이트 해제 emit이source = nil을 실어 "전체 확인"을 시키는 규약이고, State 내부 표현을 바꾸는 결정이라 M3 뒤로 미루면 되돌리는 비용이 크다. 상세는research/state-epoch-validation.md. - [해소, 2026-08-21 구현 전 QA 5라운드
C-4]Dispatch.setLength의 Observer 앵커 — 물리 target으로 확정(4라운드D-56역전).setLength가(ownerKey, i, len, anchor)로 4번째 인자를 받아 부기 키와 생명주기 앵커를 분리한다. 그래서bindLifetime은 항상 물리 Instance만 상대하고,isBoundAlive의 세 번째 분기(형태 미정으로 열려 있던 것)도 필요 자체가 없어졌다. 역전 원문은archive/bindlifetime-slot-owner-reversed.md, 지금 결론은base/dispatch-core-plan.md의 "setLength구현" 절 뒤 문단. 아래는 열려 있던 시점의 서술: 그때 확정(4라운드D-56)은 "bindLifetime의 첫 인자가 Slot일 수 있으니 백엔드가 그 경우를 핸들링하라"인데, 사용자가 그 전제 자체에 의문을 제기했다: "애초에 Slot 이 effect 나 다른 요소들을 소유할 수가 없다 … 실제 observer/effect 는 실제 inst 에 불림 … 우리가 왜 slot 을 소유 대상으로 둘 수 있게 한거였는지 다시 생각해봐야할 부분." 대안은 부기 키(ownerKey)와 생명주기 앵커(물리physicalTarget)를 분리하는 것 — 그러면bindLifetime은 항상 Instance만 받고,isBoundAlive의 세 번째 분기(지금 ⚠️ 미정)도 통째로 불필요해진다. 상세와 트레이싱은qa-request/pre-implementation-qa-round5-followup.md. Operator콤비네이터 슈가 네임스페이스 이름+포함 범위(2026-08-12 신설, 같은 날 후속으로 외부 리서치 완료) —Sum/Product/Not/비트연산 등:Compute/:Apply용 슈가 함수 모음의 이름. 흔한 단어라 top-level 노출은 위험, 후보는Operator/Op/Ops(Combinator는 코퍼스 전반에서 이미 일반명사로 쓰여서 제외) — 서브 에이전트 외부 리서치 결과Operator가 가장 선례가 강함(Pythonoperator모듈)이나 최종 확정은 여전히 사용자 몫. 같은 리서치에서 포함 범위도 새로 갈렸음 — 비트/비교 연산자 그룹과Sub/Div는 리액티브 콤비네이터로서 선례가 전혀 없어 드랍 후보로,Clamp/Min/Max는 선례가 강해 추가 후보로, Debounce/Throttle은 업계에 흔하지만Blocker와는 다른 시간 기반 메커니즘이라 이 카탈로그 밖 별개 질문으로 분리됐었음 — [2026-08-19 해소] 그 별개 질문은base/debounce-throttle-plan.md로 전부 해소·승격 완료, 더 이상 판단 대기 아님. [2026-08-13 세션 신설]Alternative(nil 대체값, coalesce/??/ 엘비스 연산자류) 후보 추가 — Haskell 비교 리서치 중 나옴, 카탈로그 확정 규칙에 그대로 맞아 포함 근거는 있음. 상세는research/operator-sugar-plan.md. 구현 자체는 맨 마지막 우선순위(순수 슈가, 없어도 무방) — 여전함.- 중첩 State 평탄화
State<State<T>>→State<T>(2026-08-13 여섯 번째 세션 신설, 백로그) — [근거 축소, 열네 번째 세션] 원래 이 항목의 주 근거는 "깊은 체인에선 힌트가nil로 전달돼 깜빡임 방지가 꺼진다"는 실제 기능 손실이었는데, 하강 diff 재디스패치로 각 레벨이 자기 값을 받게 되면서 그 손실 자체가 없어졌음(base/dispatch-core-plan.md). 남은 근거는 편의성과 Slot offset이 밀리고 당겨지는 케이스뿐이라 우선순위가 더 내려감 —state:Flatten()류 콤비네이터 아이디어는 그대로 백로그. 상세는research/operator-sugar-plan.md마지막 절. - [신설, 2026-08-18 커밋 전
/code-review high]store:GetDynamic을 콜론 메소드로 둘지, 탑레벨 함수로 둘지 — 콜론 메소드로 두면 Store의 lazy__index(없는 키를 인덱싱하면 그 자리에서Source를 만들어 저장)와 부딪혀서,__index가 고정 메소드 테이블을 먼저 확인해야 하고 그 결과GetDynamic이 모든 Store의 예약 키 이름이 된다(그 이름의 Source는 dot-access로 못 만듦). Store 키는 사용자 도메인 데이터 이름이라 충돌 확률이Modifier의 예약 이름들보다 높다. 대안은 탑레벨getDynamic(store, name)— "특정 프리미티브에 안 묶인 범용 유틸은 소문자 탑레벨"이라는 기존 네이밍 규칙에는 오히려 더 맞는다. M3/M4 착수 전 필요,base/store-plan.md의 "타입 추론 문제" 절. - [해소, 2026-08-21]
Detach홀드 중 키가 사라졌을 때의 처분 — 선택지 (c)로 확정:updateFn을KeyGone으로 한 번 더 불러 처분을 묻는다. 같이 확정된 것 — detach된 요소는userdata가 아니라slot._detached필드가 보유하고(그래야destroySlotTreewalk가 닿고 소유권도 유지됨), owner가 죽으면activateList가 설치한Effect가 정리한다. 원래 갭이 치명적이었던 이유는 gcconn 트릭 때문에 detach된 quad-제작 Instance가 GC 폴백조차 없이 영구히 남기 때문. 상세는base/slot-plan.md의 "Detach된 요소는slot._detached가 보유한다"/"KeyGone" 절. - [해소, 2026-08-21]
attachSlot책임 분해 — (B) 분해 채택으로 확정,base/slot-plan.md에 반영 완료(materializeSlotTree/mountSlotTree/얇은attachSlot). 근거 기록은research/slot-attach-decomposition.md. 아래는 그 열려 있던 시점의 서술: 한 함수가 부모 등록(offset/length) /:List실체화 / 마운트 상태 전이 / 배치 게이팅 / 자식 배치 / 재귀를 다 지고 있어서, "부모에게 알리는 길이의 최종값은 flush가 끝나야 정해진다"와 "부기가 물리 조작보다 먼저"가 동시에 만족되지 않는다(지금은 후자를 지키고 전자를 포기 — 부모recompute가 1회 헛돎). 사용자 판단으로 확장 논의 대기 — 책임 목록/순서 제약 출처/분해 후보 넷은research/slot-attach-decomposition.md. M6(:List) 착수 전 필요, 선행으로 아래Detach보관 위치가 먼저 닫히는 게 나음. - [신설, 2026-08-18 구현 전 QA] 그룹
Attribute의 위치별 claim 설계 — 같은 그룹 객체를 두 위치에 놓는 경우(Frame { a, a })를 잡으려면 위치별 claim 레지스트리가 하나 필요하다는 방향은 확정됐고(Ref처럼bindLifetime을 재사용할 수는 없음 — 그룹 값은 여러 곳에서 쓸 수 있어야 하므로), [2026-08-20 QA 4라운드] 이름도groupClaimKeys로 확정. [해소, 2026-08-21 QA 5라운드AT-1] 키도(inst, groupValue) → k로 확정 (사용자: "group 에 따라 key 가 따로 생성되므로 다른 그룹에 대해서는 잡을 필요가 없고, 그건 key->name 이 유일성을 검증해준다"),nameClaims보다 위치 claim을 먼저 본다 —base/attribute-plan.md의 "이름 소유권" 절. 이 항목은 닫혔다. - [신설, 2026-08-18 구현 전 QA] 중간 State GC 미검증 —
State → State → State → Observer체인에서 중간 노드를 강하게 붙잡는 주체가 문서 어디에도 없어 전파가 조용히 끊길 수 있음. 방향(상류 strong / 하류 weak)은 사용자가 지목했고, 명문화 여부 결정 +luau-test실측이 M3 착수 전에 필요 —base/source-state-plan.md의 "미해결 — 중간 State가 살아남는가" 절. - [신설, 2026-08-14 리뷰]
AttributeGroupHandler.process의 부분 실패 롤백 — 이름 순회 도중 소유권 충돌 error가 나면 그 전에 등록된 이름들이 이 사이클엔 회수되지 않음(클로저가 안 만들어짐). 피해는 그 인스턴스 수명으로 한정되고 재현도 시끄럽게 반복돼서 지금은 별도 장치 없이 문서화만 했는데(base/attribute-plan.md"메커니즘" 절), 원자적 롤백(그룹process에만 국소적인 unwind)을 넣을지는 열어둠. 지금 결정 불필요 — M10 구현 시점에 판단. - [해소됨, 2026-08-18]
Attribute.Merged의 이름 중복 —Merged(겹치면 error)와Overridden(겹치면 뒤가 이김)을 둘 다 제공하는 것으로 확정 (제3안). 근거·파급은base/attribute-plan.md의 "채택안 —Tag와 동형인 array-part 값 객체" 절. quad-debug세부 API 이름 —research/debug-tooling-plan.md참고. 채널 실현 가능성(BindableEvent/Function이 플러그인↔Play 중 게임 경계를 넘는지)까지 사용자가 Studio에서 직접 실측 검증 완료 — 기술적 불확실성은 다 해소됨, 남은 건 세부 API 이름뿐("이벤트 함수가 self로 instance를 읽는 게 quad 관습"이라는 언급은 2026-08-06 후속 세션에서 해소 — 채택 안 함으로 확정,base/event-plan.md"이벤트 핸들러는 self(Instance)를 받지 않는다" 절 참고). 사용자가 "quad 개발 완료 전엔 착수 못 함"으로 직접 후순위 지정한 건 여전함 — base 설계(M2 Dispatch/ M3 Source/M5D생성자) 시점에 훅 확장 지점만 고려해두면 됨.- 문서화 전략(UI 네이밍 컨벤션, Store 부작용을 게임 시스템에서 쓰는
패턴) —
research/documentation-plan.md(뼈대만). 정식 백로그 항목으로 올릴지, 착수 시점을 언제로 볼지 사용자 판단 필요. - v1 하위호환(compat) 레이어 —
quad-roblox-v1-compat—research/v1-compat-plan.md(신규, 2026-08-06, 두 차례 후속 논의로 수렴). 방향 확정: v1을 그대로 병행 실행 + 경계에서만state:Observer()(lazy 포기)로 값을 리졸브해 v1 프로퍼티에 재대입하는 브리지, v2→v1 단방향만 (양방향 불필요로 확정), 패키지명quad-roblox-v1-compat으로 확정(소스 트리에 세 번째 패키지로 추가될 예정). v2-in-v1/v1-in-v2 두 임베딩 방향 모두 기술적 근거와 안전 규칙까지 정리됐으나(문서 7번), Slot이 foreign Instance를 어떻게 다루는지만 Slot 코어 구현 시점까지 결정 불가로 남음 (위 "여러 Slot이 형제로 섞일 때 순서 보장" 항목과 같은 시점에 확인). 그 외 §8의 세부 항목(v1 자기 루트의Destroying자기청소 여부,registerClass체이닝 기능 브릿징 필요성)은 문서 자체가 "지금 결정 불필요"로 표시해둠 — 위 Slot 항목과 별도로, 실제 compat 레이어 구현 시점에research/v1-compat-plan.md§8을 다시 열어 확인. - Slot이 quad 밖에서 만들어진 임의 Instance를 받을 수 있는가
(2026-08-06 추가, 아직 안 풀림) — v1 compat 등에서 넘어온 foreign
Instance를 동적 배열 원소로 받을 수 있는지, retract 시 어떻게 다루는지.
Slot 코어 구현(M6) 시점에 확인 —
research/v1-compat-plan.md7-3.
없어진 번호에 대해: 예전 "0번(추가 프리미티브)"과 "2번(구현 착수 직전 감사 결과)"은 전원 해소되어 통째로
archive/question-resolved.md로 갔음. 우선순위1 11개의 개별 상태가 궁금하면research/pre-implementation-audit.md가 원본이자 최신.
전체 순서/우선순위는 .claude/todos.md가 최종 소스. 확정된 것들의 문서
색인은 .claude/README.md의 base/ 표(예전에 이 문서 맨 아래에 있던
요약표는 그것과 중복이라 archive로 옮김).