docs: Blocker/Effect를 base/additional-primitives.md에서 별개 파일로 재분리
State 작업 시 Effect까지 같이 볼 필요는 없다는 지적(둘은 무관한 프리미티브)과 기존 프리미티브당 1파일 컨벤션(modifier-plan.md, slot-plan.md류)에 맞춰 base/blocker-plan.md, base/effect-plan.md로 재분리. Blocker는 store-semantics.md 교차 참조를 유지, Effect는 독립 파일로 완전히 분리. 전체 상호참조 경로 갱신. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
5c9d10df66
commit
226490153e
10 changed files with 107 additions and 96 deletions
|
|
@ -34,7 +34,8 @@
|
|||
| `modifier-plan.md` | Modifier는 런타임 plug 아닌 정적 merge, immutable+clone 기반 체이닝 — 메커니즘 확정, getter 이름만 남음 |
|
||||
| `purity-and-effects-plan.md` | 컴포넌트 "순수성"이 아니라 "이식성" 문제로 재정의 — 문서 경고 수준으로 확정 |
|
||||
| `component-composition-plan.md` | 컴포넌트=플레인 함수, State/Source 읽기·쓰기 경계, Source가 State를 구조적으로 만족 — modifier/Ref 컴포넌트 경계 통과까지 전부 확정, 남은 건 API 이름뿐. **[2026-08-07 정리]** 폐기된 `StoreSource` 프록시 설계로의 역전 이력은 본문에서 빼고 `archive/store-source-proxy-reversed.md` 포인터로 압축 |
|
||||
| `additional-primitives.md` | **[2026-08-07 신설]** `Blocker`(여러 Source를 한꺼번에 바꿔도 파생값 재계산이 한 번만 되게, State 마일스톤과 함께 개발)와 `Effect`(leaf 죽음에 확정 정리) — Blocker는 메커니즘+이름 확정, Effect는 Observer와의 관계가 아직 미해결(문서 내 "미해결" 절, `question.md` 0번) |
|
||||
| `blocker-plan.md` | **[2026-08-07 신설]** `Blocker` — 여러 Source를 한꺼번에 바꿔도 파생값 재계산이 한 번만 되게, State 마일스톤(M3)과 함께 개발. 메커니즘+이름 확정 |
|
||||
| `effect-plan.md` | **[2026-08-07 신설]** `Effect` — leaf 죽음에 확정 정리, 재실행 개념 없음. Observer와의 관계가 아직 미해결(문서 내 "미해결" 절, `question.md` 0번) |
|
||||
| `ui-shorthand-plan.md` | **[2026-08-07 `research/`에서 승격]** `UICorner`/`UIPadding`/`UIScale` 인라인 편의 키 — 이름(v1 `Corner`/`PaddingAll`/`Scale`에서 Modifier 필드명과 안 겹치게 `UI` 프리픽스로 확정)·메커니즘(Handler)·패키지 배치(quad-roblox 코어)·store-bind 가능성까지 전부 확정. 이미지 라운드 트릭(`RoundSize`)은 드롭 — `archive/ui-shorthand-roundsize-dropped.md` 참고 |
|
||||
|
||||
## `reference/` — 온디맨드 참고 자료 (2026-08-07 신설)
|
||||
|
|
@ -54,7 +55,7 @@
|
|||
| `documentation-plan.md` | 문서 사이트 구조(초심자/api/심화/`quadnomicon` 4축, 백엔드별 트랙 분리) + UI 네이밍 컨벤션·Store 부작용 패턴·권장 이벤트 핸들링 3개 세부 문서 뼈대 | 하 — 착수 시점 미정, 구조/스코프만 합의된 상태 |
|
||||
| `documentation-content-map.md` | 위 4축에 실제로 뭘 채울지 `base/` 전체를 초심자/api/심화/skip으로 서베이한 콘텐츠 맵 — 초심자 core loop 목차 초안 포함 | 하 — 문서화 착수 시점의 목차/우선순위표로 쓸 것 |
|
||||
| `framework-comparison-findings.md` | quad vs Fusion/Vide/react-lua 정직한 비교(실 소스 근거) — quad 강점, 진짜 불리한 점 중 고칠 만한 것 3개, 못 고치는 트레이드오프 정리 | 하 — 사용자 검토 후 반영 여부 결정 대기 |
|
||||
| `additional-primitives-plan.md` | **[2026-08-07 범위 축소]** 확정/기각된 Effect·Blocker·Batch·Context는 `base/additional-primitives.md`·`archive/`로 분리됨 — 이제 **키 기반 동적 컬렉션 재조정**(Fusion `ForPairs`/Vide `indexes()`류에 대응하는 프리미티브가 quad엔 없음) 하나만 다룸 | 상 — 사용자 판단 대기, 착수 전 M0/M1 스코프에 영향 줄 수 있음 |
|
||||
| `additional-primitives-plan.md` | **[2026-08-07 범위 축소]** 확정/기각된 Effect·Blocker·Batch·Context는 `base/blocker-plan.md`·`base/effect-plan.md`·`archive/`로 분리됨 — 이제 **키 기반 동적 컬렉션 재조정**(Fusion `ForPairs`/Vide `indexes()`류에 대응하는 프리미티브가 quad엔 없음) 하나만 다룸 | 상 — 사용자 판단 대기, 착수 전 M0/M1 스코프에 영향 줄 수 있음 |
|
||||
| `pre-implementation-audit.md` | M0 착수 직전 크리티컬 감사(2026-08-06 신설) — `base/` 전체를 모호성/지연결정리스크/단순화후보 세 렌즈로 재검토, 11개 우선순위1(M0~M4 착수 전 확인 권장) + 11개 우선순위2 + 2개 단순화후보 | 상 — M0 착수 전 최소 우선순위1 항목 확인 권장 |
|
||||
| `v1-compat-plan.md` | v1 하위호환(compat) 레이어 — `quad-roblox-v1-compat` 패키지, v2→v1 단방향 브리지(`state:Observer()`+v1 프로퍼티 재대입), v2-in-v1/v1-in-v2 두 임베딩 방향의 기술 규칙까지 확정. quad2-try의 `quad-compat`은 빈 폴더로 실제 시도된 적 없었음을 확인 | 하 — Slot이 foreign Instance를 어떻게 다루는지만 Slot 코어 구현 시점까지 미결 |
|
||||
|
||||
|
|
@ -65,7 +66,7 @@
|
|||
| `store-source-proxy-reversed.md` | [역전됨] 2026-08-04에 확정했던 `StoreSource` 프록시 설계(Store가 Source를 감춘 별도 프록시로 감쌈) — 2026-08-06 세 번째 세션에서 "Source가 State를 구조적으로 만족" 재구성으로 완전히 대체됨. 원문·역전 이유·신구 비교표 보존, `quadnomicon` 소재 후보 |
|
||||
| `ref-phase-option-reversed.md` | [역전됨] `CreatedRef`의 `phase` 옵션 — 위치 기반 순서 + `PreRef` 신설로 대체됨 |
|
||||
| `ui-shorthand-roundsize-dropped.md` | **[기각됨, 2026-08-07 신설]** v1 `RoundSize`(이미지 9-slice 라운드 트릭) — 네이티브 `UICorner`로 대체되어 포팅 불필요. 이 판단이 한 차례 "Corner/PaddingAll/Scale 숏핸드 전체가 불필요하다"로 과잉일반화됐다가 정정된 이력 포함 |
|
||||
| `batch-rejected.md` | **[기각됨, 2026-08-07 신설]** lexical `Batch(fn)` — 코루틴 yield 위에서 구조적으로 위험해 기각, 값 기반 `Blocker`(`base/additional-primitives.md`)로 대체 |
|
||||
| `batch-rejected.md` | **[기각됨, 2026-08-07 신설]** lexical `Batch(fn)` — 코루틴 yield 위에서 구조적으로 위험해 기각, 값 기반 `Blocker`(`base/blocker-plan.md`)로 대체 |
|
||||
| `context-rejected.md` | **[기각됨, 2026-08-07 신설]** `Context`(트리 하위 암묵 전파) + 대안이던 레이어드 Store 둘 다 기각 — 명시적 타입 강제 Store 전달로 충분하다는 판단 |
|
||||
|
||||
## 참고
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# [기각됨] `Batch(fn)` — lexical block 기반 지연/합치기, `Blocker`로 대체됨
|
||||
|
||||
**기각 일시**: 2026-08-06~07. **현재 유효한 설계**: `base/
|
||||
additional-primitives.md`의 "Blocker" 절 — 이 문서가 다루는 것과 같은
|
||||
blocker-plan.md` — 이 문서가 다루는 것과 같은
|
||||
문제("여러 Source를 한꺼번에 바꿔도 파생값 재계산이 한 번만 되게")를
|
||||
값 기반으로 풀어 대체함. 이 파일은 더 이상 능동적으로 참고할 필요 없음
|
||||
(구현에 안 씀) — "왜 lexical Batch를 기각하고 값 기반 Blocker를 택했는가"가
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
# 추가 확정 프리미티브 — Blocker / Effect
|
||||
# Blocker — 여러 Source를 한꺼번에 바꿔도 파생값 재계산이 한 번만 되게
|
||||
|
||||
**상태**: base — `research/additional-primitives-plan.md`(다른 프레임워크 대비
|
||||
갭 분석)에서 갈라져 나온 두 확정 프리미티브. Batch(lexical block)/Context는
|
||||
기각되어 각각 `archive/batch-rejected.md`/`archive/context-rejected.md`로,
|
||||
아직 미확정인 키 기반 동적 컬렉션 재조정은 `research/additional-primitives-plan.md`에
|
||||
그대로 남아있음 — 이 문서는 **확정된 것만** 다룬다.
|
||||
|
||||
## Blocker — 여러 Source를 한꺼번에 바꿔도 파생값 재계산이 한 번만 되게
|
||||
**상태**: base — `research/additional-primitives-plan.md`(다른 프레임워크
|
||||
대비 갭 분석)에서 갈라져 나온 확정 프리미티브. lexical `Batch(fn)`으로
|
||||
풀려던 대안은 기각되어 `archive/batch-rejected.md`로 분리됨 — 이 문서는
|
||||
**확정된 Blocker만** 다룬다. `base/effect-plan.md`(같은 조사에서 나온
|
||||
다른 확정 프리미티브)와는 서로 무관 — Blocker는 State/Store 작업과
|
||||
밀접히 얽혀 있고 Effect는 완전히 독립된 요소라 원래도 별개 파일이었어야
|
||||
했음(2026-08-07 문서 정리에서 한 파일로 합쳤던 걸 다시 분리).
|
||||
|
||||
**왜 필요한가**: `state1, state2 -> state3`처럼 여러 소스가 한 파생값에
|
||||
합류할 때, 둘을 한 번에 바꾸면 소비자에게 두 번 전파(재계산+재대입)되는
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
bind-system-plan.md` "전파 모델 확정" 절)을 전제로 함. 별도 파일로 두되
|
||||
State와 같은 마일스톤(`ROADMAP.md` M3)에서 함께 구현할 것.
|
||||
|
||||
### 메커니즘 (확정)
|
||||
## 메커니즘 (확정)
|
||||
|
||||
```
|
||||
Blocker() -> blocker -- 생성자
|
||||
|
|
@ -47,7 +47,7 @@ gated state의 동작:
|
|||
누군가 명시적으로 `:Get()`하면 그 순간의 실제 값을 정상적으로 계산해서
|
||||
준다 — `store-semantics.md`의 "`Get()`은 라이브 레퍼런스를 준다" 원칙과 일치.
|
||||
|
||||
### 사용 예시
|
||||
## 사용 예시
|
||||
|
||||
`state1`/`state2` 각각이 아니라 **결합된 결과(`state3`) 하나에만** `:Block`을
|
||||
건다:
|
||||
|
|
@ -67,7 +67,7 @@ blocker:Off() -- onunblock 핸들 실행 → HasBlockedEmit 확인 → 딱 한
|
|||
가까운 지점)에 거는 게 원칙 — 소스가 여러 개든, 하나가 한 주기에 여러 번
|
||||
바뀌든 상관없이 이 지점 하나만 지키면 됨. 소스 쪽에 각각 거는 게 아니다.
|
||||
|
||||
### 이름 확정
|
||||
## 이름 확정
|
||||
|
||||
- 클래스: `Blocker` — `Observer`/`Modifier`/`Ref`와 같은 명사-행위자
|
||||
네이밍 관례와 일치.
|
||||
|
|
@ -80,7 +80,7 @@ blocker:Off() -- onunblock 핸들 실행 → HasBlockedEmit 확인 → 딱 한
|
|||
(gated state의 대기 플래그, `Is`/`Has` 접두어로 불리언임을 바로 알려줌).
|
||||
- 메소드: `state:Block(blocker) -> state`.
|
||||
|
||||
### 재진입(네스팅) — 의도적으로 미지원, 강한 문서화 필수
|
||||
## 재진입(네스팅) — 의도적으로 미지원, 강한 문서화 필수
|
||||
|
||||
`IsBlocked`는 카운터가 아니라 단순 불리언이고, **의도적으로 그렇게 둔다.**
|
||||
레퍼런스 카운팅으로 네스팅을 지원할 수도 있었지만, 그러면 "`On()` 여러
|
||||
|
|
@ -94,64 +94,7 @@ blocker:Off() -- onunblock 핸들 실행 → HasBlockedEmit 확인 → 딱 한
|
|||
문서(API 레퍼런스 수준)에 명시적으로 강조할 것** — 네스팅을 시도하면
|
||||
조용히 잘못된 시점에 조기 해제되는, 원인 추적이 어려운 버그로 이어짐.
|
||||
|
||||
### 상태: 핵심 메커니즘+이름 확정. 남은 건 문서화뿐
|
||||
## 상태: 핵심 메커니즘+이름 확정. 남은 건 문서화뿐
|
||||
|
||||
`quadnomicon`에서 "Batch를 기각하고 왜 Blocker로 갔는가"를 비교 설명하는
|
||||
게 좋은 소재(`archive/batch-rejected.md`와 나란히 인용).
|
||||
|
||||
---
|
||||
|
||||
## Effect — leaf 죽음에 확정 정리, 재실행 개념 없음
|
||||
|
||||
**Observer와는 별개의, 완전히 새로운 요소로 확정** — Ref/PreRef 같은
|
||||
서로 파생된 관계가 아니라 독립적으로 존재하는 primitive. Roblox엔
|
||||
`task.spawn`으로 코루틴에 반복문/타이머를 돌리는 패턴이 흔하고, Luau
|
||||
테이블엔 `__gc` 같은 GC 시점 훅이 없어서 "이게 진짜 사라지는 순간"을 아는
|
||||
유일한 방법은 `Instance.Destroying`류 명시적 신호뿐 — 이런 케이스(타이머
|
||||
시작 → leaf가 죽을 때 반드시 정지)를 위한 별도 primitive로 합의됨.
|
||||
|
||||
```
|
||||
Effect(fn) -> EffectHandle -- fn을 즉시 1회 실행, 리턴값(nil | () -> ())은
|
||||
-- 이 Effect가 바인드된 leaf가 죽을 때 정확히 1회 호출
|
||||
```
|
||||
|
||||
**재실행 개념이 없다** — 값 변화에 반응해 다시 도는 건 Observer(+클로저로
|
||||
직접 짠 cleanup)의 영역이고, Effect는 순수하게 "설치 + 확정 정리" 페어
|
||||
하나만 담당한다. children 배열에 leaf로 놓는 기존 Observer 바인딩 패턴을
|
||||
그대로 재사용(그 leaf가 살아있는 동안만 유효, leaf가 죽으면 정리 콜백
|
||||
호출). 비용은 leaf당 실제 Destroying 바인딩 하나(공유 weak table로 되는
|
||||
Observer보다 비쌈) — 필요할 때만 쓰는 걸로 충분.
|
||||
|
||||
**Observer에 cleanup 반환 계약을 추가하는 안은 기각됨** — React `useEffect`류로
|
||||
`fn`이 `nil | () -> ()`를 반환하면 다음 재실행 직전에 그걸 불러주는 안을
|
||||
검토했으나, 클로저 업밸류로 이미 쉽게 되고 잘 작동해서(`local lastConn;
|
||||
state:Observer(function() if lastConn then lastConn:Disconnect() end;
|
||||
lastConn = ... end)`) 프레임워크가 이걸 대신해줄 이유가 약하다는 판단 —
|
||||
`state:Observer(fn)` 자체는 여전히 재실행 계약만 갖고, Effect가 별도로
|
||||
"1회 설치 + 확정 정리"를 담당하는 이 분리 구조가 유지됨.
|
||||
|
||||
### ⚠️ 미해결 — Effect와 Observer의 관계, 사용자 확인 필요
|
||||
|
||||
**임의로 결론내지 않고 열어둠(2026-08-07 문서 정리 세션)**: 위 스펙은
|
||||
`Effect(fn)`를 State에 종속되지 않는 완전한 자유 함수로 서술하지만, 아래
|
||||
두 가지가 문서상 명확히 확인되지 않음:
|
||||
|
||||
1. **`Effect`가 실제로는 `state:Effect(fn)`처럼 State의 메소드(=Observer의
|
||||
변형, "재실행 없음 + 확정 정리 추가"만 다른 버전)로 구현/노출되어야
|
||||
하는 것 아닌가?** — 그렇다면 "독립 존재 가능한 프리미티브 vs 원천에
|
||||
종속된 파생 데이터"(`base/store-semantics.md`) 분류상 Effect도
|
||||
Observer처럼 후자(자유 함수 생성자 없음, 항상 `:` 메소드)로 재분류해야
|
||||
함. 지금 이 문서는 이전 조사(`research/additional-primitives-plan.md`)를
|
||||
따라 자유 함수로 서술했지만, 이게 최종 확정인지는 불명확.
|
||||
2. **`state:Observer(fn)`가 생성 시점에 `fn`을 즉시 1회 실행하는지가 문서
|
||||
어디에도 명시돼 있지 않음** — `base/bind-system-plan.md`의 Observer
|
||||
절은 "값을 안 실어줌, `fn` 본문에서 `Get()`을 다시 읽어야 함"만
|
||||
명시할 뿐 "생성 즉시 1회 호출되는지"는 다루지 않는다. Effect는
|
||||
"즉시 1회 실행"이 스펙에 명시돼 있어 이 부분만 보면 둘이 겹쳐
|
||||
보인다.
|
||||
|
||||
이 두 질문이 풀리면 Effect가 (a) 완전히 별개인 자유 함수 primitive로
|
||||
남는지, (b) `state:Effect(fn)`로 Observer 계열에 합류하는지가 갈린다.
|
||||
**확인 전까지는 위에 적은 자유 함수 스펙을 잠정 스펙으로 두되, 구현
|
||||
착수(M3~M4 전후) 전에 반드시 사용자와 다시 확인할 것** — `.claude/
|
||||
question.md`에 같은 항목 등재됨.
|
||||
60
.claude/base/effect-plan.md
Normal file
60
.claude/base/effect-plan.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# Effect — leaf 죽음에 확정 정리, 재실행 개념 없음
|
||||
|
||||
**상태**: base — `research/additional-primitives-plan.md`(다른 프레임워크
|
||||
대비 갭 분석)에서 갈라져 나온 확정 프리미티브. `base/blocker-plan.md`(같은
|
||||
조사에서 나온 다른 확정 프리미티브)와는 서로 무관 — Effect는 Store/State
|
||||
작업이나 Ref/PreRef와도 파생 관계가 아닌 완전히 독립된 요소라 별도 파일로
|
||||
둔다(2026-08-07 문서 정리에서 한 파일로 합쳤던 걸 다시 분리).
|
||||
|
||||
**Observer와는 별개의, 완전히 새로운 요소로 확정** — Ref/PreRef 같은
|
||||
서로 파생된 관계가 아니라 독립적으로 존재하는 primitive. Roblox엔
|
||||
`task.spawn`으로 코루틴에 반복문/타이머를 돌리는 패턴이 흔하고, Luau
|
||||
테이블엔 `__gc` 같은 GC 시점 훅이 없어서 "이게 진짜 사라지는 순간"을 아는
|
||||
유일한 방법은 `Instance.Destroying`류 명시적 신호뿐 — 이런 케이스(타이머
|
||||
시작 → leaf가 죽을 때 반드시 정지)를 위한 별도 primitive로 합의됨.
|
||||
|
||||
```
|
||||
Effect(fn) -> EffectHandle -- fn을 즉시 1회 실행, 리턴값(nil | () -> ())은
|
||||
-- 이 Effect가 바인드된 leaf가 죽을 때 정확히 1회 호출
|
||||
```
|
||||
|
||||
**재실행 개념이 없다** — 값 변화에 반응해 다시 도는 건 Observer(+클로저로
|
||||
직접 짠 cleanup)의 영역이고, Effect는 순수하게 "설치 + 확정 정리" 페어
|
||||
하나만 담당한다. children 배열에 leaf로 놓는 기존 Observer 바인딩 패턴을
|
||||
그대로 재사용(그 leaf가 살아있는 동안만 유효, leaf가 죽으면 정리 콜백
|
||||
호출). 비용은 leaf당 실제 Destroying 바인딩 하나(공유 weak table로 되는
|
||||
Observer보다 비쌈) — 필요할 때만 쓰는 걸로 충분.
|
||||
|
||||
**Observer에 cleanup 반환 계약을 추가하는 안은 기각됨** — React `useEffect`류로
|
||||
`fn`이 `nil | () -> ()`를 반환하면 다음 재실행 직전에 그걸 불러주는 안을
|
||||
검토했으나, 클로저 업밸류로 이미 쉽게 되고 잘 작동해서(`local lastConn;
|
||||
state:Observer(function() if lastConn then lastConn:Disconnect() end;
|
||||
lastConn = ... end)`) 프레임워크가 이걸 대신해줄 이유가 약하다는 판단 —
|
||||
`state:Observer(fn)` 자체는 여전히 재실행 계약만 갖고, Effect가 별도로
|
||||
"1회 설치 + 확정 정리"를 담당하는 이 분리 구조가 유지됨.
|
||||
|
||||
## ⚠️ 미해결 — Effect와 Observer의 관계, 사용자 확인 필요
|
||||
|
||||
**임의로 결론내지 않고 열어둠(2026-08-07 문서 정리 세션)**: 위 스펙은
|
||||
`Effect(fn)`를 State에 종속되지 않는 완전한 자유 함수로 서술하지만, 아래
|
||||
두 가지가 문서상 명확히 확인되지 않음:
|
||||
|
||||
1. **`Effect`가 실제로는 `state:Effect(fn)`처럼 State의 메소드(=Observer의
|
||||
변형, "재실행 없음 + 확정 정리 추가"만 다른 버전)로 구현/노출되어야
|
||||
하는 것 아닌가?** — 그렇다면 "독립 존재 가능한 프리미티브 vs 원천에
|
||||
종속된 파생 데이터"(`base/store-semantics.md`) 분류상 Effect도
|
||||
Observer처럼 후자(자유 함수 생성자 없음, 항상 `:` 메소드)로 재분류해야
|
||||
함. 지금 이 문서는 이전 조사(`research/additional-primitives-plan.md`)를
|
||||
따라 자유 함수로 서술했지만, 이게 최종 확정인지는 불명확.
|
||||
2. **`state:Observer(fn)`가 생성 시점에 `fn`을 즉시 1회 실행하는지가 문서
|
||||
어디에도 명시돼 있지 않음** — `base/bind-system-plan.md`의 Observer
|
||||
절은 "값을 안 실어줌, `fn` 본문에서 `Get()`을 다시 읽어야 함"만
|
||||
명시할 뿐 "생성 즉시 1회 호출되는지"는 다루지 않는다. Effect는
|
||||
"즉시 1회 실행"이 스펙에 명시돼 있어 이 부분만 보면 둘이 겹쳐
|
||||
보인다.
|
||||
|
||||
이 두 질문이 풀리면 Effect가 (a) 완전히 별개인 자유 함수 primitive로
|
||||
남는지, (b) `state:Effect(fn)`로 Observer 계열에 합류하는지가 갈린다.
|
||||
**확인 전까지는 위에 적은 자유 함수 스펙을 잠정 스펙으로 두되, 구현
|
||||
착수(M3~M4 전후) 전에 반드시 사용자와 다시 확인할 것** — `.claude/
|
||||
question.md`에 같은 항목 등재됨.
|
||||
|
|
@ -296,7 +296,7 @@ State 핸들로 넘기고 `:Get()`을 실제로 읽을 때만 계산)은 `base/b
|
|||
`Blocker` 참고.** 위 `:With`+`:Compute`만으로는 "state1, state2를 연달아
|
||||
Set하면 결합된 파생값이 두 번 재계산/재대입된다"는 문제(즉시 pull하는
|
||||
store-bind 소비자 기준)는 안 풀림 — 이건 별도 확정 프리미티브
|
||||
`base/additional-primitives.md`의 "Blocker" 절이 다룸(State 개발과 같은
|
||||
`base/blocker-plan.md`가 다룸(State 개발과 같은
|
||||
마일스톤, `ROADMAP.md` M3에서 함께 구현). lexical `Batch(fn)`으로 풀려던
|
||||
초기 시도는 코루틴 yield 위에서 구조적으로 위험해 기각됨 —
|
||||
`archive/batch-rejected.md` 참고.
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
같나요. 이것만으로 이 프로젝트는 충분하다 생각해요?" — 여러 서브에이전트
|
||||
조사 + 사용자와 라이브 논의로 계속 수렴 중. **2026-08-07 문서 정리에서
|
||||
확정/기각된 항목은 `research/additional-primitives-plan.md`에서
|
||||
분리됨**: Effect/Blocker → `base/additional-primitives.md`, Batch →
|
||||
분리됨**: Blocker → `base/blocker-plan.md`, Effect → `base/effect-plan.md`, Batch →
|
||||
`archive/batch-rejected.md`, Context(+레이어드 Store) → `archive/
|
||||
context-rejected.md`. 아래는 그중 **아직 실제로 열려있는 것만** 남김.
|
||||
|
||||
|
|
@ -32,14 +32,14 @@ context-rejected.md`. 아래는 그중 **아직 실제로 열려있는 것만**
|
|||
상세는 `research/additional-primitives-plan.md`(이제 이 주제 전용).
|
||||
- **Effect가 Observer의 변형(`state:Effect()`)인지, 완전히 독립된 free
|
||||
function인지 — 신규, 2026-08-07 문서 정리 세션에서 발견.** `base/
|
||||
additional-primitives.md`가 지금까지의 조사대로 Effect를 "재실행 없는
|
||||
effect-plan.md`가 지금까지의 조사대로 Effect를 "재실행 없는
|
||||
독립 free function"으로 서술해뒀지만, 사용자가 직접 `state:Effect()`
|
||||
형태(=Observer에 "확정 정리" 계약만 추가된 변형)로 기억하고 있어서
|
||||
확인이 필요함. 관련 하위 질문: `state:Observer(fn)`가 생성 시점에
|
||||
`fn`을 즉시 1회 실행하는지도 현재 문서 어디에도 명시돼 있지 않음(Effect는
|
||||
"즉시 1회 실행"이 스펙에 있음 — 이 부분만 보면 둘이 겹쳐 보이는 이유).
|
||||
**임의로 결론내지 않고 열어둠** — 구현 착수(M3~M4 전후) 전에 확인 필요,
|
||||
상세는 `base/additional-primitives.md`의 "미해결" 절.
|
||||
상세는 `base/effect-plan.md`의 "미해결" 절.
|
||||
- Untrack/Suspense/Error Boundary/Readonly는 조사 결과 새 프리미티브 없이
|
||||
기존 설계·Lua 자체 기능으로 이미 충분한 것으로 판단(`research/
|
||||
additional-primitives-plan.md` "빈 자리 아닌 것" 절).
|
||||
|
|
@ -200,7 +200,8 @@ context-rejected.md`. 아래는 그중 **아직 실제로 열려있는 것만**
|
|||
| Modifier(정적 merge, immutable 체이닝, State 필드 지원) | `base/modifier-plan.md` |
|
||||
| 컴포넌트화(플레인 함수, State/Source 경계, 컴포넌트 경계 modifier/Ref는 named parameter로 전달, multi-root 개념 폐기, `Modifier.Merge`) | `base/component-composition-plan.md` |
|
||||
| 컴포넌트 이식성(전역 store 참조 시 재사용성 문제) | `base/purity-and-effects-plan.md` |
|
||||
| Blocker(값 기반 emit 지연/합치기), Effect(leaf 죽음에 확정 정리 — 단 Observer와의 관계는 위 0번 열린 질문 참고) | `base/additional-primitives.md` |
|
||||
| Blocker(값 기반 emit 지연/합치기) | `base/blocker-plan.md` |
|
||||
| Effect(leaf 죽음에 확정 정리 — 단 Observer와의 관계는 위 0번 열린 질문 참고) | `base/effect-plan.md` |
|
||||
| UICorner/UIPadding/UIScale 인라인 편의 키 — 이름·메커니즘·store-bind 가능성까지 확정 | `base/ui-shorthand-plan.md` |
|
||||
| Batch(lexical) 기각, Context(+레이어드 Store) 기각 | `archive/batch-rejected.md`, `archive/context-rejected.md` |
|
||||
| Fusion/Vide 비교 리서치(주의: 일부 서술은 이후 라운드에서 뒤집힘, 문서 내 정정 표시 참고) | `reference/comparison-fusion-vide.md` |
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**상태**: research — 사용자와 라이브 논의로 대부분 수렴(2026-08-06~07),
|
||||
**2026-08-07 문서 정리에서 확정/기각된 항목을 분리**: Effect/Blocker →
|
||||
`base/additional-primitives.md`, Batch(lexical) → `archive/
|
||||
`base/blocker-plan.md`/`base/effect-plan.md`, Batch(lexical) → `archive/
|
||||
batch-rejected.md`, Context(+레이어드 Store 대안) → `archive/
|
||||
context-rejected.md`. 이 문서에는 **아직 완전히 열려있는 것 하나만** 남음
|
||||
— 키 기반 동적 컬렉션 재조정. 사용자가 "작업 전에 모든 정의를 마치고
|
||||
|
|
@ -30,11 +30,11 @@ Vide/v1/artworks 소스 근거 조사, Context 구현 난이도 판정) + 그
|
|||
| 후보 | 판정 | 현재 위치 |
|
||||
|---|---|---|
|
||||
| 키 기반 동적 컬렉션 재조정 | **진짜 빈 자리, 최우선** — 아직 열려있음 | 이 문서(아래) |
|
||||
| Effect(leaf 죽음에 확정 정리) | 채택, 단 Observer와의 관계는 미해결 | `base/additional-primitives.md` |
|
||||
| Blocker(값 기반 emit 지연/합치기) | **채택** — Batch의 대안 | `base/additional-primitives.md` |
|
||||
| Effect(leaf 죽음에 확정 정리) | 채택, 단 Observer와의 관계는 미해결 | `base/effect-plan.md` |
|
||||
| Blocker(값 기반 emit 지연/합치기) | **채택** — Batch의 대안 | `base/blocker-plan.md` |
|
||||
| Batch(함수/코루틴 스코프 lexical block) | **기각** | `archive/batch-rejected.md` |
|
||||
| Context(트리 하위 암묵 전파) + 레이어드 Store | **기각** | `archive/context-rejected.md` |
|
||||
| Observer에 cleanup 반환 계약 추가 | **기각** — 클로저 업밸류로 이미 충분 | `base/additional-primitives.md`(Effect 절에 근거만 인용) |
|
||||
| Observer에 cleanup 반환 계약 추가 | **기각** — 클로저 업밸류로 이미 충분 | `base/effect-plan.md`(근거만 인용) |
|
||||
| Untrack/Peek | 빈 자리 아님 | 아래 "빈 자리 아닌 것" 절 |
|
||||
| Suspense/비동기 경계 | 빈 자리 아님(문서화 문제로 재분류) | 아래 "빈 자리 아닌 것" 절 |
|
||||
| Error Boundary | 빈 자리 아님 | 아래 "빈 자리 아닌 것" 절 |
|
||||
|
|
@ -189,7 +189,7 @@ Slot:Add(element, index?) -- 기존 그대로, Extract로 뺀 것도 다시
|
|||
|
||||
- **quadnomicon 에세이**:
|
||||
- "왜 lexical Batch를 기각하고 대신 값 기반 Blocker를 택했는가" —
|
||||
`archive/batch-rejected.md`와 `base/additional-primitives.md`의
|
||||
`archive/batch-rejected.md`와 `base/blocker-plan.md`의
|
||||
Blocker 절을 나란히 비교.
|
||||
- "왜 Context가 없는가" — `archive/context-rejected.md` 참고.
|
||||
- "왜 push-invalidate/pull-recompute 설계가 laziness와 재계산 방지를
|
||||
|
|
@ -204,7 +204,7 @@ Slot:Add(element, index?) -- 기존 그대로, Extract로 뺀 것도 다시
|
|||
유연한 구조" — 명시적 의존성 선언(`:With`) 위에서도 실제 계산은
|
||||
조건부로 일부만 쓸 수 있다는 팁.
|
||||
- "Blocker 사용 가이드" — 파이프라인 최종 연산 지점에 배치, **네스팅
|
||||
금지를 강하게 명시**(`base/additional-primitives.md`의 "재진입" 절
|
||||
금지를 강하게 명시**(`base/blocker-plan.md`의 "재진입" 절
|
||||
참고, 문서화 시 최우선 강조 항목).
|
||||
- "여러 Source를 한꺼번에 바꿀 때 Blocker 없이도 중복 재계산을 피하는
|
||||
파이프라인/업데이트 순서 팁"(Blocker를 안 쓰는 단순 케이스용 보조 팁,
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ v1 폐기 API/버그/구조 결함 전부 v2 설계를 정당화하는 내부
|
|||
실제 일어나는 derived state)에 배치하는 게 원칙이라는 것, **네스팅
|
||||
금지를 최우선으로 강조**(겹치는 배치는 각자 새 `Blocker`를 만들 것 —
|
||||
안 지키면 조용히 잘못된 시점에 조기 해제되는 원인 추적 어려운 버그로
|
||||
이어짐) — `base/additional-primitives.md`의 "Blocker" 절
|
||||
이어짐) — `base/blocker-plan.md`
|
||||
19. 여러 Source를 한꺼번에 바꿀 때 Blocker 없이도 중복 재계산/재대입을
|
||||
피하는 파이프라인/업데이트 순서 팁(Blocker를 안 쓰는 단순 케이스용
|
||||
보조 팁) — `research/additional-primitives-plan.md` "문서화 백로그" 절
|
||||
|
|
@ -205,7 +205,7 @@ additional-primitives-plan.md`의 "문서화 백로그" 절이 원자료)**:
|
|||
후보만 있음, `Slot:Extract` 세부 시맨틱도 미정) — `research/
|
||||
additional-primitives-plan.md`(2026-08-06 신설, 설계 진행 중)
|
||||
- Effect가 `state:Effect()`로 Observer를 확장하는 형태인지, 완전히 독립된
|
||||
free function인지 (`base/additional-primitives.md`의 "미해결" 절)
|
||||
free function인지 (`base/effect-plan.md`의 "미해결" 절)
|
||||
|
||||
이 항목들은 `.claude/question.md`에도 이미 열린 질문으로 잡혀있음 — 여기선
|
||||
"확정 전엔 문서화 대상 아님"이라는 표시만 겸함.
|
||||
|
|
|
|||
22
CLAUDE.md
22
CLAUDE.md
|
|
@ -712,13 +712,19 @@ M7 착수 시 `modifier-plan.md` 8번 참고하면 됨.
|
|||
표면 없이 기존 per-instance weak-table 유틸(`base.perInstanceState`)
|
||||
재사용만으로 충분하다는 점을 추가.
|
||||
4. **`additional-primitives-plan.md`를 4갈래로 분리**: 확정된 `Blocker`/
|
||||
`Effect`는 새 `base/additional-primitives.md`로 승격(Blocker는
|
||||
State와 같은 마일스톤에서 개발하기로 해서 `store-semantics.md`에
|
||||
교차 참조 추가, `ROADMAP.md` M3에도 체크박스 반영). 기각된 `Batch`
|
||||
(lexical block)와 `Context`(+대안이던 레이어드 Store)는 각각
|
||||
`archive/batch-rejected.md`/`archive/context-rejected.md`로 분리.
|
||||
`research/additional-primitives-plan.md`엔 아직 실제로 열려있는
|
||||
것(키 기반 동적 컬렉션 재조정) 하나만 남김.
|
||||
`Effect`는 각각 새 `base/blocker-plan.md`/`base/effect-plan.md`로
|
||||
승격(Blocker는 State와 같은 마일스톤에서 개발하기로 해서
|
||||
`store-semantics.md`에 교차 참조 추가, `ROADMAP.md` M3에도 체크박스
|
||||
반영). 기각된 `Batch`(lexical block)와 `Context`(+대안이던 레이어드
|
||||
Store)는 각각 `archive/batch-rejected.md`/`archive/context-rejected.md`로
|
||||
분리. `research/additional-primitives-plan.md`엔 아직 실제로 열려있는
|
||||
것(키 기반 동적 컬렉션 재조정) 하나만 남김. **[같은 날 바로 정정]**
|
||||
처음엔 Blocker/Effect를 `base/additional-primitives.md` 한 파일로
|
||||
합쳐 승격했으나, 사용자가 "State 볼 때 Effect까지 볼 필요는 없다,
|
||||
기존 프리미티브당 1파일 컨벤션(`modifier-plan.md`/`slot-plan.md`류)에
|
||||
맞지 않는다"고 지적해 바로 두 파일로 재분리함 — Blocker는
|
||||
Store/State와 밀접해 교차 참조가 필요하지만 Effect는 완전히 독립된
|
||||
요소라 애초에 같은 파일일 이유가 없었음.
|
||||
5. **archive 제목 컨벤션을 둘로 분화** — 기존 `[역전됨]`(한 번 확정했다가
|
||||
뒤집힌 것, `store-source-proxy-reversed.md`/`ref-phase-option-reversed.md`)과
|
||||
새로 생긴 `[기각됨]`(확정한 적 없이 후보였다가 채택 안 된 것,
|
||||
|
|
@ -740,7 +746,7 @@ M7 착수 시 `modifier-plan.md` 8번 참고하면 됨.
|
|||
명시). 관련 하위 질문으로 `state:Observer(fn)`가 생성 시 `fn`을 즉시
|
||||
1회 실행하는지도 문서 어디에도 명시돼 있지 않음이 이번에 드러남(Effect는
|
||||
"즉시 1회 실행"이 스펙에 명시돼 있어 이 부분만 보면 둘이 겹쳐 보임).
|
||||
`base/additional-primitives.md`의 "미해결" 절과 `.claude/question.md`
|
||||
`base/effect-plan.md`의 "미해결" 절과 `.claude/question.md`
|
||||
0번에 반영 — 구현 착수(M3~M4 전후) 전에 반드시 재확인할 것.
|
||||
|
||||
**다음 세션이 할 일**: 안 바뀜(위 2026-08-06 네 번째 세션 절 "다음 세션이
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ Luau 코드로 부딪혀본 적 없는 세 가지**를 던지는 코드로 검
|
|||
|
||||
- [ ] `Source.luau`/`State.luau`/`Store.luau`
|
||||
- [ ] `store.key` dot-access 타입 추론 확인
|
||||
- [ ] `Blocker.luau`(`base/additional-primitives.md` 참고 — 여러 Source를
|
||||
- [ ] `Blocker.luau`(`base/blocker-plan.md` 참고 — 여러 Source를
|
||||
한꺼번에 바꿔도 파생값 재계산/재대입이 한 번만 되게 하는 primitive,
|
||||
State와 밀접히 연관돼 있어 같은 마일스톤에서 개발)
|
||||
- [ ] mock 대상 테스트
|
||||
|
|
|
|||
Loading…
Reference in a new issue