Commit graph

121 commits

Author SHA1 Message Date
9dd82136bd
qa: 8라운드 손 트레이싱 처리 — 결정 Q1~Q10 반영, M2 착수 게이트 0
발견 17건(H-107~H-123)의 사용자 결정을 base/ 전체에 반영. 7라운드 확정 중
뒤집힌 건 없고, 고친 건 전부 7라운드가 base/에 내려앉을 때 생긴 누락·충돌
(하루 차로 확정된 결정들이 서로를 못 본 자리)이다. 결정의 소스는
qa-request/pre-implementation-handtrace-round8-followup.md.

계약 변경 넷:
- Ref 콜백이 fn(value, ref) — 2번째가 곧 출처 Epoch. Effect가 Update(from)에
  넘길 유일한 통로였다(k(value)뿐이면 Update(nil) 크래시, 실측 재현).
- Observer fn이 세 자리 fn(targetState, self, emitFrom) + observer._state
  강참조. 옛 2-인자는 "self는 리시버" 계약과 정면 충돌해 무인자
  state:Observer()의 내부 콜백이 즉사했다.
- WeakSubscribe도 .Subscribed를 세운다. 안 그러면 Effect의 State dep 전량이
  조용히 침묵. 해제는 "건 경로로 푼다"(양방향 fail-fast).
- 예약 키 진단이 CheckReservedKeys<keyof<T>> — T를 통째로 넘기는 배선은
  실사용 T에서 아예 안 돈다(Source<T>가 *error-type*을 품어 유효한 Store
  전부에 스퓨리어스 에러).

사용자가 문항의 전제를 두 번 정정: Ref 콜백과 Observer 콜백은 이질적이라
애초에 통합 대상이 아니었고(Observer엔 자기 epoch가 없다), H-118은 소유권
문제가 아니라 gate-plan 5번의 문장이 틀린 것이었다(🟡🟢).

커밋 전 검증 — 감사 11라운드(44건, 0건으로 수렴) + /code-review high
7라운드(42건) = 86건. 감사가 0으로 수렴한 직후 code-review가 42건을 냈고,
그중 하나가 H-101의 "새 필드를 안 만든다"를 역전시켰다: getOffsetAt의
부수효과가 splice의 되감기 신호를 지우는 경로가 실재해, 부기 필드를
offsetCacheValidUpTo(캐시)와 offsetSetUpTo(:Set 완료) 둘로 분리했다.
"Set을 해줬느냐"와 "캐시가 유효하냐"를 한 값이 쥔 게 원인이었다.

그 외: splice 무효화 i-1, 명시 recompute 호출부 전부 재진입 게이트,
recompute 되감기 클램프, Store defaults isSource 검증, isModifier 가드를
Source 생성자로, 훅 슈가 nil 가드, pesde.lock 커밋 확정, :Single 3-인자.
2026-08-25 session/ 원문 공백은 2026-08-19 선례대로 재구성 없이 기록만.

doc-check ERROR 0 / WARN 기준선 유지.

Claude-Session: https://claude.ai/code/session_01F9zgJ4c4kDitAoQMm9qxKn
Co-authored-by: qwreey <me@qwreey.moe>
2026-08-26 17:18:30 +09:00
677feabc76
qa: 구현 전 감사 8라운드 — 7라운드 반영분 재트레이싱·실측, 발견 17건 (H-107~H-123)
3패스에 걸쳐 base/ 전 문서 완독. 개별 함수가 아니라 "7라운드에 반영된
결정들이 서로 겹칠 때 성립하는가"를 트레이싱했고, 스파이크 7개로 실측
(H-107 런타임 크래시 재현, H-112 keyof 배선 해법 실증 포함). 사용자 결정
문항 Q1~Q10 배치 정리 — 그중 🔴 다섯(H-107~H-109/H-112/H-119)은 M2 착수
전 회신 필요. 아직 base/ 반영 없음, 결정이 나면 followup을 만든다.

커밋 전 /code-review가 보고서 자체의 결함 7건을 잡아 전부 검증 후 반영:
문서 내 사실 정정 6건([code-review 정정/추가] 표시)과 인덱스 레이어
미갱신 1건 — question.md 최우선 절/todos.md 00/README.md/CLAUDE.md/
project-context.md의 "M2 게이트 0" 서술을 "8라운드 회신 대기"로 정정.

doc-check ERROR 0 / WARN 기준선 유지.

Claude-Session: https://claude.ai/code/session_01Cokkxc38ozgmcxPZraV8b7
Co-authored-by: qwreey <me@qwreey.moe>
2026-08-26 01:21:22 +09:00
eb321e1747
qa: 7라운드 발견 52건 처리·반영 — Store 재설계 시도와 철회, 타입 함수 원칙 신설
`qa-request/pre-implementation-handtrace-round7.md`의 `H-55`~`H-106`을
사용자와 대화형으로 처리하고 `base/`에 전량 반영했다. 결정의 소스는
`-followup.md`(개수·개별 항목은 여기서 세지 않는다).

## 처분

확정 39 / 무효·소멸 4(`H-73`~`H-76`) / 기각 1(`H-77`) / 범위 축소 2 /
다른 항목으로 흡수 6.

**부수로 `question.md` 최우선 절이 비었다** — 중간 State GC는 `_hold`
불변식(하류 → 상류 강함)으로, 동적 키 표면 위치는 `store:Of<<T>>(name)`
하나로 닫혔다. **M2 착수를 막는 항목이 없다.**

## 구조가 바뀐 것

- `Ref`가 `Epoch`를 만족(`.Revision` + `EpochBrand`) — 포탈 캐치업 비대칭과
  같은 `Ref` 중복 dep이 같이 닫힘
- `Weak*` 등록 표면 신설(`Ref:WeakCallback` / `Observer:WeakSubscribe`) —
  Weak 쪽이 프리미티브고 강한 쪽이 "GC 킵"을 얹은 것
- `Effect`: dep 등록이 생성자 한 곳으로, 강한 주인은 `_deps` 하나,
  억제는 사적 `Blocker`, `bindLifetime`은 핸들 하나에만 적용.
  `:Rerun()` 정의 신설(재진입은 지연 재실행), `_installed` 신설
- 전파 루프 의사코드 확정 — 구독자 집합의 원소는 Observer **값**이고
  **자식 State 노드는 `canExecute`를 안 탄다**(그대로 짜면 파생 State
  아래가 전부 침묵했다)
- `rawInvalid` → `cacheTargetCount`/`cacheCurrCount` 카운터 쌍
- `recompute` 재진입 차단 + `invalidAfter` 되감기, `gatedRecompute`가
  인덱스를 캡처하지 않고 토큰으로 조회
- `emit(commit) -> boolean`, `EpochMap:Peek` — 정책이 흡수 집합을
  버리지도 읽지도 못하던 것을 닫음
- error 계약(`level` 이분, 메시지는 영어)과 예외 계약(`pcall`로 안 감쌈)을
  `architecture.md`에 신설

## Store — 같은 날 재설계하고 철회했다

`H-75`/`H-76`으로 `WrapStore`/`ProcessStoreType`이 폐기되자 그 자리를
"`store.key`는 값, `store:Of(k)`가 프리미티브"로 채웠다가 **같은 날
철회**했다(`archive/store-value-field-redesign-withdrawn.md`). 살아남은 건
**명시적 초기화** 하나다. 최종형은 타입 인자에 `Source<T>`를 직접 쓰고
`store.key`는 평범한 레코드 필드이며 **타입 함수를 안 쓴다**.

철회 이유 중 하나가 원칙으로 승격됐다 — **"타입 함수는 타입이 못 잡는
문제를 에러로 띄우는 정도 이상으로 가지 않는다"**(`typing-limits.md` §0).
`index<>`/`keyof<>`도 Luau가 predefine한 타입 함수라 같은 함정을 갖는다.

## 툴체인

**`luau` CLI가 심볼릭 링크를 못 탄다**(디렉토리·파일 둘 다)는 것이 최소
재현으로 밝혀졌다 — pesde 워크스페이스 링크가 전부 심볼릭이라 스모크 2개가
안 돌았고 `luau-analyze`는 **조용히 통과**했다("거짓 클린"). `scripts/relink.sh`
+ `scripts/test.sh` 신설, 이제 스모크 셋 전부 PASS.

## 검증

`/code-review high` 2회(12건 + 14건)와 감사 8패스(12/6/6/4/13/3/6/0건)를
각도를 바꿔가며 돌렸고 전부 반영했다 — 마지막 패스가 무발견으로 수렴.
각 패스의 각도와 대표 발견은 `-followup.md`의 검증 절이 소스.
`doc-check.py` ERROR 0.

Co-authored-by: qwreey <me@qwreey.moe>

Claude-Session: https://claude.ai/code/session_012oLwATeQdq9TCFdENPutFG
2026-08-25 23:40:19 +09:00
56f8269236
design: M2/M3 마일스톤 순서 교체 — 반응형 코어를 먼저, 디스패치를 그 위에
`question.md`에 열려 있던 마지막 항목(마일스톤 경계)을 사용자가
**(a) 순서 교체**로 닫았다 — 이제 **M2 = 반응형 코어(Source/State/Store),
M3 = 디스패치 엔진**이다. 결정과 기각된 선택지는
`archive/question-resolved.md`의 "마일스톤 경계" 절, 경위와 시행착오는
`session/2026-08-24-02-milestone-order-swap.md`.

## 왜 (a)인가

의존이 양방향처럼 보였지만 실제로는 한 방향이었다 — 디스패치→반응형은
*본체* 의존(`setLength`가 `State<number>`를, `setOffsetSource`가
`Source<number>`를 받고 `recompute`가 `offset:Set()`을 부름)이라 우회
불가고, 반대는 *등록 표면* 의존(핸들러 셋)이라 미루면 그만이다. 옛
순서로는 디스패치 마일스톤의 `mock 대상 테스트` 체크박스조차 State 없이
불가능했고, 반응형 코어는 순수 Lua라 `luau`만으로 단독 테스트가 된다.
(b) 분할은 기존 `M2` 참조 전부를 "M2a인가 M2b인가"로 만들어 오히려 비싸고,
(c) 유지는 "순서의 소스는 `ROADMAP.md`"라는 원칙을 스스로 무효화한다.

## 그냥 맞바꾸기로는 안 끝났다

- **`Brand`/`Relate`/`LifetimeHandle`(인터페이스)이 M2 앞머리
  `### 공통 기반` 절로** — 반응형이 이 셋을 먼저 요구한다(`Source`가
  `SourceBrand`+`EpochBrand`에 등록되고, State 전파 루프가 매 발화마다
  `canExecute`를 부르며, 그 판정이 `Relate` 위에 얹힌다). 셋 다 State-free
  이자 dispatch-free라 어느 쪽에도 안 걸린다.
- **2026-08-22에 디스패치로 앞당겼던 `EpochMap`/`GateNode`/`Blocker`가
  M2로 복귀** — 앞당길 이유 자체가 순서 교체로 사라졌다. "게이팅 먼저"는
  그대로 지켜진다(게이팅이 디스패치보다 먼저 지어진다).
- **Observer/Effect 동적 경로 가드 등록과 `ObserverEffectLeafHandler`는
  M3로** — 둘 다 "핸들러를 등록한다"뿐이라 본체와 잘라내기 쉽다. 이것이
  M2가 M3에 개념상 지던 유일한 의존이고, 미뤘으므로 빌드 순서엔 역방향
  간선이 없다.
- **`EpochMap`이 State 본체보다 앞으로**(감사 5라운드 발견) — State가
  `valueEpochMap`/`emitEpochMap` 둘을 컴포지션하므로 옛 배치로는
  `State.luau`를 못 짠다. 문서 자신이 *"아래 `Source.luau`/`State.luau`가
  이걸 전제로"*라 쓰면서 그 둘이 위에 있는 형태로 증거를 남기고 있었다.

## 대가 하나 — 게이트 둘이 "바로 다음"으로 올라왔다

`question.md` 낮은 우선순위에 있던 **중간 State GC 미검증**과
**`store:GetDynamic` 위치**가 원래 반응형(옛 M3)의 게이트였는데, 반응형이
M2가 되면서 착수 직전 항목이 됐다 — 최우선 절로 승격했다. 순수 *설계*
결정 대기는 여전히 0건이다(하나는 실측 미완, 하나는 표면 위치 선택).

## 번호 재부여의 경계

라이브 문서의 `M2`/`M3` 참조 248건은 전량 새 번호로 맞췄다(코퍼스의 참조가
거의 전부 "그 내용이 사는 마일스톤"을 가리켜 기계적 맞교환으로 의미가
보존됨). **`session/`·`archive/`·`qa-request/`는 히스토리라 소급 수정하지
않았다** — 그 문서들의 `M2`/`M3`는 옛 의미(M2=디스패치, M3=반응형)이고,
이 경고를 인덱스 다섯 곳에 박아뒀다.

일괄 치환에 `\bM([23])\b`를 썼다가 Python `\w`가 유니코드라 한글이 붙은
93건(`M2는`/`M2로`)이 안 바뀌는 실수를 냈고, `git show HEAD:<경로>`로
되돌린 뒤 ASCII 경계 lookaround로 재실행했다. 그 부수로 `Relate`/
`LifetimeHandle` 참조들은 구 M2 → 신 M2로 두 번 옮겨져 **번호가 우연히
보존**됐다는 것도 드러났다(치환하면 안 되는 자리 — 감사가 잡아 되돌렸다).

## 검증

`quad-doc-auditor` 루프가 라운드마다 각도를 바꿔 **7라운드에서 새 발견
0건으로 수렴**(10→8→1→1→2→2→0). 가장 값이 큰 건 5라운드(구현 순서
시뮬레이션)로, 위 `EpochMap` 배치 오류를 잡았고 **순서 교체의 전제 자체도
검증**했다(새 M2 전체를 디스패치 심볼로 훑어 "가드 등록 둘 말고는 없음").

**수렴 뒤 사용자가 돌린 `/code-review high`가 5건을 더 잡았고 전부 유효** —
넷이 *"라벨은 치환됐는데 그 라벨을 설명하던 산문이 안 고쳐진"* 종류였고,
그중 하나는 `research/` 안의 **히스토리 블록**이 치환을 맞아 원래 논거가
문장 그대로 거짓이 된 것이었다(소급 수정 제외 대상을 세 폴더로만 잡은 게
샜다). `conventions.md`의 *"`/code-review`는 감사자를 대체하지 않는다"*가
또 재확인됐다. `doc-check.py` ERROR 0.

Co-authored-by: qwreey <me@qwreey.moe>
Claude-Session: https://claude.ai/code/session_01Jjrec9xAS7TZstMx5gi3cm
2026-08-25 00:29:15 +09:00
9622ccd3e9
design: ROADMAP 마일스톤 경계 재편 + 전반 stale 정리
`ROADMAP.md` 전문을 `base/`의 현재 확정과 대조한 전반 점검. 사용자 판단으로
마일스톤을 각주가 아니라 체크박스째 재편했다.

## 마일스톤 이동 (M3/M7 → M2)

`EpochMap.luau` / `state:Gate`+`GateNode` / `Blocker.luau` / `None`+
`Dispatch/None.luau`. 넷 다 M2가 실제로 호출하는데 각주로만 예고돼 있었고,
`GateNode`는 체크박스 자체가 없어 M2를 훑는 구현자에게 항목으로 보이지
않았다. `LifetimeHandle` 인터페이스를 M8→M2로 옮겼던 전례와 같은 처리.
`Blocker`는 `GateNode` 위의 정책으로 얹는다(노드를 다시 만들지 말 것).

##  새 미결 — M2와 M3의 의존이 양방향

이동하다 드러났다. `Dispatch.setLength`가 `State<number>`, `setOffsetSource`가
`Source<number>`를 받고 `recompute`가 `offset:Set()`을 부르며, `Dispatch.drive`
자신도 배치 등록을 Blocker로 게이팅한다 — 즉 M2는 `Source.luau`/`State.luau`
없이 구현이 안 된다. 설계가 아니라 마일스톤 순서 문제라, 선택지 셋((a) 순서
교체 / (b) M2 분할 — 경계선은 `drive` / (c) 유지)을 `question.md` 2번으로
신설하고 유일한 소스로 지정했다. `HUMAN_TODO.md` 11번이 사용자 진입점.

## 모순 정정

- `Dispatch.drive` 순회 구현은 두 패스가 아니라 단일 일반화 `for`(`F-4-1`).
  "배열→해시 먼저"는 그 루프가 지키는 계약. 코퍼스의 "두 패스"는 본체 루프의
  옛 이름으로 정리(시점 표기는 유지, 용어 각주 신설). 따름정리로 "base는
  언어 동작에 안 기댄다"는 서술이 거짓이 됐고, 재작성될 스파이크 `01`이
  검증할 것도 언어 동작 자체로 바뀐다
- 물리 조작 주입 op 이름은 `native*` 확정(옛 가칭 `mountInst`/`unmountInst`/
  `disposeInst` 폐기). 단건 경로 순서는 `setOffsetSource` → `nativeInsert` →
  `setLength` → `recompute` — 역전 배너를 스스로 단 절 안에 옛 "부기 먼저"
  주장이 두 문단 살아 있었다
- M2 첫 체크박스가 하강 diff와 폐기된 옛 모델을 한 불릿에서 둘 다 서술

## 상태 표시

- `[x]`는 "짜야 할 코드"만. 설계 확정은 `### 확정된 것` 절 또는 전용
  불릿으로 분리(M3/M6/M11) — 이제 `[x]`는 M0/M1에만 남는다
- M0에 `### 재검증 대기` 절 신설 — 설계 변경으로 무효화된 스파이크들이
  어느 체크박스에도 없어 잊히기 쉬웠다(현황의 소스는 `luau-test/STATUS.md`)
- 주입 op 개수 하드코딩을 네 문서에서 걷고 `architecture.md`의
  `EngineOps.luau` 줄 하나로 단일화(그 줄에 빠져 있던 시간 op도 채움)

## 검증

`quad-doc-auditor` 10라운드(각도를 매번 바꿔 34건) + 사용자가 돌린
`/code-review high` 9건. `doc-check.py` ERROR 0. 경위와 실측된 실패 패턴은
`.claude/session/2026-08-22-01-roadmap-milestone-review.md`.

Claude-Session: https://claude.ai/code/session_01TiW21rnti9SbLgF6twtn6D

Co-authored-by: qwreey <me@qwreey.moe>
2026-08-22 03:19:13 +09:00
871c582771
tooling: 핸드오버 준비 — session-summary.md 색인 공백 + ROADMAP/CLAUDE.md stale 정정
session-summary.md에 오늘 세션 04~08 색인 항목이 통째로 빠져 있던 걸 발견해
신설. 더 크게는 CLAUDE.md/project-context.md/ROADMAP.md가 "구현 아직 시작
전"이라는 낡은 전제를 깔고 있었는데, 실측해보니 M0 스파이크 4개와 M1
스캐폴딩 대부분이 이미 완료돼 있어 전부 정정(ROADMAP 체크박스 갱신 포함,
wally.toml→pesde.toml 표기도 같이 정정). quad-roblox-types 백로그는
todos.md/ROADMAP.md M5에 짧은 포인터 보강.

Co-authored-by: qwreey <me@qwreey.moe>
2026-08-19 20:47:31 +09:00
298dac2510
docs: 감사 툴링 재시작 검증 + 핸드오버 감사 첫 실동(수렴 실패), 인용 3건 정정
전 세션이 "재시작해야만 확인 가능"으로 남긴 3건을 전부 닫음:
- @import 3개(conventions/project-context/todos) 실제 로드 확인
- quad-doc-auditor 레지스트리 등록 확인(전 세션 전멸은 .claude/agents/가
  세션 도중 생긴 디렉토리였던 탓)
- frontmatter model: sonnet 반영 확인(트랜스크립트에 claude-sonnet-5 기록,
  워크플로에 opts.model 명시 불필요)

정의 파일은 세션 시작 시점 스냅샷으로 고정된다는 것을 1차 증거로 확정 —
quad-handover-audit이 실제 실행한 스크립트가 세션 시작 시점 상태와 바이트
단위로 동일했고 같은 세션의 편집은 반영 0. 에이전트 정의도 동일.
정의를 고쳤으면 재시작 뒤에 감사를 돌릴 것(안 그러면 거짓 초록불).
전 세션 감사가 남긴 긴 가설 배너(80줄)를 검증된 것만 남겨 압축.

quad-handover-audit 첫 실동: 에이전트 67개/6라운드, 수렴 실패
(새 발견 28→15→16→7→11→6, 라운드5에서 되레 증가). MAX_ROUNDS와
"연속 dry 2회" 조건 재검토 필요 — 결과 자체는 위 스냅샷 문제로 옛
스크립트가 돈 것이라 재시작 후 재실동 대상.

감사가 잡은 것 반영: slot-plan.md 정정 배너가 그 뒤 재역전(retract=언마운트)을
놓치고 있던 것, "spikes 44개"(실제 48개) 류 하드코딩 개수의 단일 소스화,
doc-check.py docstring이 검사 심각도를 실제 코드와 다르게 서술하던 것 등.

인용 출처 3건 재분류 — 2건은 인용 대상만 틀린 것이라 실제 소스로 재조준
(v1-compat-plan.md→component-composition-plan.md+store-plan.md,
pre-implementation-audit.md→ROADMAP.md). 진짜 출처가 없는 1건
(modifier-plan.md:536)만 question.md 3번으로 올려 사용자 판단 대기.

워크플로 개선: 반환값에 findings 추가(커밋 전 diff 리뷰 근거),
totalFindingsFixed→findingsSentToFix 개명(과대계상), 반영 에이전트 sonnet 명시.

.claude/agent-memory/는 의도적으로 커밋 제외(추적 여부는 사용자 판단).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 03:02:33 +09:00
8aeec7644f
docs: CLAUDE.md 4분할(매 세션 로드 1537→354줄), 워크플로 가짜 초록불 수정
## CLAUDE.md 분할
1537줄이라 (a) 사람이 검토 불가, (b) 공식 권장치(파일당 200줄) 7.7배
초과로 지침 준수도 자체가 저하, (c) 긴 파일 편집 시 에이전트 실수 증가.

  CLAUDE.md (39줄, 진입점)
  ├─ @.claude/conventions.md      언어/모델 관례 + 작업 방식
  ├─ @.claude/project-context.md  프로젝트 설명 + 문서 구조
  └─ @.claude/todos.md            지금 할 일
     .claude/session-summary.md   ← import 안 함(의도적, 온디맨드)

세션 히스토리 1231줄(전체의 80%)은 그 문서 스스로 "항상 읽을 필요 없음,
base/가 소스"라고 명시해온 색인이라 @import에서 뺐음. 내용 유실 없음
(1537→1647줄, 추가 헤더만큼 증가).

주의: @import는 컨텍스트를 줄이지 않음(전부 로드됨). 분할이 사는 건
사람 검토성 + 편집 정확도 + 파일 단위 자동생성 가능성.
CLAUDE.md 계열의 블록 HTML 주석은 주입 전 제거되므로 지시는 본문에 쓸 것.

## 워크플로 가짜 초록불 수정
첫 실측에서 감사 에이전트 6개 전원 실패했는데 converged:true가 나왔음
(전멸하면 fresh가 비어 "깨끗한 라운드"와 구분 불가). 감사 도구 최악의
실패 모드라 (1) 전멸이면 throw, (2) 반영 에이전트 실패 시 그 발견을
seen에서 빼 다음 라운드가 재시도하도록 수정.

## 부수
- 분할로 깨진 상호참조 20여 곳 정정(병렬 에이전트 3개).
  ref-plan.md:541의 사전 존재 오류(→ pre-implementation-audit 1-5)도 정정.
- doc-check.py: 새 파일 4개를 OURS에 등록(안 하면 깨진 참조가 WARN으로만
  잡힘), is_history()로 session-summary.md를 archive/와 같이 면제.
- doc-include-plan.md: 목적지가 통째로 생성되는 파일이 되면서 양방향
  마커 설계의 절반(목적지 마커)이 불필요해져 단방향 생성으로 단순화.

doc-check.py ERROR 0 유지.

미해결: session-summary.md 자동생성 미착수(91개 세션 파일 마커 삽입 필요),
orphan 인용 3건(modifier-plan.md:536, v1-compat-plan.md:50,
pre-implementation-audit.md:434 — 분할 이전부터 존재).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HvEKn9f67kkx2nGLG8PsP
2026-08-16 01:35:02 +09:00
a1c0e44258
tooling: 코퍼스 정합성 감사 서브에이전트/워크플로 신설
doc-check.py가 못 잡는 의미론적 stale/모순(뒤집힌 결정을 여전히 서술하는
본문 문장, 개수/목록 이중 소스 드리프트)을 신선한 맥락에서 찾는 계층 추가.

- .claude/agents/quad-doc-auditor.md — 읽기 전용 감사자(발견만 리포트,
  수정은 호출한 세션이 함). memory: project로 반복 패턴 축적.
- .claude/workflows/quad-handover-audit.js — 단일 패스가 비결정적이라
  라운드당 병렬 3회 + 파일별 즉시 반영을, 새 발견 없는 라운드가 연속
  2번 나올 때까지(최대 6라운드) 반복해 수렴시킴.
- CLAUDE.md "작업 방식"에 두 도구의 트리거 조건 명시 —
  "핸드오버 준비하고 커밋해" 류 요청 시 워크플로부터 돌릴 것,
  실제 git commit은 항상 메인 세션이 직접.
- .claude/README.md 폴더 기준 표에 agents//workflows/ 행 추가.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HvEKn9f67kkx2nGLG8PsP
2026-08-16 01:16:19 +09:00
6bfd93fd62
docs: 콜백 파라미터 무주석 추론 전방위 재시도, code-review 2회전 정합성 수정
type-recursive-issue-try-callback/ 신설(spikes 35개) — type function/
메타테이블/제네릭/이중 꺾쇠 명시 인스턴스화까지 전방위로 재시도했으나
quad의 state:Compute(fn) 단일 호출 모양을 유지한 채로는 여전히 안 됨,
근본 원인은 재귀 특유가 아니라 "제네릭 콜백 인자엔 컨텍스트 타입
전파가 안 됨"이라는 더 일반적 Luau 한계임을 확인. typing-limits.md
§1/§7에 반영, 원칙 자체는 안 바뀜.

이어진 /code-review 2회전이 이 작업과 luau-test/16 복구 세션
전반에서 정합성 문제 다수 발견 — 스파이크 결과 표 stale(16번 실패로
잔존), 폴더 개수 off-by-one 여러 건, type-recursion-issue/REPORT.md의
실제 오류(self가 제네릭이면 자유 함수로 빼도 여전히 실패한다는 사실이
"통과"로 잘못 서술됨), 옛 솔버 캐비엇 누락, 체크리스트 항목 간 모순,
이 세션 자체의 히스토리 누락 등 — 전부 수정. doc-check.py ERROR 0 유지.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HvEKn9f67kkx2nGLG8PsP
2026-08-15 19:36:44 +09:00
eae94d0574
docs: typeof(named fn) 간접참조로 0-Y 우회 실측, luau-test/16 복구
typing-limits.md §1에 검증된 선언 스타일 규약(③) 추가 — 재귀 메소드를
인라인 대신 이름 붙은 함수 + typeof로 선언하면 LHS 명시 없이도
다운스트림이 안전해짐(체이닝 50단·타입 변경·중첩 self 호출 확인).
setmetatable 확장은 quad 계약에서 솔버 버그를 만나 채택 안 함.

luau-test/16(type function으로 Store<T> 필드 합성)을 복구해 done/으로
이동 — 원인은 설계 문제가 아니라 API 버전 드리프트, §5를 검증 완료로
승격.

전체 실측: audit/type-recursive-issue-with-typeof/(REPORT.md + spikes
15개). code-review 지적 4건(불건전 판정 오류, 음성 대조군 개수, 체이닝
깊이 주장의 재현 스파이크 누락, store-plan.md stale 참조) 전부 반영.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 15:06:39 +09:00
3e2c63e3d1
docs: 문서 stale 감소용 include 도구 백로그 신설(doc-include.py)
반복된 stale 문제(같은 사실이 여러 곳에 중복 서술)를 근본적으로 줄이는
방법으로 마커 기반 include 도구를 논의 — AsciiDoc tagged include/
markdown-magic 선례 확인 후 build-vs-buy 검토, doc-check.py와 짝인 Python
직접 제작 채택. research/doc-include-plan.md에 플랜 초안(마커 문법,
CLAUDE.md 세션 히스토리 파일럿 범위, 열린 질문) 작성 — 세부는 사용자가
다듬을 예정, 구현 착수는 안 함. README.md 색인/CLAUDE.md 백로그·세션
히스토리 동기화.
2026-08-14 22:56:21 +09:00
dcd3f2c732
docs: quad 재귀 약어 브레인스토밍 research 문서 신설
GNU/WINE류로 Quad를 재귀 약어화하는 카피 후보 정리 — 나중에 README.md
헤딩용, 설계 결정/착수 게이팅과 무관.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 13:58:01 +09:00
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
573dd452af
docs(base): dispose(value) 시그니처/범위 확정 — question.md 0-B 해소
범위를 Slot+엔진 객체로 좁히고 Observer/Effect는 명시적으로 제외
(GC-native bindLifetime만으로 충분, 트리 부기 없음). isSlot이 아니면
disposeInst 주입 op으로 위임(addTag/removeTag/setAttribute와 같은
패턴). 부수적으로 OnDestroyed 이름 재검토 조건도 종결.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 06:18:28 +09:00
2c575d91f0
docs: PostRef 반영 후 코퍼스 정합성 감사 — 모순 5건 정정
- CLAUDE.md 아홉 번째 세션 항목 제목이 "미보장으로 역전"으로 남아 본문
  (철회·보장 유지)과 정면 모순 → 정정
- CLAUDE.md 여섯 번째 세션 항목이 "OnRendered는 지금 의도적으로 구현 안 함"을
  현재형 확정으로 서술 중 → 아홉 번째 세션 역전 포인터 추가
- research/documentation-content-map.md:
  (1) "PreRef는 retract 체인에 아예 안 올라감" — 2026-08-14 두 번째 세션의
      ProcessedPreRef 정정이 미반영된 옛 근거였음(이번 변경과 무관한 기존
      stale) → 정정, PostRef도 동일하다고 명시
  (2) hook/pre-hook 프레이밍에 PostRef(post-hook) 3항 확장 + 순서 보장
      왕복을 에세이 소재로 메모
  (3) 서베이가 2026-08-06 파일 구성 기준이라 bind-system-plan.md 포인터가
      전부 분할 전 것 → 파일 상단에 읽는 법 배너
- luau-test/README.md: 13번 재작성 시 PostRef까지 커버할 것
- base/lifecycle-hooks-plan.md: 시그니처의 `Instance`는 가독성용 표기이고
  실제로는 백엔드 타입을 모르는 자리라는 주석(quad-base 소속과의 정합)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 05:59:31 +09:00
f9f0babc87
docs(base): PreRef/PostRef 계열 안 fire 순서 미보장안 철회 — 배열 index 순서 보장 유지
직전 커밋(bcd02f1)에서 미보장으로 뒤집었던 것을 같은 세션에 철회.
반례는 `FastQuery(...) -> PreRef`류 조합 — 앞자리 항목이 뒤 항목의
전제를 만들어주는 정당한 합성이고, children 마운트 선후가 배열 위치로
정해지는 것과 같은 성격. 보장 비용 0(pre-pass가 어차피 index 순서)이고
배열 파트 index 순서는 이미 백엔드 이식성 때문에 명시적 계약이라 새로
내주는 자유도 없음. 보장 + 스타일 권고를 같이 기재.

- archive/preref-order-guaranteed-reversed.md → preref-order-unguaranteed-withdrawn.md
  (제안·철회 양쪽 논거 보존)
- OnRendered의 "부모에 붙기 전에 불림" 캐비엇은 사용자 지시대로 이름 유지 +
  명시만(ref-plan "보장 범위" 항목, lifecycle-hooks-plan ⚠️ 항목)
- ref-plan/lifecycle-hooks-plan/ROADMAP/README/CLAUDE.md/세션 로그 동기화

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 05:54:05 +09:00
bcd02f1cec
docs(base): PostRef 확정·OnRendered 채택, PreRef/PostRef 계열 안 순서 미보장으로 역전
- base/ref-plan.md: "PostRef" 절 신설(PreRef의 거울상 — pre-pass 공동 수집,
  ProcessedPostRef 센티널+전담 Handler, 동적 경로 가드, _fired, 타입 차단).
  보장 범위를 명시: 자기 서브트리 완성은 보장하되 이 인스턴스가 부모에
  붙기 전에 불림(React componentDidMount와 다름).
- 복수 PreRef/PostRef의 계열 안 fire 순서를 "배열 index 순서 보장"에서
  미보장으로 역전 — 구현이 아니라 계약만 좁힘
  (archive/preref-order-guaranteed-reversed.md 신설).
- research/lifecycle-hooks-plan.md → base/ 승격, OnRendered 채택 반영
  (마지막 열린 항목이던 채택 여부/메커니즘/스코프/패키지 전부 확정).
- dispatch-core-plan/brand/architecture/slot/modifier/typing-limits/README/
  ROADMAP/question.md 전파. doc-check.py ERROR 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 05:45:31 +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
2d9cc7b5f7
docs(base): Fallback/Traceback 승격 — research/에서 base/fallback-plan.md로
pcall 기반 Fallback과 xpcall+debug.traceback 기반 Traceback으로 분리,
정확한 제네릭 시그니처(OkComp/ErrComp/Args... 독립 제네릭)와 err: any를
확정. 패키지(quad-base)·이름(Fallback/Traceback) 확정으로 남은 열린
질문이 없어져 base/로 승격. 스파이크를 audit/fallback-xpcall-spike.luau로
옮기고 base/fallback-plan.md와 이름을 맞춰 내부 함수를 Traceback으로
정정, audit/fallback-xpcall-verification.md에 실측 결과 기록. README/
question.md/archive/question-resolved.md/lifecycle-hooks-plan.md의 상호
참조 동기화.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 04:32:29 +09:00
f6117723eb
docs(session): 생명주기 훅 세션 로그 신설, CLAUDE.md 세션 번호 재조정
session/2026-08-14-06-lifecycle-hooks-plan.md로 OnCreated/OnDestroyed
백로그 세션 전체 기록(워크트리 조사, 사용자 refinement 두 차례, 메인
병합, 동시 편집 충돌 대응까지) 신설. 다른 세션이 04/05를 이미 써서
CLAUDE.md 세션 히스토리에서 이 항목을 원래 "세 번째" 자리에서 맨 끝
"여섯 번째"로 옮기고 파일명(03→06)/역참조를 재조정 — 실제 작업 순서와
문서 번호가 어긋나는 이유를 양쪽에 메모로 남김.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 04:08:48 +09:00
af513aeb84
fix(lifecycle): canExecute/unbindLifetime을 value 1-인자로 정정, Subscribed 오염 제거
canExecute(inst,value) 2-인자 시그니처를 폐기하고 canExecute(value)로 정정.
2-인자는 증상이었고 원인은 2026-08-08 세션이 .Subscribed에 "leaf 바인딩
생존"이라는 두 번째 의미를 겹쳐 얹은 것 — .Subscribed는 전역 :Subscribe()
전용 필드이고 bindLifetime과 무관함. bindLifetime이 바인딩 시점에 inst의
gcconn 참조를 value 쪽 Relate로 복사해두면 생존을 value 하나로 물을 수 있음.

- canBound(handle) 폐기 → canExecute(value)로 통합(이중 바인딩 게이트 겸함)
- unbindLifetime도 1-인자로 축소 — 호출부가 _mountedInst를 되짚을 필요 없어져
  "홀더가 갈아치워지면 해제가 빗나가는" 잠재 버그 클래스 소멸(slot-plan 5곳)
- gcconn/gchold를 lazy 생성에서 Instance 생성 시점으로 전환, 클로저가 inst까지
  캡처 — Instance userdata 포인터 동일성은 inst-키 Relate 전체의 전제였음
  (relate-plan에 "전제" 절 + "안전히 유지되면 항상 SetWeak" 일반 규칙 신설)
- canExecute의 실제 호출부를 State 전파 루프로 명시(구독자 weak + 발화마다
  게이팅) — 이게 코드로 한 번도 안 적힌 게 오류가 여섯 세션 살아남은 이유

역전 원문/오염 경로/교훈은 archive/canexecute-inst-arg-reversed.md.
luau-test/10은 폐기된 모델을 검증 중이라 rewrite-required/로 이동.

부수: 3~4차 세션이 남겨둔 CLAUDE.md 세션 히스토리 항목과 4차 세션 로그
파일도 미커밋 상태여서 같이 실림. doc-check ERROR 1건(CLAUDE.md:1156 →
session/2026-08-14-03-lifecycle-hooks-plan.md)은 그 파일이 디스크 어디에도
없어서 남음 — 3차 세션 쪽에서 채워야 함.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 04:03:49 +09:00
c5ea3aa597
docs(research): Fallback의 xpcall+traceback 메커니즘 실측 확인
component-fallback-plan.md가 열어뒀던 "xpcall 에러 핸들러 배선 실측
필요" 질문을 luau 스파이크(component-fallback-xpcall-spike.luau)로
확인 — 클로저 업밸류 배선, 3단 중첩 debug.traceback 캡처 등 10개 검증
전부 통과. 부수적으로 error(msg) 기본 호출이 위치 접두("파일:줄: ")를
자동으로 붙인다는 캐비엇을 새로 확인해 "프로덕션에서의 동작" 절에 반영.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 02:54:37 +09:00
790ebba78f
docs(research): 컴포넌트 에러 격리 유틸 Fallback 백로그 신설
컴포넌트 함수를 감싸 에러 시 플레이스홀더를 그려주는 pcall/xpcall 래퍼
아이디어를 백로그로 문서화(research/component-fallback-plan.md), README/
question.md/CLAUDE.md 인덱스 반영. 후속 code-review로 발견된 결함(코드
스팬이 줄바꿈에 걸쳐 깨진 곳 4군데, 워크트리가 계획 문서 없이 시작되는
원인을 "git 미추적"으로 오진단했던 세션 로그 서술)도 같이 정정.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 01:17:40 +09:00
32e9db0773
fix(docs): 리뷰 라운드 — 의사코드 결함 3건 + doc-check 사각지대 수정
다른 에이전트 감사와 사용자 트레이싱으로 69466ab에서 나온 지적 반영.
핵심 알고리즘(하강 diff/인덱스 체인)엔 버그 없음이 확인됐고, 의사코드와
문서 정합성에서 나온 것들:

1. `nameClaims`가 Relate의 3-인자 계약 위반(`GetStrong(inst)` /
   `SetStrong(inst, claims)`) → `(inst, name[, key])`로 정정. 같은 커밋의
   `tagNameMap`은 이미 3-인자였어서 대조로 드러남.
2. TagHandler가 생존 이름의 홀더를 비웠다가 곧이은 process에서 `addTag`를
   헛되이 재호출 — 문서 서술("addTag 자체가 안 불림")과 정반대였음.
   생존 이름은 홀더를 유지하도록 정정하고, `addTag`도 `removeTag`처럼
   배치 호출로 통일(`{string}` 시그니처 도입 근거와 맞춤).
3. 그룹 process의 부분 실패 경로(순회 중 충돌 error) 문서화 — 피해가
   인스턴스 수명으로 한정되고 재현이 시끄럽게 반복됨을 트레이싱으로
   확인, 롤백 장치는 안 넣고 question.md 3번에 열어둠.

doc-check.py: REF 정규식이 줄 단위라 파일명과 절 제목이 줄바꿈에 걸친
인용을 통째로 놓치고 있었음(이번 2단계 분할뿐 아니라 9차 세션 1단계
분할 stale까지 숨어 있던 원인). 파일 전체 스캔 + 개행 허용으로 고치고,
새로 드러난 stale 참조 30여 곳을 dispatch-core/event-plan/ref-plan/
typing-limits로 정정. 오탐 없음(참조–인용 스팬 3줄 미만 전수 확인).

부수: 세션 로그에 리뷰 라운드 절 추가(커밋 메시지 줄수 오기 2291→1213
정정 포함), CLAUDE.md의 스파이크 이동 서술에 `19` 누락 보강,
luau-test/README 상단 요약표를 STATUS.md와 동기화.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KckSawrsJSJmDBcSojJPxZ
2026-08-14 00:29:25 +09:00
69466abc47
docs(dispatch): 0-Z/0-A 확정 — Attribute 전용 키+이름 claim, 하강 diff 전면 반영
`question.md` 최우선 두 건을 한 패스로 닫고, 배너를 달고 있던 7개 문서 +
인덱스 레이어 전체를 갱신했다.

0-Z (Attribute 이름 소유권):
- 그룹은 비공개 `GetKey`로 이름마다 자기 전용 키를 써서 위임 → 교차 오염
  구조적 제거. 이름 소유권은 `AttributeKeyHandler`의 이름 claim이 판정
  (`nameClaims` Relate, 다른 키가 같은 이름을 노리면 즉시 error).
- 권고안 (a)(그룹 안 claimant Relate)는 그룹↔직접 쓰기를 못 잡아 기각 —
  두 경로가 만나는 말단 핸들러에서 공개 키는 같은 객체라 소유자 구분 불가.

0-A (재디스패치 = 하강 diff):
- 래핑 핸들러의 선행 `retractFrom` 폐기, `Dispatch.process`가 슬롯의
  `handler`를 먼저 비교(같으면 클로저에 새 값 전달 후 재process, 다르면
  그 자리부터 전량 철거).
- 귀결: `retractFrom`이 3-인자로 축소(힌트를 외부에서 만들어 넣을 자리
  소멸), `isX(hintValue)` 가드 규칙 폐지, 깊은 체인 힌트 유실 캐비엇 삭제,
  Dispatch의 점유 체크 폐지.
- 9차 세션이 미뤄둔 2단계 분할을 같이 수행 — 디스패치 코어를
  `base/dispatch-core-plan.md`로 분리하며 재작성(bind-system-plan은
  2263→1219줄). 옛 모델은 archive/dispatch-hintvalue-model-reversed.md.

패키지 재배치 (사용자 제기):
- Tag/Attribute의 부기 알고리즘 전체를 quad-base로, 백엔드는
  `addTag`/`removeTag(inst,{string})`/`setAttribute(inst,name,v)` 3개 op만
  주입(웹 className/data-* 대응). 엔진 고유 타입 패밀리만 백엔드.
- `HANDLER_PRIORITY_FALLBACK` 신설 — base 제공 핸들러의 밴드, 백엔드가
  평범한 우선순위로 덮어쓰면 언제나 이김.

부수: 스파이크 04/19가 옛 모델을 검증 중이라 rewrite-required로 이동,
question.md 최우선 칸 비움, 새 소소 항목 2건 등록(Merged 이름 중복,
`hintValue` 이름 재검토). doc-check ERROR 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KckSawrsJSJmDBcSojJPxZ
2026-08-13 23:53:15 +09:00
93f548a2af
docs(type): 0-Y 해소 — 재귀 제네릭 반환은 Luau 상위 한계로 확정, typing-limits.md 신설
44개 스파이크로 question.md 0-Y를 재실측한 결과, 여섯 번째 세션의
"콜백이 raw 값을 받으면 완전 클린" 판정이 틀렸음이 드러남 — 그건 진단
0건만 확인한 것이었고, luau-analyze --annotate로 열어보니 반환 타입이
Unifiable<Error>로 조용히 새고 있었음(틀린 대입도 안 잡힘).

진짜 원인은 콜백 계약이 아니라 Compute가 State<U>(자기 이름을 다른 타입
인자로 감싼 타입)를 반환한다는 것 자체 — RFC relax-recursive-type-restriction이
Promise<T>.andThen으로 예시 든 바로 그 패턴. 사용자 확정: quad가 타입을
비틀 일이 아니라 상위 Luau의 현 한계이고, RFC/이슈 수혜를 받을 때 해결될
일이라 당장 할 수 있는 바 없음.

- base/typing-limits.md 신설 — 흩어져 있던 타입 한계 5건 통합, 대전제
  "Luau 한계를 우회하려 타입/API를 비틀지 않는다", 새 API 설계 체크리스트
- audit/type-recursion-issue/ 신설 — REPORT.md + spikes 44개(audit 폴더에
  스크립트를 같이 둔 첫 예외, 판정 재현에 개별 실행이 필요해서)
- 0-Y 해소 전파: question.md(최우선 2건→1건) / archive / base 5개 /
  research 2개 / 인덱스 4개 / luau-test(08을 done/으로, review-required 비움)
- audit/luau-test-first-run-2026-08-13.md: 판정이 뒤집힌 당사자라 배너뿐
  아니라 본문 표·문단·결론까지 전수 수정
- HUMAN_TODO 6번 신설: luau-lsp 기본이 옛 솔버라 CLI와 진단이 다름

교훈: luau-analyze 진단 0건은 타입 해소를 뜻하지 않음 — 타입 스파이크는
--annotate로 실제 추론 타입을 확인하고 음성 대조군을 같이 둘 것.

doc-check.py ERROR 0 유지(WARN 59건, 변경 전과 동일).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KckSawrsJSJmDBcSojJPxZ
2026-08-13 22:08:51 +09:00
ed99a16aaf
docs(audit): 12차 세션 — 순차 직접 감사 반복, 새 문제 없음 확인
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6hzeUi5QdLPEk69B6cXFa
2026-08-13 19:04:30 +09:00
ae39172124
docs(audit): 11차 세션 — 순차 직접 감사, 부정확성 4건 수정
서브 에이전트 없이 직접 코퍼스 전체를 순회한 감사(base/research/reference/
luau-test/audit/archive 전부 확인, doc-check.py ERROR 0 유지). 발견한
부정확성은 전부 9~10차 세션의 문서 재편 이후 반영이 누락된 stale 카운트/
포인터:

- question.md 0-Z/0-A: 반영 대상 문서 개수가 "6개"로 남아 ref-plan.md가
  누락돼 있던 것을 "7개"로 정정(dispatch-redispatch-diff-plan.md 6절과
  일치).
- HUMAN_TODO.md 4번: 동일한 6→7 stale 카운트 정정.
- ROADMAP.md 백로그: 2026-08-13 세 번째 세션에 이미 불필요로 해소된
  objectListClass.__newIndex 재현 테스트가 여전히 할 일로 남아있던 것 정정.

세션 로그(session/2026-08-13-11-...)와 CLAUDE.md 세션 히스토리 요약도 추가.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6hzeUi5QdLPEk69B6cXFa
2026-08-13 18:52:10 +09:00
aaefa08c1c
docs(audit): 10차 세션 — 병렬 에이전트 코퍼스 감사, 부정확성 7건 수정
9차 세션의 구조 변경(luau-test 재편/bind-system-plan 분할/question.md
트림)이 남긴 반영 누락을 6개 병렬 에이전트로 찾아 즉시 수정:

- luau-test 재편 후 깨진 flat 경로 참조 9곳을 파일명+실제 폴더로 정정
- bind-system-plan.md 분할 후 자기참조/외부참조 깨짐 8곳 정정
- ref-plan.md에 0-Z 배너가 안 옮겨와 옛 재디스패치 모델을 무배너로
  서술 중이던 것 발견 — 배너 추가, 반영 대상 6개→7개로 갱신
- "8차 세션"으로 잘못 표기된 9차 세션 작업 17곳(git 커밋 타임스탬프로
  교차검증) 정정
- question.md 트림 중 빠진 열린 질문(State<State<T>> 평탄화) 복원,
  트림 후 깨진 참조 2곳 정정
- ROADMAP.md M0 섹션에 0-Y/0-Z 게이트 표시 누락 보강

doc-check.py ERROR 0 유지. 새로 연 설계 질문 없음 — 전부 기존 서술
정합성 문제.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6hzeUi5QdLPEk69B6cXFa
2026-08-13 18:32:53 +09:00
540c142969
docs(session): 9차 세션 기록 — 구조 재편 3건 + 재발 방지 도구
CLAUDE.md 관례대로 세션 로그 신설 + 압축 요약 추가.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6hzeUi5QdLPEk69B6cXFa
2026-08-13 18:14:06 +09:00
0fe92fc22a
tools(docs): 코퍼스 기계 점검 doc-check.py 신설 + 중대 변경 핸드오버 체크리스트
사용자 질문: "이런 깊은 감사를 재발 방지하는 방법이 있나. 중대 변경에 대해
그 사항을 아는 세션이 stale 없게 핸드오버해야 하는데 그런 게 없어서 쌓임."

진단: 7·8차 감사에서 찾은 55건이 거의 전부 **변경한 세션이 그 자리에서
안 한 일**이었고, 그중 상당수는 grep으로 잡히는 기계적 종류였음. 그래서
규율 문서만 쓰지 않고 **실제 검사기**를 만듦.

.claude/tools/doc-check.py — 라이브 문서 61개 대상:
  [ERROR] 깨진 파일 참조(우리 문서 명명 관례에 맞는 것만; 아직 없는 소스
          트리 .luau와 외부 문서명은 오탐이라 WARN으로 분리)
  [WARN]  절 참조 불일치 — `foo.md` "절 제목"이 그 파일에 없음
  [ERROR] README 색인 누락
  [WARN]  날짜 없는 시한부 주장("아직 안 돌려봄"/"열린 질문 없음" 등)
  [WARN]  미반영 ⚠️ 배너 단 파일 vs 반영 목록 일치
현재 ERROR 0 / WARN 58(대부분 절 제목 의역 인용, 판단 대상).

**검사기가 즉시 실효를 증명함** — 같은 세션에 bind-system-plan.md를 쪼개며
"이중 바인딩 금지" 절 참조 4곳을 ref-plan.md로 잘못 옮긴 걸(실제로는
Observer/Effect 절이라 이동 대상이 아니었음) 이 스크립트가 잡아내 되돌림.

CLAUDE.md "작업 방식"에 중대 변경 핸드오버 체크리스트 6단계 명문화:
doc-check 실행 → 부정당한 *본문 문장* 전수 grep(배너만 달고 본문 방치가
최다 실패) → 뒤집힌 원문은 archive로 → 개수/상태는 소스 하나만 → 시한부
주장엔 날짜 → 인덱스 레이어 3개 동시 갱신.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6hzeUi5QdLPEk69B6cXFa
2026-08-13 18:13:09 +09:00
0eedbad0b9
refactor(question): 해소 항목을 archive로 분리 — question.md 525 → 279줄
사용자 지적: "question.md 또한, 사람이 봐야하는 문서인데 해결된 것이 많아서
필터해서 필요한 부분만 읽어보기 힘듦."

- archive/question-resolved.md 신설 — 분리 직전 전문을 그대로 보존
  (결정 내용은 하나도 안 바뀜, 읽는 자리만 이동)
- question.md는 **사용자가 답해야 할 것만** 남김:
  최우선 2건(0-Y/0-Z, M0를 막고 있고 사용자가 직접 판단하겠다고 이관)
  → 결정 대기 2건(0-A 컨텍스트/0-B) → 용어 미확정 6건 → 낮은 우선순위 5건
- 통째로 해소된 옛 "0번(추가 프리미티브)"/"2번(구현 착수 직전 감사)"과
  맨 아래 확정 요약표(README base 표와 중복)는 archive로
- 재발 방지: "항목을 해소하면 여기서 지우고 archive로 옮길 것"을 문서 상단에
  명시

인바운드 참조 보호: 절 번호 1/3은 헤딩에 유지(참조 ~10곳), 없어진 0번/2번을
가리키던 CLAUDE.md·effect-plan.md 2곳은 실제 원본(pre-implementation-audit.md,
archive)으로 재지정. 없어진 번호에 대한 안내를 question.md 하단에 남김.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6hzeUi5QdLPEk69B6cXFa
2026-08-13 18:08:39 +09:00
3ca2696208
docs(session): 8차 감사 세션 기록 — 직전 6라운드 감사의 순차 직접 재검증
CLAUDE.md 관례대로 세션 로그 신설 + 압축 요약 추가.

6라운드 재검증 결과 16건 추가 발견(9→2→3→2→0→0)으로 수렴 종료.
직전 세션이 "수렴"으로 끝낸 지점에서 나온 것이고, 그중 1건은 문서
정합성이 아니라 실제 의사코드 결함(retractFrom의 nil 가드).

감사 사각지대 둘을 다음 라운드용 일반 교훈으로 기록:
1. 정정 배너를 달면 그 배너가 부정하는 본문 문장까지 같은 커밋에서
   고쳤는지 확인 — 직전 감사가 CLAUDE.md 헤더에만 배너를 달고 본문
   bullet은 그대로 둔 게 이번 최대 발견의 원인
2. 영역 분할 병렬 감사는 "아무 영역에도 안 속한 파일"을 통째로 빠뜨림
   — HUMAN_TODO.md가 6라운드 동안 한 번도 안 열렸고 하필 사람에게 가장
   중요한 문서였음. 레포 루트 파일 목록으로 커버리지부터 체크할 것

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6hzeUi5QdLPEk69B6cXFa
2026-08-13 17:56:09 +09:00
1221512341
fix(dispatch,docs): 7차 감사 4라운드 — retractFrom의 nil 가드가 계약 위반을 조용히 삼키던 것, CLAUDE.md 문서 지도 누락
실제 의사코드 결함 1건(문서 정합성이 아니라 로직):
- `Dispatch.retractFrom`이 `if retractor then ... end`로 감싸고 있어서,
  핸들러가 계약을 어기고 `nil`을 반환해도 조용히 넘어감. 그런데 문서
  두 곳(핸들러 계약 절, Handler 작성 체크리스트 7번)은 "생략하면
  `attempt to call a nil value`로 크래시"라고 서술 — 그 가드 때문에
  크래시조차 안 나는 게 실제였음.
  더 나쁜 건 실제 결과: `list[index] = nil`로 **배열에 구멍**이 나서
  (a) `#list`가 Lua 명세상 미정의가 되어 retractFrom의 순회 시작점이
  어긋나고, (b) 그 자리가 비어 보여 `Dispatch.process`의 점유 체크를
  통과 → **소유권 충돌 감지가 조용히 꺼짐**(0-Z가 다루는 바로 그 안전망).
  가드에 걸리는 유일한 경우가 계약 위반뿐이므로(정상 경로는 process가
  NOOP 마커를 먼저 박음) 프로젝트의 "즉시 error" 원칙대로 error로 전환,
  서술 두 곳도 실제 실패 모드로 정정.

CLAUDE.md "계획 문서 구조"에 `luau-test/`와 `audit/`가 통째로 누락돼
있던 것 추가 — 항상 로드되는 진입점인데, 지금 스파이크 상태의 소스
(`luau-test/STATUS.md`)와 0-Y의 근거(`audit/`)로 가는 길이 이 지도에
없었음. README의 `audit/` 행에도 파일 2개 명시(gcconn-trick-verification.md는
README 어디에도 등재돼 있지 않았음).

색인 완전성 전수 확인: base 17 / research 10 / archive 17 / reference 3
전부 README 등재됨(누락은 위 audit 1건뿐이었고 이번에 해소).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6hzeUi5QdLPEk69B6cXFa
2026-08-13 17:53:00 +09:00
09b22d0e80
docs(audit): 7차 감사 2라운드 — 0-Z 반영 목록에서 architecture.md/ROADMAP 누락 발견, 링크 전수 검증
1. `research/dispatch-redispatch-diff-plan.md` 6절(0-Z 확정 시 파일별 반영
   목록)이 base 4개만 나열 — 그런데 `architecture.md`와 `ROADMAP.md`도
   같은 ⚠️ 배너를 달고 있음(전자는 소스트리의 chains/retractFrom 서술,
   후자는 M2/M4/M6/M10 체크리스트). 목록대로만 옮기면 이 둘이 옛 모델로
   남는 실제 핸드오버 갭이라 6절에 추가하고, "배너 단 파일 = 반영 대상,
   반영 후 배너 제거" 규칙으로 명문화. CLAUDE.md 0번/question.md 0-Z·0-A의
   "4개" 표기도 6개로 동기화.
   ※ architecture.md는 모든 세션이 "먼저 읽으라"고 지목하는 진입점이라
     누락 시 파급이 가장 큼.

2. CLAUDE.md 세션 히스토리(2026-08-09 열두 번째)의 "**아직 결과 미확인** —
   M0 착수 전 최우선 확인 대상"이 현재형으로 읽히던 것 정정.

전수 검증해 문제 없던 것:
- 문서 간 파일 참조 152개 링크 체크 — 라이브 문서(base/research/reference/
  README/ROADMAP/question/CLAUDE) 깨진 링크 0건. 깨진 참조는 전부
  session/(원문 보존 대상), initreq/(읽기 전용 클론), archive/ 히스토리 안.
- luau-test README/STATUS 파일명 ↔ 실제 파일 일치(04 개명, gc-trigger 헬퍼 포함)
- Handler 계약 정의부(process가 retractor 반환, 반환 생략 불가) 일관
- Dispatch.process/retractFrom 의사코드 손 트레이싱 — 점유 마커 선행,
  #list hole 없음, hint가 target 인덱스에만, index>#list일 때 no-op 정상
- Relate API arity(Set 3인자/Get 2인자) 문서 간 일치
- 폐기된 이름(retractUnder/processAs/retractSelfAndUnder) 잔존 8건은 전부
  "옛 이름은 X였음" 형태의 의도된 히스토리 표기

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6hzeUi5QdLPEk69B6cXFa
2026-08-13 17:48:11 +09:00
d3f8c4d2d2
docs(audit): 7차 감사(직접 검증) — 실측 반영 누락 3건 + Slot 언마운트 미반영 6건 정정, 역전 서사 archive 이전
직전 6라운드 감사(에이전트 병렬)가 "수렴"으로 종료했으나, 손으로 재검증하니
가장 영향 큰 층위에서 stale이 남아 있었음:

1. CLAUDE.md "지금 할 일" 1번 본문 — 항상 로드되는 진입점인데 "스파이크
   20개 중 19개를 여전히 안 돌려봄"이라고 서술(사실은 여섯 번째 세션에
   런타임 12개 전원 통과), "19는 재작성 대기"(사실은 재작성 완료·통과),
   "설계는 더 이상 안 막힘"(실측이 0-Y를 새로 염). 4라운드에서 헤더에
   정정 배너만 붙이고 본문 bullet은 안 고친 게 원인.
2. question.md 2번 — 같은 "아직 사용자가 안 돌려봄"이 잔존, 자기 문서
   최상단 0-Y/0-Z와도 모순.
3. pre-implementation-audit.md — 16/17 "결과 미확인" 잔존(17 통과, 16 실패).

Slot 파괴→언마운트 전환(여섯 번째 세션)의 미반영도 추가로 6곳:
- slot-plan.md 최상단 "상태" 줄이 여전히 "retract=폐기"(앞에서부터 읽는
  구현자가 구 모델로 짤 위험 — 4라운드가 같은 사유로 다른 곳을 고쳤던 것)
- reconcile이 rawRemove(파괴)를 부른다는 서술 3곳(391/450/1708 부근).
  rawUnmount도 releaseOwner를 부르므로 소유권 논증 자체는 성립 — 함수명만
  stale이라 논증 유지 근거를 함께 명시
- question.md 확정 요약표 Slot 행, README.md slot-plan 행(여섯 번째 세션
  전환 전체가 색인에 누락 — 언마운트/rawUnmount/portal/dispose 전부)

역전 서사 archive 이전(사용자 지시):
- archive/slot-discard-no-portal-reversed.md 신설 — base/slot-plan.md에
  히스토리로만 남아 있던 세 덩어리(2026-08-04 "폐기, 옮기지 않음" 확정,
  State<Slot?> 왕복 분석, 포탈 검토+숙제 셋)를 원문 보존해 이전하고 본문엔
  요약 포인터만 남김. slot-plan.md 1982 → 1919줄

검증했으나 정확했던 것: 4개 base 문서의 0-Z 배너, architecture.md 0-Z
포인터, ROADMAP 게이트 서술, luau-test/STATUS.md 분류, luau-test/README.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6hzeUi5QdLPEk69B6cXFa
2026-08-13 17:44:26 +09:00
8569e570d6
docs(audit): 6라운드 코퍼스 감사 수렴 — 검증 라운드 마무리 + 세션 기록
검증 라운드(커밋 없이 직전 5라운드 수정 검증 + D./DI. 전수 재확인 +
6라운드 동안 한 번도 안 건드린 파일 3개 전체 정독)에서 유효한 새 문제
0건 확인, 사소한 표현 하나만 정리(modifier-plan.md 9-2의 "당장의
fallback" 문단이 이미 확정된 결론인데 여전히 조건문 톤이던 것).

발견 건수 추이(8→7→11→9→4→0)로 수렴 판단, 반복 종료. CLAUDE.md 관례대로
세션 기록 신설 + 압축 요약 추가(session/2026-08-13-07-corpus-audit-six-rounds.md).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 17:31:20 +09:00
6e097c92d0
docs(audit): 코퍼스 6차 감사 — 실측 결과 미반영/DI 앞서간 표기/Splice 누락 4건 정정
5차 감사(파괴/0-Y/0-Z 두 패턴 최종 검증 + 다른 카테고리 전용 탐색)에서
발견한 것 정리:

- modifier-plan.md 9-2/ROADMAP.md M7: Modifier.Overridden 서브타입
  이슈가 이미 luau-test/09로 실측 통과됐는데(fallback any 정상 작동
  확인) 3곳(ROADMAP/modifier-plan.md/luau-test/README.md 중 실제
  "미검증" 서술이 있던 2곳)이 여전히 "미검증"으로 남아있던 것 정정
- ROADMAP.md M6/slot-plan.md: `DI`→`D` 리네임이 question.md 1번에서
  아직 미확정인데 `D.InstSlot`으로 앞서서 확정된 것처럼 쓰던 것을
  현재 우세 표기 `DI.InstSlot`(+ 미확정이라는 캐비엇)로 정정
- ROADMAP.md M6: 확정·실측 통과된 `Slot:Splice`가 CRUD 체크리스트
  항목 제목에서 아예 누락돼 있던 것 추가
- CLAUDE.md: "지금 할 일" 0번이 "0-Y/0-Z 두 결정"이라 명시하는데
  question.md엔 0-B(dispose 시그니처)도 열려 있어 개수가 안 맞던 것 —
  0-B는 M0가 아니라 M6만 막는다는 캐비엇 추가

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 17:26:57 +09:00
91fd7b88a8
docs(audit): 코퍼스 5차 감사 — 0-Y/0-Z 포인터 4곳 + 파괴 용어 잔존 5곳 전수 정리
4차 감사(반복되던 두 패턴을 grep으로 전수 스윕)에서 발견한 것 정리:

- architecture.md: 모든 세션이 "먼저 읽으라"는 진입점 파일인데 소스
  트리의 chains/retractFrom 서술에 0-Z 포인터가 전혀 없었음 — 최상단
  배너 추가(가장 중요한 gap, question.md 0-A가 경고하던 바로 그 함정)
- tween-plan.md/operator-sugar-plan.md/effect-plan.md: self-lazy-핸들
  계약(0-Y)에 의존하는 실행 예시/메커니즘 서술에 포인터가 전혀 없었음
  — 3곳 추가
- CLAUDE.md: "지금 할 일" 0번(0-Y/0-Z가 최우선 게이트)과 1번("M0 착수
  전 남은 유일한 게이트는 luau-test뿐")이 정면 모순 — 0-Y/0-Z 발견
  이전에 쓰인 문장이 안 갱신된 stale, 정정
- slot-plan.md 3곳/additional-primitives-plan.md/
  dispatch-redispatch-diff-plan.md: reconcile/Slot:List/재귀 재emit
  가드 설명이 여전히 "파괴"를 현재형으로 서술 — 2026-08-13 여섯 번째
  세션의 언마운트 전환 반영해 정정(지난 세 라운드가 놓친 인스턴스들,
  전수 grep으로 확인)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 17:20:45 +09:00
56ba2b3f37
docs(audit): 스파이크 상태판 신설 + 코퍼스 전반 모순·stale 감사 정정
## luau-test/STATUS.md 신설 (사용자 요청)

"사람이 보기엔 뭐를 바로 봐야하는지 눈에 안 띄어서" — 파일별 상태를
🔴 사람 결정 필요 / 🟠 스파이크 깨짐 /  미실행 /  통과로 분류하고
봐야 할 것을 위에 배치. 역할 분담도 명시: STATUS.md가 상태의 소스,
README.md는 각 파일의 검증 의도·배경, audit/는 실행 결과 상세.

## 코퍼스 전반 감사 (에이전트 둘, 보고받은 것 전부 직접 사실 확인 후 수정)

가장 위험: ROADMAP.md가 최우선 게이트(question.md 0-Z, 하강 diff 재설계)를
전혀 안 짚고 있었음. base 4개 문서엔 ⚠️ 배너를 달아뒀는데 정작 구현 순서의
소스인 ROADMAP엔 없어 M2/M4/M10 담당자가 옛 모델로 구현할 위험이 실재.
→ 세 마일스톤 전부에 배너/포인터 추가.

두 번째: slot-plan.md 앞부분이 뒤집힌 결정을 여전히 "확정"으로 자칭.
"폐기, 옮기지 않음, portal은 오버엔지니어링"과 "열린 질문" 절에 역전 표시가
없어 앞에서부터 읽는 구현자가 구 모델로 짤 위험 → 🔄 역전 배너.
더 심각하게 reconcile 의사코드가 여전히 rawRemove(파괴)를 부르고 있었음
(같은 문서가 "[반영 완료]"라 태그해둔 것과 정면 모순) → rawUnmount 신설.
filter/toggle 근거 절도 "제거=파괴" 전제라 캐비엇 추가(결론은 유효).

그 외:
- ROADMAP M11 Tween이 이미 확정된 넷을 미결로 둠(override 정책/옵션 값
  모양/Animate 시그니처/initValue) + research/tween-plan.md 죽은 링크 4곳
- bind-system-plan.md:328, architecture.md:213의 "4종 계약" 잔여
  (isHandlable(k,v) 구식 시그니처 포함)
- store-semantics.md의 "State는 가칭" stale — 2026-08-12에 최종 확정됨
- luau-test/README.md의 04/19 판정 기준이 재작성된 파일을 못 따라감.
  특히 19 C섹션 기준이 정상 동작(nested error)을 실패로 오판하게 돼 있었음
- documentation-content-map.md의 4종 계약 / Attribute<T> 옛 이름
- modifier-plan.md의 "정정이 원문에 소급 안 됨" 패턴
- attribute-plan.md "이름 소유권"이 0-Z 미결인데 "최종"이라 적힌 것 캐비엇
- relate-plan.md의 kSlotMap 역할 서술 부정확, 상호참조 방향 오류 2곳

판단해서 안 고친 것: effect-plan.md의 "cleanup" 14곳 — Handler retract
(내부 배관)와 달리 Effect(fn)에서 사용자가 작성한 fn이 반환하는 React식
콜백이라 다른 층위. 매 감사마다 재지적되므로 lifecycle-pattern.md에
"확인 완료, 의도된 별개 개념"으로 못박음.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 16:48:32 +09:00
b90b3a6b94
fix(slot,docs): 리뷰 지적 5건 정정 — 언마운트/파괴 모순, 계약 개수 모순, 해제 순서 역전
다른 에이전트 리뷰가 짚은 5건을 전부 사실 확인 후 수정.

1. (가장 심각) slot-plan.md의 SlotHandler.process 반환 클로저가 여전히
   destroySlotTree를 불러, 같은 커밋에서 확정한 "State<Slot> 교체는 파괴가
   아니라 언마운트" 결정과 정면 모순 — 그 결정이 적용돼야 할 최상위 dispatch
   경로가 바로 이 클로저인데 "구현상 바뀌어야 하는 것" 절이 reconcile만
   언급하고 빠뜨렸음. 그대로 뒀으면 언마운트 결정 자체가 무의미해질 뻔함.
   → 비파괴 경로 unmountSlotTree 신설(destroySlotTree와의 차이는 딱 둘:
     실제 Destroy 안 함, 자식 releaseOwner 안 함 — 자식이 계속 그 slot
     소유라 통째로 재마운트 가능 = 포탈). 클로저를 unmountSlotTree +
     setOffsetSource(None) -> setLength(0) + unbindLifetime + releaseOwner로
     교체. "자동 경로는 언마운트, 명시적 Remove/Clear/dispose만 파괴"로 정리.

2. bind-system-plan.md "확정된 것" 절이 폐기된 4-메소드 계약을 여전히 확정
   사실로 서술 — 같은 파일 상단은 이미 3-메소드로 갱신돼 자기 문서 내 모순.

3. question.md의 Slot 해제 순서가 거꾸로 — setLength(0)을 먼저 부르라고 돼
   있었는데, 같은 커밋이 slot-plan.md에 추가한 경고가 정확히 그 순서가
   죽어가는 서브트리 Source에 헛된 :Set()을 날린다고 명시.

4. ROADMAP.md M6에 이번 세션 Slot 결정이 전혀 미반영(M0/M2/M4/M10엔 반영됨)
   — 언마운트 전환/dispose/claimOwner vs claimOwnerAt 분리/버그 4건 추가.

5. CLAUDE.md 여섯 번째 세션 항목이 자체 규칙(2~4줄+링크) 위반, 63줄까지
   불어남 — 과거 3000줄 비대화를 유발한 패턴 재발. 15줄로 압축.

6번(StoreBind가 최초 발화에서도 retractFrom을 부르는 것)은 사용자 판단으로
그대로 둠 — 빈 슬롯 retractFrom은 무시 가능하고 일관성이 낫다는 결정.

추가: question.md 0-Y에 사용자 방향 기록 — 순환 타입을 만들기보다 State 타입
자체를 구울 때 인라이닝하는 쪽(Modifier flat 타입 생성과 같은 결). 사람이
직접 확인할 부분이라 0-Z(Attribute)와 함께 사용자 판단 목록으로 이관.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 16:32:04 +09:00
124b706e2c
test(luau-test): 첫 실측 라운드 — 런타임 12개 전원 통과, 타입 이슈 1건 발견
luau/luau-analyze 바이너리가 사용 가능해져, 2026-08-09에 스파이크를 만들기
시작한 이래 처음으로 실제로 돌림(CLAUDE.md가 "M0 착수 전 남은 유일한
게이트"로 꼽아온 항목). 전문: .claude/audit/luau-test-first-run-2026-08-13.md

## 설계 검증 결과 — 런타임은 전부 성립

- 04가 직전 커밋의 감사에서 찾은 버그를 음성 대조군으로 재현: chains:SetStrong을
  process 뒤에 두면 체인 깊이가 3 대신 1로 무너지고, 죽은 store가 나중에 UI를
  덮어씀(STALE). 감사→수정 사이클이 실측으로 닫힘.
- 07은 보강해야 실제 검증이 됐음. 3번 섹션이 sanity check만 하고 있었고 헤더가
  내세운 연쇄 GC 주장은 미검증이었음. 파일이 스스로 적어둔 "weak table 엔트리를
  셀 표준 API가 없다"는 전제도 틀렸음(outer가 __mode="k"라 GC 후 pairs에서
  사라짐) — _countEntries + weak-value canary로 4번 섹션 신설, GC-native
  아키텍처의 핵심 전제(연쇄 GC)가 실측 확정됨.
- 18이 relate-plan.md의 상호 순환 경고를 실증 — 추측이 아니라 실제로 GC 안 됨.
- 01/02/03/05/06/20도 전부 통과.

## 타입 — 진짜 설계 이슈 1건 (question.md 0-Y 신설)

:Compute(fn)의 lazy 핸들 계약이 Luau 양방향 추론과 충돌.
`state:Compute(function(s) return s:Get() * 2 end)`가 타입 에러를 냄.
최소 재현으로 원인 확정: read/self 표기 조정으로는 안 풀리고, 콜백이 raw 값을
받으면 완전 클린. Effect/Observer/Animate/Operator 등 같은 계약을 공유하는
API 전부에 걸림 — M0 착수 전 결정 필요.

## 문서 결함 발견 — modifier-plan.md

"데이터를 테이블에 직접 두고"가 "self 최상위 리터럴 키"로 읽힐 여지가 있었는데,
그렇게 하면 __index가 rawget 성공 시 안 불려 같은 필드 재호출이 죽음. 그 재호출
패턴이 문서 3·4절의 대표 용례라 실사용에서 즉시 터지는 경로였음 — 경고 문단 추가.

## 스파이크 수정

- 17: self 최상위 키 저장 → 내부 저장소 구조로 재작성(크래시 해소)
- 11: 브랜드 판별 크래시로 "다른 Modifier" 케이스가 엉뚱하게 통과하던 것 수정
- 19: B/C를 폐기 설계(rawNew+owners, 3분기 claimOwner)에서 현행 설계로 재작성,
      음성 대조군으로 옛 로직이 Slot{a,a}/Frame{slot,slot}을 통과시킴을 재현
- 07: 위 참고

남은 것은 13/15/16의 스파이크 격리·API 재확인(설계 문제 아님).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 16:19:00 +09:00
8c784288b0
audit(dispatch,slot): c33ae04 전체 감사 — 실제 버그 4건 수정, Slot 언마운트 전환, 재디스패치 모델 재설계안
c33ae04(인덱스 기반 Dispatch 재설계) 전체를 직접 정독. 방향은 옳으나 새로 쓴
의사코드가 손 트레이싱을 안 거친 채 커밋됐음이 드러나 실제 버그 4건 발견·수정:

1. Dispatch.process가 chains:SetStrong을 h.process 뒤에 둬서 최초 마운트에서
   하위 위임 retractor가 통째로 유실(재귀가 자기 테이블을 만들었다 바깥이
   덮어씀 — Slot이면 서브트리 중복 마운트로 직결). SetStrong hoist + 재귀 중
   hole 방지용 no-op 점유 마커 추가.
2. Attribute 그룹이 process에서 retractFrom을 선행 호출해 인덱스 1이 무조건
   비워지는 바람에 점유 체크(=소유권 충돌 감지)가 전혀 작동 안 함. 철거를
   반환 클로저로 이동.
3. SlotHandler가 claim 실패에도 파괴적 클로저를 반환 — nested는 엄격
   claimOwner, top-level은 claimOwnerAt(inst,k)로 분리. rawRemove의
   releaseOwner 누락, destroySlotTree의 GC 타이밍 의존 오류도 수정.
4. Ref retractor가 spurious 재발행에서도 relate를 지워 dedup 무력화.

사용자 설계 결정:
- State<Slot> 교체 = 파괴가 아니라 언마운트(state<Frame>와 동일). 포탈이
  별도 기능이 아니라 이 결정의 귀결이 됨. 해제는 setOffsetSource(None) →
  setLength(0) 순서 고정(반대면 죽는 중인 서브트리 Source에 헛된 Set이
  날아감). dispose(value) 신설 — 트리가 아직 요구하면 파괴 거부하고 error.
- 재디스패치를 "하강 diff"로 재설계 — 래핑 핸들러의 retractFrom 선행 호출을
  폐기하고 Dispatch.process가 핸들러를 먼저 비교. 힌트가 None/래퍼로 오염돼
  깜빡임 방지가 조용히 꺼지는 결함이 계기. 아직 research/에만 있고 base
  미반영(Attribute 이름 소유권 하나가 남음) — base 4개 문서에 경고 배너.

전파 누락 정리: ROADMAP.md가 2026-08-08 이전 모델로 남아있던 것, base 내
"3종 vs 4종 계약" 모순 6개 문서, luau-test/04가 없어진 가드를 검증하던 것
(04는 인덱스 모델 + 버그 1 재현 음성 대조군으로 전면 재작성).

재발 방지: bind-system-plan.md "Handler 작성 체크리스트"(7항목),
relate-plan.md "언제 Relate를 쓰고 언제 쓰면 안 되는가" 신설.

다음 세션 최우선: question.md 0-Z(Attribute 이름 소유권) — 사용자가 직접
스케치하며 심층 분석 예정.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 16:01:49 +09:00
c33ae041b0
design(dispatch): 사각지대 손 트레이싱 라운드 + Dispatch 인덱스 기반 전면 재설계
네 번째 세션: State<State<T>> 발견 방식을 서브에이전트로 코퍼스 전체에
반복해 Tag 참조 카운트(객체 identity 키잉)/Attribute 그룹 자기충돌 버그
발견·수정. Attribute 소유권 충돌 방지를 위해 처음엔 Dispatch.processAs/
retractSelfAndUnder 체크포인트 핸들러 패턴을 신설.

다섯 번째 세션: 체크포인트 패턴이 임시방편이라는 지적에서 출발해, chains의
핸들러 객체 identity 기반 추적 자체가 State<State<T>>를 UB로 만든 근본
원인이었음을 재확인 — 재귀 깊이 인덱스로 재설계(같은 키 재귀는 index+1,
다른 키 위임은 항상 1부터), Handler 계약을 process/retract 2-메소드에서
process가 자기 retract 클로저를 반환하는 1-메소드로 축소. 이걸로
State<State<T>>가 UB에서 정상 지원 대상으로 바뀌고, 전날 만든 체크포인트
패턴 전체가 불필요해져 archive로 이전. 여러 핸들러(StoreBind/Ref/Tag/Slot/
Attribute)의 private Relate 상태 저장소도 대거 정리됨.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132hkscPQWa34iyHrHdoRiF
2026-08-13 14:24:48 +09:00
35c66d4cd0
decide(v1-compat): objectListClass.__newIndex 오타 기능, v2 무관으로 스코프 아웃
v1 재현 테스트가 필요하다고 남아있던 question.md 항목을 사용자가 정리 —
당시 실수였던 건 맞지만 v2는 오브젝트 id 주입/조회 개념 자체가 없어져
재현 여부와 무관하게 v2 마이그레이션 가이드에서 다룰 대상이 아님.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 10:55:27 +09:00
6e9f6fefa1
fix(dispatch): State<State<T>> 재진입 디스패치 체인 파손 버그 발견·수정, Operator Alternative 후보 신설
Haskell Monad/Applicative 비교 리서치 중 사용자가 retractUnder의 꼬리부터
cutoff 로직을 재검토하다 제기한 의심을 pseudocode 손 트레이싱으로 확인 —
store가 emit하는 값 자체가 또 State/Source면 같은 (inst,k)에 같은 핸들러가
중복 push되어 안쪽 구독이 등록 직후 스스로 끊기는 실제 체인 파손 버그였음.
Dispatch.process에 중복 핸들러 즉시 error 가드를 추가하고, 같은 시나리오를
이미 다루고 있었지만 no-op retract 스텁 때문에 증상을 못 잡던 luau-test/04의
사각지대도 재작성. operator-sugar-plan.md에 Alternative(nil 대체값) 후보 신설.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 10:49:34 +09:00
5e6498a3e1
audit(lifecycle): partial gcconn trick verification, close Relate cycle spike gap
User confirmed the two Roblox-engine-dependent assumptions behind the
gcconn trick (ClassName signal never fires, Connection.Connected flips
synchronously on Destroy) via a Studio script; record what's verified vs
still open in a new audit/ folder and document the GC-trigger technique
used. While re-auditing the corpus, found relate-plan.md's ephemeron/
mutual-cycle claim was never actually run in Luau, and CLAUDE.md's
open-questions list still listed State as unresolved after it was
finalized in session 20 — add spike 18 and fix the stale entry. A
background sweep synced .claude/README.md's summary rows against
sessions 8-21 and added spikes 19/20 for newer ownership/refcount
mechanisms lacking coverage.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PGWwZ8khc3Zq7DAnd4Uw6a
2026-08-13 10:09:47 +09:00