diff --git a/.claude/README.md b/.claude/README.md index cce9246..d2dc136 100644 --- a/.claude/README.md +++ b/.claude/README.md @@ -24,7 +24,7 @@ | `base/` | 결정 완료 + 프로젝트 전체에 걸치는 컨텍스트 — plan/done 개념 없음, 계속 참조되는 배경지식. **항상 읽어야 하는** 배경지식만 여기 둠(다른 문서를 이해하는 데 전제되는 것) | | `reference/` | **[2026-08-07 신설]** 결정 자체가 아니라 다른 문서가 근거로 인용하는 온디맨드 참고 자료(v1 스냅샷, 프레임워크 비교 리서치) — "완료" 개념 없는 건 `base/`와 같지만, 항상 읽을 필요는 없고 해당 문서가 인용될 때만 열어보면 됨. `quadnomicon` 소재 후보가 많음. **[2026-08-21 확장] 확정된 결정의 "왜 그렇게 정했나" 근거 기록도 여기 둔다** — `research/`(아직 상의 필요)도 `archive/`(뒤집혔거나 기각됨)도 아니고, `base/`가 근거로 인용하는 온디맨드 자료라는 이 폴더의 기준에 정확히 맞기 때문(`slot-attach-decomposition.md`/`epoch-brand-composition.md`가 그렇게 들어옴) | | `research/` | 아직 착수 전, 사용자와 스코프/설계를 더 상의해야 함 | -| `qa-request/` | 원래 용도는 "구현 완료(코드/에이전트 검증까지 끝남) + 사용자 본인의 실기기(Roblox Studio) QA만 남음". **[2026-08-18 확장]** 구현 전에도 **사용자 심사 라운드의 산출물**을 여기 둠 — `pre-implementation-qa-round1.md`(1라운드: `base/` 확정 문서 전체를 문항으로 재확인받아 **"아니오"가 나온 항목만** 모은 결함 목록 + 신규 요구사항(`N-n`) + 부수 오탈자. **같은 날 전부 `base/`에 반영 완료**라 지금은 "무엇이 왜 틀렸었나"의 근거 기록이고, 지금 유효한 설계는 항상 `base/`가 소스. 아직 안 닫힌 것은 `question.md` 최우선 절과 `.claude/todos.md` 00번이 소스), `pre-implementation-qa-round2.md`(2라운드: 확정 의사코드를 실제로 손으로 실행해보는 트레이싱 — **완료**, 발견된 크래시 `RC-1`(`recompute` 트리거 모델)도 같은 날 후속 세션에서 Blocker 게이팅 설계로 해결·반영까지 끝남, `archive/question-resolved.md`에 논의 요지 정리), `pre-implementation-qa-round3.md`(3라운드: `RC-1` 해법(Blocker 게이팅)이 실제로 `attachSlot`/`recompute`에 반영된 걸 손으로 트레이싱 — **완료**, `RC-3`/`RC-4`(`activateList`가 자기 Slot의 Blocker보다 먼저 실행되는 순서 문제)와 `bk.N` 수명주기 미정을 발견했다가 같은 세션에 사용자가 최초 분석 오류를 직접 정정하며 전부 해결·`base/` 반영까지 끝남, `archive/question-resolved.md`에 논의 요지 정리. `ROADMAP.md` M3가 M2의 `Blocker.luau`에 의존하게 된 마일스톤 순서 불일치는 각주로 반영 — **[2026-08-24]** 그때 열어뒀던 마일스톤 재편은 M2/M3 순서 교체로 닫혔다). `pre-implementation-qa-round4.md`(4라운드: 사용자 요청으로 **`base/` 확정 전체를 "예가 나와야 정상인 문항"으로 다시 뽑은 전수 문항지** — **[2026-08-21] 완료·종결**. 1~3라운드와 달리 이 파일은 **문항지 원본 그대로 남긴다** — 처리 결과 전량이 `-followup.md`에 쌓였으므로 "아니오만 남기는 재편"은 안 하기로 함(같은 정보가 두 곳에 갈라지는 걸 피함). 문항 수/문서별 분포는 그 파일 자신이 소스). `pre-implementation-qa-round4-response.md`(사용자 회신 원문 — 이 라운드는 회신을 **별도 파일**로 받았다, 1~3라운드와 다른 점), `pre-implementation-qa-round4-followup.md`(**[2026-08-20 시작, 2026-08-21 종결]** 그 회신 처리 결과 — A~H 8개 절이 4차에 걸쳐 시간순으로 쌓였고 **마지막 H절이 최신이자 소스**. B·C절의 재질문/판단 대기 항목은 F·G절을 거쳐 **H절에서 전량 닫혔다**(`Detach` 보존 주체, `KeyGone`, `Owned`, `attachSlot` 분해). **열린 질문 없음**. **[2026-08-21 정정]** 여기 적혀 있던 "5라운드 문항지는 만들지 않는다"는 뒤집혔다 — 같은 날 사용자 요청으로 5라운드를 만들었다), `pre-implementation-qa-round5.md`(**[2026-08-21 신설·처리 완료]** 5라운드: 4라운드에서 "예"로 넘어간 자리는 건너뛰고 **(1) 4라운드에 문항이 아예 없던 영역**(`project-setup-plan.md`/`quad-types-plan.md`, 그리고 **문서가 아니라 실제 커밋된 M1 코드**), **(2) 4라운드 회신 이후 새로 확정된 것**(`Detach`/`_detached`/`KeyGone`/`Owned`/`attachSlot` 분해 등), **(3) 큰 문서의 심화**(예: `debounce-throttle-plan.md`)만 묻는다. 문항 수는 그 문서 자신이 소스), `pre-implementation-qa-round5-response.md`(사용자 회신 원문 — 4라운드와 같이 별도 파일), `pre-implementation-qa-round5-followup.md`(**[2026-08-21]** 그 회신 처리 결과 — 즉시 반영분 / 재질문 / 사용자 판단 필요 / 새로 만든 문서 둘(`gate-plan.md`·`state-epoch-plan.md` — 같은 날 확정되며 `base/`로 승격)까지. **처리 결과의 소스는 이 파일**). `pre-implementation-handtrace-round6.md`(**[2026-08-22 신설]** 6라운드: 문항지가 아니라 **손 트레이싱**이다(2·3라운드와 같은 성격) — 사용자가 지목한 최근 확정 5개 영역(`Effect(fn, ...deps)`/`Gate`·`Blocker`/State 전파(`rawInvalid`·emit 지연)/Slot의 `native*`·offset·length·mount/`Brand`·`Epoch`·`EpochMap`)을 실제 값으로 돌려본 결과. 발견 번호는 `H-n`. **[2026-08-23] 2차 패스** — 1차가 안 본 영역(디스패치 코어 전체/라이프타임 유틸/Ref·Tag·Attribute·UI 숏핸드 핸들러/Slot의 `raw*` 계층). **[2026-08-23] 3차 패스** — 1·2차가 한 번도 안 연 문서 전체(Store/State/Source 코어, Modifier·컴포넌트 합성, 이벤트·라이프사이클·에러 격리, Tween·시간 게이트, 타입 계약과 실제 커밋된 M1 코드) + 통합 시나리오. **[2026-08-24] 4차 패스** — 문서 단위가 아니라 **축을 바꿔서**(핸들러 레지스트리 전수/두 대형 핸들러 문서 심층/`luau-test` 스파이크 실제 재실행/프리미티브 조합 매트릭스/`reference`·`archive`·로드맵 M2~M9/엔진·언어 사실 주장 전수 검증). 3·4차는 추론으로 끝내지 않고 로컬 `luau`/`luau-analyze`와 공식 문서로 **직접 재현·교차검증**했고, 그 부수로 기존 `H-2`의 크래시 주장이 틀렸음도 드러났다(3차 패스 머리의 정정 절). 발견 번호는 패스를 가로질러 이어서 매긴다. 발견 수/심각도 분포는 그 문서 자신이 소스. 각 패스의 "확인만 하고 문제 없었던 것" 절은 다시 트레이싱할 필요 없는 자리를 적어둔 것. **⭐ [2026-08-24] 전량 처리·반영 완료** — 그 문서는 이제 **발견 당시의 기록**이라 각 항목의 "갈래"는 선택 전 목록이니 그대로 믿지 말 것), `pre-implementation-handtrace-round6-followup.md`(**[2026-08-24 신설] 6라운드의 결정과 근거가 여기 소스다** — `H-1`~`H-54`를 사용자와 대화형으로 하나씩 결정한 기록이고, 반영 후 `/code-review high`가 잡은 7건(그중 셋이 이번 반영이 만든 회귀)도 D절에 있다. 진행 경위와 사용자 발언 원문은 `session/2026-08-24-01-handtrace-round6-resolution.md`). `pre-implementation-handtrace-round7.md`(**[2026-08-25 신설, 회신 대기]** 7라운드: 6라운드와 같은 손 트레이싱이되 범위가 **M2(반응형 코어)와 M2→M3 경계**다. 패스 6개가 각기 다른 각도를 쓴다 — 1차는 프리미티브 사이의 *호출 순서*를 시간축으로 겹쳐 보기, 2차는 문서가 "확인했다"고 적은 런타임/타입 주장을 실제로 `luau`/`luau-analyze`에 걸어보기, 3차는 **커밋된 M1 코드·툴체인을 이 저장소에서 그대로 돌려보기** + 1·2차가 뺐던 "M2를 *소비하는* 문서", 4차는 **M2 코어를 문서 그대로 옮긴 참조 구현을 돌려보기** + 아무 문서도 안 정한 **예외 경로**, 5차는 **확정된 M2 표면을 실제 Luau 타입으로 선언해 `luau-analyze`에 걸어보기**(확정 시그니처가 확정 관용구를 통과시키는가), 6차는 **그 참조 구현을 M2→M3 경계(Length/Offset 부기·Dispatch 체인)까지 이어 붙여 돌려보기** + **quad 자신이 던지기로 확정한 error 42곳의 계약 감사**. 발견 번호는 6라운드에서 이어서 `H-55`부터, 패스를 가로질러 연속으로 매긴다. 발견 수/심각도 분포는 그 문서 자신이 소스. 각 패스의 "문제가 없던 것" 부록은 다시 파지 않아도 되는 자리를 적어둔 것. **아직 아무것도 `base/`에 반영하지 않았다** — 판정은 사용자가 하고, 결정이 나면 6라운드처럼 `-followup.md`를 새로 만든다), `pre-implementation-handtrace-round7-verification.md`(**[2026-08-25 신설]** 그 52건이 **정말 유효한지만** 판정한 검증 패스 — 새 발견은 없다. ⚠️ **재실행이 아니라 대조로 판정했다**: 4·5·6차 패스가 쓴 전사물(`audit/handtrace-round7-reference-impl/spikes/`), `pre-implementation-handtrace-round7-followup.md`(**[2026-08-25 신설] 그 52건에 대한 사용자 결정과 `base/` 반영 결과 — 결정 단위 12묶음(🅐~🅜) 순서로 대화형 처리. **이 파일이 결정의 소스**이고 발견 원문은 앞의 두 파일. 무효/기각 7건(`H-73`~`H-77` 계열: `<>`가 값 호출부에서 동작함이 실측으로 드러나 Store 재설계로 이어짐, `RunInit` 누수는 성립 안 하는 사용법), 나머지는 전량 반영. **부수로 `question.md` 최우선 두 항목이 같이 닫혀 M2 착수 게이트가 0이 됐다**)과 `base/` 확정 의사코드를 줄 단위로 맞춰봤고(전사 오류로 생긴 발견은 **없었다**, 미신고 차이 3개는 전부 발견을 만들지 않는 방향), Luau 언어 동작·저장소 상태를 주장하는 것만 직접 재실행했다. 판정 분포와 항목별 근거는 그 문서 자신이 소스 — 여기서 세지 않는다. **결정 전에 반드시 읽을 것**: 부정 주장·개수 주장 몇 건이 정정됐고, 특히 **이미 사용자가 판단한 항목을 다시 묻게 되는 자리**가 하나 있다. 마지막 절의 **batch용 요약**이 유효 항목을 "한 결정으로 닫히는 묶음"으로 재편성해뒀으니 회신은 번호순이 아니라 그 묶음 단위로 하는 게 싸다), `pre-implementation-handtrace-round8.md`(**[2026-08-26 신설, 회신 대기]** 8라운드: 7라운드 반영으로 새로 쓰인 `base/` 서술을 **서로 겹쳐서** 재트레이싱한 것 — 개별 함수가 아니라 "반영된 결정들이 조합될 때 성립하는가"가 주제. 3패스에 걸쳐 `base/` 전 문서를 완독했고, 발견 번호는 `H-107`부터 이어 매김(발견 수·심각도 분포는 그 문서 자신이 소스), 실측 스파이크는 발견 항목에 인라인 전사. 사용자 결정 문항 Q1~Q10이 §4에 배치 회신용으로 정리돼 있다. 커밋 전 `/code-review`가 이 문서 자체의 결함 7건을 잡아 반영됐다(각 항목의 `[code-review 정정/추가]` 표시). **⭐ [2026-08-26] 전량 처리·반영 완료** — 그 문서는 이제 **발견 당시의 기록**이라 각 항목의 "갈래"는 선택 전 목록이니 그대로 믿지 말 것), `pre-implementation-handtrace-round8-followup.md`(**[2026-08-26 신설] 8라운드의 결정과 근거가 여기 소스다** — Q1~Q10을 사용자와 대화형으로 처리한 기록. **역전은 없고** 전부 "7라운드 확정이 `base/`에 내려앉을 때 생긴 누락·충돌"을 닫은 것. ⭐ 사용자가 **문항의 전제 자체를 정정한 것이 둘** 있다(Ref 콜백 ↔ Observer 콜백은 애초에 통합 대상이 아니다 / `H-118`은 소유권 문제가 아니라 문장이 틀린 것) — 결정만 읽지 말고 그 두 절을 볼 것), `pre-implementation-handtrace-round9-brief.md`(**[2026-08-26 신설]** 9라운드를 돌릴 감사자에게 주는 **지시서** — 발견 보고가 아니라 그 앞단이다. 이런 지시서를 저장하는 건 이번이 처음으로, 7·8라운드 것은 대화에만 있었고 저장되지 않았다(8라운드 본문이 인용하는 "감사 지시서 §2"가 코퍼스 어디에도 없는 이유). 스코프를 **커밋 `9dd8213` 하나의 델타**로 정의한 게 핵심 — 8라운드 결정 반영과 그 뒤 `/code-review high` 7패스 수정이 전부 그 커밋에 들어 있고 아무도 트레이싱한 적이 없다. 레인 셋(A: 그 델타의 상호 간섭 / C: `audit/handtrace-round7-reference-impl/`을 지금 계약으로 갱신해 실행 / B: 8라운드 §6이 남긴 M5+ 값 단위 트레이싱)과 우선순위 근거, `-round8-followup.md`가 적어둔 **반복 실패 모드 7개**를 사냥 목록으로 옮겨 실었다. 각도 문자(A~H)는 8라운드와 같은 걸 유지해 상호참조가 되게 했다), `pre-implementation-handtrace-round9.md`(**[2026-08-26]** 9라운드 발견 보고 — 레인 A(`9dd8213` 델타 상호 간섭)·C(참조 구현을 현재 계약으로 재전사해 `luau` 실행)·G(Luau 사실 재확인)·D(ROADMAP M2 시뮬레이션)·B(M5+ 값 단위, 첫 시도) — 발견 `H-124`~`H-141`, 🔴 둘(`recompute`의 `lengthList[i]` nil 읽기 / 재마운트 시 `_baseObserver` 미바인드 캐시 stale) 다 실측 재현. §4 배치 문항 Q1~Q10 + §5 이상 없음(⭐ `keyof<{}>` 빈 Store 실측으로 클린) + §6), `pre-implementation-handtrace-round9-followup.md`(**[2026-08-27] 9라운드 결정의 소스 — 전량 처리 완료** — Q1(`recompute` 되감기 판정을 읽기 앞으로) / Q2(`Offset`·`_baseObserver`를 Slot 생성자로, `materializeSlotTree` 순서, `_destroyed` 플래그) / Q3(`element → index`는 `bk.indexOfElement` 하나 — 사용자가 정한 적 없는 `token` 폐기, `H-137` 소멸, `H-141` 신설) / Q4(`EffectHandle` 네 진입점 의사코드) / Q5(M2에 `Ref` 최소형) / Q6(`WeakUnsubscribe` 관대) / Q7(폐기 블록 `archive/`) / Q8(`InstanceChildHandler` 부기) / **Q9(문항 전제가 틀림 — Tween 절 스케치 한 줄 복사 오류)** / Q10(`reconcile` 배치 Blocker) + `H-138`(숏핸드 우선순위) / `H-139`(`New`/`drive` 파이프라인 의사코드) / **`H-142`(props에 `Parent` 금지 — 순서 문제 소멸)** / **`H-143`~`H-146`**(`/code-review`가 낸 새 메커니즘 넷 — 전부 권고 (a), `H-144`는 사용자 요청으로 재구독 뒤 epoch·Blocker 상호작용을 재트레이싱한 기록 포함). 진행 표가 상태의 소스, 사용자 회신 원문 셋 인용; **[2026-08-28]** `H-143`~`H-146` 반영분의 감사 8라운드 표와 `/code-review high` 기록도 여기), `pre-implementation-handtrace-round10-brief.md`(**[2026-08-28 신설]** 10라운드 지시서 — 델타가 아니라 **광범위** 스코프(M2~M8, 레인 A 반응형 코어 전체 / C 참조 구현 갱신·실행 / B 디스패치·Slot / D 타입·M1 코드), 신선한 탐사자가 한 번에 문항지를 만들어 사용자가 배치로 결정하게 하는 것이 목적), `pre-implementation-handtrace-round10.md`(**[2026-08-28 신설, 회신 대기]** 10라운드 발견 보고 + §4 배치 문항지 — 씨앗은 `/code-review`가 낸 `H-147`~`H-149`(죽은 핸들에서 `Rerun` / `Parent` 거부 전용 문구는 새 메커니즘 / Observer `Subscribe` 위임과 `level 2`), 탐사자 발견은 `H-150`부터. 레인 C 실행 기록은 `audit/handtrace-round10-reference-impl/`. **[2026-08-28 탐사 완료]** 🔴 0 / 🟡 5 / 🟢 3, §4 문항 7건(기존 3 + `H-150` `Effect._blocker` 죽은 부품 / `H-151` 게이트 우회 계약 / `H-153` Store 예약 이름 런타임 가드 / `H-154` `InstanceChildHandler` dedup) — 전부 권고 (a). 레인 A·C 완료, B 부분, D `./scripts/test.sh` ALL PASS), `pre-implementation-handtrace-round10-followup.md`(**[2026-08-28] 10라운드 결정의 소스 — 전량 처리 완료.** 사용자가 *"하나하나 같이 보자"*라 대화형으로 처리. **문항의 전제를 뒤집은 것 둘**: `H-147`은 "죽은 핸들에서 `Rerun`"이 아니라 **`fn`/cleanup이 자기 구독을 바꿀 수 있다는 허용 자체가 모순**(→ (A) 금지, `H-143` 소멸, `rawRerun(force)`/`Rerun` 분리), `H-148`은 "문구"가 아니라 **루트 마운트 표면의 부재**(→ `Claim` + `D.Mapper`, `base/claim-plan.md`). 나머지: `H-149` Observer 진입점 인라인 / `H-150` `_blocker` 제거 / `H-151` `Refresh` 캐치업 폐기 — 게이트는 emit 경로만 미룬다 / `H-153` Store 예약 이름 가드 / `H-154` dedup. 새로 생긴 `H-158`(`:Block` 슈가)도 같은 날 확정 — 폐기, `state:Apply(blocker)`. **[2026-08-28 후속 3]** `Claim` 갈래 여덟 전량 확정 → `base/claim-plan.md`로 승격, 그 경위도 이 파일 끝 절). `m2-implementation-round11-brief.md`(**[2026-08-28 신설]** **M2 자율 구현 규약**이자 단위 끝마다 띄우는 탐사자 지시서 — 세 갈래 분류(자율 수정 / §4 배치 / 즉시 중단), 단위 넷, 두 층 커밋 게이트, 첫 단위 계획은 §6), `m2-implementation-round11.md`(**[2026-08-28 신설]** M2 구현 중 발견 원문 + §4 배치 문항지, 번호는 `H-165`부터 — 종이 트레이싱이 아니라 실제 코드를 옮기고 돌리다 나온 것. **[2026-08-31 개명]** 원래 `pre-implementation-handtrace-round11*`이었으나 구현 **중** 문서라 이름이 틀려 사용자 지시로 개명 — brief도 같이). **⭐ [2026-08-31 명명 규약, 사용자 확정]** 구현 라운드 파일은 **`mN-implementation-roundNN`** — 라운드 번호는 마일스톤을 가로질러 **단순 증가**하고(다음 라운드는 어느 마일스톤이든 round12), 마일스톤 접두가 어느 마일스톤의 라운드인지 담는다. 근거: *"m3 을 진행하다 m2 에 하자가 있음을 확인하면 다시 m2 로 올라가 round 가 진행되다 돌아오는 경우도 있을것 … 접두가 둘 다 있는게 정보를 온전히 담아줘"* — 번호만으로는 순서가, 접두만으로는 소속이 안 담긴다. 지시서도 같이 남길 것(`-roundNN-brief.md`). round1~10의 옛 이름(`pre-implementation-*`)은 그대로 둔다 — 실제로 구현 전 라운드였으니 이름이 맞다 | +| `qa-request/` | 원래 용도는 "구현 완료(코드/에이전트 검증까지 끝남) + 사용자 본인의 실기기(Roblox Studio) QA만 남음". **[2026-08-18 확장]** 구현 전에도 **사용자 심사 라운드의 산출물**을 여기 둠 — `pre-implementation-qa-round1.md`(1라운드: `base/` 확정 문서 전체를 문항으로 재확인받아 **"아니오"가 나온 항목만** 모은 결함 목록 + 신규 요구사항(`N-n`) + 부수 오탈자. **같은 날 전부 `base/`에 반영 완료**라 지금은 "무엇이 왜 틀렸었나"의 근거 기록이고, 지금 유효한 설계는 항상 `base/`가 소스. 아직 안 닫힌 것은 `question.md` 최우선 절과 `.claude/todos.md` 00번이 소스), `pre-implementation-qa-round2.md`(2라운드: 확정 의사코드를 실제로 손으로 실행해보는 트레이싱 — **완료**, 발견된 크래시 `RC-1`(`recompute` 트리거 모델)도 같은 날 후속 세션에서 Blocker 게이팅 설계로 해결·반영까지 끝남, `archive/question-resolved.md`에 논의 요지 정리), `pre-implementation-qa-round3.md`(3라운드: `RC-1` 해법(Blocker 게이팅)이 실제로 `attachSlot`/`recompute`에 반영된 걸 손으로 트레이싱 — **완료**, `RC-3`/`RC-4`(`activateList`가 자기 Slot의 Blocker보다 먼저 실행되는 순서 문제)와 `bk.N` 수명주기 미정을 발견했다가 같은 세션에 사용자가 최초 분석 오류를 직접 정정하며 전부 해결·`base/` 반영까지 끝남, `archive/question-resolved.md`에 논의 요지 정리. `ROADMAP.md` M3가 M2의 `Blocker.luau`에 의존하게 된 마일스톤 순서 불일치는 각주로 반영 — **[2026-08-24]** 그때 열어뒀던 마일스톤 재편은 M2/M3 순서 교체로 닫혔다). `pre-implementation-qa-round4.md`(4라운드: 사용자 요청으로 **`base/` 확정 전체를 "예가 나와야 정상인 문항"으로 다시 뽑은 전수 문항지** — **[2026-08-21] 완료·종결**. 1~3라운드와 달리 이 파일은 **문항지 원본 그대로 남긴다** — 처리 결과 전량이 `-followup.md`에 쌓였으므로 "아니오만 남기는 재편"은 안 하기로 함(같은 정보가 두 곳에 갈라지는 걸 피함). 문항 수/문서별 분포는 그 파일 자신이 소스). `pre-implementation-qa-round4-response.md`(사용자 회신 원문 — 이 라운드는 회신을 **별도 파일**로 받았다, 1~3라운드와 다른 점), `pre-implementation-qa-round4-followup.md`(**[2026-08-20 시작, 2026-08-21 종결]** 그 회신 처리 결과 — A~H 8개 절이 4차에 걸쳐 시간순으로 쌓였고 **마지막 H절이 최신이자 소스**. B·C절의 재질문/판단 대기 항목은 F·G절을 거쳐 **H절에서 전량 닫혔다**(`Detach` 보존 주체, `KeyGone`, `Owned`, `attachSlot` 분해). **열린 질문 없음**. **[2026-08-21 정정]** 여기 적혀 있던 "5라운드 문항지는 만들지 않는다"는 뒤집혔다 — 같은 날 사용자 요청으로 5라운드를 만들었다), `pre-implementation-qa-round5.md`(**[2026-08-21 신설·처리 완료]** 5라운드: 4라운드에서 "예"로 넘어간 자리는 건너뛰고 **(1) 4라운드에 문항이 아예 없던 영역**(`project-setup-plan.md`/`quad-types-plan.md`, 그리고 **문서가 아니라 실제 커밋된 M1 코드**), **(2) 4라운드 회신 이후 새로 확정된 것**(`Detach`/`_detached`/`KeyGone`/`Owned`/`attachSlot` 분해 등), **(3) 큰 문서의 심화**(예: `debounce-throttle-plan.md`)만 묻는다. 문항 수는 그 문서 자신이 소스), `pre-implementation-qa-round5-response.md`(사용자 회신 원문 — 4라운드와 같이 별도 파일), `pre-implementation-qa-round5-followup.md`(**[2026-08-21]** 그 회신 처리 결과 — 즉시 반영분 / 재질문 / 사용자 판단 필요 / 새로 만든 문서 둘(`gate-plan.md`·`state-epoch-plan.md` — 같은 날 확정되며 `base/`로 승격)까지. **처리 결과의 소스는 이 파일**). `pre-implementation-handtrace-round6.md`(**[2026-08-22 신설]** 6라운드: 문항지가 아니라 **손 트레이싱**이다(2·3라운드와 같은 성격) — 사용자가 지목한 최근 확정 5개 영역(`Effect(fn, ...deps)`/`Gate`·`Blocker`/State 전파(`rawInvalid`·emit 지연)/Slot의 `native*`·offset·length·mount/`Brand`·`Epoch`·`EpochMap`)을 실제 값으로 돌려본 결과. 발견 번호는 `H-n`. **[2026-08-23] 2차 패스** — 1차가 안 본 영역(디스패치 코어 전체/라이프타임 유틸/Ref·Tag·Attribute·UI 숏핸드 핸들러/Slot의 `raw*` 계층). **[2026-08-23] 3차 패스** — 1·2차가 한 번도 안 연 문서 전체(Store/State/Source 코어, Modifier·컴포넌트 합성, 이벤트·라이프사이클·에러 격리, Tween·시간 게이트, 타입 계약과 실제 커밋된 M1 코드) + 통합 시나리오. **[2026-08-24] 4차 패스** — 문서 단위가 아니라 **축을 바꿔서**(핸들러 레지스트리 전수/두 대형 핸들러 문서 심층/`luau-test` 스파이크 실제 재실행/프리미티브 조합 매트릭스/`reference`·`archive`·로드맵 M2~M9/엔진·언어 사실 주장 전수 검증). 3·4차는 추론으로 끝내지 않고 로컬 `luau`/`luau-analyze`와 공식 문서로 **직접 재현·교차검증**했고, 그 부수로 기존 `H-2`의 크래시 주장이 틀렸음도 드러났다(3차 패스 머리의 정정 절). 발견 번호는 패스를 가로질러 이어서 매긴다. 발견 수/심각도 분포는 그 문서 자신이 소스. 각 패스의 "확인만 하고 문제 없었던 것" 절은 다시 트레이싱할 필요 없는 자리를 적어둔 것. **⭐ [2026-08-24] 전량 처리·반영 완료** — 그 문서는 이제 **발견 당시의 기록**이라 각 항목의 "갈래"는 선택 전 목록이니 그대로 믿지 말 것), `pre-implementation-handtrace-round6-followup.md`(**[2026-08-24 신설] 6라운드의 결정과 근거가 여기 소스다** — `H-1`~`H-54`를 사용자와 대화형으로 하나씩 결정한 기록이고, 반영 후 `/code-review high`가 잡은 7건(그중 셋이 이번 반영이 만든 회귀)도 D절에 있다. 진행 경위와 사용자 발언 원문은 `session/2026-08-24-01-handtrace-round6-resolution.md`). `pre-implementation-handtrace-round7.md`(**[2026-08-25 신설, 회신 대기]** 7라운드: 6라운드와 같은 손 트레이싱이되 범위가 **M2(반응형 코어)와 M2→M3 경계**다. 패스 6개가 각기 다른 각도를 쓴다 — 1차는 프리미티브 사이의 *호출 순서*를 시간축으로 겹쳐 보기, 2차는 문서가 "확인했다"고 적은 런타임/타입 주장을 실제로 `luau`/`luau-analyze`에 걸어보기, 3차는 **커밋된 M1 코드·툴체인을 이 저장소에서 그대로 돌려보기** + 1·2차가 뺐던 "M2를 *소비하는* 문서", 4차는 **M2 코어를 문서 그대로 옮긴 참조 구현을 돌려보기** + 아무 문서도 안 정한 **예외 경로**, 5차는 **확정된 M2 표면을 실제 Luau 타입으로 선언해 `luau-analyze`에 걸어보기**(확정 시그니처가 확정 관용구를 통과시키는가), 6차는 **그 참조 구현을 M2→M3 경계(Length/Offset 부기·Dispatch 체인)까지 이어 붙여 돌려보기** + **quad 자신이 던지기로 확정한 error 42곳의 계약 감사**. 발견 번호는 6라운드에서 이어서 `H-55`부터, 패스를 가로질러 연속으로 매긴다. 발견 수/심각도 분포는 그 문서 자신이 소스. 각 패스의 "문제가 없던 것" 부록은 다시 파지 않아도 되는 자리를 적어둔 것. **아직 아무것도 `base/`에 반영하지 않았다** — 판정은 사용자가 하고, 결정이 나면 6라운드처럼 `-followup.md`를 새로 만든다), `pre-implementation-handtrace-round7-verification.md`(**[2026-08-25 신설]** 그 52건이 **정말 유효한지만** 판정한 검증 패스 — 새 발견은 없다. ⚠️ **재실행이 아니라 대조로 판정했다**: 4·5·6차 패스가 쓴 전사물(`audit/handtrace-round7-reference-impl/spikes/`), `pre-implementation-handtrace-round7-followup.md`(**[2026-08-25 신설] 그 52건에 대한 사용자 결정과 `base/` 반영 결과 — 결정 단위 12묶음(🅐~🅜) 순서로 대화형 처리. **이 파일이 결정의 소스**이고 발견 원문은 앞의 두 파일. 무효/기각 7건(`H-73`~`H-77` 계열: `<>`가 값 호출부에서 동작함이 실측으로 드러나 Store 재설계로 이어짐, `RunInit` 누수는 성립 안 하는 사용법), 나머지는 전량 반영. **부수로 `question.md` 최우선 두 항목이 같이 닫혀 M2 착수 게이트가 0이 됐다**)과 `base/` 확정 의사코드를 줄 단위로 맞춰봤고(전사 오류로 생긴 발견은 **없었다**, 미신고 차이 3개는 전부 발견을 만들지 않는 방향), Luau 언어 동작·저장소 상태를 주장하는 것만 직접 재실행했다. 판정 분포와 항목별 근거는 그 문서 자신이 소스 — 여기서 세지 않는다. **결정 전에 반드시 읽을 것**: 부정 주장·개수 주장 몇 건이 정정됐고, 특히 **이미 사용자가 판단한 항목을 다시 묻게 되는 자리**가 하나 있다. 마지막 절의 **batch용 요약**이 유효 항목을 "한 결정으로 닫히는 묶음"으로 재편성해뒀으니 회신은 번호순이 아니라 그 묶음 단위로 하는 게 싸다), `pre-implementation-handtrace-round8.md`(**[2026-08-26 신설, 회신 대기]** 8라운드: 7라운드 반영으로 새로 쓰인 `base/` 서술을 **서로 겹쳐서** 재트레이싱한 것 — 개별 함수가 아니라 "반영된 결정들이 조합될 때 성립하는가"가 주제. 3패스에 걸쳐 `base/` 전 문서를 완독했고, 발견 번호는 `H-107`부터 이어 매김(발견 수·심각도 분포는 그 문서 자신이 소스), 실측 스파이크는 발견 항목에 인라인 전사. 사용자 결정 문항 Q1~Q10이 §4에 배치 회신용으로 정리돼 있다. 커밋 전 `/code-review`가 이 문서 자체의 결함 7건을 잡아 반영됐다(각 항목의 `[code-review 정정/추가]` 표시). **⭐ [2026-08-26] 전량 처리·반영 완료** — 그 문서는 이제 **발견 당시의 기록**이라 각 항목의 "갈래"는 선택 전 목록이니 그대로 믿지 말 것), `pre-implementation-handtrace-round8-followup.md`(**[2026-08-26 신설] 8라운드의 결정과 근거가 여기 소스다** — Q1~Q10을 사용자와 대화형으로 처리한 기록. **역전은 없고** 전부 "7라운드 확정이 `base/`에 내려앉을 때 생긴 누락·충돌"을 닫은 것. ⭐ 사용자가 **문항의 전제 자체를 정정한 것이 둘** 있다(Ref 콜백 ↔ Observer 콜백은 애초에 통합 대상이 아니다 / `H-118`은 소유권 문제가 아니라 문장이 틀린 것) — 결정만 읽지 말고 그 두 절을 볼 것), `pre-implementation-handtrace-round9-brief.md`(**[2026-08-26 신설]** 9라운드를 돌릴 감사자에게 주는 **지시서** — 발견 보고가 아니라 그 앞단이다. 이런 지시서를 저장하는 건 이번이 처음으로, 7·8라운드 것은 대화에만 있었고 저장되지 않았다(8라운드 본문이 인용하는 "감사 지시서 §2"가 코퍼스 어디에도 없는 이유). 스코프를 **커밋 `9dd8213` 하나의 델타**로 정의한 게 핵심 — 8라운드 결정 반영과 그 뒤 `/code-review high` 7패스 수정이 전부 그 커밋에 들어 있고 아무도 트레이싱한 적이 없다. 레인 셋(A: 그 델타의 상호 간섭 / C: `audit/handtrace-round7-reference-impl/`을 지금 계약으로 갱신해 실행 / B: 8라운드 §6이 남긴 M5+ 값 단위 트레이싱)과 우선순위 근거, `-round8-followup.md`가 적어둔 **반복 실패 모드 7개**를 사냥 목록으로 옮겨 실었다. 각도 문자(A~H)는 8라운드와 같은 걸 유지해 상호참조가 되게 했다), `pre-implementation-handtrace-round9.md`(**[2026-08-26]** 9라운드 발견 보고 — 레인 A(`9dd8213` 델타 상호 간섭)·C(참조 구현을 현재 계약으로 재전사해 `luau` 실행)·G(Luau 사실 재확인)·D(ROADMAP M2 시뮬레이션)·B(M5+ 값 단위, 첫 시도) — 발견 `H-124`~`H-141`, 🔴 둘(`recompute`의 `lengthList[i]` nil 읽기 / 재마운트 시 `_baseObserver` 미바인드 캐시 stale) 다 실측 재현. §4 배치 문항 Q1~Q10 + §5 이상 없음(⭐ `keyof<{}>` 빈 Store 실측으로 클린) + §6), `pre-implementation-handtrace-round9-followup.md`(**[2026-08-27] 9라운드 결정의 소스 — 전량 처리 완료** — Q1(`recompute` 되감기 판정을 읽기 앞으로) / Q2(`Offset`·`_baseObserver`를 Slot 생성자로, `materializeSlotTree` 순서, `_destroyed` 플래그) / Q3(`element → index`는 `bk.indexOfElement` 하나 — 사용자가 정한 적 없는 `token` 폐기, `H-137` 소멸, `H-141` 신설) / Q4(`EffectHandle` 네 진입점 의사코드) / Q5(M2에 `Ref` 최소형) / Q6(`WeakUnsubscribe` 관대) / Q7(폐기 블록 `archive/`) / Q8(`InstanceChildHandler` 부기) / **Q9(문항 전제가 틀림 — Tween 절 스케치 한 줄 복사 오류)** / Q10(`reconcile` 배치 Blocker) + `H-138`(숏핸드 우선순위) / `H-139`(`New`/`drive` 파이프라인 의사코드) / **`H-142`(props에 `Parent` 금지 — 순서 문제 소멸)** / **`H-143`~`H-146`**(`/code-review`가 낸 새 메커니즘 넷 — 전부 권고 (a), `H-144`는 사용자 요청으로 재구독 뒤 epoch·Blocker 상호작용을 재트레이싱한 기록 포함). 진행 표가 상태의 소스, 사용자 회신 원문 셋 인용; **[2026-08-28]** `H-143`~`H-146` 반영분의 감사 8라운드 표와 `/code-review high` 기록도 여기), `pre-implementation-handtrace-round10-brief.md`(**[2026-08-28 신설]** 10라운드 지시서 — 델타가 아니라 **광범위** 스코프(M2~M8, 레인 A 반응형 코어 전체 / C 참조 구현 갱신·실행 / B 디스패치·Slot / D 타입·M1 코드), 신선한 탐사자가 한 번에 문항지를 만들어 사용자가 배치로 결정하게 하는 것이 목적), `pre-implementation-handtrace-round10.md`(**[2026-08-28 신설, 회신 대기]** 10라운드 발견 보고 + §4 배치 문항지 — 씨앗은 `/code-review`가 낸 `H-147`~`H-149`(죽은 핸들에서 `Rerun` / `Parent` 거부 전용 문구는 새 메커니즘 / Observer `Subscribe` 위임과 `level 2`), 탐사자 발견은 `H-150`부터. 레인 C 실행 기록은 `audit/handtrace-round10-reference-impl/`. **[2026-08-28 탐사 완료]** 🔴 0 / 🟡 5 / 🟢 3, §4 문항 7건(기존 3 + `H-150` `Effect._blocker` 죽은 부품 / `H-151` 게이트 우회 계약 / `H-153` Store 예약 이름 런타임 가드 / `H-154` `InstanceChildHandler` dedup) — 전부 권고 (a). 레인 A·C 완료, B 부분, D `./scripts/test.sh` ALL PASS), `pre-implementation-handtrace-round10-followup.md`(**[2026-08-28] 10라운드 결정의 소스 — 전량 처리 완료.** 사용자가 *"하나하나 같이 보자"*라 대화형으로 처리. **문항의 전제를 뒤집은 것 둘**: `H-147`은 "죽은 핸들에서 `Rerun`"이 아니라 **`fn`/cleanup이 자기 구독을 바꿀 수 있다는 허용 자체가 모순**(→ (A) 금지, `H-143` 소멸, `rawRerun(force)`/`Rerun` 분리), `H-148`은 "문구"가 아니라 **루트 마운트 표면의 부재**(→ `Claim` + `D.Mapper`, `base/claim-plan.md`). 나머지: `H-149` Observer 진입점 인라인 / `H-150` `_blocker` 제거 / `H-151` `Refresh` 캐치업 폐기 — 게이트는 emit 경로만 미룬다 / `H-153` Store 예약 이름 가드 / `H-154` dedup. 새로 생긴 `H-158`(`:Block` 슈가)도 같은 날 확정 — 폐기, `state:Apply(blocker)`. **[2026-08-28 후속 3]** `Claim` 갈래 여덟 전량 확정 → `base/claim-plan.md`로 승격, 그 경위도 이 파일 끝 절). `m2-implementation-round11-brief.md`(**[2026-08-28 신설]** **M2 자율 구현 규약**이자 단위 끝마다 띄우는 탐사자 지시서 — 세 갈래 분류(자율 수정 / §4 배치 / 즉시 중단), 단위 넷, 두 층 커밋 게이트, 첫 단위 계획은 §6), `m2-implementation-round11.md`(**[2026-08-28 신설]** M2 구현 중 발견 원문 + §4 배치 문항지, 번호는 `H-165`부터 — 종이 트레이싱이 아니라 실제 코드를 옮기고 돌리다 나온 것. **[2026-08-31 개명]** 원래 `pre-implementation-handtrace-round11*`이었으나 구현 **중** 문서라 이름이 틀려 사용자 지시로 개명 — brief도 같이). **⭐ [2026-08-31 명명 규약, 사용자 확정]** 구현 라운드 파일은 **`mN-implementation-roundNN`** — 라운드 번호는 마일스톤을 가로질러 **단순 증가**하고(다음 라운드는 어느 마일스톤이든 round12), 마일스톤 접두가 어느 마일스톤의 라운드인지 담는다. 근거: *"m3 을 진행하다 m2 에 하자가 있음을 확인하면 다시 m2 로 올라가 round 가 진행되다 돌아오는 경우도 있을것 … 접두가 둘 다 있는게 정보를 온전히 담아줘"* — 번호만으로는 순서가, 접두만으로는 소속이 안 담긴다. 지시서도 같이 남길 것(`-roundNN-brief.md`). round1~10의 옛 이름(`pre-implementation-*`)은 그대로 둔다 — 실제로 구현 전 라운드였으니 이름이 맞다. `m3-implementation-round12-brief.md`(**[2026-08-31 신설, §0 회신 대기]** M3 자율 구현 규약 초안 + 착수 문항지 — §0 표(Q1 규약 재사용/Q2 단위 넷/Q3 M2 하자 혼입 규칙)가 사용자가 읽을 자리, 회신되면 M2 brief와 같은 지위가 된다. 발견 문서 `m3-implementation-round12.md`는 착수 시 신설, 번호 `H-212`부터) | | `archive/` | 완료 + 사용자가 실사용/실기기로 직접 검증까지 마침 (구현 대상). **[2026-08-06 확장]** 완전히 뒤집힌 설계 결정을 원문+역전 이유+diff와 함께 보존하는 용도로도 사용(제목 `[역전됨]` — 한 번 확정했다가 뒤집힌 것) — 더 이상 능동적으로 참고 안 해도 되지만(토큰 낭비 방지 위해 `base/`/`research/`에서 뺌) `quadnomicon` 소재로는 나중에 쓸 수 있음. **[2026-08-07 확장]** 후보였다가 채택 안 된 것(확정한 적 없이 검토 후 기각)도 같은 방식으로 보존, 제목은 구분을 위해 `[기각됨]` — `[역전됨]`과 의미가 다르므로 혼동하지 말 것. **[2026-08-07 세 번째 확장]** 설계 반전/기각과 별개로, 에이전트가 문서 작성 중 스스로 낸 개념 혼동을 정정한 이력은 `[에이전트 실수]` 태그로 `agent-mistake.md` 하나에 모음(`.claude/session-summary.md`/`session/` 로그와의 중복 방지) | | `feedback/` | 실사용 피드백을 정리한 긴 로그 — **[2026-08-19 기준] 폴더 자체가 아직 없음**(M0/M1 스캐폴딩만으론 안 생기고 실제로 렌더링해보고 쓰는 단계부터, 첫 피드백이 생길 때 만들면 됨). `qa-request/`는 **[2026-08-18] 더 이상 비어 있지 않음**(구현 전 QA 1라운드 산출물이 들어감) — 여긴 아직 폴더도 없음 | | `luau-test/` | **[2026-08-09 신설]** `base/` 확정 사항 중 "추론만으로 확정하고 실제 Luau로 부딪혀본 적 없는 것"(M0 스파이크 대상)을 `luau`/`luau-analyze`/`luau-lsp`/Roblox Studio로 사용자가 직접 돌려볼 독립 실행 스크립트 모음. **[2026-08-13 여섯 번째 세션, 첫 실측]** `luau`/`luau-analyze` 바이너리가 생겨 처음으로 실제 실행 — **런타임 12개 전원 통과**, 타입 쪽에서 `:Compute(fn)` lazy 핸들 계약이 Luau 추론과 충돌하는 게 드러남(당시 `question.md` 0-Y). **[2026-08-13 열세 번째 세션]** 그 0-Y가 해소되며 `review-required/`가 **비었음** — 계약은 유지 확정, 남은 건 Luau 자체 한계라 `base/typing-limits.md`가 담당. **`STATUS.md`가 상태의 소스**(pass / 사람 결정 필요 / 스파이크 깨짐 / 미실행 분류 — 사람이 먼저 볼 것만 위에), `luau-test/README.md`는 각 파일의 검증 의도·배경, 실행 결과 상세는 `audit/luau-test-first-run-2026-08-13.md` | diff --git a/.claude/qa-request/m3-implementation-round12-brief.md b/.claude/qa-request/m3-implementation-round12-brief.md new file mode 100644 index 0000000..e1c475d --- /dev/null +++ b/.claude/qa-request/m3-implementation-round12-brief.md @@ -0,0 +1,108 @@ +# M3 자율 구현 규약(안) — 12라운드 지시서 + 착수 문항지 + +> **이 파일이 무엇인가**: **[2026-08-31 신설, §0 회신 대기]** M3(디스패치 엔진) +> 구현 구간의 규약 초안이자 착수 문항지다. **§0 표가 사용자가 읽을 유일한 +> 자리** — 회신이 §0에 기록되면 이 파일이 M2의 `m2-implementation-round11-brief.md`와 +> 같은 지위(규약 소스 + 단위 끝 탐사자 지시서)가 된다. 산출물(발견 문서)은 +> 착수 시 `m3-implementation-round12.md`로 신설. +> +> **명명**: `mN-implementation-roundNN` 규약(2026-08-31 사용자 확정, +> `.claude/README.md` `qa-request/` 행이 소스) — 라운드 번호는 마일스톤을 +> 가로질러 단순 증가라 M3의 첫 라운드가 **round12**, 발견 번호는 round11이 +> `H-211`까지 썼으므로 **`H-212`부터**. +> +> §2~§5는 M2 규약을 준용하되 M3에 맞게 고친 자리에 `[M3 변경]` 표시를 달았다 — +> M2와 어디가 다른지는 그 표시만 훑으면 된다. + +--- + +## §0 ⭐ 착수 문항 (배치 회신용) + +| 문항 | 무엇 | 선택지 | 권고 | 권고 근거 | +|---|---|---|---|---| +| **Q1** | M2 규약의 재사용 범위 | (a) 골격 그대로 — 발견 세 갈래(§2) / 리뷰 발견 취급(§3) / 커밋 게이트 두 층·단위 끝 절차(감사 루프 → `/code-review high` → 커밋 → fable 탐사자 → "§4를 보라" 한 줄)(§4) — 에 **M3 전용 게이트 하나 추가**: 새 핸들러를 짜기 전 `dispatch-core-plan.md`의 "Handler 작성 체크리스트" 절 필독(실제 반복된 실수 목록이라 M2엔 대응물이 없던 것) / (b) 절차를 줄임(예: 탐사자 생략) / (c) 다른 방식 | **(a)** | M2 실측 — ③(즉시 중단) 0회, 배치 회신 3번으로 발견 47건(`H-165`~`H-211`) 처리, 단위 절단 덕에 관여 시점이 촘촘해 손실 구간이 없었다. 탐사자는 매 단위 ①만 내고도 문서-코드 어긋남을 7건(`H-191`~`H-197`) 잡은 실적이 있어 유지 가치가 실증됨 | +| **Q2** | 단위 절단 | (a) **넷** — §1의 제안(코어 → 부기 → `None`/`Nil` 핸들러 → Leaf·가드·종합) / (b) 셋(코어+부기 합침 — 단위당 비용 커짐) / (c) 다른 절단 | **(a)** | 의존이 단방향(코어 → 부기(NilHandler가 부기 API를 등록) → 핸들러 → 가드·종합)이고, M2와 단위당 규모가 비슷해 비용 감각이 검증된 눈금 그대로다. 단위 2가 M2 소비의 첫 실전(Observer 콜백·Blocker·접두합 캐시)이라 M2 결함이 있다면 일찍 드러난다 | +| **Q3** | M3 진행 중 **M2 하자**가 나올 때 | (a) 경미한 것(문서 stale·주석·기존 계약 **안**의 코드 오류)은 M3 라운드 파일(`m3-implementation-round12.md`)에 `H-nnn`으로 기록하고 ① 갈래로 자율 수정, **M2 설계 결정이 필요한 규모**(새 메커니즘·확정 역전)면 그때 `m2-implementation-round13`(그 시점의 다음 번호)을 새로 열어 §4 배치 문항으로 / (b) 규모 무관 전부 M3 파일에 / (c) 규모 무관 전부 M2 파일 신설 | **(a)** | 명명 규약의 취지(*"m3 을 진행하다 m2 에 하자가 있음을 확인하면 다시 m2 로 올라가 round 가 진행되다 돌아오는 경우"*) 그대로 — 접두가 소속을 담으려면 **결정이 필요한 것만** M2 라운드로 승격하고, 잔손질까지 파일을 쪼개면 발견 흐름이 갈라진다 | + +**통보(문항 아님 — 규약·코드 배치라 여기 명시만)**: 발견 문서는 착수 시 +`m3-implementation-round12.md` 신설, 번호 `H-212`부터. **mock 확장은 불필요** — +M3 핸들러가 부르는 건 quad-base 자기 부기 API(`setLength` 등)뿐이고 엔진 +op(`addTag`/`setAttribute`/`native*`)는 M5/M10 몫이라 지금 mock(생명주기 4종 + +`onDestroying` + mock Instance)으로 충분하다. 코어 테스트는 실핸들러가 아직 +없으므로 **spec 파일 로컬의 테스트 전용 핸들러**로 돌린다(코드 배치). + +## §1 범위와 순서 — 단위 넷 (제안, Q2) + +소스는 `ROADMAP.md` M3 체크박스(13개, 개수·상세는 거기가 소스). 단위 안의 +순서는 체크박스 순서를 따르되 단위 배정은 아래: + +1. **Handler 계약 + 디스패치 코어** — `Handler.luau`(계약 타입 3종: + `isHandlable(inst,k,v)`/`priority`/`process(...) -> retractor`), + `Dispatch/init.luau`(`getHandler`/`process`(하강 diff)/3-인자 + `retractFrom`/`addHandler`/`drive` 단일 일반화 `for`), `chains` 부기 + (Relate 기반), 계약 검증(`process`가 retractor를 안 돌려주면 즉시 error), + 우선순위 동률·매치 실패 처리, `quad-types` `Quad.Dispatch`(`H-25`). + 파이프라인 정본은 `base/dispatch-core-plan.md`와 + `base/bind-system-plan.md`의 "`New(name)(props)` 파이프라인 의사코드" 절. +2. **Length/Offset 부기** — `setLength`(+`anchor`/`element` 인자)/ + `setOffsetSource`/`getOffsetAt` + **접두합 캐시 계약 전체**(`bk.offsetCache`/ + `offsetCacheValidUpTo`/`offsetSetUpTo` 두 필드/`recomputeBlocker`/ + `bk.indexOfElement` weak-key, 무효화 자리는 `dispatch-core-plan.md`의 + 무효화 표가 소스), len이 State일 때의 Observer 콜백. **M2 소비의 첫 + 실전**(Observer·Blocker·Source). +3. **`None` 센티널 + `NoneHandler`/`NilHandler`** — 첫 실핸들러 둘. + `H-39`(말단 핸들러의 `setOffsetSource(None)`→`setLength(0)` 등록 계약)의 + 첫 적용이자 Handler 작성 체크리스트 게이트의 첫 실행. `architecture.md` + 소스 트리에 탑레벨 `None.luau` 줄도 이때 추가(ROADMAP가 예고). +4. **`Dispatch/Leaf.luau`(`ObserverEffectLeafHandler`) + Observer/Effect 동적 + 경로 가드 등록 + mock 대상 종합 테스트**(ROADMAP M3 마지막 항목) — + M2 값(Observer/Effect/bindLifetime)을 디스패치가 실제로 물어 올리는 자리. + +- 각 모듈은 M2처럼 **"`base/` 확정 의사코드를 그대로 옮긴 구현 + 그 절의 + 계약을 검증하는 spec"** 짝으로, 테스트는 `./scripts/test.sh`로만. +- **[M3 변경] 이름 해석 규칙 하나**: `base/` 의사코드의 자유 이름 + (`bindLifetime`/`canExecute`/`Effect`/`Blocker` 등)은 전부 + `InitDispatch(module)`이 쥔 `module.xxx`이고 생명주기 넷은 발화 시점에 + 늦게 읽는다(`H-174` (a) — round11 §5의 M3 예고가 소스). +- **[M3 변경] 미리 알려진 주의 둘**(round11 §6): `H-186`(교차 인스턴스 UB)의 + 이웃인 교차 `bindLifetime`은 UB로 닫혔으니 가드를 새로 만들지 말 것 / + Slot 쪽(`materializeSlotTree`)이 Observer 사적 필드를 직접 쓰는 자리는 + M6 몫이되 그 경계가 이 마일스톤 코드에 들어오면 발견으로 올릴 것. + +## §2 세 갈래 (M2 §2 준용) + +`m2-implementation-round11-brief.md` §2 그대로 — ① 문서가 답을 가진 것은 +`H-nnn` 기록 + `base/`·코드 같은 커밋 자율 수정 / ② 새 +필드·인자·이름·메커니즘·확정 역전은 코드에 넣지 말고 +`m3-implementation-round12.md` §4 표에 갈래+권고+근거로 배치(코드엔 +`-- TODO(H-nnn)` 마커만, "옛 메커니즘 복원" 표시 포함) / ③ 짠 코드 상당 +부분을 무효화할 규모면 즉시 중단·보고. **[M3 변경]** M2 하자는 §0 Q3의 +결정을 따른다. + +## §3 리뷰·감사 발견의 취급 (M2 §3 준용) + +그대로 — 리뷰의 "새 메커니즘"은 ②로, 반영 전 소유자·기각 이력 grep. + +## §4 관여 시점 (M2 §4 준용) + +커밋 게이트 두 층(매 커밋 doc-check ERROR 0 / 단위 끝 감사 루프 → +`/code-review high` → 커밋 → fable 탐사자 → "§4를 보라" 한 줄), 세션 원문 +규율, 인덱스 3층 갱신 — 전부 그대로. **[M3 변경]** 머리말 갱신 문구는 +"M3 진행 중". + +## §5 탐사자 지시 (단위 끝마다) + +M2 §5를 그대로 쓰되 치환 셋: 대상 라운드 파일은 +`m3-implementation-round12.md`, 이 파일의 §1~§3을 먼저 읽고, 대조 대상 +`base/` 절은 `dispatch-core-plan.md`(특히 "Handler 작성 체크리스트" 절과 +무효화 표)·`bind-system-plan.md`가 중심. `git stash` 금지·실행 우선·한 줄 +대조·`grep -rn "TODO(H-"` 전수 확인은 동일. + +## §6 첫 단위(코어) 작업 계획 — §0 회신 후 확정 + +Q1·Q2가 (a)로 닫히면 여기 M2 §6과 같은 급의 파일·spec 표를 채워 사용자 +확정을 받는다(코드 배치는 그 계획이 소스). 초안 요지만: `Handler.luau`는 +계약 타입만 담는 잎 / `Dispatch/init.luau`가 `InitDispatch(module)` 팩토리 +(`module-lifecycle-plan.md`의 예시 그대로 — `H-174` (a)의 원형) / +`chains`는 `Relate` 인스턴스 / spec은 `spec.dispatch.luau` + spec-로컬 +테스트 핸들러. diff --git a/.claude/qa-request/m3-implementation-round12.md b/.claude/qa-request/m3-implementation-round12.md new file mode 100644 index 0000000..1ab8078 --- /dev/null +++ b/.claude/qa-request/m3-implementation-round12.md @@ -0,0 +1,6 @@ +# M3 구현 **12라운드** — 발견 원문 + 배치 문항지 (스텁) + +> **[2026-08-31 스텁]** 규약 문항지(`m3-implementation-round12-brief.md`)의 +> §0 회신이 아직이라 **비어 있다** — M3 착수와 함께 round11 파일과 같은 +> 구조(요약 표 / 상세 / §4 배치 문항 / §5 이상 없음 / §6 남은 의심)로 +> 채워진다. 발견 번호는 **`H-212`부터**(round11이 `H-211`까지 썼다). diff --git a/.claude/session/2026-08-31-01-unit2-code-review.md b/.claude/session/2026-08-31-01-unit2-code-review.md index 3453c04..472d267 100644 --- a/.claude/session/2026-08-31-01-unit2-code-review.md +++ b/.claude/session/2026-08-31-01-unit2-code-review.md @@ -126,3 +126,14 @@ notification 시점에 파인더 4개가 미완인 채 멈춤. 이번엔 opus `git mv` + 전 코퍼스 치환 22곳(잔존 0), round1~10의 `pre-implementation-*` 옛 이름은 실제로 구현 전 라운드라 그대로. CLAUDE.md/project-context.md 머리말을 "M0~M2 완료, 다음은 M3"로, todos 00을 종결로. **M2 종결** — 다음 액션은 M3 착수 규약 문항. + +## 같은 날 후속 5 — M3 규약 문항지 신설 + +사용자 요청(*"m3 규약 문항지 만들어줘. M2 와 같은 방식으로 개발되어도 괜찮을것 +같아?"*)으로 `qa-request/m3-implementation-round12-brief.md` 신설 — M2 규약 준용 +초안 + §0 문항 셋(Q1 규약 재사용(+Handler 체크리스트 게이트 추가) / Q2 단위 넷: +코어 → Length/Offset 부기 → None·Nil 핸들러 → Leaf·가드·종합 / Q3 M2 하자 혼입 +규칙 — 경미는 M3 라운드에 ①, 결정 규모면 m2-implementation-round13 신설). 메인 +의견: M2 방식 재사용 권고 — 실측 근거(③ 0회, 배치 회신 3번에 47건, 관여 촘촘). +M3 특이점 셋만 얹음: Handler 작성 체크리스트 필독 게이트, 자유 이름 → module.xxx +해석 규칙(H-174), spec-로컬 테스트 핸들러(코드 배치). §0 회신 대기. diff --git a/.claude/todos.md b/.claude/todos.md index e524bda..81790ff 100644 --- a/.claude/todos.md +++ b/.claude/todos.md @@ -23,9 +23,10 @@ 개명(구현 중 문서라 옛 이름이 안 맞았음; 명명 규약 `mN-implementation-roundNN`은 `.claude/README.md` `qa-request/` 행이 소스 — 라운드 번호는 마일스톤을 가로질러 단순 증가). M2 종료 보고도 전달 — **M2 종결.** - **다음 액션: M3(디스패치 엔진) 착수 — 자율 구현 규약을 M2처럼 쓸지, 단위를 - 어떻게 자를지 등 새 규약 문항을 만들어 사용자와 정할 것**(2026-08-29 - 체크포인트의 "M3은 새 규약 문항" 그대로). + **다음 액션: M3(디스패치 엔진) 착수 — [2026-08-31] 규약 문항지 + `qa-request/m3-implementation-round12-brief.md` 작성 완료, §0 표(문항 셋) + 사용자 회신 대기.** 회신되면 그 파일이 M3 규약 소스가 되고 §6(첫 단위 + 계획) 확정 후 착수(2026-08-29 체크포인트의 "M3은 새 규약 문항" 이행). 아래는 착수 전(2026-08-26) 서술: **[2026-08-26] 8라운드까지 전부 처리 완료 — M2 착수 게이트가 0이다.**