docs(base): 코퍼스 전체 정합성 감사 반영, 기각된 대안 archive 이관
병렬 서브에이전트 4개로 base/reference/research/archive 전체를 재감사해 발견한 14건 수정 — canExecute(inst,value) 시그니처 통일, Dispatch.process가 Dispatch 체인/retractUnder와 모순되던 서술 정정, "프로바이더"→Handler 잔재 정리, Overridden 오타, :Peek 반환 타입에 None 누락, Peek/isState 미정 표기 해소 누락, slot CRUD 의미론 갭 미표기, Relate 개명 반영 누락, pre-implementation-audit.md 자기모순(이미 해소된 1-2 재언급, 옛 UI 숏핸드 이름), documentation-content-map.md 신구 이름 자기모순 및 TagService/CollectionService 재발, README.md archive 색인 누락 행, agent-mistake.md 카테고리 태그 누락. modifier-plan.md 9-1번 절에 인라인으로 남아있던 기각된 Apply-mutable 대안 두 개의 전체 경위를 archive/modifier-apply-mutable-rejected.md로 이관하고 본문은 결론+포인터로 압축 — quadnomicon 개발로그 소재 확보, 컨텍스트 비대화 방지. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
959a519533
commit
4f3badf414
14 changed files with 104 additions and 56 deletions
|
|
@ -71,6 +71,8 @@
|
|||
| `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/blocker-plan.md`)로 대체 |
|
||||
| `context-rejected.md` | **[기각됨, 2026-08-07 신설]** `Context`(트리 하위 암묵 전파) + 대안이던 레이어드 Store 둘 다 기각 — 명시적 타입 강제 Store 전달로 충분하다는 판단 |
|
||||
| `modifier-apply-mutable-rejected.md` | **[기각됨, 2026-08-08 신설]** `Modifier.Apply`/setter를 mutable로 바꾸는 방안(및 "Apply 경계에서만 clone" 절충안) — 둘 다 형제 서브트리 오염 방지가 clone 비용 절감보다 우선이라 기각 |
|
||||
| `tag-hash-key-model-reversed.md` | [역전됨] 구 `Tag` 모델(해시 파트 boolean 키, 태그 개수만큼 키 갱신) — 2026-08-08 세 번째 세션에서 array-part 값 객체(`Tag(...)`, `:Added`/`:Removed`/`:Contains`/`:Apply`/`Merged`) 모델로 완전히 대체됨 |
|
||||
| `agent-mistake.md` | **[에이전트 실수, 2026-08-07 신설]** 설계 반전이 아니라 에이전트가 문서 작성 중 개념을 혼동했다가 같은 세션 안에서 스스로 정정한 사례 모음(`canExecute`/`isHandlable` 혼동, `isSource` 불필요 오판) — CLAUDE.md 세션 로그의 중복 서술을 여기로 옮기고 포인터만 남김 |
|
||||
|
||||
## 참고
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# 에이전트 실수 기록
|
||||
# [에이전트 실수] 에이전트 실수 기록
|
||||
|
||||
CLAUDE.md 세션 로그 안에 흩어져 있던 "에이전트가 같은 세션 안에서 스스로
|
||||
정정한 실수" 서술을 여기로 모음 — 최종 결론은 이미 각 `base/` 문서에
|
||||
|
|
|
|||
46
.claude/archive/modifier-apply-mutable-rejected.md
Normal file
46
.claude/archive/modifier-apply-mutable-rejected.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# [기각됨] Modifier `Apply`/setter를 mutable로 바꾸는 방안 (전체·절충안 둘 다)
|
||||
|
||||
**상태**: 후보였다가 채택 안 됨(확정한 적 없이 검토 후 기각) — `base/
|
||||
modifier-plan.md` 9-1번 절에서 이 판단의 결론(판단 기준 자체는 "동질적/
|
||||
이질적"이 아니라 "계산 의존성 유무")만 남기고 아래 전체 경위는 이 문서로
|
||||
옮김. `batch-rejected.md`/`context-rejected.md`와 같은 카테고리 —
|
||||
`quadnomicon` 소재 후보.
|
||||
|
||||
## 배경
|
||||
|
||||
2026-08-07 다섯 번째 세션 후속. `Apply` 체이닝이 호출마다 clone을 만들기
|
||||
때문에, 항목 수천 개짜리 리스트 UI처럼 무거운 Modifier를 대량으로
|
||||
재생성하는 상황에서 이 clone 비용이 누적되는 게 아닌지 사용자가 우려 —
|
||||
대안으로 (a) `Apply`/setter를 아예 mutable로 바꾸는 방안, (b) `Overridden`를
|
||||
"여러 값을 합칠 특수 상황"이 아니라 "성능 최적화 수단"으로 승격하는 방안을
|
||||
검토했음(이 문서는 (a)와 그 절충안만 다룸 — (b)는 기각되지 않고 "계산
|
||||
의존성 유무" 판단 기준으로 정리되어 `modifier-plan.md` 본문에 그대로 남음).
|
||||
|
||||
## (a) `Apply`를 mutable로 바꾸는 방안 — 기각
|
||||
|
||||
3번 절에서 immutable+clone을 확정한 이유가 정확히 "같은 modifier
|
||||
레퍼런스를 공유하는 형제 서브트리가 mutate로 오염되는 것"을 막기
|
||||
위해서였음 — 이건 특정 세션 판단이 아니라 2026-08-04부터 계속 지켜온
|
||||
하드 제약. `Apply`/setter가 mutable이면 여러 컴포넌트가 참조하는 공유
|
||||
테마 상수 하나에 어느 한쪽이 체이닝만 해도 다른 쪽까지 같이 바뀌는
|
||||
클래스의 버그가 그대로 돌아옴 — clone 비용 절감이 이 안전성보다
|
||||
우선순위가 높다고 볼 근거가 없어 기각. (단, `table.clone`은 Luau native
|
||||
shallow-copy라 Modifier 필드 수(한 자리~여남은 개) 기준 개별 clone 비용
|
||||
자체는 이미 3번 절에서 무시 가능하다고 판단됨 — 이번에 새로 문제 삼는 건
|
||||
"한 번 비용의 크기"가 아니라 "체인 길이 × 인스턴스 수로 누적되는 clone
|
||||
*횟수*"라는 별개 축.)
|
||||
|
||||
## (a-1) 절충안 — "`Apply` 진입 시 한 번만 clone하고 그 안에서는 mutable로" — 검토했으나 기각
|
||||
|
||||
clone 횟수를 체인 길이만큼이 아니라 `Apply` 호출당 1번으로 줄이자는
|
||||
아이디어(`Apply` 경계에서만 복사, 내부 setter들은 그 복사본을 그대로
|
||||
mutate).
|
||||
|
||||
**기각 이유**: 이렇게 해도 버그 클래스 자체가 안 없어짐 — `Apply`를
|
||||
거치지 않고 setter를 직접 호출하는 흔한 경로(`mod:FontSize(...)`처럼
|
||||
체이닝 자체가 아니라 단발 호출)는 여전히 mutable이라, 공유 레퍼런스에
|
||||
대고 단발 setter 하나만 불러도(예: 서브트리 어딘가에서 폰트 두께만 살짝
|
||||
바꾸는 경우) 그대로 오염됨 — "`Apply` 안에서는 안전, 밖에서는 안 안전"처럼
|
||||
**어디서 터지느냐만 달라질 뿐 문제 자체는 그대로 남는 비일관적인
|
||||
절충**이라 실익이 없음. 전부 clone하는 지금 방식이 버그 클래스를 균일하게
|
||||
없애는 유일한 방법 — 확정 유지.
|
||||
|
|
@ -35,7 +35,7 @@ quad는 이제 "스크립트"가 아니라 **라이브러리**다. DOMless Roblo
|
|||
5. **id 기반 전역 조회 폐지, Tag 시스템으로 대체.** v1의 `Store.GetObject(id)`/
|
||||
`Frame "id" {}`류는 더 이상 없음 — "id 매핑이 비현실적"이라는 게 이유.
|
||||
네임스페이싱 문제는 있지만 별도 네임스페이스 개념을 추가하면 라이브러리
|
||||
복잡도가 너무 올라간다고 판단 — 당장은 TagService 그대로 사용. **대신
|
||||
복잡도가 너무 올라간다고 판단 — 당장은 `CollectionService` 그대로 사용. **대신
|
||||
Ref가 도입됨** — 단 Ref의 용도는 "id로 조회"가 아니라 "외부에서 이미
|
||||
관리되고 있는 instance를 quad로 점진적으로 마이그레이션/래핑하기 위해
|
||||
직접 참조를 얻는 것"(`base/bind-system-plan.md`의 Ref 절 참고) — 둘을
|
||||
|
|
|
|||
|
|
@ -220,10 +220,13 @@ NoneHandler.process(inst, k, v) = process(inst, k, nil) -- 재귀 재호출
|
|||
- `Dispatch.getHandler(inst,k,v): Handler?` — 순수 스캔(`handler.isHandlable(inst,k,v)`+
|
||||
`priority`), 부작용 없음.
|
||||
- `Dispatch.process(inst,k,v)` — 오케스트레이터: `getHandler` 호출 →
|
||||
이전에 이 키를 담당하던 핸들러와 다르면 이전 핸들러의 `retract` 호출 →
|
||||
새로 매치된 핸들러의 `.process` 호출. **재귀 재디스패치(Tween/일반
|
||||
store-bind/`NoneHandler`)는 전부 이 `Dispatch.process`를 다시 부르는
|
||||
것** — 원래 있던 재귀 관례 그대로, 새로 바뀐 것 없음.
|
||||
매치된 핸들러를 `(inst,k)` 체인 꼬리에 push → 그 핸들러의 `.process`
|
||||
호출. **"이전 핸들러와 다르면 retract"라는 diff는 `Dispatch.process`
|
||||
자신의 일이 아님** — 재귀/래핑 핸들러(Tween/일반 store-bind/
|
||||
`NoneHandler`)가 재-dispatch 전에 스스로 `Dispatch.retractUnder(inst,
|
||||
k, self, newV)`를 먼저 불러 자기 밑을 정리하는 책임을 짐(정확한
|
||||
메커니즘·기각된 대안은 아래 "Dispatch 체인" 절 참고 — 전역 소유자
|
||||
슬롯 하나로 diff하는 안은 래핑 핸들러에서 깨져서 기각됨).
|
||||
- `Dispatch.addHandler(handler: Handler)` — 핸들러를 우선순위 레지스트리에
|
||||
등록. `Dispatch.process`/`getHandler`와 마찬가지로 base엔 인터페이스만
|
||||
있고, quad-roblox의 concrete Handler들(PropertyHandler/EventHandler/
|
||||
|
|
@ -1448,7 +1451,8 @@ Modifier처럼 플래튼하지 않는가"는 설계 근거를 알고 싶은 사
|
|||
- `base/store-semantics.md`에 있던 "`isInit=false`면 허용, `isInit=true`+
|
||||
생존확인 거짓이면 불허" 분기 초안은 폐기. state-invalidate 리스너
|
||||
클로저도 `base/lifecycle-pattern.md`의 "생명 바인드 유틸"(canExecute
|
||||
predicate)로 등록하면, 발화 시 `canExecute(handle)` 하나만 확인하고 거짓이면
|
||||
predicate)로 등록하면, 발화 시 `canExecute(inst, value)`(2026-08-08 세션
|
||||
최종 시그니처) 하나만 확인하고 거짓이면
|
||||
그냥 no-op — `isInit` 분기라는 별도 개념 자체가 불필요(사용자 확정:
|
||||
"canExecute 하나로 통일").
|
||||
|
||||
|
|
|
|||
|
|
@ -365,33 +365,14 @@ Modifier가 들고 있는 모든 필드는 항상 "그 시점에 이미 완전
|
|||
**동기**: `Apply` 체이닝이 호출마다 clone을 만들기 때문에, 항목 수천 개짜리
|
||||
리스트 UI처럼 무거운 Modifier를 대량으로 재생성하는 상황에서 이 clone
|
||||
비용이 누적되는 게 아닌지 사용자가 우려 — 대안으로 (a) `Apply`/setter를
|
||||
아예 mutable로 바꾸는 방안, (b) `Overridden`를 "여러 값을 합칠 특수 상황"이
|
||||
아니라 "성능 최적화 수단"으로 승격하는 방안을 검토.
|
||||
아예 mutable로 바꾸는 방안(과 그 절충안), (b) `Overridden`를 "여러 값을
|
||||
합칠 특수 상황"이 아니라 "성능 최적화 수단"으로 승격하는 방안을 검토.
|
||||
|
||||
**(a) `Apply`를 mutable로 바꾸는 방안 — 기각.** 3번 절에서 immutable+clone을
|
||||
확정한 이유가 정확히 "같은 modifier 레퍼런스를 공유하는 형제 서브트리가
|
||||
mutate로 오염되는 것"을 막기 위해서였음 — 이건 특정 세션 판단이 아니라
|
||||
2026-08-04부터 계속 지켜온 하드 제약. `Apply`/setter가 mutable이면 여러
|
||||
컴포넌트가 참조하는 공유 테마 상수 하나에 어느 한쪽이 체이닝만 해도 다른
|
||||
쪽까지 같이 바뀌는 클래스의 버그가 그대로 돌아옴 — clone 비용 절감이
|
||||
이 안전성보다 우선순위가 높다고 볼 근거가 없어 기각. (단, `table.clone`은
|
||||
Luau native shallow-copy라 Modifier 필드 수(한 자리~여남은 개) 기준
|
||||
개별 clone 비용 자체는 이미 3번 절에서 무시 가능하다고 판단됨 — 이번에
|
||||
새로 문제 삼는 건 "번 비용의 크기"가 아니라 "체인 길이 × 인스턴스 수로
|
||||
누적되는 clone *횟수*"라는 별개 축.)
|
||||
|
||||
**(a-1) 절충안 — "`Apply` 진입 시 한 번만 clone하고 그 안에서는
|
||||
mutable로" — 검토했으나 기각.** clone 횟수를 체인 길이만큼이 아니라
|
||||
`Apply` 호출당 1번으로 줄이자는 아이디어(`Apply` 경계에서만 복사, 내부
|
||||
setter들은 그 복사본을 그대로 mutate). **기각 이유**: 이렇게 해도 버그
|
||||
클래스 자체가 안 없어짐 — `Apply`를 거치지 않고 setter를 직접 호출하는
|
||||
흔한 경로(`mod:FontSize(...)`처럼 체이닝 자체가 아니라 단발 호출)는
|
||||
여전히 mutable이라, 공유 레퍼런스에 대고 단발 setter 하나만 불러도(예:
|
||||
서브트리 어딘가에서 폰트 두께만 살짝 바꾸는 경우) 그대로 오염됨 —
|
||||
"`Apply` 안에서는 안전, 밖에서는 안 안전"처럼 **어디서 터지느냐만
|
||||
달라질 뿐 문제 자체는 그대로 남는 비일관적인 절충**이라 실익이 없음.
|
||||
전부 clone하는 지금 방식이 버그 클래스를 균일하게 없애는 유일한 방법 —
|
||||
확정.
|
||||
**(a) `Apply`/setter를 mutable로 바꾸는 방안(및 "`Apply` 경계에서만 clone"
|
||||
절충안) — 둘 다 검토 후 기각.** 3번 절의 immutable+clone 하드 제약(형제
|
||||
서브트리 오염 방지)이 clone 비용 절감보다 우선순위가 높다는 결론, 절충안도
|
||||
"어디서 터지느냐만 달라질 뿐 문제 자체는 남는" 비일관적 타협이라 기각 —
|
||||
전체 경위·반박 논리는 `archive/modifier-apply-mutable-rejected.md` 참고.
|
||||
|
||||
**(b) 판단 기준 — "동질적 vs 이질적 프로퍼티"가 아니라 "필드 간 계산
|
||||
의존성 유무"로 명시.** 사용자가 처음엔 "동질적(폰트 굵기 보정처럼 연관된
|
||||
|
|
@ -461,7 +442,7 @@ Modifier 값을 변수/모듈 상수로 만들어 재사용하는, 기존에도
|
|||
시점에 실 테스트 결과에 따라 다시 좁히는 걸 목표로 로드맵에 남김
|
||||
(`ROADMAP.md` M7).
|
||||
|
||||
**`:Peek<<T>>(key): T | State<T> | nil`** — Modifier 필드를 확정하지
|
||||
**`:Peek<<T>>(key): T | State<T> | None | nil`** — Modifier 필드를 확정하지
|
||||
않고 그대로 읽는 접근자. 이름을 `Get`이 아니라 `Peek`로 정한 이유: 이
|
||||
프로젝트 전역에서 `State:Get()`은 "확정한다"(pull + recompute + 최종값
|
||||
반환)는 의미로 이미 자리잡았는데, Modifier의 읽기는 정반대(들고 있는
|
||||
|
|
@ -508,5 +489,6 @@ Source도 같이 잡아줌 — **[2026-08-07 여덟 번째 세션 정정] `isSou
|
|||
- **[해소됨]** `Overridden` 이름 — 2026-08-08 세션에서 확정(`Add`/`Remove`
|
||||
→`Added`/`Removed`, `Merge`→`Merged`와 같은 분사형 네이밍 컨벤션에
|
||||
맞춰 불규칙동사 `override`의 정확한 과거분사를 씀, `Overrided`는 오기).
|
||||
`Peek`/`isState` — 동작은 위 9번 절에서 확정, 정확한 이름은 다른
|
||||
가칭들과 마찬가지로 `.claude/question.md`의 용어 정리 라운드까지 잠정.
|
||||
`Peek`/`isState` — 동작은 위 9번 절에서 확정, 이름도 2026-08-08 다섯
|
||||
번째 세션(`.claude/question.md` 용어 정리 라운드)에서 더 나은 대안 없어
|
||||
현재 이름 그대로 최종 확정됨.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# 모듈 라이프사이클 — 프로바이더 패턴, bind/store는 누가 구현하는가 (base로 승격됨)
|
||||
# 모듈 라이프사이클 — Handler 패턴, bind/store는 누가 구현하는가 (base로 승격됨)
|
||||
|
||||
**상태**: base — "누가 store를 구현하는가"까지 포함해 전부 확정되어
|
||||
`research/`에서 승격됨(`base/architecture.md`의 "구현 착수: 소스 트리 구조
|
||||
|
|
@ -14,10 +14,12 @@ bind는 누가 어떻게 구현" / "스토어는 누가 구현해…" 절. 확
|
|||
Slot과 맞물려서 잘 생각해서 구현해야 하는 부분. **기울어진 방향**: mount가
|
||||
처리하는 게 맞아 보이지만, 그러면 확장성이 있을지가 문제. 결론: **표준 구현체는
|
||||
인터페이스만 두고, 실제 구현은 `quad-roblox` 같은 백엔드 서브패키지가 해당
|
||||
인터페이스를 구현**. 런타임에 프로바이더로 Roblox를 주입받는 방향(반대로
|
||||
"프로바이더로 base를 받는" 게 아니라) — 이유: 여긴 가상돔이 없어서, base
|
||||
쪽이 "누가 실제로 그려주는지" 모르는 채로 있다가 Roblox 프로바이더를 주입받는
|
||||
모양이 더 자연스러워 보임.
|
||||
인터페이스를 구현**. 런타임에 Handler로 Roblox를 주입받는 방향(반대로
|
||||
"Handler로 base를 받는" 게 아니라) — 이유: 여긴 가상돔이 없어서, base
|
||||
쪽이 "누가 실제로 그려주는지" 모르는 채로 있다가 Roblox Handler를 주입받는
|
||||
모양이 더 자연스러워 보임. (이름 자체는 이후 "Handler"로 확정 —
|
||||
`base/bind-system-plan.md`의 핸들러 계약 절 참고, 이 문서는 여전히
|
||||
초안 당시 표현인 "프로바이더"로 쓰여 있던 걸 정정.)
|
||||
|
||||
## pluggable 플러그 초기화는 누구 몫인가
|
||||
|
||||
|
|
|
|||
|
|
@ -134,3 +134,10 @@ Slot은 바인딩되는 순간 그 안의 요소를 전부 own해버리는 데
|
|||
- **여러 Slot이 형제로 섞일 때 순서 보장**은 아직 열려있음(위 "여러 Slot이
|
||||
섞일 때 순서 보장" 절 참고) — Roblox 단일 백엔드로는 급하지 않음, Slot
|
||||
코어 로직 구현 시점에 재검토.
|
||||
- **`add`/`remove`/`clear` CRUD 의미론 자체가 아직 정의 안 됨** — 위
|
||||
"개념" 절이 이 세 연산을 뮤터블 메타 배열에 지원되는 것처럼 나열만
|
||||
하고 정확한 동작(예: `add`가 위치를 지정하는지, `remove`가 값 동등성
|
||||
기준인지 참조 기준인지, `clear`가 재마운트 가능한 자리를 남기는지)은
|
||||
정의돼 있지 않음. `research/pre-implementation-audit.md`가 이미 지적한
|
||||
갭이고, 2026-08-07 아홉 번째 세션에서 사용자가 직접 다루기로 보류함 —
|
||||
Slot 코어 로직 구현 착수 전 반드시 확정 필요.
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ purity-and-effects-plan.md`와 연결됨).
|
|||
어떻게 되는가 — 별도 메커니즘을 새로 만들 필요 없이, `base/
|
||||
lifecycle-pattern.md`의 "생명 바인드 유틸"(canExecute predicate)을 state-
|
||||
invalidate 리스너 클로저 등록에도 그대로 재사용하면 됨: 발화 시
|
||||
`canExecute(handle)` 하나만 확인, 거짓이면 no-op. 한때 검토했던 `isInit=false`면
|
||||
`canExecute(inst, value)`(2026-08-08 세션 최종 시그니처 — `base/
|
||||
lifecycle-pattern.md` 참고) 하나만 확인, 거짓이면 no-op. 한때 검토했던 `isInit=false`면
|
||||
허용/`isInit=true`+생존확인 거짓이면 불허 분기 초안은 폐기 — `canExecute`
|
||||
하나로 통일(사용자 확정). 상세는 `base/bind-system-plan.md`의
|
||||
"Store/State/Source 온톨로지" 절 참고.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ tag:Contains(name): boolean -- 멤버십 확인
|
|||
tag:Apply(factory): U -- factory(self) 체이닝 설탕(Modifier와 동일 패턴)
|
||||
Tag.Merged(tag1, tag2, ...): Tag -- 여러 Tag의 합집합(무손실). Modifier의
|
||||
Overridden(필드 단위 덮어쓰기, 손실 있음)와
|
||||
다른 연산이라 이름도 다름 — Override는
|
||||
다른 연산이라 이름도 다름 — Overridden은
|
||||
"이미 계산된 걸 합침", Merged는 "집합을
|
||||
합침"
|
||||
```
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ base가 범용 유틸로 제공하기로 확정한 per-instance weak-keyed 저
|
|||
|
||||
## 남은 열린 질문 (단순화 후보, 사소함)
|
||||
|
||||
- Corner/PaddingAll/Scale 3개 거의 동일한 형태의 Handler를 각각 만들지,
|
||||
- UICorner/UIPadding/UIScale 3개 거의 동일한 형태의 Handler를 각각 만들지,
|
||||
`{key -> {ChildClassName, ChildDefaultName, Property, wrap=fn}}` 룩업
|
||||
테이블로 구동되는 단일 `Handlers/InstanceShorthand.luau`로 통합할지 —
|
||||
`research/pre-implementation-audit.md` 3-2번 참고, 강제 사항 아님,
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
|
||||
### architecture.md
|
||||
- 초심자: DOMless 즉시 Instance 생성 모델 / 특수 바인드 키 / Ref 기본 개념 / modifier 기본 사용법(스타일링) / Store·State·Source 온톨로지 핵심 동작 / quad-base·quad-roblox 패키지 구조 존재 사실
|
||||
- api: Class 함수형+`:` 체이닝 예외 규칙 / store 바인드=전체 교체 의미론 / Tag/retract(TagService 기반) / modifier 병합 우선순위 규칙(→심화: CSS cascade 회피 근거) / PropertyChangedSignal이 pluggable 핸들러로 구현 / Source·State·Store 타입 정의
|
||||
- api: Class 함수형+`:` 체이닝 예외 규칙 / store 바인드=전체 교체 의미론 / Tag/retract(CollectionService 기반) / modifier 병합 우선순위 규칙(→심화: CSS cascade 회피 근거) / PropertyChangedSignal이 pluggable 핸들러로 구현 / Source·State·Store 타입 정의
|
||||
- 심화: Class가 OOP 아닌 함수형인 이유 / metatable 체이닝 폐기 이유(v1 clone 문제) / id 기반 전역 조회 폐지 이유 / Style(Default) 시스템 폐기→modifier 대체 근거 / 멀티 백엔드(GTK 등) 지향 이유 / push-invalidate·pull-recompute 전파 모델 상세, 다이아몬드 의존성 해결 근거
|
||||
- skip: Tracker 미구현, lang 모듈 분리, Signal 클래스 미구현 판단 과정, 소스 트리·모노레포 구조, 테스트 전략(mock 설계)
|
||||
|
||||
|
|
@ -92,9 +92,9 @@ v1 폐기 API/버그/구조 결함 전부 v2 설계를 정당화하는 내부
|
|||
- skip: 세션 날짜/확정 이력, 문서 승격/정정 안내
|
||||
|
||||
### store-semantics.md / tween-plan.md / ui-shorthand-plan.md
|
||||
- 초심자: Store 생성+`myStore.key = value` 문법 / `store.key`로 State 얻기 개념 / Tween 기본 바인드 키+취소 기본 동작 / UI 숏핸드 인라인 키 기본 예시(`Frame { PaddingAllOffset = 50 }`)
|
||||
- 초심자: Store 생성+`myStore.key = value` 문법 / `store.key`로 State 얻기 개념 / Tween 기본 바인드 키+취소 기본 동작 / UI 숏핸드 인라인 키 기본 예시(`Frame { UIPaddingOffset = 50 }`)
|
||||
- api: `:With`+`:Compute` 시그니처(→심화) / `source:Emit()` 존재+"Get() 결과 캐시 금지" 캐비엇(버그 유발 포인트라 api에도 명시 가치 있음, →심화; 2026-08-06 후속 세션에서 `Store:Emit(key)`→`source:Emit()`로 호출부 변경, `store-semantics.md` 참고) / Tween 핸들러가 Instance 직접 받음(Ref 불필요) / retract는 Destroy 시 호출 안 됨(→심화) / UI 숏핸드 키 목록 레퍼런스 표 / Modifier와 순수 인라인 키 동등성
|
||||
- 심화: Source·Store·State·Observer 온톨로지(독립 프리미티브 vs 파생 데이터 원칙, 생성자 모양 근거) / `Emit`이 Source 전용인 이유(디버깅 그래프 무결성) / `Store<T>`의 T가 Modifier 불가인 이유 / Tween을 반응 그래프 밖 특수 bind key로 둔 이유(Fusion 반면교사) / RoundSize 포팅 불필요 vs Corner/PaddingAll/Scale 필요 이유 / "작고 opt-in 아닌 편의 기능은 코어 포함" 원칙
|
||||
- 심화: Source·Store·State·Observer 온톨로지(독립 프리미티브 vs 파생 데이터 원칙, 생성자 모양 근거) / `Emit`이 Source 전용인 이유(디버깅 그래프 무결성) / `Store<T>`의 T가 Modifier 불가인 이유 / Tween을 반응 그래프 밖 특수 bind key로 둔 이유(Fusion 반면교사) / RoundSize 포팅 불필요 vs UICorner/UIPadding/UIScale 필요 이유 / "작고 opt-in 아닌 편의 기능은 코어 포함" 원칙
|
||||
- 열린 질문(문서화 보류): tween-plan.md의 오버라이드/삭제후재시작/끝점이동 옵션 키 이름 미정 / ui-shorthand의 RoundSize 완전 드롭 여부
|
||||
- skip: 세션 정정 이력, v1 소스 조사 경위
|
||||
|
||||
|
|
|
|||
|
|
@ -518,12 +518,12 @@ M11 착수 시.
|
|||
쉬워진다든가)가 있다면 한 줄 추가하고, 없다면 "그냥 클로저 업밸류를
|
||||
쓰라"는 문서화 패턴으로 대체해 API 표면 자체를 줄이는 걸 검토.
|
||||
|
||||
### 3-2. Corner/PaddingAll/Scale 개별 Handler 대신 데이터 테이블 구동 단일 제네릭 Handler
|
||||
### 3-2. UICorner/UIPadding/UIScale 개별 Handler 대신 데이터 테이블 구동 단일 제네릭 Handler
|
||||
|
||||
**위치**: `base/ui-shorthand-plan.md` "메커니즘 — 새 아키텍처 개념
|
||||
불필요" 절.
|
||||
|
||||
**문제**: 문서는 "Corner/PaddingAll/Scale 같은 특수 키를 인식하는
|
||||
**문제**: 문서는 "UICorner/UIPadding/UIScale 같은 특수 키를 인식하는
|
||||
Handler"라고만 서술해, 사실상 3개의 거의 동일한 형태(리터럴 값 하나 →
|
||||
고정 이름 자식 찾기/생성 → 프로퍼티 세팅)의 Handler를 각각 만드는
|
||||
그림이다. 문서 자체가 "앞으로 비슷한 제안이 오면 이 선례를 따르라"고
|
||||
|
|
@ -531,8 +531,8 @@ Handler"라고만 서술해, 사실상 3개의 거의 동일한 형태(리터럴
|
|||
선형으로 늘어나는 구조.
|
||||
|
||||
**제안**: `{key -> {ChildClassName, ChildDefaultName, Property, wrap=fn}}`
|
||||
형태의 룩업 테이블 하나로 구동되는 단일 `Handlers/InstanceShorthand.luau`
|
||||
로 통합하는 안을 검토. 새 shorthand 키 추가가 "테이블에 항목 하나 추가"로
|
||||
형태의 룩업 테이블 하나로 구동되는 단일 `Handlers/InstanceShorthand.luau`로
|
||||
통합하는 안을 검토. 새 shorthand 키 추가가 "테이블에 항목 하나 추가"로
|
||||
끝나 M10 이후 유지보수 비용이 줄어듦. 강제 사항 아님, 구현 시점에 결정할
|
||||
정도의 사소한 개선 후보.
|
||||
|
||||
|
|
@ -595,8 +595,11 @@ Handler"라고만 서술해, 사실상 3개의 거의 동일한 형태(리터럴
|
|||
반영 완료. 1-10(`store.key` 레코드 필드 타이핑)을 M0로 앞당기는 것 검토,
|
||||
1-11(Modifier `__index` 트릭)도 비용이 낮으니 M0 후보로 포함 검토는 계속
|
||||
열려있음.
|
||||
- **M2(Dispatch) 착수 전**: 1-2, 1-3, 1-4를 한 번에 확정(전부 base
|
||||
dispatch 엔진의 에러/상태관리 규칙이라 같이 결정하는 게 효율적).
|
||||
- **M2(Dispatch) 착수 전**: 1-3, 1-4를 한 번에 확정(전부 base dispatch
|
||||
엔진의 에러/상태관리 규칙이라 같이 결정하는 게 효율적). 1-2는 2026-08-08
|
||||
세 번째 세션에 Dispatch 체인+`retractUnder`로 이미 해소됨(위 1-2번 항목
|
||||
참고) — 남은 건 M2 스파이크에서 다단 체인 케이스가 실제로 맞게
|
||||
동작하는지 실측하는 것뿐.
|
||||
- **M2/M3 착수 전**: 1-6(canExecute 실제 구현) 실측(1-9는 반영 완료, 위
|
||||
항목 참고).
|
||||
- **나머지**: 해당 마일스톤 착수 시점에 이 문서를 다시 열어 관련 항목만
|
||||
|
|
|
|||
|
|
@ -69,9 +69,10 @@ Ref나 네임스페이스드 조회가 필요하지 않음. Tween의 store-bind
|
|||
라이브러리가 강제하지 않고, `[Tween(key, tweenData, {onOverride=...})]`처럼
|
||||
키 설정으로 사용자가 고를 수 있게 열어둠 — `retract(inst, k, v)`가 이전
|
||||
값(v)을 받으므로 여기서 선택된 동작을 구현. `retract`가 접근해야 할 "이전에
|
||||
생성한 실제 Tween 객체"는 `base/bind-system-plan.md`가 말하는 base 제공
|
||||
범용 유틸(`inst`를 키로 하는 weak-keyed per-instance 상태 저장소)에 담아두면
|
||||
됨. **GC 확인(2026-08-07 여섯 번째 세션, 사용자 제안 검증)**: 이 저장소는
|
||||
생성한 실제 Tween 객체"는 `base/relate-plan.md`가 정의하는 `Relate`(`inst`를
|
||||
weak 키로 하는 범용 릴레이션 프리미티브, 옛 가칭 `base.perInstanceState`를
|
||||
대체)에 담아두면 됨. **GC 확인(2026-08-07 여섯 번째 세션, 사용자 제안
|
||||
검증)**: 이 저장소는
|
||||
`inst`로 weak-keyed된 바깥 릴레이션 안에 `k`별 안쪽 릴레이션이 중첩된
|
||||
구조라, `inst`가 죽으면 그 안에 담긴 Tween 인스턴스 릴레이션도 별도
|
||||
정리 로직 없이 같이 GC됨 — `base/bind-system-plan.md`의 "핸들러 내부
|
||||
|
|
|
|||
Loading…
Reference in a new issue