# Slot — 뮤터블 자식 배열, 엄격한 단일 마운트 소유권 (base로 승격됨) **상태**: base — 설계 방향(소유권 귀속, 재마운트 시 throw, retract=폐기)과 소스 트리 상 패키지 경계까지 확정되어 `research/`에서 승격됨(`base/ architecture.md`의 "구현 착수: 소스 트리 구조 확정" 절 참고). 원본: `.claude/initreq/raw-userinput.md` "slot을 구현하도록 하기로 했음" 절. Fusion의 `Children` SpecialKey와 Vide의 mount 무가드 비교는 `base/comparison-fusion-vide.md` 참고 — 결론: **두 라이브러리 어디에도 이런 엄격한 단일 마운트 가드가 없음, quad의 진짜 개선점.** ## base/roblox 패키지 경계 (2026-08-04, 5차 라운드 확정) Slot의 add/remove/clear 재조정 로직(추상 자식 참조 기준 — "이 자리에 뭐가 있어야 하는가"를 결정하는 순수 로직)은 `quad-base/src/Dispatch/Slot.luau`가 소유. 실제 트리 조작(Instance `Parent` 설정/`Destroy`)은 `quad-roblox/src/ Handlers/Slot.luau`가 그 위에서 적용/해제만 담당 — 다른 모든 인터페이스/구현 분리와 동일한 패턴(`base/architecture.md`의 소스 트리 참고). Slot 자체는 당연히 Instance들을 담게 될 것으로 취급. **추가로 필요해진 핸들러**: Slot과는 별개로, `k`가 number이고 `v`가 이미 만들어진 Instance인 경우(중첩 인스턴스를 자식으로 직접 넣는 경우, 예: `Frame { Frame {} }`)를 위한 핸들러도 필요 — `quad-roblox/src/Handlers/ InstanceChild.luau`. Slot은 "뮤터블 배열"을 다루고 이 핸들러는 "정적으로 하나 박아넣는" 더 단순한 경우라 별개로 둠. ## 개념 `add`/`remove`/`clear`/`get`/`set` 등 뮤터블 연산을 지원하는 메타 배열. 실제 바인드가 일어나면 child로 풀리고, 이 메타 배열에 CRUD를 하면 실제 children이 적절히 제어됨. ## 핵심 제약: 소유권 귀속과 단일 마운트 Slot에 들어간 요소는 **ownership이 귀속**되며 다른 곳에 마운트할 수 없게 된다. `isMounted`를 관리해서, **한 인스턴스에 대한 다중 마운팅이 라이브러리 차원에서 절대 일어나지 않도록 강제**하는 게 v1 대비 핵심 디자인 변화. v1의 `mount()`는 별다른 강제를 안 했지만(`base/quad-v1-architecture.md`의 mount.lua 분석 참고 — 실제로는 부모/자식 부기까지 했지만 다중 마운트 방지는 없었음), v2는 mount 함수 자체가 이 강제를 담당. Fusion의 `Children` SpecialKey는 이걸 "특정 SpecialKey 하나의 내부 부기"로만 구현했고(재사용 가능한 1급 프리미티브가 아님), Vide는 아예 이 개념이 없어서 같은 target에 두 번 `mount()`하면 조용히 두 개의 독립 루트가 생김 — 둘 다 반면교사. ## 여럿 존재 가능, 부모가 실제 데이터 테이블만 다루면 됨 Slot은 하나의 instance 안에 여럿 존재할 수 있다. 전부 하나의 children으로 들어가지만, 실제 렌더된 instance에서 `GetChildren()`을 직접 하지 않고도 부모가 생성한 "실제 slot 데이터 테이블"만 다루면 되게 해서 **추상화 수준을 낮은 직접 바인딩에서 한 단계 떼어냄**(간접화를 통한 추상화). ## 마운트된 Slot의 재마운트는 즉시 throw (확정) **사용자 확인 완료**: 이미 사용된(마운트된) slot을 재마운트하려 하면 **즉시 `error()`로 중단** — warn+no-op 아님. 개발 중 바로 잡아낼 수 있게 강하게 실패하는 쪽 선택. 마운트되는 순간 slot의 실제 대상은 고정된다 — 따라서 **글로벌 스코프에서 slot을 쓰는 건 그다지 좋지 않을 수 있음**(재사용/재마운트가 막히므로). ## 클래스가 슬롯을 받는 방법 "네이밍된 슬롯"이 필요한가에 대한 사용자 자문: 그냥 슬롯 바인드 테이블을 값으로 넘기면 되는 것 아닌가 — 결국 array처럼 구현된 Store라고 생각하는 게 편하다는 방향. **기울어진 결론**: 별도 "Named Slot" 개념 없이, store나 파라미터로 넘기고 그게 그냥 ref처럼 바인드되는 모양. **확정(2026-08-04, 로드맵 인수인계 라운드)**: 위 방향 그대로 확정 — 별도 "Named Slot" 개념 없음, 슬롯 바인드 테이블을 store나 파라미터로 그냥 넘기면 ref처럼 바인드됨 — **사용자 확정**("A. 맞음. 리프노드에선 그렇게 마운트됨"). 단, 이 확정은 "리프 레벨에서 슬롯 하나가 마운트되는 방식"에 한정 — 여러 Slot이 형제로 섞이는 경우의 순서 보장 문제는 별도로 열려있음, 바로 아래 참고. ### 여러 Slot이 섞일 때 순서 보장 — 열린 질문 (2026-08-04 신규) `Frame { Slot1, 일반자식, Slot2 }`처럼 Slot과 Slot 사이에 다른 요소가 끼거나 Slot이 여럿 형제로 존재할 때, 최종 자식 순서가 저작 순서(위쪽 Slot의 요소가 항상 아래쪽 Slot의 요소보다 앞)를 안정적으로 지키는지는 아직 설계 안 됨 — **사용자 확정**("순서도 따름, 만약 웹이라면 순서에 맞춰서 마운트 되어야 하고, 아래쪽 slot은 위쪽 slot의 요소보다 무조건 아래 있어야함... 이게 가능하냐는 생각해봐야할 이야기임"). Roblox 자체는 z-순서를 주로 `LayoutOrder`/`ZIndex`로 푸는 편이라 당장 급하게 막히는 지점은 아니지만, `architecture.md`가 명시한 "quad-base는 다른 렌더 백엔드(GTK, 웹 DOM 등)에서도 재사용 가능해야 한다"는 전제와 직결되는 문제 — DOM류 백엔드는 형제 순서 자체가 렌더 순서라 이 보장이 없으면 못 씀. **후순위 열린 질문으로 유지**, Slot 코어 로직 구현 시점에 다시 볼 것 — M0/M1 단계를 막지는 않음(Roblox 단일 백엔드로는 당장 문제 없음). ## Slot과 Store 바인드의 관계 (`retract` 순서) Slot이 store 바인드로 들어오는 경우, pluggable 처리기에 `retract`(구 cleanup, `base/lifecycle-pattern.md` 참고) 핸들러가 필요함 — 한번 넘어간 slot 요소가 나중에 `retract`되면 삭제되는지, 아니면 "부모의 소유이니 부모가 처리"해야 하는지 검토 필요. **기울어진 결론(잠정안, 이후 정정됨)**: 부모가 정리 정도만 미리 수행하고 다시 `process`하면 되므로, 부모에게 위임(자식 slot 요소 자체가 스스로 정리를 실행하는 게 아니라). > **정정(2026-08-04 검증 라운드)**: 위 "부모 위임" 잠정안은 이후 **폐기** > 쪽으로 정정됨 — 아래 "확정" 절과 `.claude/question.md`("Slot의 `retract` > 동작이 '부모 위임' 잠정안에서 '폐기(옮기지 않음)'로 확정") 참고. 이 문단은 > 검토 과정의 히스토리로만 남겨둠, 현재 유효한 동작 아님. 이건 `base/bind-system-plan.md`의 "Store 바인드는 재실행 래핑" 확정 모델과 맞물림 — slot이 store 값으로 오면, store 바인드 핸들러가 이전 slot 상태를 `retract`하고 새 slot 상태로 다시 `process`하는 사이클을 돈다는 뜻. Slot 핸들러 자신이 감시 중인 값(배열/스토어)이 바뀔 때 child를 갱신하는 추적(구독)도 `base/bind-system-plan.md`가 말하는 "process 함수가 다른 값 변경을 추적해도 됨" 범위에 속하고, `retract` 시점엔 그 추적만 풀면 됨 — Destroy 시점엔 `retract`가 호출되지 않는다는 원칙(`base/lifecycle-pattern.md`)도 동일하게 적용. **확정(2026-08-04 검증 라운드): retract되는 slot은 옮겨지지 않고 그냥 폐기된다.** Slot은 바인딩되는 순간 그 안의 요소를 전부 own해버리는 데이터형 — 새 slot 상태로 교체될 때 이전 slot의 내용을 다른 곳으로 옮기는 경로는 없음, 그냥 버림. React의 portal(`<>`)류로 나중에 옮길 수 있게 하는 것도 검토됐으나 **이번 마일스톤에서는 오버엔지니어링으로 판단, 하지 않음** — 필요성이 명확해지면 그때 별도로 다시 논의. ## 자식으로 넘기는 클래스 스토어 자식에게 내려주는 클래스 스토어는 부모 쪽에서 미리 만들어서 내려보내는 게 편할 것 같다는 방향 — `store<>` 형태로 구성된 스토어를 만들면 됨(타입 표기는 러프한 스케치, 실제 문법은 tbox의 명시적 제네릭 적용 패턴 `f<>(...)` — `.claude/initreq/tbox/CLAUDE.md:40-41` — 참고해서 확정할 것). ## 열린 질문 (`.claude/question.md`에도 취합) - 재마운트 에러 처리(throw), retract 시 폐기(옮기지 않음) 둘 다 확정. 남은 건 실제 구현 단계에서 이 "폐기" 동작이 실사용에서 불편하지 않은지 재검증하는 정도 — 설계 방향 자체는 더 이상 열려있지 않음. - "클래스가 슬롯을 받는 방법"(Named Slot 없음)도 확정됨(위 "클래스가 슬롯을 받는 방법" 절 참고). - **여러 Slot이 형제로 섞일 때 순서 보장**은 아직 열려있음(위 "여러 Slot이 섞일 때 순서 보장" 절 참고) — Roblox 단일 백엔드로는 급하지 않음, Slot 코어 로직 구현 시점에 재검토.