Commit graph

4 commits

Author SHA1 Message Date
7f3bc4da4e
docs(base): Observer/Effect Leaf dedup 추가 + Tag/Attribute 자기등록 모델 역전
State<Observer>/State<Effect>가 재-dispatch될 때 안쪽 값이 안 바뀌어도
Dispatch가 값 비교 없이 매번 재바인딩하던 것에 RefLeafHandler와 같은
old ~= v dedup을 추가(correctness 아니라 순수 성능 최적화 — == 비교가
매번 도는 Relate weak-table 쓰기보다 항상 쌈).

가장 큰 변경은 Tag/Attribute 핸들러 등록 모델 역전: 직전 커밋이 확정한
"TagHandler/AttributeKeyHandler/AttributeGroupHandler가 quad-base 모듈
로드 시점에 스스로 등록한다"는 결론 자체가 틀렸음이 드러남 — 이건
lifecycle-pattern.md가 이미 거부해둔 InitNamespace류 top-level 부작용
패턴과 같은 클래스였고, module-lifecycle-plan.md가 이미 확정해둔 "등록은
백엔드 팩토리가 BaseModule을 뮤테이션하는 시점" 원칙과 정면으로 어긋났음.
정정: 저 이름들은 참조 카운트/이름 claim 알고리즘 구현일 뿐이고,
HANDLER_PRIORITY_FALLBACK에 실제로 꽂히는 건 이를 감싸는 별도 이름의
TagFallbackHandler/AttributeKeyFallbackHandler/AttributeGroupFallbackHandler
— 등록 주체는 quad-base 모듈이 아니라 백엔드 팩토리. dispatch-core-plan.md/
tag-plan.md/attribute-plan.md/module-lifecycle-plan.md/architecture.md
전부 재반영, ROADMAP.md M10 체크리스트에 새 Fallback 파일 3개 추가(빠져
있으면 구현자가 만들 필요를 몰랐을 갭), 뒤집힌 원문은
archive/tag-attribute-load-time-registration-reversed.md.

/code-review를 두 라운드 돌려 findings 15건 확정 반영 — 죽어있던
Observer/Effect FALLBACK 동적 경로 가드(k 타입 미체크), bindLifetime
pseudocode의 canExecute/canBound 혼용, "결정 대기" 절이 삭제됐는데 비어
있다고 서술하던 3개 파일, "동적 경로 가드"가 볼드 텍스트뿐 실제 헤딩이
아니라 깨져있던 절 참조 6곳(###으로 승격), CLAUDE.md 11번째 세션 기록
~103줄→~13줄 압축, Tag/Attribute 정정이 프로즈만 고치고 놓친 pseudocode
2곳. 별개로 RefLeafHandler.isHandlable이 PostRef 도입 이후 안 갱신돼
`and not isPostRef(v)`를 빠뜨렸던 사전 존재 버그도 같이 발견·정정.
doc-check.py ERROR 0 유지.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 12:32:17 +09:00
e35905ceca
docs: 코퍼스 전체 감사 + canBound/canExecute 재분리, Ref 0-W 해소
전체 .claude/ 코퍼스를 doc-check.py + 6개 병렬 서브에이전트로 감사해
stale 세션 번호, 잘못된 인용, 자기모순 배너 등 15개 파일의 실제 사실
오류를 발견·수정. 이어서 question.md 0-W(같은 Ref 객체가 두 자리에
동시에 놓이는 문제)를 선택지 (a)로 확정 — RefLeafHandler가 새 Relate
없이 bindLifetime/unbindLifetime을 재사용해 이중 배치를 방지.

이 과정에서 bindLifetime의 이중 바인딩 가드(bound 문맥)와 State emit
전파 게이팅(execute 문맥)이 서로 다른 질문인데 canExecute 하나로
뭉쳐 있던 걸 발견 — canBound를 별도 진입점으로 재도입(판정 로직은
비공개 헬퍼 하나를 공유, 코드 중복 없음). Tag/Attribute의 미지원
백엔드 처리 모델도 여러 라운드 논의 끝에 확정: TagHandler 등은
quad-base가 스스로 등록하고, addTag/removeTag/setAttribute만 백엔드
팩토리가 채우는 타입 계약 — 안 채운 슬롯은 명시적으로 에러내는 스텁.

/code-review high가 추가로 3건(gcconn-trick-verification.md 배너,
README.md 인덱스 4곳, luau-test/STATUS.md의 재작성 지침) 발견해 정정.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXqrGrh83Sh61C3tUCMdmY
2026-08-14 11:03:24 +09:00
623c9316fe
docs: Debounce/Throttle 백로그 신설 + "emit은 항상 전파" base 역전 정정
워크트리(worktree-debounce-throttle-plan)에서 네 라운드로 다듬은 결과를
메인의 3단계 분할 구조에 맞춰 필요한 변경만 이식.

## 신설: research/debounce-throttle-plan.md

- Blocker가 이미 쓰는 게이티드 노드의 릴리스 트리거만 타이머로 바꾼 것.
  공개 Blocker API엔 "상류 신호 도착" 통지가 없어 그 위엔 못 얹음 →
  M3에서 게이트를 공용 Gate로 뺄 것.
- 두 도구의 차이는 "신호가 창 타이머를 리셋하는가" 한 비트뿐.
  공개 생성자 2개 + 내부 구현 1개(초안이 옮겨온 lodash식 maxWait 공식엔
  trailing 통과 직후 이중 발화 버그가 있었음).
- quad-base + 주입 op 2개: setTimeout(func, delay) -> Timeout /
  clearTimeout. Roblox는 task.delay/task.cancel로 배선(인자 순서 반대).
  os.clock()은 Luau 표준 라이브러리라 주입 대상 아님(diff 전용).
  Timeout = { __type_timeout: true, _native: any }.

## 역전: emit은 자기 invalid 상태와 무관하게 항상 전파된다

source-state-plan.md의 "이미 invalid였다면 그 아래로 더 전파하지 않는다"가
확정된 Observer 계약(fn이 :Get()을 안 불러도 됨)과 정면 충돌 — 액면대로면
:Get() 안 하는 Observer는 한 번 울고 영구 침묵. architecture.md가 같은
다이아몬드 문제를 pull-recompute로 설명하는 것과도 어긋나 있었음.

정정 모델: invalid는 캐시 낡음 표시일 뿐, 중복 재계산은 pull-recompute+
캐시가 막고 중복 통지는 안 접음(접으려면 Blocker 같은 명시적 게이트).

- source-state-plan.md: 전파 규칙 재작성, "다이아몬드 의존성은 무엇이
  푸는가" 절 신설, Observer 절 상호 참조. 플래튼 기각/:With 빌더 기각
  근거를 캐시 공유로 재작성(두 결론 유지, 근거 강도는 상승)
- architecture.md, blocker-plan.md(전파를 지연시키는 유일한 요소로 위치
  명문화), comparison-fusion-vide.md, framework-comparison-findings.md
- ROADMAP M0 체크리스트: 확인할 것이 정반대가 됨
- luau-test 05 → rewrite-required/(옛 모델을 통과 상태로 검증 중이었음),
  STATUS.md 개수 동기화(rewrite 6→7, done 14→13)
- audit: 05 행 정정 + "12개 전원 통과"를 액면대로 읽지 말라는 경고
- archive/invalidate-dedup-propagation-reversed.md 신설

doc-check: ERROR 0 / WARN 84(작업 전 85).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 05:22:06 +09:00
17a2e4f05f
docs(base): bind/store/state 3단계 분할, UI 숏핸드 Tween 지원, existing-instance-bind 기각
세 건을 한 커밋에 처리:

1. ui-shorthand-plan.md — Tween 지원 확정. 숏핸드가 자식 프로퍼티를 직접
   대입하지 않고 Dispatch.process(child, prop, ..., 1)로 위임하면 Tween이
   공짜로 따라옴(해석 코드는 PropertyHandler 하나에만 남음). "process 중
   inst를 바꾸는 건 키를 바꾸는 것과 같은 층위라 UB 아님"을
   dispatch-core-plan.md에 일반 규칙으로 명문화. wrap을 Tween<T>.Value에만
   적용되도록 들어올리는 헬퍼가 새로 필요한 유일한 부품. ROADMAP M10에
   통째로 빠져 있던 UI 숏핸드 항목도 보강.

2. existing-instance-bind — 기각, research/ → archive/. 사유: Length/Offset
   등 quad가 만든 트리를 전제한 부기를 바깥에서 밀고 당기는 버그 표면이
   치명적으로 넓어짐. "열려 있음"을 전제로 쓰인 본문 7곳도 같이 정정
   (architecture.md의 "아직 미정" 절은 유일 항목이었어서 절 자체를 갱신).

3. bind-system-plan.md 3단계 분할 + store-semantics.md 흡수(순수 이동):
   - base/store-plan.md 신설 — Store = 이름 붙은 Source 모음
   - base/source-state-plan.md 신설 — 반응형 코어(Source⊇State, 전파 모델,
     :With/:Compute/:Apply/previous, Observer, 구독·생명주기 게이트)
   - bind-system-plan.md 1238→203줄(인스턴스 생성·이벤트 네이밍 + 색인)
   - store-semantics.md 삭제
   참조 40여 곳 스윕. doc-check.py ERROR 0, WARN 101→84.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 05:10:49 +09:00