diff --git a/.claude/base/modifier-plan.md b/.claude/base/modifier-plan.md index 7fbd15d..950a0fc 100644 --- a/.claude/base/modifier-plan.md +++ b/.claude/base/modifier-plan.md @@ -535,7 +535,13 @@ Modifier 값을 변수/모듈 상수로 만들어 재사용하는, 기존에도 요구까지 방어/최적화하려고 구조를 복잡하게 만들지 않는다" 원칙과 동일. ### 9-2. `Overridden`가 서로 다른(그러나 상하위 관계인) Modifier 타입을 섞는 경우 — -타입 시그니처 미확정, 실 Luau 테스트 필요 (2026-08-07 다섯 번째 세션 후속) +타입 시그니처 미확정 (2026-08-07 다섯 번째 세션 후속) + +**[해소됨, 2026-08-13 첫 실측 라운드]** `luau-test/09-type-modifier-overridden-subtype.luau`로 +실측 완료 — 아래에서 우려한 지점이 그대로 재현됨(`Overridden`의 리턴 +타입 불일치로 서브타입이 깨짐), fallback(`any`)은 정상 작동 확인. +"실 Luau 테스트 필요"는 더 이상 유효하지 않음 — 아래는 그 결론에 이른 +원래 문제 제기/후보안 기록. **문제**: Modifier 타입은 위 4번 절 "FrameModifier 타입" 언급대로 Roblox 클래스별로 생성기가 뽑아내는 flat 타입인데, 그 밑의 Roblox 클래스 자체엔 diff --git a/.claude/base/slot-plan.md b/.claude/base/slot-plan.md index e571f65..de3bad7 100644 --- a/.claude/base/slot-plan.md +++ b/.claude/base/slot-plan.md @@ -95,7 +95,9 @@ InstanceChild.luau`. Slot은 "뮤터블 배열"을 다루고 이 핸들러는 " - **`T`의 실제 의미**: 위 배제 덕에 "이 Slot이 실제로 담을 수 있는 최종 마운트 가능한 값의 타입" 그 자체로 단순해짐 — quad-roblox엔 사실상 `T = Instance` 하나뿐(컴포넌트 호출 결과도 결국 Instance)이라 - `D.InstSlot = Slot<>`가 사실상 "그" Slot 타입. `Slot()`가 + `DI.InstSlot = Slot<>`(`DI` 네임스페이스 이름 자체는 + `question.md` 1번 용어정리 대기 중, 여기선 잠정 표기)가 사실상 "그" + Slot 타입. `Slot()`가 기본값(`T` 생략 시) 없이 항상 명시를 요구하는지, `quad-base`에선 `any`로 기본값을 두는지는 tbox 제네릭 적용 문법 확정 시 같이 정할 것 (이 문서 "자식으로 넘기는 클래스 스토어" 절의 기존 미결과 같은 갈래). diff --git a/CLAUDE.md b/CLAUDE.md index 64a5573..ad60000 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -110,7 +110,10 @@ modifier/Ref의 컴포넌트 경계 통과 방식) 논의도 2026-08-04 세션 ## 지금 할 일 (우선순위순) -0. **⭐ 최우선 — `.claude/question.md` 0-Y / 0-Z 두 결정.** +0. **⭐ 최우선 — `.claude/question.md` 0-Y / 0-Z 두 결정.** (`question.md`엔 + 0-B `dispose(any)` 시그니처/범위도 열려 있지만, M6 구현 세부만 막을 뿐 + M0 착수 자체는 안 막아서 이 최우선 두 개와 급 다르게 취급 — 별도 항목 + 아님.) **0-Y(신설, 2026-08-13 첫 실측에서 발견): `:Compute(fn)`의 lazy 핸들 계약을 유지할 것인가.** 콜백이 lazy `State` 핸들을 받는 커링 계약이 diff --git a/ROADMAP.md b/ROADMAP.md index 88a9ce5..87e18ec 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -311,8 +311,11 @@ Luau 코드로 부딪혀본 적 없는 세 가지**를 던지는 코드로 검 이때 확정(CRUD/`:List` 여부 무관 항상 노출, 순서 계산과 "n개 검색됨" UI 둘 다 겸함) — 구현 시 이 두 API를 `:List`/CRUD의 `raw*`가 호출. - [x] **Slot의 `Add`/`Remove`/`Extract`/`ExtractAll`/`Clear`/`Move`/`Swap`/ - `Get`/`IndexOf` CRUD 의미론 확정** (2026-08-09 세 번째 세션, 2026-08-09 - 열한 번째 세션에 식별 기준 재정정) — 에러 조건까지 전부 확정 + `Get`/`IndexOf`/`Splice` CRUD 의미론 확정** (2026-08-09 세 번째 세션, + 2026-08-09 열한 번째 세션에 식별 기준 재정정, `Splice`는 2026-08-12 + 열다섯 번째 세션 신설 — **[2026-08-13 5차 감사에서 추가] `Splice`가 + 이 체크리스트에 누락돼 있었음, `luau-test/20`으로 산술 실측 통과됨**) + — 에러 조건까지 전부 확정 (`base/slot-plan.md` "CRUD API 확정"). "재마운트 시 즉시 throw"도 `isMounted` 이중 추적 분리로 개별 element/Slot 컨테이너 기준이 명확히 갈림(같은 문서 "`isMounted` 이중 추적 분리" 절). @@ -333,8 +336,10 @@ Luau 코드로 부딪혀본 적 없는 세 가지**를 던지는 코드로 검 타입 제약 확정** — `nil`/`None` 둘 다 raw 요소로 금지(Slot 안엔 실제 마운트 가능한 `T`만), 핸들러 계층 값(Ref/PreRef/Observer/ Effect/Modifier)은 self-ref 컨텍스트가 없어 의미 불성립이라 즉시 - error(`Modifier` 필드와 같은 판별 메커니즘 재사용) — `D.InstSlot = - Slot<>`가 quad-roblox의 사실상 유일한 Slot 타입. + error(`Modifier` 필드와 같은 판별 메커니즘 재사용) — `DI.InstSlot = + Slot<>`(`DI` 네임스페이스 이름 자체는 `question.md` 1번 + 용어정리 대기 중, 여기선 잠정 표기)가 quad-roblox의 사실상 유일한 + Slot 타입. - [ ] `Slot:List(data, updateFn, keyFn?)` — 키 기반 동적 컬렉션 재조정, `keyFn(item, index) -> key` 생략 시 원본 `data` 배열 위치(raw index)를 그대로 key로 사용(중간 삽입/삭제 시 identity 보존 안 됨, 캐스케이드 @@ -467,9 +472,10 @@ Luau 코드로 부딪혀본 적 없는 세 가지**를 던지는 코드로 검 2026-08-08 세션) — 필드별 raw 덮어쓰기, 특별한 State/함수 분기 불필요(`modifier-plan.md` 9번) - [ ] `Overridden`가 서브타입 관계인 서로 다른 Modifier 타입(예: `FrameModifier`/ - `GuiObjectModifier`)을 섞을 때의 타입 시그니처 실 Luau 테스트 - (`modifier-plan.md` 9-2번, 미검증 — 안 되면 일단 `Overridden(...: any): - any`로 느슨하게 열어두고 이 항목으로 되돌아올 것) + `GuiObjectModifier`)을 섞을 때의 타입 시그니처 — **[해소됨, + 2026-08-13 첫 실측 라운드]** `luau-test/09`로 실측 완료, 우려대로 + 깨짐 확인됨 → `Overridden(...: any): any`로 느슨하게 열어두는 게 + 실제 구현 방향(`modifier-plan.md` 9-2번) - [ ] `State` 조합에 `isModifier` 기반 명시적 error 적용 (`modifier-plan.md` 7번, 2026-08-09 세션 확정) — 타입 차단은 되면 좋은 보너스로 선택 검증(필수 아님)