Commit graph

80 commits

Author SHA1 Message Date
cebef6d973
decide(slot): Slot:Single + Slot-in-Slot nesting, fix recompute off-by-one
Slot:Single confirmed as pure :List sugar (resolves the original
State<Frame?> offset-access motivation directly). Slot-in-Slot nesting
confirmed for component-composition uniformity: Dispatch.setLength/
setOffsetSource reused recursively keyed by the Slot object itself
(no new primitive), Slot.Length becomes a contribution-sum, teardown
is a flat destroySlotTree + explicit unbindLifetime instead of
recursive Clear(). Slot(initial?) constructor revived as pure :Add
sugar, with a new _crudUsed <-> _listed mutual-exclusion guard.

Also fixes a real off-by-one bug in the existing (pre-nesting)
Length/Offset recompute — offset was accumulating inclusive of its
own position instead of exclusive. A reentrancy guard was considered
and rejected: each Slot owns an independent bookkeeping table, so
nesting alone never re-enters the same one; genuine reentrancy is
now named UB under the same Source-to-State unidirectional-flow
principle already governing Source/State.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ymPLYAQmEYnTrnrdAwxpU
2026-08-11 13:55:31 +09:00
895a17c212
decide(slot): Slot:List index/offset ownership moves to updateFn
- Slot no longer auto-binds LayoutOrder onto mounted elements (was
  magic/layering violation) - index (raw, compacted position) and
  offset (Slot.Offset, now a public field like Length) are passed to
  updateFn as plain values; actual property binding is entirely
  updateFn's responsibility via its own userdata-managed Source
- updateFn(item, index, offset, prev, userdata) param order now
  mirrors return order (prev, userdata) instead of the reversed one
- updateFn's three branches (discard/redraw/update-only) documented
  explicitly - only updateFn knows which applies, so deciding Set
  timing outside it wastes writes on soon-to-be-discarded Sources
- fix reconcile bug: rawAdd/rawMove was using the raw data-array loop
  index instead of a compacted mounted-position counter, which could
  error once filtering was in play; introduced candidateIndex
- add duplicate-key guard (seen[key] check, ~free) and explicit
  key/index terminology disambiguation (raw data index vs key vs
  updateFn's compacted index all get confused otherwise)
- sync ROADMAP.md M6 and .claude/README.md summaries to match

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 12:06:38 +09:00
b668109eaf
decide(bind-system): :Compute trailing deps as fn positional args, fix previous ordering
Expose :Compute(fn, ...)'s trailing deps to fn as lazy State-handle
positional args (removes the closure-capture duplication/drift risk in
curried fn factories). Confirms self's lazy-handle sugar generalizes
here because trailing args are local to one call, unlike :With chains.

previous must sit right after self, before the deps pack
(fn(self, previous?, ...deps)) — not after it as first proposed:
Luau's "..." must trail the parameter list, so a fixed arg after a
generic type pack is very likely unrepresentable. Adds luau-test 15
with a negative control (old broken ordering) and positive control
(corrected ordering) to verify, plus the remaining open question
(whether heterogeneous dep types survive one generic pack).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BBBW9GakG8J3CFumTSJ8bw
2026-08-11 10:52:20 +09:00
9370acd394
decide(bind-system): Compute(fn, ...) trailing-args sugar 확정
Compute 노드는 결과를 담을 새 State 노드를 어차피 만들어야 하므로
추가 의존성 구독을 그 노드에 얹는 건 공짜 sugar로 확정. Effect/Observer는
자기 자신이 State 노드가 아니라 다중 의존성 병합에 새 노드가 실제로
필요해서 동일 sugar를 의도적으로 제외, :With(...)를 코드에 그대로
노출하도록 유지.
2026-08-11 10:29:35 +09:00
2be4fffeca
decide(bind-system): OnChange 특수 키 신설 - GetPropertyChangedSignal 바인딩, 제네릭 없이 확정
이벤트 문자열 키 패턴이 GetPropertyChangedSignal엔 안 통해서(프로퍼티 이름이
값 세팅 키와 겹침) 별도 OnChange(name) DI 키를 신설. Attribute와 달리 제네릭
타입 파라미터 없이 콜백 타입은 인라인 명시 - 이벤트 바인딩과 같은 급의 타입
안전성 트레이드오프. 전부 quad-roblox 소속, State<function>은 기존 이벤트
store-bind 메커니즘 재사용. 프로퍼티별 정적 코드 생성 안은 규모 폭발로 기각.
2026-08-10 01:08:02 +09:00
7466e9216b
decide(tween): 값-레벨 Tween<T> 래퍼로 재설계, pre-implementation-audit 1-1 해소
독립 Dispatch 핸들러("v가 Store인 아무 k나 잡는 우선순위 최상위 핸들러")
모델을 PropertyHandler가 소비하는 값-레벨 래퍼(Tween<T>)로 전환. State/
Source 언랩(범용 StoreBind)과 "이 값이 트윈 대상인가" 판단을 분리해,
일반 반응형 프로퍼티 바인딩이 Tween 파일을 거쳐가는지 불명확했던 구조적
모호함(pre-implementation-audit.md 1-1)을 해소.

- Tween.Value는 plain T만(반응성은 바깥 :Compute가 전담, 이중 경로 방지)
- hasBeenSet+활성 엔진 트윈을 3-상태 릴레이션 슬롯(RobloxTween|true|nil)
  하나로 통합, 첫 세팅은 항상 애니메이션 없이 스냅
- 활성 트윈 정리 후에만 새 값 세팅(순서 뒤바뀌면 값이 덮어써질 위험)
- 타입은 T'=T|Tween<T> 치환만으로 기존 T|State<T> 모양에 자동 통합
- useTween은 :Apply(Animate(...))로 해소, 새 옵션 필드 불필요
- PropertyHandler가 항상 매치되는 유일한 핸들러가 되어 Tween↔프로퍼티
  handler-switch에 의존하던 retract 케이스가 사라짐

구 모델은 archive/tween-special-bind-key-reversed.md로 보존. 코퍼스
전체(bind-system-plan.md/architecture.md/modifier-plan.md/ROADMAP.md/
question.md/README.md/attribute-plan.md)의 stale Tween 참조 동기화,
CLAUDE.md 세션 요약 추가.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 00:53:26 +09:00
f198fd9c6b
fix(base): 중간검토(질문 모드)에서 발견된 설계 결함 다수 수정
.claude/base/ 전체를 배치별로 리스팅해 사용자 확인을 받는 중간검토
세션 — Ref 콜백/대기자 배열의 None 소진이 무한 성장 버그였던 것을
nil로 되돌리고, isRef/isPreRef를 isState/isSource와 같은 상위-하위
합성으로 재정정, Slot CRUD 식별 기준을 element 레퍼런스에서 인덱스
기준으로 전환(ExtractAll/Get/IndexOf 신설), 컴포넌트 리프 바인딩에서
Source 직접 사용이 정상 경로라는 정정, Dispatch 직접 호출 UB 명시,
Tag retract 전제 명시, Attribute 타입 파라미터화 확정, EffectHandle
내부 Observer cascade/Subscribe GC 예외 경고 등을 반영. CLAUDE.md에
세션 요약, stale해진 research/documentation-content-map.md 일부 항목도
동기화.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYfAz3BsaTrmMM8hnzn6mj
2026-08-09 23:37:46 +09:00
5836c2d12a
decide(base): Slot:List의 data:Observer 구독을 마운트 시점 lazy bindLifetime으로 통일
Dispatch.setLength는 이미 마운트 시점에 bindLifetime을 걸었지만, Slot:List의
data:Observer(fn) 구독은 :List() 호출 시점(inst를 모르는 시점)에 즉시
생성되어 Destroy 후에도 재실행/관측을 멈출 방법이 없었음. :List()는 이제
설정만 저장하고, 실제 구독+최초 reconcile은 Slot 마운트 시점에 activateList로
수행 — 마운트 이후 :List() 호출 시 self._mounted로 즉시 활성화.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYfAz3BsaTrmMM8hnzn6mj
2026-08-09 21:42:24 +09:00
b9cfe8e99d
decide(base): Slot 형제 순서 보장(Length/Offset), bindLifetime/unbindLifetime과 canBound 이중 바인딩 게이트 통합
여러 Slot이 형제로 섞일 때 LayoutOrder 순서 보장 메커니즘을
Dispatch.setLength/setOffsetSource 누적합+리액티브 바인딩으로 확정하고
base/slot-plan.md의 관련 열린 질문을 해소. 이 과정에서 발견된 라이프사이클
게이트의 실제 모양(진짜 독립 경로는 :Subscribe()/bindLifetime 둘뿐이고
leaf 부착은 bindLifetime 호출 그 자체라는 점, canBound의 내부 플래그가
canExecute가 보는 .Subscribed와 동일 필드라는 점)을 반영해 이중 바인딩
금지 규칙과 기존 StoreBind 예제를 정정.
2026-08-09 20:58:56 +09:00
baa004ad42
decide(base): Slot CRUD(Add/Remove/Extract/Clear/Move/Swap)·요소 타입 제약 확정, Slot:List 신설
- Slot CRUD를 Add/Remove/Extract/Clear/Move/Swap 6종으로 확정, get/set 드롭
- "원시 연산 최소화" 원칙 뒤집고 Move/Swap 추가 — Extract+Add 기반 리오더가
  Parent 조작 두 번(detach+reattach)이라 무겁고, :List 없이 수동 구성한
  Slot엔 리오더 수단 자체가 없었음. Swap은 element 아닌 index 기준(element면
  위치 조회에 2n 들어 O(1) 약속이 깨짐)
- isMounted 이중 추적 분리(Slot 컨테이너 self._mounted vs 개별 element
  전역 weak-set), pre-implementation-audit.md 1-7/1-8 해소
- 요소 타입 제약 신설 — nil/None 둘 다 raw 요소로 금지, 핸들러 계층 값
  (Ref/PreRef/Observer/Effect/Modifier)은 self-ref 컨텍스트가 없어 의미
  불성립이라 즉시 error(Modifier 필드와 같은 판별 메커니즘 재사용).
  Slot<T>() 제네릭화
- Slot:List(data, updateFn, keyFn?) 신설 — 키 기반 동적 컬렉션 재조정,
  research/additional-primitives-plan.md에서 승격·통합. keyFn 생략 시
  index를 key로 사용(80% 케이스 커버, 캐스케이드 갱신 트레이드오프 명시)
- updateFn<UD>(item, index, userdata, prev)이 매 reconcile 사이클마다
  호출 — filter/toggle이 Visible 토글이 아니라 실제 파괴/재생성이 되도록
  재설계(200+ 항목에서 lazy하지 않은 문제 회피), prev 재사용이 저비용 경로
- :List가 Source를 더 이상 안 만들고 userdata로 그 권한을 updateFn에 위임 —
  result/userdata 반환값 커플링 제거, 정리 루프는 mounted가 아니라 직전
  keyIndex 전체를 순회해야 함(userdata만 살아남는 케이스 커버)
- userdata는 GC-native 값만 허용, 명시적 cleanup 필요한 값은 UB로 명문화 —
  item=nil 정리 훅 추가안은 부모 Destroy 경로에서 안 불려 절반만 동작하므로
  기각(retract가 Destroy 시 안 불리는 것과 같은 이유)
- question.md/ROADMAP.md/README.md 동기화, slot-plan.md 자체 정합성 재감사
  (stale 백로그 섹션 제거 등)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYfAz3BsaTrmMM8hnzn6mj
2026-08-09 19:21:22 +09:00
911ab559ea
fix(base): 코퍼스 전체 stale 마커/모순 감사 및 무효화된 인라인 서사 archive 이전
이미 해소된 결정이 미해결로 표시되거나 문서 간 모순되던 항목 7개 파일
수정, 뒤집힌/무효화된 설계 서술이 정정 표시만 붙은 채 본문에 남아있던
곳을 기존 archive 컨벤션대로 이전(quad2-try 리서치, Observer cleanup
계약, keyed collection state method, debug channel ReplicatedStorage).
CLAUDE.md에 세션 로그 반영.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYfAz3BsaTrmMM8hnzn6mj
2026-08-09 16:36:59 +09:00
8169b90a0e
decide(base): canBound 이름 확정, Compute previous 방어/스코핑 명확화, Modifier 핸들러값·State<Modifier> UB→error 전환
- Bound 플래그 → canBound(handle) 탑레벨 함수로 확정(canExecute와 같은 결)
- :Compute의 previous 인자 오버엔지니어링 의심 기각, 결과 노드 귀속으로 스코핑 명확화(self.Cache 안 씀 — 팬아웃 충돌 회피)
- Modifier 필드의 Ref/PreRef/Observer/Effect/Slot/Modifier 값: UB → isX predicate 기반 즉시 error
- State/Source가 Modifier를 값으로 담는 것(State<Modifier>)도 동일하게 error로 통일, Slot 등은 계속 허용
- Tween initValue/useTween 논의 신설(미확정)
- pre-implementation-audit.md 3-1/2-2/문서모순 절 해소 반영, question.md/ROADMAP.md 동기화

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYfAz3BsaTrmMM8hnzn6mj
2026-08-09 16:00:19 +09:00
1a612ecfa0
decide(base): Modifier.Override를 Overridden으로 이름 확정
Add/Remove→Added/Removed, Merge→Merged와 같은 분사형 네이밍 컨벤션을
Override에도 적용하되, override가 불규칙동사임을 반영해 정확한 과거분사
Overridden을 채택(Overrided는 오기). question.md 용어 재검토 목록에서
제거하고 관련 base/research 문서 전반에 반영.
2026-08-08 03:37:32 +09:00
54a46aaf7e
decide(base): Tag를 array-part 값 객체로 재설계, Dispatch 체인+retractUnder로 retract 전파 확정
Tag를 해시 파트 boolean DI 키에서 Modifier식 immutable clone 체이닝 값
객체로 재설계(구 모델은 archive/tag-hash-key-model-reversed.md로 보존).
이 과정에서 재귀 재-dispatch(StoreBind/Tween/NoneHandler)의 retract가
다단 체인까지 정확히 전파되지 않던 설계 공백(pre-implementation-audit.md
1-2번)이 드러나, Dispatch가 (inst,k)별 핸들러 체인을 직접 소유하고
retractUnder로 꼬리부터 정리하는 방식으로 해결.
2026-08-08 03:23:44 +09:00
9ab63863a9
decide(base): Dispatch 탑레벨 싱글톤 확정, 네이밍 케이싱 컨벤션 신설, Handler 세 번째 카테고리 명문화
Ref/Observer/PreRef leaf Handler 위치를 quad-base로 확정하며 question.md
미결 항목 해소.
2026-08-08 01:15:06 +09:00
c865e99860
decide(base): Relate 프리미티브 신설, bindLifetime/canExecute 확정, retract 필수화
- Relate(inst-weak 릴레이션, SetWeak/GetWeak/SetStrong/GetStrong, 비싱글톤)
  신설 — base.perInstanceState(inst) placeholder를 정식 대체
- bindLifetime(inst,value)/canExecute(inst,value) 탑레벨 함수로 확정,
  Relate 위에 구현(gcconn/gchold), LifetimeHandle.bind식 네임스페이싱 기각
- canExecute 시그니처를 (handle)에서 (inst,value)로 재정정 — Observer 자신의
  Subscribed 상태를 먼저, inst의 gcconn.Connected를 그 다음 확인
- store-bind 재실행 구독 메커니즘 = state:Observer(fn):Subscribe() 재사용으로 명문화
- 핸들러 계약: retract 필드는 no-op이라도 항상 정의(생략 시 핸들러 교체
  순간 크래시) — 확정
- question.md/ROADMAP.md/architecture.md/README.md 전체 동기화
2026-08-08 00:54:48 +09:00
33790df6ee
decide(base): CreatedRef 폐기, PreRef pre-pass 확정, None 소진 정정, nil-hole 방지 관용구 확정
CreatedRef 이름 완전 폐기 — Ref(default)/PreRef(default)가 이미 Compose식
Type(args) 팩토리 생성자로 확정돼 있어 별도 래퍼가 불필요했음(2026-08-04
Ref 일반화 이전 시절의 잔재). bind-system-plan.md/ROADMAP.md/question.md/
architecture.md/documentation-content-map.md 전체 동기화.

PreRef pre-pass 구현 위치 확정 — 새 Dispatch.* 함수나 flatten에 얹지 않고
이미 확정된 Dispatch.drive(inst, flattened) 자신이 두 번 순회(pre-pass +
정상 두 패스)하는 것으로 확정. flatten에 얹는 안은 재바인드 시 flatten
재호출 가능성과 충돌해 기각. 복수 PreRef는 배열 index 순서, 동적 경로로
도착한 PreRef는 전용 Handler가 즉시 error.

소진 슬롯을 nil이 아니라 None으로 — 사용자가 Luau REPL 반례로 직접 발견:
키가 촘촘한 저범위 정수에서 벗어나면(nil 구멍 포함) 순회 순서가 index
오름차순을 안 지킴, table.insert가 쓰는 #t도 구멍 있는 테이블에서 정의
안 됨. Ref 콜백/대기자 배열과 PreRef pre-pass 둘 다 None 소진으로 정정.
배열 파트 None(순수 스킵)과 해시 파트 None(NoneHandler 경유)이 다른
경로임을 명시.

props.Modifier/props.Ref forwarding에 `or None` 필수 관용구 확정 —
nil-hole 위험도가 국소적이지 않고 테이블 전체에 영향을 준다는 게 이번
실측으로 드러나 방어 필요, 기존 None 스킵 메커니즘 재사용이라 새 코드
불필요.

부수 발견/보강: Modifier() 바닥 생성자가 문서에 없던 갭 보강, Brand 태그
목록에 RefTag/PreRefTag/ModifierTag가 빠져있던 갭 보강(isRef/isPreRef는
isState와 달리 단순 항등 — PreRef가 일반 Ref 핸들러에 안 잡히려면 필수).

archive/agent-mistake.md 관례에 따라 이번 세션의 실수(Modifier.Rounded(8)
stale 치환 시 잘못된 예시로 대체)는 CLAUDE.md 세션 로그에 경위 그대로
남김.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-07 20:29:36 +09:00
98bd46af09
docs: 코퍼스 전체 정합성 감사 반영, agent-mistake.md 신설
여러 세션에 걸쳐 쌓인 stale 참조/자기모순을 서브에이전트 병렬 감사로
찾아내 전부 수정:

- bind-system-plan.md: CreatedRef {phase=...} 옵션이 폐기 이후에도 두
  곳에 방치돼 있던 것을 archive 포인터로 정리
- question.md: Ref 이름 재검토 대상 여부 자기모순 해소, framework-
  comparison-findings.md/v1-compat-plan.md §8 누락 항목 보강
- UICorner 숏핸드 개명(구 Modifier.Rounded(8))을 modifier-plan.md/
  store-semantics.md/ui-shorthand-plan.md/documentation-content-map.md/
  pre-implementation-audit.md 5곳에 전파
- canExecute(handle) 시그니처 정정을 bind-system-plan.md/
  store-semantics.md 예시 호출부에 전파
- architecture.md/ROADMAP.md/CLAUDE.md의 stale 문구·누락 참조 정정
- store-semantics.md 제목을 "State는 Source 위의 캐시 레이어"로 정정
  (Store 아님 — 사용자 확인)

archive/agent-mistake.md 신설 — 설계 반전/기각과 구분되는 세 번째
카테고리로, 에이전트가 문서 작성 중 스스로 낸 개념 혼동을 같은 세션
안에서 정정한 사례(canExecute/isHandlable 혼동, isSource 오판) 전용.
CLAUDE.md 세션 로그의 중복 서술을 옮기고 포인터만 남김.

slot-plan.md의 CRUD 의미론 갭은 사용자 요청으로 이번 라운드에서 보류.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-07 19:34:40 +09:00
d947abf17a
decide(base): None 센티널, Dispatch 네이밍, Brand 판별 메커니즘 확정
- Modifier 필드를 인라인 키/setter로 명시적으로 지우는 `None` 센티널
  확정 — merge는 안 바뀌고, 디스패치 쪽 NoneHandler가 Tween store-bind와
  같은 재귀 재디스패치로 처리(base 드라이버/개별 핸들러 시그니처 불변).
- Dispatch.getHandler/process/addHandler/drive로 오케스트레이터 이름
  공식화, isHandlable에 inst 추가, canExecute 시그니처를 (handle)->boolean
  으로 정정(zero-arg 클로저 폐기).
- isState를 Brand 공유 레지스트리로 일반화해 isObserver/isSource/isTag
  등 10종 판별자로 확장, isSource 별도 필요하다고 정정.
- Tag/Attribute retract 불필요함을 확인, 전용 문서(tag-plan.md/
  attribute-plan.md) 신설.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-07 18:10:58 +09:00
71729db816
decide(base): Compute 커링, state:Apply 확정, Effect Subscribe/Unsubscribe, 이중 바인딩 금지
- :Compute(fn)에도 Observer/Effect와 동일한 커링 권장 노트 추가
- state:Apply(factory) 확정 — ":With"/":Compute" 자동 등록 조합기였던
  백로그안 기각, Modifier:Apply와 동일한 순수 체이닝 설탕으로 재정의
- EffectHandle:Subscribe()/:Unsubscribe() 신설 — leaf 없이 쓰는 독립
  Effect 지원, :Unsubscribe()는 마지막 cleanup을 1회 트리거해야 함
- Observer/Effect 이중 바인딩(leaf 부착 + 수동 Subscribe) 금지 확정,
  Bound 플래그로 즉시 error
- ROADMAP.md M3/question.md에 반영, effect-plan.md 오기 정정
2026-08-07 16:59:40 +09:00
b7ce11cf7f
docs: 이번 세션 결정사항 코퍼스 전체 반영 감사 및 보강
세션 clear 전 정합성 점검 — 이미 커밋된 결정들이 다른 문서에 제대로
퍼져있는지 확인하고 빠진 곳을 보강:

- ROADMAP.md M3에 Observer(즉시실행 확정)/Effect(fn, state?) 체크박스
  추가(그동안 base 문서에만 있고 로드맵엔 전혀 없었음), M8 Ref 체크박스를
  :Set/:Callback/:Wait API + 파일 분리 + resume payload 정정 내용으로 갱신
- base/architecture.md 소스트리에 Modifier.luau/Blocker.luau/Effect.luau가
  통째로 누락돼 있던 것 추가(Ref.luau 코멘트도 최신 API로 갱신은 이미 완료)
- README.md의 effect-plan.md 요약이 "Observer와 관계 미해결"로 남아있던 것
  정정
- documentation-content-map.md의 "아직 문서화 보류" 목록에서 해소된
  Effect/Observer 항목 제거
- CLAUDE.md 다섯 번째 세션 절에 당시 기록 안 됐던 Override 서브타입
  미검증 이슈(modifier-plan.md 9-2번) addendum 추가

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-07 16:25:20 +09:00
4dd7659620
docs(base): Override 서브타입 Modifier 타입 시그니처 미검증 기록
FrameModifier/GuiObjectModifier처럼 서브타입 관계인 Modifier끼리
Override로 섞을 때 필드 setter 리턴 타입이 갈려 구조적 서브타이핑이
안 풀릴 수 있음을 modifier-plan.md 9-2번에 남기고, 실 Luau 테스트가
필요한 항목으로 ROADMAP.md M7에 추가.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-07 16:01:05 +09:00
18d6942366
decide(base): Modifier Override/Peek/isState 확정, Apply 사용 원칙 정리
- Modifier.Merge를 Override로 개명, 동작(필드별 baked 값 교체) 확정 —
  props.Modifier 단일 슬롯용 특수 상황으로 문서화 범위를 좁히고 Apply를
  기본 관용구로 유도
- :Peek<<T>>(key): T|State<T>|nil 필드 읽기 접근자, isState(x) 판별
  predicate(weak-key 레지스트리 기반) 신설
- Apply를 mutable로 바꾸는 방안과 "Apply 경계에서만 clone" 절충안 모두
  검토 후 기각 — immutable 전체 clone 유지
- Apply vs Override 판단 기준을 "계산 의존성 유무"로 명문화, FuncSource
  기각 사유를 기존 확정 원칙에서 연역해 문서화
- ROADMAP/question.md/pre-implementation-audit.md/documentation-content-map.md
  등 교차 참조 전부 갱신

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-07 15:45:07 +09:00
226490153e
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>
2026-08-07 14:45:57 +09:00
5c9d10df66
docs: .claude/ 코퍼스 정리 — reference/ 신설, 승격/기각 분리, 역전 이력 트리밍
base 밖으로 늘 읽을 필요 없는 참고자료(quad-v1-architecture, comparison-fusion-vide)를
새 reference/ 폴더로 분리하고, ui-shorthand-plan을 base로 승격(RoundSize 드롭+
UICorner/UIPadding/UIScale 리네임), additional-primitives-plan을 Blocker/Effect(base
승격)·Batch/Context(archive 기각)·키 기반 컬렉션 재조정(research 잔류)으로 4분할했다.
component-composition-plan의 중복 역전 서사는 기존 archive 포인터로 압축하고, archive
제목 컨벤션을 [역전됨]/[기각됨]로 분화했다. tween-plan에는 retract/canExecute 구분
메모와 트윈 옵션 값 모양 논의를 추가했다. Effect가 Observer 변형인지는 임의로
결론내지 않고 question.md에 열린 질문으로 남겼다.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-07 14:39:20 +09:00
e4d6181fcf
decide(base): Ref/PreRef 디스패치 타이밍 확정, phase 옵션은 archive로 역전
- CreatedRef의 {phase="created"|"mounted"} 옵션 폐기, 위치 기반 순서로 대체
- base 디스패치가 배열 파트(children/Ref)를 해시 파트(프로퍼티/이벤트)보다
  먼저 처리하도록 명시적으로 두 패스 계약화
- PreRef 신설: 프로퍼티/이벤트보다도 먼저 채워져야 하는 케이스(Roblox
  ChildAdded/DescendantAdded/Changed의 동기 발화 대응) 전용, Modifier/
  Store 타입 차단 + 위치 무관 호이스팅
- Ref 콜백/대기자 실행 구현 디테일(coroutine vs function 분기) 추가
- 역전된 원 서술은 archive/ref-phase-option-reversed.md로 보존
- architecture.md/question.md/documentation-content-map.md/ROADMAP.md 동기화

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-07 13:38:06 +09:00
7901ea96c4
decide(base): Modifier :Apply(factory) 팩토리 체이닝 추가
Compose 확장 함수 패턴을 콤비네이터로 흉내낸 얇은 sugar로 확정 —
modifier-plan.md 8번 절, ROADMAP.md M7 체크박스, CLAUDE.md 세션 요약 반영.
2026-08-07 11:52:39 +09:00
4b839b09e1
문서 사이트 구조/quadnomicon 신설, 프레임워크 정직 비교, Source가 State를 만족하는 서브타입 재구성
세 갈래 작업:

1. 문서 사이트 구조 확정(초심자/api/심화 3축 + quadnomicon 4번째 축) —
   research/documentation-plan.md 0번 항목, research/documentation-content-map.md
   신설(초심자 core loop 목차 초안, 파일별 분류, 심화 에세이 후보 15개).

2. quad vs Fusion/Vide/react-lua 정직 비교 — research/framework-comparison-findings.md
   신설. 3개 에이전트가 실제 소스(Fusion/Vide 로컬 클론)+웹 리서치(react-lua)로
   검증. quad 강점(Slot 단일 마운트 가드, 열린 우선순위 축, 명시적 의존성,
   다이아몬드 dedup)과 고칠 만한 약점 식별.

3. Source가 State를 구조적으로 만족하는 서브타입으로 재구성(핵심 변경) —
   store.key 타입 문제(레코드 타입 읽기/쓰기 비대칭)를 풀다가 StoreSource
   프록시 설계(2026-08-04 확정분)를 완전히 대체:
   - Source<T>가 State<T>를 구조적으로 만족(단방향 호환), Store는
     "이름 붙은 Source 모음"으로 단순화 — 별도 wrapper 생성/캐싱 불필요
   - store.key = value(__newindex) 폐기 → store.key:Set(value)
   - Store:Emit(key) → source:Emit()
   - base/store-semantics.md에 새 절로 반영, bind-system-plan.md/
     component-composition-plan.md/architecture.md 정정
   - ROADMAP.md M0에 Luau 솔버 검증 항목 추가(재귀 타입 조합)
   - 폐기된 StoreSource 원문은 archive/store-source-proxy-reversed.md에
     역전 이유·신구 비교와 함께 보존(quadnomicon 소재 후보)

전체 코퍼스 stale 참조 재점검: architecture.md 요약절, README.md 승격 누락,
Modifier UB 규칙 확장 등 발견해서 수정.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 21:29:56 +09:00
bc0a8b9f5f
quad-debug/UI 숏핸드/Attribute 타입 논의(2026-08-06) 결과 반영
- research/debug-tooling-plan.md 신설: 런타임 디버깅 플러그인 quad-debug
  설계 — BindableEvent/Function이 Studio 플러그인↔Play 중 게임 경계를
  넘는지 실측 검증 완료, 채널 위치/페이로드 제약/UUID 기반 on-demand
  compute/Element Inspector/Explorer-플러그인 트리 동기화까지 정리
- research/ui-shorthand-plan.md 신설: v1 Corner/PaddingAll/Scale 인라인
  숏핸드 조사, quad-v2 포팅 확정(RoundSize만 네이티브 UICorner로 대체돼
  불필요), quad-roblox 코어 직접 포함 원칙 확정
- research/documentation-plan.md 신설: UI 네이밍 컨벤션 + Store 부작용을
  게임 시스템에서 쓰는 패턴 문서화 뼈대
- base/bind-system-plan.md: Attribute 특수 키 타입 파라미터화 신규 논의 추가
- base/modifier-plan.md, README.md, question.md, ROADMAP.md, CLAUDE.md:
  위 신규 문서 색인/요약 반영

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 15:23:18 +09:00
470f188d0f
로드맵 인수인계 라운드(2026-08-04) 결과 반영 — ROADMAP.md 신설, 설계 단계 종료
component-composition-plan을 research/에서 base/로 승격하고, 구현 착수 전
리스크 감사에서 나온 M0 스파이크 항목(Store/State propagation, dispatch,
컴포넌트 경계 named-parameter 전달)을 문서에 반영. quad-base 테스트 mock
방향(Vide 선례 채택) 확정.
2026-08-04 17:11:23 +09:00