docs(audit): 코퍼스 5차 감사 — 0-Y/0-Z 포인터 4곳 + 파괴 용어 잔존 5곳 전수 정리
4차 감사(반복되던 두 패턴을 grep으로 전수 스윕)에서 발견한 것 정리:
- architecture.md: 모든 세션이 "먼저 읽으라"는 진입점 파일인데 소스
트리의 chains/retractFrom 서술에 0-Z 포인터가 전혀 없었음 — 최상단
배너 추가(가장 중요한 gap, question.md 0-A가 경고하던 바로 그 함정)
- tween-plan.md/operator-sugar-plan.md/effect-plan.md: self-lazy-핸들
계약(0-Y)에 의존하는 실행 예시/메커니즘 서술에 포인터가 전혀 없었음
— 3곳 추가
- CLAUDE.md: "지금 할 일" 0번(0-Y/0-Z가 최우선 게이트)과 1번("M0 착수
전 남은 유일한 게이트는 luau-test뿐")이 정면 모순 — 0-Y/0-Z 발견
이전에 쓰인 문장이 안 갱신된 stale, 정정
- slot-plan.md 3곳/additional-primitives-plan.md/
dispatch-redispatch-diff-plan.md: reconcile/Slot:List/재귀 재emit
가드 설명이 여전히 "파괴"를 현재형으로 서술 — 2026-08-13 여섯 번째
세션의 언마운트 전환 반영해 정정(지난 세 라운드가 놓친 인스턴스들,
전수 grep으로 확인)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
b228efc2a6
commit
91fd7b88a8
8 changed files with 43 additions and 12 deletions
|
|
@ -1,5 +1,12 @@
|
|||
# quad-v2 전체 아키텍처 (현재 상태 요약)
|
||||
|
||||
> **⚠️ [2026-08-13 4차 감사에서 발견] 이 문서는 세션 시작 시 가장 먼저
|
||||
> 읽는 진입점인데, 아래 소스 트리의 `chains`/`retractFrom`(Dispatch/init.luau
|
||||
> 항목)과 `retractFrom`에 재귀 위임(Attribute.luau 항목) 서술은 현행
|
||||
> (교체 예정) 재-dispatch 모델을 전제로 쓰여 있음 — `question.md` **0-Z**
|
||||
> 해소 전엔 그대로 구현하면 옛 모델로 짜게 됨. 상세는
|
||||
> `base/bind-system-plan.md` 최상단 배너, `research/dispatch-redispatch-diff-plan.md`.
|
||||
|
||||
**상태**: base — 횡단 결정의 최종 상태 요약. 특정 기능 plan이 아니라 프로젝트
|
||||
전체에 걸친 결정이라 완료 개념 없음. 근거가 된 원본 브레인스토밍은
|
||||
`.claude/initreq/raw-userinput.md`(안 옮기고 그대로 둠 — 이 문서들로 나누기 전의
|
||||
|
|
|
|||
|
|
@ -32,7 +32,10 @@ Effect(fn, state?) -> EffectHandle
|
|||
**`state` 지정 시(2026-08-07 여섯 번째 세션 확정)**: Effect는 내부적으로
|
||||
`state:Observer(...)`를 감싸는 걸로 구현 — `fn`은 포지셔널 인자로 `state`를
|
||||
받고(`fn(state)`, `:Compute`의 `fn(self)` 포지셔널-self 패턴 재사용,
|
||||
모듈화 목적 — 클로저 캡처 없이 `fn`을 독립적으로 정의/재사용 가능),
|
||||
모듈화 목적 — 클로저 캡처 없이 `fn`을 독립적으로 정의/재사용 가능
|
||||
— **[2026-08-13 4차 감사] 이 `fn(state)`가 lazy `State` 핸들을 받는다는
|
||||
전제 자체가 `question.md` 0-Y로 열려 있음, `Effect`는 0-Y가 명시적으로
|
||||
지목하는 영향 대상 중 하나**),
|
||||
Observer가 이제 등록 즉시 1회 실행되므로(아래 Observer 절 참고) 그 첫
|
||||
실행이 "설치"를 겸함. 이후 `state`가 무효화될 때마다 **직전 `fn` 호출이
|
||||
리턴한 cleanup을 먼저 호출한 뒤 `fn`을 재호출**, 그리고 Effect가 바인드된
|
||||
|
|
|
|||
|
|
@ -468,11 +468,12 @@ nested `Slot`을 파괴 후 재사용하는 경로가 정확히 이 케이스).
|
|||
상호 강참조" 패턴과 다른 모양 — GC 문제 없음.
|
||||
|
||||
- **같은 바인딩이면 완전히 무시하는 게 이 자리에선 효율 문제가 아니라
|
||||
정합성 문제** — Slot은 아래 "확정" 절대로 "폐기, 옮기지 않음"(portal
|
||||
없음)이 이미 정책으로 확정돼 있어서, 이 no-op 가드가 없으면 **재귀 재
|
||||
emit이 있을 때마다 마운트된 서브트리 전체가 파괴됐다 다시 만들어짐**
|
||||
(자식들이 들고 있던 스크롤 위치/포커스/애니메이션 상태 전부 유실) —
|
||||
Tag의 `Contains` 힌트가 막으려던 "깜빡임" 문제보다 훨씬 파괴적인 버전.
|
||||
정합성 문제** — 이 no-op 가드가 없으면 **[정정, 2026-08-13 4차 감사]
|
||||
재귀 재emit이 있을 때마다 마운트된 서브트리 전체가 언마운트됐다 다시
|
||||
마운트됨**(작성 당시엔 아직 destroy 모델이었음, 위 "확정" 절 언마운트
|
||||
전환 참고 — 물리 트리 이탈+재마운트라 여전히 자식들이 들고 있던 스크롤
|
||||
위치/포커스/애니메이션 상태는 유실됨, 파괴가 아니라는 것만 정정) —
|
||||
Tag의 `Contains` 힌트가 막으려던 "깜빡임" 문제보다 훨씬 파급이 큰 버전.
|
||||
`store.key:Set(sameSlotAgain)`처럼 사용자가 실수로 같은 객체를 다시
|
||||
emit하거나, 상위 `:Compute`가 재계산됐는데 결과가 우연히 같은 Slot
|
||||
레퍼런스인 경우 등이 실제로 이 경로를 탈 수 있음. `retract`가 `old ~= v`
|
||||
|
|
@ -704,7 +705,8 @@ splice 의미)와 `Swap`(O(1), 순수 페어 교환)을 공개 CRUD에 추가
|
|||
|
||||
Fusion `ForPairs`/`ForKeys`/`ForValues`, Vide `indexes()`/`values()`, React
|
||||
`key` prop에 대응하는 프리미티브 — 데이터 배열을 정체성(key) 기준으로
|
||||
diff해서 변경분만 생성/갱신/파괴한다. **독립 타입이 아니라 `Slot`의
|
||||
diff해서 변경분만 생성/갱신/언마운트한다(**[정정, 2026-08-13 4차 감사]**
|
||||
원래 "파괴"였으나 언마운트 전환 반영). **독립 타입이 아니라 `Slot`의
|
||||
콜론 메소드**로 확정(아래 "왜 자유 함수/새 타입이 아닌가" 참고) — 자기
|
||||
자신을 변경하고 자신을 반환, `Ref():Callback(fn)`류의 기존 체이닝 패턴과
|
||||
동일:
|
||||
|
|
@ -1146,8 +1148,10 @@ raw `i`를 그대로 위치 인자로 썼는데, 앞쪽 item이 filter로 마운
|
|||
방식, `data`가 참조를 유지한 채 뮤테이션+`Emit()`되는 경로도 지원해야
|
||||
하는 이상 최소 한 번은 훑어야 하는 게 불가피함.
|
||||
- **`updateFn`을 매번 부르는 게 비싼 게 아닌 이유** — 흔한 경로(`prev`
|
||||
그대로 반환)는 함수 호출 하나뿐, 실제 Instance 생성/파괴가 있는 건
|
||||
key가 새로 나타나거나/사라지거나/filter로 구조가 바뀌는 경우뿐.
|
||||
그대로 반환)는 함수 호출 하나뿐, 실제 Instance 생성/**[정정,
|
||||
2026-08-13 4차 감사] 언마운트**(파괴 아님 — 위 "구현" 절 `rawUnmount`
|
||||
참고)가 있는 건 key가 새로 나타나거나/사라지거나/filter로 구조가
|
||||
바뀌는 경우뿐.
|
||||
200개 중 값만 갱신되는 사이클엔 200번의 값싼 함수 호출이 있을 뿐,
|
||||
200번의 재구성이 있는 게 아님.
|
||||
- **`mounted`/`userdata`를 정리하는 루프가 `mounted`가 아니라 이전
|
||||
|
|
|
|||
|
|
@ -219,6 +219,9 @@ end
|
|||
-- Animate(info)는 factory(self) -> State를 반환 — :Apply 전용
|
||||
-- (2026-08-12 세션 후속 논의로 :Compute 직결에서 정정됨, 아래
|
||||
-- "왜 `:Apply`로 정정됐는가" 절 참고)
|
||||
-- [2026-08-13 4차 감사] 아래 selfH:Get()은 :Compute의 self-lazy-핸들
|
||||
-- 계약에 의존 — 그 계약 자체가 question.md 0-Y로 열려 있음. 0-Y가
|
||||
-- raw 값 쪽으로 결론나면 이 구현도 selfH:Get() -> selfH로 바뀜.
|
||||
local function Animate(info)
|
||||
return function(self)
|
||||
return self:Compute(function(selfH)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,9 @@ Vide/v1/artworks 소스 근거 조사, Context 구현 난이도 판정) + 그
|
|||
|
||||
React `key` prop, Vue `v-for :key`, Solid `<For>`, Fusion `ForPairs`/
|
||||
`ForKeys`/`ForValues`, Vide `indexes()`/`values()`에 대응하는 프리미티브 —
|
||||
데이터 배열을 정체성(key) 기준으로 diff해서 변경분만 생성/갱신/파괴한다.
|
||||
데이터 배열을 정체성(key) 기준으로 diff해서 변경분만 생성/갱신/언마운트한다
|
||||
(**[정정, 2026-08-13 4차 감사]** 원래 "파괴"였으나 2026-08-13 여섯 번째
|
||||
세션의 언마운트 전환 반영 — 최신 소스는 `base/slot-plan.md`).
|
||||
**최종 확정 형태는 자유 함수도 새 타입도 아니라 `Slot`의 콜론 메소드**
|
||||
(`Slot():List(data, updateFn, keyFn?) -> Slot`) — 상세 시그니처/구현
|
||||
의사코드/왜 자유 함수·새 타입이 아닌지/`Move` 기반 리오더/`userdata` 기반
|
||||
|
|
|
|||
|
|
@ -47,7 +47,9 @@ Attribute는 클로저가 no-op이라 무해하지만, `TagHandler`였다면
|
|||
자기 타입일 때만 동작 — 위 경로들에선 소리 없이 전량 정리로 퇴화함.
|
||||
**정확성은 유지되지만(그래서 지금까지 안 드러남) 깜빡임/재생성 방지라는
|
||||
존재 이유가 무너짐.** 특히 `Slot`은 "가드가 없으면 마운트된 서브트리
|
||||
전체가 파괴됐다 재생성"이라 파급이 큼.
|
||||
전체가 **[정정, 2026-08-13 4차 감사]** 언마운트됐다 재마운트"(작성 당시
|
||||
아직 destroy 모델 — 파괴가 아니라는 것만 정정, 파급이 크다는 결론은 그대로)라
|
||||
파급이 큼.
|
||||
|
||||
## 2. 채택 모델 — 재디스패치는 "철거 후 재구축"이 아니라 "하강 diff"
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,12 @@
|
|||
함수를 지우고 고쳐도 안전 — 우선순위가 낮은 이유. **지금 이 문서를 쓰는
|
||||
목적은 구현 착수가 아니라 설계/네이밍 논의를 미리 남겨두는 것뿐.**
|
||||
|
||||
> **⚠️ [2026-08-13 4차 감사에서 발견]** 아래 모든 `Operator.*` 예시가
|
||||
> `h:Get()`(self-lazy-핸들 계약)에 의존 — 그 계약 자체가 `question.md`
|
||||
> **0-Y**로 열려 있음(`Effect`/`Observer`/`Animate`/`Operator`가 전부
|
||||
> 같은 계약 공유 대상으로 명시됨). 우선순위가 어차피 최하위라 지금
|
||||
> 당장 막는 건 없지만, 나중에 착수 시점엔 0-Y 결론부터 확인할 것.
|
||||
|
||||
## 동기
|
||||
|
||||
`:Compute`/`:Apply`는 `fn(self, ...)` 람다를 요구하는데, `not self:Get()`처럼
|
||||
|
|
|
|||
|
|
@ -147,7 +147,11 @@ modifier/Ref의 컴포넌트 경계 통과 방식) 논의도 2026-08-04 세션
|
|||
1. **구현 시작 — 루트 `ROADMAP.md`의 M0부터.** 설계 단계는 2026-08-04 로드맵
|
||||
인수인계 라운드로 종료. `research/pre-implementation-audit.md` 우선순위1은
|
||||
2026-08-12 열일곱 번째 세션에 마지막 넷(1-3/1-4/1-10/1-11)까지 전부
|
||||
해소되어 **11개 전원 완료** — M0 착수 전 남은 유일한 게이트는:
|
||||
해소되어 **11개 전원 완료** — 이 항목(우선순위1) 기준 남은 유일한
|
||||
게이트는 아래였음(**[2026-08-13 4차 감사 정정] 위 0번 항목의 0-Y/0-Z가
|
||||
이후 같은 날 발견돼 실제로는 게이트가 하나 더 있음 — "유일한"은 그
|
||||
발견 전 서술이 안 갱신된 stale, 0-Y/0-Z가 최우선으로 먼저 해소돼야
|
||||
함**):
|
||||
- **`.claude/luau-test/`(2026-08-09 신설, 2026-08-13 기준 20개 —
|
||||
2026-08-12 열일곱 번째 세션에 16/17 추가, 2026-08-13에 세션 8~21이
|
||||
만든 커버리지 갭을 메우는 18/19/20 추가) 스파이크 결과** —
|
||||
|
|
|
|||
Loading…
Reference in a new issue