RC-1 Blocker 게이팅이 실제로 attachSlot에 반영된 걸 손으로 트레이싱하다 :List 최초 population이 이중 처리되는 결함(RC-3/RC-4)과 recompute가 의존하는 bk.N의 수명주기가 문서에 없던 갭을 발견. 필자의 최초 분석 오류(bk.N을 그때그때 실제 개수로 두면 크래시가 되돌아온다는 판단)를 사용자가 직접 정정 — Blocker 게이팅은 bk.N이 아니라 blocker:IsOn()만 보므로 무관함이 밝혀졌고, RC-3/RC-4도 slot._mounted를 activateList 호출 뒤로 미루는 사용자 설계로 해결됨. ROADMAP M2가 M3의 Blocker.luau에 의존하게 된 마일스톤 순서 불일치도 발견해 각주로 반영. quad-doc-auditor 감사 루프 4라운드(1~3라운드 총 9건 발견·수정, 4라운드 무발견으로 종료) 거쳐 doc-check.py ERROR 0 확인 후 커밋. Co-authored-by: qwreey <me@qwreey.moe>
21 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의 "인스턴스 생성 / 이벤트 네이밍 인체공학" 절. PopOnly(가칭, 2026-08-18 신설)::Listreconcile에서 "파괴하지 말고 자리만 비우라"를 지시하는 반환 센티널(base/slot-plan.md의 "nil리턴은 파괴가 기본" 절). 메커니즘은 확정됐고 이름만 열려 있음 — 사용자: "PopOnly 확정. 다만 이름은 변경될 수 있음. 이름에 대해서는 더 생각해보아야함".Slot(2순위): Vue의 "slot"(콘텐츠 주입 지점)과 이름은 같지만 의미가 다름(quad의 Slot은 자식 배열 재조정 프리미티브) — Vue 배경 있는 사람이 헷갈릴 수 있음.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-18 구현 전 QA 3라운드] M2가 M3의
Blocker.luau에 구조적으로 의존하게 됨 — 이대로 각주만 두고 로드맵 순서를 유지할지,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 마일스톤 정합성" 절. 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와는 다른 시간 기반 메커니즘이라 이 카탈로그가 아니라 quad-roblox 쪽 별도 프리미티브로 다룰지 판단이 필요한 별개 질문으로 분리됨. [2026-08-13 세션 신설]Alternative(nil 대체값, coalesce/??/ 엘비스 연산자류) 후보 추가 — Haskell 비교 리서치 중 나옴, 카탈로그 확정 규칙에 그대로 맞아 포함 근거는 있음. 상세는research/operator-sugar-plan.md. 구현 자체는 맨 마지막 우선순위(순수 슈가, 없어도 무방) — 여전함.- [신설, 2026-08-14] Debounce/Throttle — 남은 열린 질문(개수는
research/debounce-throttle-plan.md12절이 소스, 여기서 반복 안 함) — 사용자 요청("Blocker와 유사하게 만들어야 한다")으로research/debounce-throttle-plan.md신설. 네 번의 리뷰 라운드로 패키지 경계·주입 op 시그니처·Timeout타입·동작 정식화는 전부 확정됐고, 사용자 취향/방향이 갈리는 것만 남음 — 주요 4개:- 의미론 — 창이 열려 있는 동안
:Get()이 최신값을 주는가 (Blocker와 동일) vs 지연된 값을 주는가(권장, VueUse/RxJS와 일치). - 제어 핸들 —
state:Apply(Debounce{...})로 끝낼지,Blocker와 글자 그대로 같은 모양(Debouncer객체 +state:Debounce(d)+d:Flush()/:Cancel())으로 갈지. "검색창에서 Enter 누르면 즉시 커밋"류가 잦다고 보면 후자가 처음부터 나음. - 이름 — Roblox 관용 "debounce"(재진입 방지 불리언)와 정면 충돌. 업계 표준 이름을 유지하고 문서로 경고할지, 다른 이름을 쓸지.
Time = 0허용 여부 — "이번 스텝 합치기"로 유용하지만 스케줄러 타이밍에 의존하는 준-Blocker가 됨. 이 외에 사소한 것 둘도 12절에 열려있음: 공개 생성자 2개 개정안이 사용자 확인만 남은 상태,base/blocker-plan.md가 인용하는 "Get()은 라이브 레퍼런스" 문구에 한 줄 명확화가 필요(확정 문서 수정이라 승인 대기, 아직 안 건드림). 우선순위 낮음 — M0를 막지 않고 코어 계약도 안 건드림. 다만 M3에서Blocker를 구현할 때 게이티드 노드를 공용으로 빼두는 것만은 그 시점에 해야 함(따로 하면 같은 설계를 두 번 함).
- 의미론 — 창이 열려 있는 동안
- 중첩 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-18 커밋 전
/code-review high]PopOnly로 홀드 중이던 요소의 키가 데이터에서 사라지면 어떻게 처분하는가 — 지금 의사코드대로면mounted[key]가 이미nil이라 파괴 대상이 아니고, 소멸 루프가userdata[key]까지 지워서 파괴되지도updateFn에게 되돌려지지도 않고 참조만 끊긴다. 같은 절의 표("키가 사라지면 파괴")와도, "버릴 시점은updateFn이 정한다"와도 어긋남. 선택지 (a) 소멸 루프가userdata의old까지 확인해 파괴, (b) 지금 동작(참조만 끊고 GC)을 정식화하고 표를 고침, (c)updateFn을 마지막으로 한 번 더 불러 처분을 물음. [정정, 2026-08-18/code-review high] M6(:List가 있는 마일스톤) 착수 전 필요 — M8(Ref) 아님,base/slot-plan.md의 "nil리턴은 파괴가 기본" 절. - [신설, 2026-08-18 구현 전 QA] 그룹
Attribute의 위치별 claim 설계 — 같은 그룹 객체를 두 위치에 놓는 경우(Frame { a, a })를 잡으려면 위치별 claim 레지스트리가 하나 필요하다는 방향은 확정됐고(Ref처럼bindLifetime을 재사용할 수는 없음 — 그룹 값은 여러 곳에서 쓸 수 있어야 하므로), 키를 무엇으로 할지((inst, groupValue) → k인지groupKey단위인지)와 기존nameClaims와의 공존 방식이 미정 —base/attribute-plan.md의 "이름 소유권" 절. - [신설, 2026-08-18 구현 전 QA]
SetAndDispose류 편의 콤비네이터 —Get()→Set(new)→ 옛 값dispose의 3단계를 매번 손으로 쓰는 게 불편하다는 사용자 지적에서 나옴.source:Apply(SetAndDispose(new))(단 이때Apply는State가 아니라Source를 넘겨야 함)와source:SetAndDispose(new)콜론 메서드 중 어느 쪽인지, 그리고 이번 범위인지 백로그인지 미정 — M3 착수 전 방향만이라도 정할 것 (state:Apply시그니처에 영향),base/slot-plan.md의dispose절. - [신설, 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로 옮김).