docs: 코퍼스 전체 사실관계 감사 — bind-system-plan.md 분할 후 stale 참조 정정

병렬 서브에이전트 4개로 base/research/reference/luau-test/audit/archive/root
전 영역 재감사. bind-system-plan.md 3단계 분할(1238→203줄) 이후 다른 문서가
여전히 옛 줄번호/위치를 가리키던 stale 참조 11곳을 실제 위치
(source-state-plan.md/event-plan.md/dispatch-core-plan.md 등)로 정정,
HUMAN_TODO.md의 이중 바인딩 게이트 서술을 canBound 재도입(11차 세션) 반영으로
정정, 날짜 없는 완결 주장 4건에 날짜 태그 추가. doc-check.py ERROR 0 유지.
This commit is contained in:
qwreey 2026-08-14 22:53:24 +09:00
parent 7002441d00
commit f8294871d2
Signed by: qwreey
GPG key ID: D28DB79297A214BD
13 changed files with 34 additions and 26 deletions

View file

@ -327,7 +327,8 @@ pull-recompute(`Get()` 시점) — Fusion식 eager 노드 없이도 다이아몬
읽기는 `:Get()` 하나로 통일 — `.value` 표기는 Ref 전용으로 좁혀짐). 값 하나만
다룰 땐 Store와 별개인 가벼운 `Source` 프리미티브를 독립적으로도 씀.
`store.key` dot-access를 타입 추론 1급 경로로 삼는 것도 3차 라운드에서
정식 확정됨 — **더 이상 열린 질문 아님**, 남은 건 정확한 API 이름뿐.
정식 확정됨 — **더 이상 열린 질문 아님**, [2026-08-04 기준] 남은 건 정확한
API 이름뿐.
상세는 `base/source-state-plan.md`의 "Source가 State를 만족함"/"핵심
온톨로지" 절 참고.

View file

@ -104,7 +104,7 @@ blocker:Off() -- onunblock 핸들 실행 → HasBlockedEmit 확인 → 딱 한
문서(API 레퍼런스 수준)에 명시적으로 강조할 것** — 네스팅을 시도하면
조용히 잘못된 시점에 조기 해제되는, 원인 추적이 어려운 버그로 이어짐.
## 상태: 핵심 메커니즘+이름 확정. 남은 건 문서화뿐
## 상태: 핵심 메커니즘+이름 확정. [2026-08-07 기준] 남은 건 문서화뿐
`quadnomicon`에서 "Batch를 기각하고 왜 Blocker로 갔는가"를 비교 설명하는
게 좋은 소재(`archive/batch-rejected.md`와 나란히 인용).

View file

@ -3,7 +3,7 @@
**상태**: base — 2026-08-04 세션(6차 라운드 이후) 채팅 논의로 핵심 골격 +
modifier/Ref 컴포넌트 경계 통과 문제까지 전부 확정. 사용자가 "지금 quad에서
가장 문제되는 부분"으로 직접 지목했던 주제였으나 이번 라운드에서 수렴 완료.
남은 건 API 이름뿐(아래 "남은 열린 질문" 참고). `base/bind-system-plan.md`
[2026-08-04 기준] 남은 건 API 이름뿐(아래 "남은 열린 질문" 참고). `base/bind-system-plan.md`
Store/State/Source 온톨로지가 먼저 확정된 뒤에야 이 논의가 열림 — 그
문서가 선행 컨텍스트.

View file

@ -65,7 +65,7 @@ init.luau`, ~1000줄) + `charm-sync`(클라/서버 상태 복제 diff 레이어)
`patch.luau:10,19-30`이 diff 페이로드에서 "안 바뀜"과 "명시적으로
지움"을 `nil`로는 구분 못 해서 `None = {__none="__none"}`을 따로
둔 이유 — quad의 배열/해시 파트 `None` 센티널 정당화(`base/
bind-system-plan.md:180-266`)와 동기 없이 같은 결론에 수렴한 사례.
dispatch-core-plan.md` "`None` 센티널" 절)와 동기 없이 같은 결론에 수렴한 사례.
새 아이디어는 아니고 인용 근거로만 가치 있음.
- **charm의 `previous` 유사 메커니즘 두 가지 — quad가 이미 확정한
`:Compute(fn)``previous` 인자(`base/source-state-plan.md` "previous"
@ -129,6 +129,6 @@ computed.test.luau:84-104` · `packages/charm/test/observe.test.luau:92-196` ·
`packages/charm-sync/src/server.luau:27-32,124-133,192-207,209-250` ·
`README.md:185-196,262-287` · `base/store-plan.md` · `base/source-state-plan.md` ·
`base/blocker-plan.md:25-44,65-68` · `base/lifecycle-pattern.md`(GC-native
원칙) · `archive/batch-rejected.md` · `base/bind-system-plan.md:180-266`
원칙) · `archive/batch-rejected.md` · `base/dispatch-core-plan.md`
(None 센티널) · `research/additional-primitives-plan.md`(Blocker/키 기반
컬렉션 미결 상태).

View file

@ -66,7 +66,7 @@ Store/Slot/Tween/bind-dispatch 설계 결정에 근거로 인용될 때만 열
|---|---|---|---|
| 전파 모델 | push+pull 하이브리드, eager 집합만 즉시 재계산, 생성순 정렬로 글리치 방지 | 순수 push, 즉시 동기 재평가, 다이아몬드 중복 재평가 미해결(저자 인정) | ⚠️ **[정정] 아래 서술은 리서치 당시(2026-08-03 이전) 검토 방향이며 이후 뒤집힘 — 최종 확정은 `base/source-state-plan.md`의 "전파 모델 확정" 절 참고**(push-invalidate는 신호만 쏘고 값은 안 실음, 재계산은 `Get()` 시점 pull-recompute로만, Fusion식 eager 노드·생성순 정렬은 아예 채택 안 함 — quad엔 그런 다단계 즉시 재계산이 필요한 소비자가 없다는 판단). 당시 스냅샷 원문: "Store는 값 자체에 항상 eager 발화, retract(구 cleanup)가 key/value를 먼저 확인" 요구사항은 Vide의 push 모델 + eval-전-retract 패턴에 더 가까움. 단 Vide의 naive BFS 대신 Fusion의 생성순 정렬 글리치 방지 규율은 채택할 것. |
| 정리/스코프 | 배열+메타테이블, dependency-agnostic, bind 시점에만 lifetime soft-check | dependency edge와 구조적 owner를 분리한 2중 관계, destroy는 owned만 cascade, 활성 스코프 destroy 하드 가드 | 둘 다 GC 비의존 eager 수동 정리 — rbvm의 Connected+GC 관용구와 정반대 축. quad의 Slot은 Vide처럼 "마운트 소유권"과 "반응 의존성"을 별개 관계로 분리하는 게 안전해 보임(`base/lifecycle-pattern.md`의 rbvm 패턴과는 다른 층위 — rbvm은 인스턴스 파괴 감지, 이건 Slot 내부 소유권 모델). |
| 키/값 디스패치 개방성 | SpecialKey 모양은 열려있으나 우선순위 4단계 하드고정 | action()은 등록 없는 태그 인식 방식이지만 key/value 버림, 콜백+우선순위만 | quad는 Fusion의 "디스패처가 key+value+target을 다 받는" 풍부함과 Vide의 "등록 없이 태그로 인식" 인체공학을 합치되, 우선순위 축은 열린 숫자 공간으로 일반화해야 함(`base/bind-system-plan.md`). |
| 키/값 디스패치 개방성 | SpecialKey 모양은 열려있으나 우선순위 4단계 하드고정 | action()은 등록 없는 태그 인식 방식이지만 key/value 버림, 콜백+우선순위만 | quad는 Fusion의 "디스패처가 key+value+target을 다 받는" 풍부함과 Vide의 "등록 없이 태그로 인식" 인체공학을 합치되, 우선순위 축은 열린 숫자 공간으로 일반화해야 함(`base/dispatch-core-plan.md`). |
## 추가로 기록해둘 것

View file

@ -73,7 +73,7 @@ v2에서 대체될 예정 — Ref 도입과 네임스페이싱 판단까지 포
1. Metatable 체이닝으로 "불변 빌더" 흉내내기 → 대신 팩토리 함수로 필요한 곳만 복사
(`raw-userinput.md` "복사 구현은 지양" 항목, `.claude/initreq/raw-userinput.md:83-86`).
2. 하드코딩된 중앙 디스패처 → pluggable `isHandlable(key,value)` + 우선순위 핸들러
레지스트리 (`base/bind-system-plan.md`).
레지스트리 (`base/dispatch-core-plan.md`).
3. 흩어진 "GC 안 되게 참조 붙잡기" 핫팩 → rbvm 스타일 `Connected` 계산 속성 +
명시적 라이프타임 홀더 (`base/lifecycle-pattern.md`).
4. mount가 여러 책임(부모 부기+파괴+child 레지스트리)을 한 모듈에 다 지는 구조 →

View file

@ -86,7 +86,7 @@ State 메소드로 두려던 초기 폼팩터가 기각된 경위만 여전히
직접 전달은 좁은 케이스에 한정, 일반적으론 State + callback이 기본"으로
못박아둬서 캡슐화 깨짐 문제 자체가 대부분 상황에서 안 생김.
- **Fusion `Observer`/`Attribute`**: quad `state:Observer(fn)` +
`bind-system-plan.md`의 Attribute 논의로 이미 커버 중, 신규 아님.
`base/attribute-plan.md`의 Attribute 논의로 이미 커버 중, 신규 아님.
- **디바운스/스로틀**: ~~Fusion/Vide/v1 어디에도 공개 프리미티브로 없음 —
세 레포 모두 없다는 것 자체가 "quad도 굳이 안 만들어도 된다"는 정황.~~
**[2026-08-14 뒤집힘]** 사용자가 직접 "`Blocker`와 유사하게 만들어야

View file

@ -14,8 +14,9 @@
(quad 모듈 내부+CollectionService 태그), 페이로드 제약(순수 직렬화 값만),
UUID 기반 on-demand compute, Element Inspector, flash 범위 축소까지
설계가 한 라운드 더 수렴함(아래 "핵심 설계 방향" 7/8번, React DevTools
절 4번). **남은 건 세부 API 이름과 구현 착수뿐** — 남은 열린 질문은 전부
후순위/백로그 표시된 것들, 다음 세션에서 뭔가 막혀있지 않음.
절 4번). **[2026-08-06 기준] 남은 건 세부 API 이름과 구현 착수뿐** —
남은 열린 질문은 전부 후순위/백로그 표시된 것들, 다음 세션에서 뭔가
막혀있지 않음.
## 배경 — 팀원 피드백 원문 요지
@ -98,7 +99,7 @@ quad2-try, artworks)를 조사, 일반 지식으로 Roblox 엔진 제약도 확
### 1. "존재하는 State 목록"이 아니라 "무엇이 무엇에 연결됐는가" — 사용자 확정
`bind-system-plan.md`에 이미 있듯 State는 `store.key`로 접근할 때마다
`base/store-plan.md`에 이미 있듯 State는 `store.key`로 접근할 때마다
매번 새로 만들어지는 ephemeral 캐시 핸들이라 "지금 존재하는 State 목록"이라는
개념 자체가 성립하지 않음. **사용자가 이 논의 중 직접 정정**: 값 목록을
보여주는 대신, Frame을 선택했을 때 "어디에 어떻게 훅이 연결돼 있는지", "이
@ -256,7 +257,7 @@ trace 이벤트 페이로드는 처음부터 함수/클로저 없이 **순수
### 6. "관측해야 실체화된다" 원칙 — quad-debug 자신이 위반하면 안 됨
`bind-system-plan.md`의 전역 원칙: 어떤 파생값도 `:Get()`으로 직접
`base/source-state-plan.md`의 전역 원칙: 어떤 파생값도 `:Get()`으로 직접
읽히기 전까지 계산되지 않음. quad-debug UI가 트리뷰를 그리면서 모든 State를
자동으로 펼쳐 값을 미리 읽어버리면, 원래 필요 없었을 계산을 디버그 도구가
유발하는 부작용이 생김 — **디버그 도구 자체도 lazy해야 함**: 사용자가 UI에서

View file

@ -139,7 +139,7 @@ UICorner/UIPadding/UIScale 숏핸드가 만드는 자식)는 `_`나 `QUAD_` 같
**뼈대(아직 설계 아님, 물음표만)**:
- **"왜 thin wrapper를 안 주는가"**를 설명하는 절 — 메모리 낭비(클로저
래핑 비용)와 오버엔지니어링(Modifier 정적 flatten과 경쟁하는 두 번째
쓰기 경로, KV 핸들러 분기 비용)이 핵심 논거. `bind-system-plan.md`의
쓰기 경로, KV 핸들러 분기 비용)이 핵심 논거. `base/event-plan.md`의
결정문을 그대로 요약하면 될 듯.
- **권장 이벤트 핸들링 패턴** 자체 — Instance가 필요하면 Ref로 캡쳐해서
쓰는 예제, Store/Source를 만들고 State로 파이핑되는 초기점을 바꿔가며

View file

@ -83,7 +83,7 @@
외부로 반출/장기 보관되는 경우. 이건 이미 권장하지 않는 사용 패턴이고,
Ref의 관례(React `useRef`와 동일한 수준 — 만든 컴포넌트 자신이 쓰거나
자식에게 넘겨 쓰는 용도, 경계를 넘어 반출/전역 보관하지 않음)를
`base/bind-system-plan.md`에 명시적으로 문서화하는 것으로 충분 —
`base/ref-plan.md`에 명시적으로 문서화하는 것으로 충분 —
런타임 추적이 아니라 관례 문서화가 맞는 대응. `Tag`/`Attribute`/`Tween`
같이 quad가 실제로 소유·관리하는 요소에 대해서는 더 자세한 전용
디버깅 유틸(quad-debug 백로그)을 제공할 수 있고 그게 투자 대비 가치가

View file

@ -363,7 +363,7 @@ M7의 전제가 Luau 공식 동작대로 성립함. 별도로, 프로퍼티에 A
### 2-1. Source가 State를 만족하는 제네릭 검증이 실패했을 때의 대안(Plan B)이 전혀 없음
**[해소됨, 2026-08-13 첫 실측 라운드]** 검증 자체는
`08-type-source-satisfies-state.luau`(`luau-test/review-required/`)로 실행돼 핵심 질문(Source가
`08-type-source-satisfies-state.luau`(`luau-test/STATUS.md` 기준 `done/`)로 실행돼 핵심 질문(Source가
State를 구조적으로 만족)이 통과했음 — 아래 "검증이 실패했을 때"라는
전제 자체가 (핵심 케이스에 한해) 더 이상 미래형이 아님. 다만 통과와
별개로 좁은 잔여 케이스(`State<T>`가 자기 자신을 다른 타입 인자로

View file

@ -10,9 +10,10 @@
## 1. 선행 조사: quad2-try의 `quad-compat`은 실제로 시도된 적 없음
`base/bind-system-plan.md:715`에서 quad2-try의 서브패키지 9개(`quad-docs`,
`quad-debug`, `quad-compat`, `quad-2`, `quad-roblox`, `quad-lang`, `quad-gtk`,
`quad-core` 등)를 나열하며 "`quad-core` 밖엔 참고할 게 없다"고 기록돼있는데,
`archive/quad2-try-research-findings-rejected.md`에서 quad2-try의 서브패키지
9개(`quad-docs`, `quad-debug`, `quad-compat`, `quad-2`, `quad-roblox`,
`quad-lang`, `quad-gtk`, `quad-core` 등)를 나열하며 "`quad-core` 밖엔
참고할 게 없다"고 기록돼있는데,
직접 확인한 결과 `out/quad-compat/`**파일이 0개인 완전히 빈 디렉토리**.
compat.lua나 어댑터 코드는 전혀 없고, README/커밋 메시지에도 "왜 포기했는지"
단서가 없음 — 애초에 착수된 적이 없다는 뜻.
@ -110,7 +111,8 @@ v2 위에 재현하려 하지 말고, **v1을 그대로, 수정 없이 계속
"v1 컴포넌트를 그대로 두고 옆에 놓기"에는 애초에 적용되지 않음.
2. **v2→v1 값 전달(사용자가 든 예시)도 이미 있는 재료로 충분히 얇음**:
- v2 쪽: `state:Observer()`를 인자 없이 호출하면 "이 State를 계속
능동 관측 상태로 유지"하는 유틸로 동작(`base/bind-system-plan.md:441`)
능동 관측 상태로 유지"하는 유틸로 동작(`base/source-state-plan.md`
"인자 없는 `state:Observer()`" 절)
— 이걸로 lazy를 포기하고 항상 최신값이 계산되게 강제하는 부분이 이미
설계돼 있음. 사용자가 말한 "포기하고 전부 관측된 값으로" 정확히 이 API.
- v1 쪽: 만들어진 v1 인스턴스에 `instance.Text = value`처럼 그냥
@ -258,7 +260,7 @@ v2 트리 안에 과거 v1 컴포넌트를 리프로 박아넣는 것, (B) 기
브리지가 흡수해야 하는 케이스가 있는지 — 단순 프로퍼티 재대입만으로
충분한 범위인지 실사용 예시로 확인 필요.
- (2순위 문법 설탕 어댑터를 실제 채택할 경우) 이벤트 self 관습을 compat에서
되살릴 때, `base/bind-system-plan.md`가 명시한 반대 근거 4번(quad-debug
되살릴 때, `base/event-plan.md`가 명시한 반대 근거 4번(quad-debug
추적 밖 mutate 경로)을 어떻게 처리할지 — quad-debug는 어차피 후순위라
지금 결정 불필요할 수도 있음.

View file

@ -90,12 +90,16 @@ op만 주입(웹의 `className`/`data-*` 대응 때문). 상세는
에이전트가 A 섹션을 재작성해야 함.** `bindLifetime`/`canExecute`/
`unbindLifetime` 재정정으로 A가 폐기된 모델(`canBound`, `bindLifetime`
`.Subscribed` 세팅, 2-인자 `canExecute`)을 검증 중이라 파일이
`.claude/luau-test/rewrite-required/`로 옮겨졌음. **남은 확인거리**는
이중 바인딩 게이트(이제 `canExecute` 하나)와 unbind/Destroy 후 재바인딩
허용, `value` 쪽에 복사된 gcconn만으로의 생존 판정, Instance userdata
동일성, 그리고 B(Attribute의 Instance 참조 타입)/C(CollectionService
태그 왕복) — 목록은 `.claude/audit/gcconn-trick-verification.md`
"아직 확인 안 된 것"이 소스. GC 강제 트리거가 필요하면
`.claude/luau-test/rewrite-required/`로 옮겨졌음. **[2026-08-14 열한
번째 세션 재정정]** 이중 바인딩 게이트는 `canExecute` 하나가 아니라
**`canBound`**로 별도 진입점 재도입됨(`canExecute`는 emit 게이팅 전용,
판정 로직은 비공개 헬퍼 하나를 공유 — `base/lifecycle-pattern.md`
"`canBound` vs `canExecute`" 절). **남은 확인거리**는 이중 바인딩
게이트(`canBound`)와 unbind/Destroy 후 재바인딩 허용, `value` 쪽에
복사된 gcconn만으로의 생존 판정, Instance userdata 동일성, 그리고
B(Attribute의 Instance 참조 타입)/C(CollectionService 태그 왕복) —
목록은 `.claude/audit/gcconn-trick-verification.md`의 "아직 확인 안
된 것"이 소스. GC 강제 트리거가 필요하면
`.claude/luau-test/not-run/gc-trigger-helper.server.luau` 참고. 위
1번(MCP 연결)이 되면 에이전트가 대신 돌릴 수도 있음.