docs(base): 동적 자식 추가/제거는 Slot/state<Frame>만 정당, 그 외는 UB로 명문화
Slot의 Length/Offset 카운팅이 Dispatch.setLength/setOffsetSource 호출에 의존하는데, 이 둘을 우회하는 경로(외부에서 직접 .Parent = inst로 자식을 끼워 넣는 것)가 UB라는 게 문서 어디에도 명시돼 있지 않았던 갭을 보강. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
df4a77b02d
commit
577277823a
3 changed files with 48 additions and 0 deletions
|
|
@ -582,6 +582,20 @@ quad-web의 해당 Handler는 offset 변경 관측 시 아무것도 안 하는 n
|
||||||
`base/slot-plan.md`의 "여러 Slot이 섞일 때 순서 보장" 절이 이 메커니즘으로
|
`base/slot-plan.md`의 "여러 Slot이 섞일 때 순서 보장" 절이 이 메커니즘으로
|
||||||
해소됨 — 상세는 그 문서 참고.
|
해소됨 — 상세는 그 문서 참고.
|
||||||
|
|
||||||
|
**동적 자식 추가/제거의 유일한 정당 경로는 `Slot` 또는 `state<Frame>`류
|
||||||
|
store-bind — 그 외 방식은 UB로 확정(2026-08-10 세션).** `Length`/`Offset`
|
||||||
|
카운팅은 그 위치를 담당하는 Handler(`Dispatch/Slot.luau`, store-bind
|
||||||
|
프로퍼티 핸들러)가 `Dispatch.setLength`/`Dispatch.setOffsetSource`를
|
||||||
|
호출해줘야만 정합적으로 유지됨 — 이 두 API를 부르지 않고 quad가 관리하는
|
||||||
|
부모 Instance에 자식을 끼워 넣는 경로(예: 사용자 코드가 `newInst.Parent =
|
||||||
|
parentInst`를 직접 호출해 Slot이 마운트해둔 부모 밑에 자식을 몰래
|
||||||
|
추가/제거하는 것)는 `lengthList`/`sourceList`가 그 변화를 전혀 모르게
|
||||||
|
만들어 카운트·형제 순서 계산이 조용히 어긋남 — 별도 방어 로직 없는 UB.
|
||||||
|
`Slot`이든 `state<Frame>`이든 둘 다 이미 이 두 API를 정확히 호출하는
|
||||||
|
유일한 정당 경로로 확정돼 있음(위 `setLength`/`setOffsetSource` 절
|
||||||
|
참고) — 새 경로를 만들 필요 없이 "동적 자식은 반드시 이 둘 중 하나를
|
||||||
|
거쳐야 한다"는 규칙만 문서화하면 됨.
|
||||||
|
|
||||||
## Store 바인드는 특수 경우인가, 아니면 pluggable 바인드를 재실행하는 래핑인가
|
## Store 바인드는 특수 경우인가, 아니면 pluggable 바인드를 재실행하는 래핑인가
|
||||||
|
|
||||||
사용자 원 메모: "스토어 바인드는 특수 경우로 둘지, 아니면 다른 pluggable 바인드를
|
사용자 원 메모: "스토어 바인드는 특수 경우로 둘지, 아니면 다른 pluggable 바인드를
|
||||||
|
|
|
||||||
|
|
@ -666,6 +666,14 @@ UI에 직접 관측, (2) `Dispatch.setLength(inst, i, slot.Length)`가 형제
|
||||||
마운트된 것"만 반영 — 수동 Visible 토글을 쓰면 `Length`가 그걸 못 잡는
|
마운트된 것"만 반영 — 수동 Visible 토글을 쓰면 `Length`가 그걸 못 잡는
|
||||||
게 맞고, 그건 사용자가 별도 State로 계산해야 하는 몫.
|
게 맞고, 그건 사용자가 별도 State로 계산해야 하는 몫.
|
||||||
|
|
||||||
|
**동적 자식은 반드시 `Slot` 또는 `state<Frame>`류 store-bind를 통해서만
|
||||||
|
추가/제거 — 그 외 경로는 UB(2026-08-10 세션, `base/bind-system-plan.md`의
|
||||||
|
"Length/Offset" 절 반영).** 둘 다 `Dispatch.setLength`/`setOffsetSource`를
|
||||||
|
정확히 호출하는 유일한 정당 경로라, 이걸 우회해서(예: 외부 코드가 Slot이
|
||||||
|
마운트해둔 부모 Instance에 직접 `.Parent = parentInst`로 자식을 끼워
|
||||||
|
넣는 것) 자식을 추가/제거하면 `Length`/형제 순서 계산이 그 변화를 몰라
|
||||||
|
조용히 어긋남 — 별도 방어 로직 없음, 문서 경고로만 남김.
|
||||||
|
|
||||||
## 백로그 — `Slot():Single(state, updateFn?)` (2026-08-09 여섯 번째 세션, 미착수)
|
## 백로그 — `Slot():Single(state, updateFn?)` (2026-08-09 여섯 번째 세션, 미착수)
|
||||||
|
|
||||||
`:List`의 key-map(`mounted`/`userdata`/`keyIndex`) 없이 "0개 아니면 1개"만
|
`:List`의 key-map(`mounted`/`userdata`/`keyIndex`) 없이 "0개 아니면 1개"만
|
||||||
|
|
|
||||||
26
CLAUDE.md
26
CLAUDE.md
|
|
@ -2492,3 +2492,29 @@ M0가 공식적으로 짜야 할 스파이크(위 "지금 할 일" 1번, `ROADMA
|
||||||
**다음 세션이 할 일**: 사용자가 luau-test 실행 결과를 갖고 오면 그것부터
|
**다음 세션이 할 일**: 사용자가 luau-test 실행 결과를 갖고 오면 그것부터
|
||||||
반영. 아직 없으면 `ROADMAP.md` M0 착수 우선순위는 그대로(위 "지금 할 일"
|
반영. 아직 없으면 `ROADMAP.md` M0 착수 우선순위는 그대로(위 "지금 할 일"
|
||||||
1번 참고) — 단, 이 폴더 결과를 먼저 확인하고 진행하는 게 순서.
|
1번 참고) — 단, 이 폴더 결과를 먼저 확인하고 진행하는 게 순서.
|
||||||
|
|
||||||
|
## 2026-08-10 세션 — 동적 자식 추가/제거는 `Slot`/`state<Frame>`만 정당,
|
||||||
|
그 외는 UB로 명문화(문서 갭 보강)
|
||||||
|
|
||||||
|
사용자 질문에서 시작: Slot이 마운트한 객체 수를 `Length`/`Offset`
|
||||||
|
누적합으로 세는 방식(2026-08-09 여섯 번째 세션 확정)이 되면서, 이 카운팅을
|
||||||
|
안 거치고 quad가 관리하는 부모 Instance에 외부에서 직접 `.Parent = inst`로
|
||||||
|
자식을 끼워 넣는 게 UB로 문서화돼 있는지 확인 요청 — 검토 결과 **문서
|
||||||
|
어디에도 명시돼 있지 않은 진짜 갭**이었음(기존 UB 목록엔 Handler 순환/
|
||||||
|
이중 바인딩/`Dispatch.process` 우회 직접 호출/`setLength`·`setOffsetSource`
|
||||||
|
생략 등은 있었지만 이 케이스는 빠져있었음, 인접했던 "수동 Visible 토글은
|
||||||
|
Length가 못 잡는 게 맞다"는 캐비엇은 이미 마운트된 element를 나중에
|
||||||
|
숨기는 별개 시나리오라 이것과 다름).
|
||||||
|
|
||||||
|
**확정**: 동적 자식 추가/제거의 유일한 정당 경로는 `Slot` 또는
|
||||||
|
`state<Frame>`류 store-bind 뿐 — 둘 다 그 위치의 Handler가
|
||||||
|
`Dispatch.setLength`/`Dispatch.setOffsetSource`를 정확히 호출하는 것으로
|
||||||
|
이미 보장돼 있음. 이 두 경로를 거치지 않고 quad가 마운트해둔 부모
|
||||||
|
Instance에 직접 `.Parent =` 대입으로 자식을 넣거나 빼면 `lengthList`/
|
||||||
|
`sourceList`가 그 변화를 전혀 몰라 `Length` 카운트와 형제 순서(offset)
|
||||||
|
계산이 조용히 어긋남 — 새 방어 로직 없이 UB로 문서화만 함(다른 UB
|
||||||
|
케이스들과 같은 톤). `base/bind-system-plan.md`("Length/Offset" 절
|
||||||
|
말미)/`base/slot-plan.md`("Slot.Length" 절 말미)에 반영 완료.
|
||||||
|
|
||||||
|
**다음 세션이 할 일**: 안 바뀜(`ROADMAP.md` M0부터, luau-test 결과 확인
|
||||||
|
우선) — 이번 세션은 순수 문서 갭 보강이라 우선순위엔 영향 없음.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue