research: Context 난이도 판정 완료 — 기각 권고, 레이어드 Store 대안 확정
서브에이전트 조사: 동기 콜스택 한정 버전은 구현 난이도 낮지만(Fusion Contextual 이식 가능), quad가 정상 패턴으로 확정한 Slot 비동기 추가에서 조용히 defaultValue로 폴백하는 함정 있음 + quad-debug의 "모든 연결은 선언된 그래프" 철학과 충돌. Roblox Luau는 thread-local이 없어 완전 자동 버전은 플랫폼 한계로 사실상 불가(Node AsyncLocalStorage/Python contextvars와 동일 문제). 대안 비교 결과 레이어드 Store(__index 델리게이션, Modifier/ Source가 이미 쓰는 패턴과 동일 계열)가 서브트리 오버라이드 가치를 명시적 전달 철학·비동기 안전성 유지하며 대부분 재현 — 최종 권고안으로 채택. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
ec5fb8184b
commit
67438a172e
2 changed files with 86 additions and 38 deletions
|
|
@ -17,15 +17,22 @@
|
|||
Fusion/Vide/quad v1 소스를 서브에이전트 2개로 병렬 조사 완료, 상세는
|
||||
`research/additional-primitives-plan.md`. 요지:
|
||||
|
||||
- **키 기반 동적 컬렉션 재조정(가장 시급)**: Fusion `ForPairs`/`ForKeys`/
|
||||
`ForValues`, Vide `indexes()`/`values()`, React `key` prop에 대응하는
|
||||
프리미티브가 quad엔 전혀 없음 확인 — `Slot`은 CRUD 껍데기일 뿐 diff
|
||||
엔진이 아님. 인벤토리/리더보드/채팅로그 같은 실전 리스트 UI에 직결.
|
||||
Slot 확장으로 갈지 별도 프리미티브(가칭 `Keyed`/`ForEach`)로 갈지부터
|
||||
전혀 정해진 게 없음 — 사용자 판단 필요.
|
||||
- **키 기반 동적 컬렉션 재조정(가장 시급, 설계 스케치 진행 중)**: Fusion
|
||||
`ForPairs`/`ForKeys`/`ForValues`, Vide `indexes()`/`values()`, React
|
||||
`key` prop에 대응하는 프리미티브가 quad엔 전혀 없음 확인 — `Slot`은
|
||||
CRUD 껍데기일 뿐 diff 엔진이 아님(`pre-implementation-audit.md` 1-7번과
|
||||
같은 지점). 가칭 `state:Keyed(keyFn, renderFn) -> Slot`(State의 파생
|
||||
데이터 메소드로 프레이밍, `state:Observer(fn)`와 같은 논리) 스케치
|
||||
진행 중 — 사용자 피드백 반영 중, 상세는 `research/additional-primitives-plan.md`
|
||||
"진행 중 논의" 절.
|
||||
- Effect/Watch(자동 cleanup 공개 API), Batch/Transaction(이벤트 store-bind
|
||||
churn 문제 직결), Context(트리 전파, 단 `purity-and-effects-plan.md`
|
||||
이식성 원칙과 상충)는 부차적 후보로 확인, 착수 여부 미정.
|
||||
churn 문제 직결)은 부차적 후보로 확인, 착수 여부 미정.
|
||||
- **Context — 기각 권고로 결론(2026-08-06, 서브에이전트 난이도 판정
|
||||
완료)**: 완전 자동 버전은 Roblox Luau 플랫폼 한계로 사실상 불가, 얕은
|
||||
버전(동기 콜스택 한정)도 quad가 정상 패턴으로 확정한 Slot 비동기 추가에서
|
||||
조용히 깨짐 + quad-debug의 "모든 연결은 선언된 그래프" 철학과 충돌 —
|
||||
대신 **레이어드 Store**(`__index` 델리게이션 기반 서브트리 오버라이드)를
|
||||
실제 필요 시점에 검토할 것으로 대체 결정.
|
||||
- Untrack/Suspense/Error Boundary/Readonly는 조사 결과 새 프리미티브 없이
|
||||
기존 설계·Lua 자체 기능으로 이미 충분한 것으로 판단.
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ Fusion/Vide/react-lua 강점/약점 비교)와는 다른 질문 — 그 문서
|
|||
| 키 기반 동적 컬렉션 재조정 | **진짜 빈 자리** | 높음 — 가장 시급 |
|
||||
| Effect/Watch(자동 cleanup 포함 사이드이펙트) | 진짜 빈 자리 | 중간 |
|
||||
| Batch/Transaction | 부분적 빈 자리(이미 문서화된 churn 문제와 직결) | 중~낮 |
|
||||
| Context(트리 하위 암묵 전파) | 부분적 빈 자리, 철학과 상충 | 낮음 |
|
||||
| Context(트리 하위 암묵 전파) | **기각 권고**(난이도 판정 완료, 2026-08-06) — 레이어드 Store로 대체 | - |
|
||||
| Untrack/Peek | 빈 자리 아님 | - |
|
||||
| Suspense/비동기 경계 | 빈 자리 아님(문서화 문제로 재분류) | - |
|
||||
| Error Boundary | 빈 자리 아님 | - |
|
||||
|
|
@ -122,25 +122,31 @@ State에 이벤트를 직접 물리면... churn 비용"). 즉 여러 Source가 `
|
|||
Vide `batch.luau:4-21`가 정확히 이 역할(여러 `source:set()`을 하나의
|
||||
flush로 묶음).
|
||||
|
||||
## 4. Context(트리 하위 암묵 전파) — 부분적 빈 자리, 철학과 상충
|
||||
## 4. Context(트리 하위 암묵 전파) — 난이도 판정 완료, 기각 권고 (2026-08-06)
|
||||
|
||||
Fusion `Utility/Contextual.luau:28-88`(코루틴 스택 기반 스코프 값), Vide
|
||||
`context.luau:14-72`(scope 그래프 조회)가 대응 개념. quad는 컴포넌트
|
||||
경계를 named parameter로만 넘기기로 이미 확정했고(`component-composition-plan.md`),
|
||||
Context는 본질적으로 "명시적 전달을 건너뛰는" 도구라 quad의 명시성 철학과
|
||||
다소 충돌함.
|
||||
Fusion `Utility/Contextual.luau:28-88`(코루틴 키 weak table push-pop), Vide
|
||||
`context.luau:14-72`(scope 그래프 조회)가 대응 개념. 서브에이전트에게 구현
|
||||
난이도 평가를 위임한 결과(상세 근거는 아래 "진행 중 논의" 절의 Context
|
||||
서브섹션 참고), **동기적 저작 트리 안에서만 작동하는 얕은 버전은 구현
|
||||
난이도가 낮지만(Fusion 코드를 사실상 그대로 이식 가능), quad가 이미
|
||||
정상 패턴으로 확정한 "Slot에 이벤트 핸들러/코루틴에서 비동기로 자식이
|
||||
추가되는 경우"엔 조용히 기본값으로 폴백하는 함정이 생김**을 확인 —
|
||||
Roblox Luau에 thread-local/async-context-propagation 훅이 없어 완전
|
||||
자동화는 사실상 불가능(플랫폼 한계, 구현 노력의 문제가 아님). Node
|
||||
`AsyncLocalStorage`/Python `contextvars`가 같은 문제를 "자동"이 아니라
|
||||
"async 경계마다 명시적 캡처+재진입"으로 푸는 것과 동일한 결론.
|
||||
|
||||
Roblox ModuleScript의 `require()` 캐싱이 사실상 싱글톤 전역 접근점 역할을
|
||||
자연스럽게 하므로(`local Theme = Store({...})`를 모듈로 export해서 아무
|
||||
컴포넌트에서나 require해 직접 읽으면 됨), **단일 게임 내부 UI 시나리오에선
|
||||
이게 사실상 Context 대체재로 충분**함 — quad가 이미 허용하는 "Store는
|
||||
부작용 허용" 철학과도 맞음. 다만 (a) 서브트리별 스코프 분리가 안 되고,
|
||||
(b) `purity-and-effects-plan.md`의 이식성 원칙과 정면 충돌함(여러 게임에
|
||||
배포할 재사용 가능한 컴포넌트 라이브러리를 만들려는 순간, 테마 하나
|
||||
넘기려고 모든 중간 레이어에 `props.Theme`를 수동으로 계속 꿰어야 하는
|
||||
전형적 prop-drilling이 그대로 남음). "라이브러리로서의 지속 가능성"이라는
|
||||
프로젝트 목표와는 긴장 관계 — artworks에서 이걸 뒷받침할 "수동 전역
|
||||
context 테이블 전달" 패턴은 확인 못 함(급하지 않다는 방증).
|
||||
**기각 권고 근거**: 얕은 버전조차 (a) quad가 스스로 정상 패턴으로 확정한
|
||||
Slot 비동기 추가에서 가장 먼저 깨지고, (b) `research/debug-tooling-plan.md`의
|
||||
"모든 연결은 선언된 그래프여야 한다"는 quad-debug 철학과 충돌하는 안 보이는
|
||||
채널을 만듦. 대신 **레이어드 Store**(자식 Source 모음이 자기한테 없는 키는
|
||||
부모로 `__index` 폴백 — Modifier/Source가 이미 쓰는 델리게이션 패턴과 동일
|
||||
계열)가 Context의 핵심 가치(서브트리별 오버라이드)를 명시적 전달 철학과
|
||||
비동기 안전성을 유지하면서 대부분 재현함 — 오버라이드 Store 참조는 여전히
|
||||
prop으로 명시 전달해야 하지만, 이건 `component-composition-plan.md`가 이미
|
||||
확정한 비용이라 새로 감수하는 게 아님. Roblox `require()` 캐싱 싱글톤(단일
|
||||
전역, 서브트리 오버라이드 불가)은 오버라이드가 필요 없는 단순 케이스에는
|
||||
여전히 충분.
|
||||
|
||||
## 빈 자리 아닌 것으로 확인된 것들
|
||||
|
||||
|
|
@ -175,9 +181,8 @@ context 테이블 전달" 패턴은 확인 못 함(급하지 않다는 방증).
|
|||
2. **Effect 공개 API** — `process`/`retract`가 이미 증명한 패턴을 얇게
|
||||
노출하는 정도라 구현 비용 낮음.
|
||||
3. **Batch** — 이미 문서화된 churn 문제의 직접 해법, opt-in 유틸 수준.
|
||||
4. **Context** — 급하지 않음(Roblox `require` 캐싱이 단일 게임 시나리오는
|
||||
충분히 대체), 다만 "재사용 가능 컴포넌트 라이브러리"를 장기 목표로
|
||||
본다면 재검토 가치 — `purity-and-effects-plan.md`와 같이 봐야 함.
|
||||
4. **Context** — 기각 권고(2026-08-06 난이도 판정 완료). 서브트리 오버라이드가
|
||||
실제로 필요해지면 Context가 아니라 **레이어드 Store**를 검토할 것.
|
||||
|
||||
## 진행 중 논의 (2026-08-06 후속 세션)
|
||||
|
||||
|
|
@ -227,18 +232,54 @@ quad는 `renderFn(key, itemState)`가 항상 key+itemState를 다 주고 안 쓰
|
|||
**다음 단계**: 사용자 피드백 반영해 스케치 다듬고, 이견 없으면 M6(Slot)
|
||||
착수 시점에 `slot-plan.md`/`bind-system-plan.md`에 정식 반영.
|
||||
|
||||
### Context — 구현 난이도 판정 진행 중
|
||||
### Context — 구현 난이도 판정 완료 (2026-08-06)
|
||||
|
||||
사용자 확인: Context는 React `useContext`(Provider가 위에서 값을 심고,
|
||||
하위 어디서든 prop 없이 읽는 패턴)와 같은 개념 맞음. 구현 난이도가
|
||||
채택 여부를 사실상 결정한다는 사용자 판단에 따라 서브에이전트에게
|
||||
난이도 평가 위임(진행 중) — 특히 "컴포넌트 호출 자체는 동기적 콜스택으로
|
||||
Context 전파가 가능해 보이지만, Slot에 나중에(이벤트 핸들러/코루틴에서)
|
||||
비동기로 추가되는 자식까지 자동으로 따라오게 하는 건 훨씬 어려워 보인다"는
|
||||
사용자 직관을 검증 대상으로 명시. 결과는 후속 라운드에 반영.
|
||||
하위 어디서든 prop 없이 읽는 패턴)와 같은 개념 맞음. 구현 난이도가 채택
|
||||
여부를 사실상 결정한다는 사용자 판단에 따라 서브에이전트에게 난이도 평가를
|
||||
위임했고, 결과 수렴 완료 — **위 "4. Context" 절이 최종 결론**. 요지만
|
||||
재정리:
|
||||
|
||||
사용자가 제시한 대안(Store 병합, 타입 안전 서브셋 전달, 레이어 계층을 가진
|
||||
Store)도 같은 서브에이전트에게 난이도/효용 비교를 같이 시킴.
|
||||
- **난이도 등급**: 동기적 저작 트리에 한정한 얕은 버전 = **낮음**(Fusion
|
||||
`Contextual`의 "코루틴을 키로 하는 weak table push-pop"을 그대로 이식
|
||||
가능, quad-base 단독으로 완결, quad-roblox 분리조차 불필요). 완전
|
||||
자동(비동기 Slot 추가까지 자동 전파) = **매우 높음, 사실상 불가** —
|
||||
Roblox Luau에 thread-local/async-context-propagation 훅이 없어서 quad가
|
||||
소유하지 않는 임의의 콜백 경계(`Signal:Connect`, `task.spawn`, Promise)를
|
||||
가로챌 방법이 없음. 이건 quad 설계의 문제가 아니라 플랫폼 자체의 한계.
|
||||
- **사용자의 직관이 정확히 맞았음**: 동기 콜스택 부분은 싸지만, Slot에
|
||||
나중에(이벤트 핸들러/코루틴에서) 비동기로 자식이 추가되는 케이스에서
|
||||
Fusion 방식은 **에러 없이 조용히 `defaultValue`로 폴백**함 — "테마가
|
||||
가끔 기본값으로 보인다"는 형태의 원인 추적 어려운 버그를 만듦(Vide
|
||||
방식은 폴백 대신 에러를 던지지만, 애초에 이 시나리오를 지원 대상으로
|
||||
설계한 적이 없어 참고할 답이 없기는 마찬가지). Node
|
||||
`AsyncLocalStorage`/Python `contextvars`도 "자동"이 아니라 "async 경계마다
|
||||
명시적으로 값을 캡처해서 재진입"하는 방식으로 같은 문제를 풀고 있어,
|
||||
이식해도 결국 "prop drilling 비용"이 "매 async 경계 캡처+재진입 보일러
|
||||
플레이트 비용"으로 자리만 옮김.
|
||||
- **기각 이유(효용 대비 비용)**: 얕은 버전조차 채택할 가치가 낮음 — (1)
|
||||
`base/slot-plan.md`가 정상 패턴으로 명시한 Slot 비동기 추가에서 가장
|
||||
먼저, 가장 조용히 깨짐, (2) `research/debug-tooling-plan.md`의 "모든
|
||||
연결은 선언된 그래프여야 한다"는 quad-debug 철학과 충돌하는 안 보이는
|
||||
채널을 만듦.
|
||||
- **대안 비교 결과**: Store 병합(난이도 매우 낮음, 그러나 drilling 자체는
|
||||
안 없앰) < 타입 안전 서브셋 전달(난이도 낮음, 하지만 트리 전파 문제와는
|
||||
별개 축이라 해결책이 아님) < **레이어드 Store**(난이도 낮음~중간, Context의
|
||||
핵심 가치인 "서브트리별 오버라이드"를 대부분 재현하면서 명시적 전달
|
||||
철학·비동기 안전성 둘 다 유지 — Modifier의 제네릭 `__index` 트릭,
|
||||
Source가 State를 만족시키는 `__index` 델리게이션과 같은 이미 검증된
|
||||
패턴 계열이라 구현 리스크도 낮음) — **레이어드 Store가 최종 권고안.**
|
||||
사용자가 스스로 "어려울 것 같다"고 짐작했던 것과 달리, quad2-try에서
|
||||
금지한 `Class:Extend()`류 행위(메소드) 상속과는 다른 층위(순수 데이터
|
||||
값 조회의 `__index` 폴백일 뿐)라 실제로는 낮은 난이도로 판정됨 — 다만
|
||||
Luau 타입 레벨에서 "자식 키 ∪ 부모의 나머지 키"를 구조적으로 표현하는
|
||||
부분은 M0가 이미 검증 대상으로 잡은 `Source<T> satisfies State<T>`류
|
||||
솔버 위험과 비슷한 급이라, 도입한다면 같은 스파이크에 끼워 검증하는 게
|
||||
합리적.
|
||||
- **결론**: Context라는 이름의 범용 프리미티브는 채택하지 않음. 테마/로케일
|
||||
서브트리 오버라이드가 실제로 필요해지는 시점에 레이어드 Store를 별도
|
||||
후보로 검토(지금 착수 우선순위 낮음, 키 기반 컬렉션 재조정이 여전히
|
||||
더 시급).
|
||||
|
||||
## 참고: 조사에 사용한 소스 근거
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue