diff --git a/.claude/README.md b/.claude/README.md index 1ff3447..49d6f15 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`로 승격, 그 경위도 이 파일 끝 절). 다음 라운드가 필요해지면 라운드마다 파일을 새로 만들고 이름에 라운드 번호를 넣을 것(지시서도 같이 남길 것 — `-roundN-brief.md`) | +| `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`로 승격, 그 경위도 이 파일 끝 절). `pre-implementation-handtrace-round11-brief.md`(**[2026-08-28 신설]** **M2 자율 구현 규약**이자 단위 끝마다 띄우는 탐사자 지시서 — 세 갈래 분류(자율 수정 / §4 배치 / 즉시 중단), 단위 넷, 두 층 커밋 게이트, 첫 단위 계획은 §6), `pre-implementation-handtrace-round11.md`(**[2026-08-28 신설]** M2 구현 중 발견 원문 + §4 배치 문항지, 번호는 `H-165`부터 — 종이 트레이싱이 아니라 실제 코드를 옮기고 돌리다 나온 것). 다음 라운드가 필요해지면 라운드마다 파일을 새로 만들고 이름에 라운드 번호를 넣을 것(지시서도 같이 남길 것 — `-roundN-brief.md`) | | `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/conventions.md b/.claude/conventions.md index 3257a05..35e9eed 100644 --- a/.claude/conventions.md +++ b/.claude/conventions.md @@ -374,4 +374,16 @@ haiku, 일반 작업은 sonnet. 특히 소스코드를 많이 읽어야 하는 `upstream`(`github.com/qwreey/quad`, 사용자 본인 소유)에 PR이 merge될 때 GitHub 기여 그래프에 반영되게 하기 위함 — 관련 리모트 정책은 메모리 `git-remote-push-policy` 및 위 `SAFETY.md` 항목 참고. - +- **⭐ [2026-08-28 신설] M2 자율 구현 규약 — 본문은 + `qa-request/pre-implementation-handtrace-round11-brief.md`가 소스, 여기선 + 가리키기만.** 사용자 결정(2026-08-28, *"수정하고 너가 진행하자"*)으로 M2는 + 자율 구간으로 돈다. 요지 셋: (1) 발견은 **세 갈래** — 문서가 이미 답을 가진 + 건 `H-nnn`으로 기록하고 `base/`+코드를 같은 커밋에서 자율로 고침 / 새 + 필드·인자·이름·메커니즘·확정 역전은 코드에 넣지 말고 `round11.md` §4 표에 + 쌓아 배치 회신(코드엔 `-- TODO(H-nnn)` 마커만) / 짠 코드 상당 부분을 무효화할 + 규모면 즉시 중단·보고. (2) 단위 넷(공통 기반+mock 생명주기 → `EpochMap` → + `Source/State/Store` → `Observer`/`Effect` → `GateNode`/`Blocker`+탑레벨)이 + 끝날 때마다 감사 루프 → `/code-review high` → 커밋 → 신선한 탐사자 → 사용자에게 + "§4를 보라" 한 줄. (3) 커밋 게이트는 두 층 — 매 커밋 doc-check ERROR 0, 단위 + 끝 감사 루프. 이걸로 `HUMAN_TODO.md` 2번(자율 루프 설정 여부)은 닫혔다 — + 세션 안 자율 구간으로 확정, cron/`/schedule`은 안 쓴다. diff --git a/.claude/project-context.md b/.claude/project-context.md index 33e0e36..0bee5b6 100644 --- a/.claude/project-context.md +++ b/.claude/project-context.md @@ -11,7 +11,9 @@ Roblox 엔진에서 동작하는 DOMless UI 렌더러 **quad**를 처음부터 길게 잡음. **[2026-08-24 기준] M0(스파이크 검증)/M1(스캐폴딩) 완료, 다음은 M2(반응형 -코어 — Source/State/Store)**(마일스톤이 넘어갈 때 루트 `CLAUDE.md` 머리말도 +코어 — Source/State/Store)** — **⭐ [2026-08-28] M2 착수, 자율 구현 구간 진행 +중**(규약 `qa-request/pre-implementation-handtrace-round11-brief.md`, 발견 +`-round11.md`; 단위 넷 중 첫 단위 = 공통 기반 + `H-97` mock 생명주기)(마일스톤이 넘어갈 때 루트 `CLAUDE.md` 머리말도 같이 고칠 것 — 같은 상태를 두 곳이 서술하고 있음). **⚠️ [2026-08-24] M2와 M3의 번호·순서가 맞바뀌었다** — 열려 있던 마일스톤 순서 문제가 (a) 순서 교체로 닫힌 결과다(경위는 `archive/question-resolved.md`의 "마일스톤 경계" diff --git a/.claude/qa-request/pre-implementation-handtrace-round11-brief.md b/.claude/qa-request/pre-implementation-handtrace-round11-brief.md new file mode 100644 index 0000000..22d221a --- /dev/null +++ b/.claude/qa-request/pre-implementation-handtrace-round11-brief.md @@ -0,0 +1,125 @@ +# M2 자율 구현 규약 — 11라운드 지시서 + +> **이 파일이 무엇인가**: **[2026-08-28 신설]** M2(반응형 코어) 구현을 자율 구간으로 +> 돌리기 위한 규약이자, 단위가 끝날 때마다 띄우는 **11라운드 탐사자**에게 그대로 +> 주는 지시서다. 산출물은 `pre-implementation-handtrace-round11.md`(발견 원문 + +> §4 배치 문항지). 9·10라운드 지시서(`-round9-brief.md`/`-round10-brief.md`)와 +> 같은 관례이되, **이번 라운드는 종이가 아니라 실제 코드가 감사 도구다** — +> 10라운드 지시서가 *"이후로는 M2 구현 자체가 더 나은 감사 도구"*라고 예고한 +> 그 자리. +> +> **왜 이 규약인가**: 사용자 결정(2026-08-28) — 별도 에이전트가 초안한 +> 규약을 검토해 순서 오류 하나(`EpochMap`이 `Source/State` 뒤에 가 있던 것)와 +> 소스 단일화 몇 건을 고친 뒤 채택. 사용자 원문: *"수정하고 너가 진행하자. +> epochmap 순서 하나 고치고 진행할 수 있겠니?"* 원칙은 10라운드와 같다 — +> *"인간을 기다리는거 엄청 비효율이라서 … batch 로 처리될 필요가 있는듯"* +> (`-round10-brief.md`). 발견을 하나씩 물으러 오지 말 것. +> +> `conventions.md`의 "작업 방식"에 짧은 항목이 있고 **본문은 이 파일이 소스**다. + +--- + +## §1 범위와 순서 + +- **단위(unit)** 넷. 단위 하나가 끝날 때마다 §4 "관여 시점"으로 온다. + 1. **공통 기반** — `ROADMAP.md`의 "공통 기반 — 반응형보다 먼저" 절 전부: + `Brand.luau` / `Relate.luau`(M1에 이미 커밋됨 — 남은 건 + `base/relate-plan.md` 대조 + 테스트) / `LifetimeHandle.luau` 인터페이스 / + `Ref.luau` 최소형(`H-128`) / `Void`(`H-162`). **여기에 `H-97`의 mock 생명주기 + 4종**(`bindLifetime`/`unbindLifetime`/`canBound`/`canExecute`의 mock 백엔드 + 구현)을 끼운다 — `ROADMAP.md`엔 M2 꼬리에 있지만 이게 없으면 두 번째 단위부터 + "구현 + 테스트 짝" 원칙이 성립하지 않는다(전파 루프가 매 발화마다 + `canExecute`를 부른다). + 2. **`EpochMap` → `Source`/`State`/`Store`** — **`EpochMap.luau`가 State 본체보다 + 먼저다.** `ROADMAP.md` "반응형 본체" 절이 *"`Source.luau`/`State.luau`가 이걸 + 전제로 짜여야 하므로 `EpochMap.luau`(위 항목)가 State 본체보다 먼저 온다"*로 + 못 박아 뒀다(`State`가 `valueEpochMap`/`emitEpochMap`을 컴포지션). 초안 + 규약이 `EpochMap`을 `Effect` 뒤에 뒀던 것이 이 규약이 고친 유일한 순서 + 오류다. + 3. **`Observer` → `Effect`** — `Effect`는 Observer 뒤(의존). + 4. **`GateNode` → `Blocker`** + `quad-types`의 `Quad` 탑레벨 값 전부(`H-80`) + + **mock 대상 전파 루프 테스트**(`ROADMAP.md` M2 마지막 항목). + 단위 안의 순서는 `ROADMAP.md` 체크박스 순서를 따른다. +- **각 모듈은 "`base/` 의사코드를 그대로 옮긴 구현 + 그 절의 계약을 검증하는 + 테스트"로 짝지어** 진행한다. 테스트는 **`./scripts/test.sh`로만** 돌린다 — + `luau` CLI가 심볼릭 링크를 못 타서 그냥 돌리면 거짓 클린이 난다 + (`project-context.md`). +- **코드 배치와 테스트 파일 이름**은 첫 단위 계획(§6)이 정한다 — 이 규약이 + 아니라 그 계획이 소스. + +## §2 세 갈래 — 발견은 이렇게 분류해서 처리한다 + +1. **자율로 고치고 넘어가는 것**: `base/` 의사코드를 옮기다 드러나는 오류(순서, + 빠진 `end`, 이름 불일치, 문서 간 stale), 테스트 실패 중 **"문서가 이미 답을 갖고 + 있는 것"**. + → `H-nnn` 번호를 매겨 `pre-implementation-handtrace-round11.md`에 기록하고 + **`base/`와 코드를 같은 커밋에서** 고친다. 묻지 않는다. 번호는 **`H-165`부터** + (10라운드 후속이 `H-164`까지 썼다). +2. **모아서 올리는 것**: 새 필드·인자·이름·표면·메커니즘이 필요해지는 것, 확정을 + 뒤집어야 하는 것, "이 갈래들이 공유하는 전제"가 흔들리는 것. + → **코드에 넣지 말고** `round11.md` §4 표에 **갈래 + 권고 + 권고 근거**로 쌓는다. + 권고가 "옛 메커니즘 복원"이면 **그 표시를 단다** — 2026-08-28의 `Refresh` 복원 + 권고(`H-159`)가 `_rerunRequired`로 뒤집혔듯, 그런 자리는 사용자가 다른 모양을 + 갖고 있을 가능성이 높다. + 막힌 부분은 코드에 **`-- TODO(H-nnn): 한 줄 요지`** 마커 + 문항 번호로 남기고 + 그 모듈의 나머지를 계속 진행한다. 마커 형식을 이 하나로 고정하는 이유: + `quad-doc-auditor`는 코드를 안 보므로 `grep -rn "TODO(H-" quad-base/src`가 + 잔여를 전수 확인하는 유일한 수단이다. +3. **즉시 멈추고 사용자를 부르는 것**: 2번 중에서 **이미 짠 코드의 상당 부분을 + 무효화할 규모**의 전제 흔들림 — 그 위에 코드를 더 쌓으면 손해인 경우만. 멈추고 + 상황을 한 문단으로 보고한다(자율 구간이라 사용자가 즉답할 수 없으니, 보고 자체가 + 그 세션의 끝이다). + +## §3 리뷰·감사 발견의 취급 + +- `/code-review`와 `quad-doc-auditor`가 **"새 메커니즘"으로 분류한 발견은 반영하지 + 말고 2번으로 쌓는다.** 이 코퍼스의 반복 실패 모드(`token`, 전용 에러 문구, + `wasAlive`)가 정확히 "리뷰 제안을 승인된 것처럼 넣은 것"이었다 + (`conventions.md`의 *"새 필드·인자·이름·메커니즘은 발견이지 결정이 아니다"* + 항목이 소스). +- 반영 전에 (a) 그 책임의 현재 소유자와 (b) 그 모양이 과거에 기각된 적 있는지를 + 먼저 grep한다 — `base/`의 "검토 후 안 만들기로 한 것"류 목록과 `archive/`. + +## §4 관여 시점 + +- **커밋 게이트는 두 층이다.** + - **매 커밋**: `python3 .claude/tools/doc-check.py` ERROR 0. 1번 갈래는 커밋 + 단위가 작아 단위 하나에 커밋이 여럿 생기는데, 그 중간 커밋도 이 게이트를 탄다. + - **단위 끝**: 감사 루프(`quad-doc-auditor` **한 턴에 하나**, diff 범위, + **`git stash` 금지**를 프롬프트에 직접 명시, 새 발견 0건까지) → doc-check + ERROR 0 → `/code-review high` → 커밋. 그 뒤 **신선한 컨텍스트의 fable 탐사자 + 하나**를 이 파일(§5)을 지시서로 띄워 실제 코드를 돌려보고 `round11.md`에 + 발견을 이어 붙이게 한 다음, 사용자에게 **"`round11.md` §4를 보라"고 한 + 줄로** 알린다. 사용자는 §4 표만 읽고 갈래를 배치로 회신한다. +- 세션이 일단락될 때마다 `session/YYYY-MM-DD-NN-slug.md` 원문을 남기고, + `todos.md` 00번·`project-context.md`·`CLAUDE.md` 머리말을 **"M2 진행 중"**으로 + 갱신한다(`conventions.md`의 세션 원문 규율 그대로). +- 비용 참고: 단위당 감사 루프 + `/code-review high` + 탐사자 조합은 수십만 토큰이다. + 그래서 단위를 넷으로 쪼갰다 — 관여 시점이 촘촘해지고 3번 갈래의 손실도 작아진다. + +## §5 탐사자 지시 (단위 끝마다 띄우는 fable 탐사자에게) + +당신은 Roblox 엔진용 DOMless UI 렌더러 **quad**의 M2 구현을 감사한다. 저장소 +루트가 작업 디렉토리다. 당신은 신선한 컨텍스트에서 시작한다 — 앞선 세션의 가정을 +물려받지 않는 것이 당신의 가치다. **`git stash`를 쓰지 말 것**(작업 트리 대조는 +`git show HEAD:<경로>` / `git diff HEAD -- <경로>`). + +1. 먼저 읽을 것: `CLAUDE.md` → `.claude/conventions.md`(특히 *"새 필드·인자·이름· + 메커니즘은 발견이지 결정이 아니다"*와 *"하나의 무언가가 두 일을 하고 있지 + 않은지"*) → 이 파일 §1~§3 → `pre-implementation-handtrace-round11.md`(지금까지의 + 발견, 당신의 번호는 마지막 번호 다음부터). +2. 대상: 이번 단위의 커밋 범위(`git log`로 확인)에 들어온 `quad-base/src/`· + `quad-base/test/`와, 그 코드가 옮겨 적은 `base/` 절. +3. 할 일: (a) **코드를 실제로 돌린다** — `./scripts/test.sh` 전체, 그리고 계약 + 절이 요구하는데 테스트가 없는 경로는 임시 스크립트로 직접 태운다(임시 파일은 + `quad-base/test/`에 남기지 말고 발견 본문에 인라인). (b) 코드와 `base/` 절을 + **한 줄씩 대조**한다 — 옮기다 바뀐 것, 문서에 없는 분기, 문서엔 있는데 코드에 + 없는 것. (c) `grep -rn "TODO(H-" quad-base/src`로 남은 마커를 전수 확인한다. +4. 산출물: `round11.md`에 `H-nnn`으로 이어 붙인다. **§2의 세 갈래로 분류해서 + 적되, 1번 갈래도 직접 고치지 말고 발견으로만 남긴다**(수정은 메인 세션이 + 한다). 2번 갈래는 §4 표에 갈래 + 권고 + 권고 근거, "옛 메커니즘 복원" 표시. +5. 이상 없다고 확인한 자리도 §5 형식으로 적는다(다음 탐사자가 다시 파지 않게). + +## §6 첫 단위(공통 기반) 작업 계획 + +사용자 확인 뒤 여기에 확정본을 적는다 — **[2026-08-28 기준] 확인 대기.** diff --git a/.claude/qa-request/pre-implementation-handtrace-round11.md b/.claude/qa-request/pre-implementation-handtrace-round11.md new file mode 100644 index 0000000..6d22a48 --- /dev/null +++ b/.claude/qa-request/pre-implementation-handtrace-round11.md @@ -0,0 +1,38 @@ +# M2 구현 **11라운드** — 발견 원문 + 배치 문항지 + +> **이 파일이 무엇인가**: **[2026-08-28 신설]** M2 자율 구현 구간 +> (`-round11-brief.md`가 규약)에서 나온 발견 전부. 앞 라운드들과 달리 **종이 +> 트레이싱이 아니라 실제 코드를 옮기고 돌리다 나온 것**이다. 번호는 `H-165`부터 +> (10라운드 후속이 `H-164`까지 썼다). +> +> **갈래 표기**(규약 §2): **①** 자율로 고침(같은 커밋에서 `base/`+코드) / +> **②** §4 표에 쌓아 배치 회신 대기 / **③** 즉시 중단·보고. +> +> **상태의 소스는 이 파일 자신** — 요약 표의 상태 열이 최신. + +## 요약 표 + +| 번호 | 갈래 | 단위 | 심각도 | 한 줄 | 상태 | +|---|---|---|---|---|---| +| — | — | — | — | **[2026-08-28 기준] 아직 발견 없음** | — | + +## 상세 + +(단위별로 `### \`H-nnn\` 🔴/🟡/🟢 — 제목` 절을 이어 붙인다. 각 절엔 (1) 어디서 +(파일:줄 / `base/` 절), (2) 무엇이, (3) 문서가 이미 답을 갖고 있는가, (4) 어떻게 +처리했는가(①이면 커밋 해시).) + +## §4 ⭐ 사용자 결정이 필요한 것 (배치 회신용) + +| 문항 | 무엇 | 선택지 | 권고 | 권고 근거 | 옛 메커니즘 복원? | +|---|---|---|---|---|---| +| — | **[2026-08-28 기준] 비어 있음** | — | — | — | — | + +코드 쪽 잔여 마커: `grep -rn "TODO(H-" quad-base/src` — 이 표의 문항과 1:1이어야 +한다. + +## §5 이상 없다고 확인한 것 + +(탐사자가 실제로 돌려보고 계약대로였던 자리 — 다음 탐사자가 다시 파지 않게.) + +## §6 남은 의심 / 못 본 것 diff --git a/.claude/todos.md b/.claude/todos.md index fd61783..20ecc25 100644 --- a/.claude/todos.md +++ b/.claude/todos.md @@ -5,7 +5,15 @@ (`.claude/question.md`, `luau-test/STATUS.md` 등). -00. **⭐⭐⭐ [2026-08-26] 8라운드까지 전부 처리 완료 — M2 착수 게이트가 0이다.** +00. **⭐⭐⭐ [2026-08-28] M2 착수 — 자율 구현 구간 진행 중.** 규약은 + `qa-request/pre-implementation-handtrace-round11-brief.md`(세 갈래 분류 / + 단위 넷 / 관여 시점), 발견과 배치 문항은 `-round11.md`(§4 표가 사용자가 + 읽을 유일한 자리). **진행 상태의 소스는 `ROADMAP.md` M2 체크박스**, 여기서 + 세지 않는다. 첫 단위 = 공통 기반(`Brand`/`Relate` 대조/`LifetimeHandle` + 인터페이스/`Ref` 최소형/`Void`) + `H-97` mock 생명주기 4종. + 아래는 착수 전(2026-08-26) 서술: + + **[2026-08-26] 8라운드까지 전부 처리 완료 — M2 착수 게이트가 0이다.** 8라운드(`qa-request/pre-implementation-handtrace-round8.md`, 7라운드 반영분을 서로 겹쳐 재트레이싱 + 실측, 3개 패스, 발견 17건 `H-107`~`H-123`)의 결정 문항 Q1~Q10을 사용자와 대화형으로 처리해 diff --git a/CLAUDE.md b/CLAUDE.md index a0a81e7..e3b53d5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,7 +2,9 @@ Roblox 엔진용 DOMless UI 렌더러 **quad**를 처음부터 다시 짜는 프로젝트. **[2026-08-24 기준] M0(스파이크 검증)/M1(스캐폴딩)까지 완료, 다음은 -M2(반응형 코어 — Source/State/Store)**. **⚠️ [2026-08-24] M2와 M3의 +M2(반응형 코어 — Source/State/Store)** — **⭐ [2026-08-28] M2 착수, 자율 구현 +구간 진행 중**(규약은 `.claude/qa-request/pre-implementation-handtrace-round11-brief.md`, +발견·배치 문항은 `-round11.md`). **⚠️ [2026-08-24] M2와 M3의 번호·순서가 맞바뀌었다** — 예전엔 M2=디스패치, M3=반응형이었는데 의존이 한 방향(디스패치 → 반응형)이라 반응형을 먼저 짓기로 확정했다. 그래서 **2026-08-24 이전에 쓰인 `session/`·`archive/`·`qa-request/` 문서의 diff --git a/HUMAN_TODO.md b/HUMAN_TODO.md index 33ea5cb..915c724 100644 --- a/HUMAN_TODO.md +++ b/HUMAN_TODO.md @@ -54,7 +54,13 @@ git.qwreey.moe에 제한된 계정 생성). 로컬 git 저장소는 이미 초 커밋까지 해뒀음(원격 없음) — 원격을 추가하고 싶으면 그 계정 정보를 알려줄 것, 그 전까지는 로컬 커밋만 계속 쌓아둠. -## 2. 자율 작업 루프/스케줄 설정 +## 2. ~~자율 작업 루프/스케줄 설정~~ **[해소됨, 2026-08-28]** + +**사용자가 M2를 세션 안 자율 구현 구간으로 확정**했다 — 규약은 +`.claude/qa-request/pre-implementation-handtrace-round11-brief.md`, 요지는 +`.claude/conventions.md`의 "M2 자율 구현 규약" 항목. cron/`/schedule`은 안 쓴다 +(사용자 개입 지점은 단위가 끝날 때 `-round11.md` §4 표를 배치로 회신하는 것뿐). +아래는 해소 전 원문. 사용자가 잠들어 있는 동안에도 계획된 TODO를 이어서 진행하길 원한다는 요청이 있었음 (`req.md` 참고). 이건 세션을 넘어 지속되는 자동 실행이라 다음 중 하나를 사용자가 diff --git a/ROADMAP.md b/ROADMAP.md index e842d8b..dfc1c9d 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -260,6 +260,12 @@ Luau 코드로 부딪혀본 적 없는 세 가지**를 던지는 코드로 검 > 디스패치로 옮겼던 **`EpochMap`/`GateNode`/`Blocker`는 되돌아왔습니다** — > 앞당길 이유 자체가 순서 교체로 사라졌고, "게이팅 먼저"는 그대로 > 지켜집니다. +> +> **⭐ [2026-08-28 착수] M2는 자율 구현 구간으로 돕니다** — 규약(세 갈래 분류, +> 단위 넷, 관여 시점)은 `.claude/qa-request/pre-implementation-handtrace-round11-brief.md`가 +> 소스, 발견은 `-round11.md`. 단위 순서는 이 문서의 체크박스 순서 그대로이되 +> **`H-97`의 mock 생명주기 4종은 첫 단위(공통 기반)로 당겨** 짠다 — 그게 없으면 +> 두 번째 단위부터 전파 루프 테스트가 안 돈다. ### 공통 기반 — 반응형보다 먼저 (구 M2, 지금의 M3에서 이동) @@ -297,6 +303,8 @@ Luau 코드로 부딪혀본 적 없는 세 가지**를 던지는 코드로 검 분리로 처음 눈에 띈 잔재를 **[2026-08-24]** 정정한 것) — `brand-plan.md`의 `Brand` 절, 2026-08-07 여덟 번째 세션 신설) - [ ] `Relate.luau`(전체가 quad-base, 순수 Lua — `base/relate-plan.md`) — + **[2026-08-28 확인] 파일은 M1 커밋 `205af32`에 이미 있다**(`RunInit`이 + 쓴다) — 이 체크박스의 남은 일은 `base/relate-plan.md` 대조와 테스트뿐. `Relate()` 비싱글톤 생성자, `:SetWeak`/`:GetWeak`/`:SetStrong`/`:GetStrong`. `inst`(첫 인자)는 항상 weak, `StrongMap`/`WeakMap` 서브테이블은 lazy 생성(첫 `Set` 호출 시에만), `WeakMap`은 공유 메타테이블(`{__mode="v"}`) @@ -355,6 +363,10 @@ Luau 코드로 부딪혀본 적 없는 세 가지**를 던지는 코드로 검 **[2026-08-27 `/code-review`]** 아래 `H-80` 탑레벨 목록의 규칙(*"이 마일스톤이 얹는 탑레벨 값 전부"*)대로 **`quad-types`의 `Quad`에 `Ref` 생성자 필드도 여기서** 추가한다 — M8의 `H-25` 체크박스는 이걸로 흡수. +- [ ] **[2026-08-28 `H-162`] `Void`** — 단일 no-op 함수 export. no-op 클로저를 + 돌려주는 자리는 새 클로저 대신 이것. 아래 `H-80` 탑레벨 목록에만 있고 + 여기 체크박스가 없어 "개수·목록은 소스 하나" 규약에 어긋나던 것을 M2 + 착수 규약 커밋에서 신설. ### 반응형 본체