docs: M3 자율 구현 규약 확정 — round12 §0 전량 (a)·§6 첫 단위 계획 승인

- §0 회신 기록: Q1(M2 골격 + Handler 체크리스트 게이트)/Q2(단위 넷)/
  Q3(M2 하자는 규모로 가름) 전부 권고 (a) 사용자 채택
- §6 신설·승인: Dispatch/Handler.luau(타입 전용 잎) + Dispatch/init.luau
  (InitDispatch(module), chains는 인스턴스별 Relate, HANDLER_PRIORITY_* 상수
  정의+재노출) + quad-types Dispatch 필드(H-25) / drive는 단위 1에서 (b) 본체
  루프만 — 배치 게이팅은 단위 2, pre-pass·postRefList는 M8 / 스파이크 01
  재작성은 spec.drive.luau 상시 회귀로 대체
- round12.md 스텁을 실 스켈레톤(요약 표/§4/§5/§6)으로 교체, H-212부터
- 인덱스 3층 갱신: README qa-request 행, CLAUDE.md·project-context 머리말,
  todos.md 00번 — "M3 진행 중"

Co-authored-by: qwreey <me@qwreey.moe>
Claude-Session: https://claude.ai/code/session_01LF78pXeFGD1ZSVD3ifteYG
This commit is contained in:
qwreey-agent-selene 2026-08-31 14:59:23 +09:00
parent 3e7dcfead2
commit f14ba09cd6
No known key found for this signature in database
6 changed files with 94 additions and 28 deletions

File diff suppressed because one or more lines are too long

View file

@ -11,10 +11,12 @@ Roblox 엔진에서 동작하는 DOMless UI 렌더러 **quad**를 처음부터
길게 잡음.
**⭐ [2026-08-31 기준] M0(스파이크 검증)/M1(스캐폴딩)/M2(반응형 코어 —
Source/State/Store) 완료, 다음은 M3(디스패치 엔진)** — M2는 자율 구현
Source/State/Store) 완료, M3(디스패치 엔진) 진행 중** — M2는 자율 구현
구간(규약 `qa-request/m2-implementation-round11-brief.md`, 발견 `-round11.md`)
으로 2026-08-28 착수~08-31 종결(단위 넷 구현·감사·리뷰·탐사 완료, §4 문항·
코드 마커 0). **M3 착수 전 새 자율 규약 문항은 사용자와 정할 것**
코드 마커 0). **M3도 같은 방식의 자율 구간으로 2026-08-31 착수** — 규약은
`qa-request/m3-implementation-round12-brief.md`(같은 날 §0 세 문항·§6 첫 단위
계획 사용자 확정), 발견은 `-round12.md`(`H-212`부터). 진행 상태는
`.claude/todos.md` 00번이 소스(마일스톤이 넘어갈 때 루트 `CLAUDE.md` 머리말도
같이 고칠 것 — 같은 상태를 두 곳이 서술하고 있음). **⚠️ [2026-08-24] M2와
M3의 번호·순서가 맞바뀌었다** — 열려 있던 마일스톤 순서 문제가 (a) 순서

View file

@ -1,10 +1,10 @@
# M3 자율 구현 규약(안) — 12라운드 지시서 + 착수 문항지
# M3 자율 구현 규약 — 12라운드 지시서 + 착수 문항지
> **이 파일이 무엇인가**: **[2026-08-31 신설, §0 회신 대기]** M3(디스패치 엔진)
> 구현 구간의 규약 초안이자 착수 문항지다. **§0 표가 사용자가 읽을 유일한
> 자리** — 회신이 §0에 기록되면 이 파일이 M2의 `m2-implementation-round11-brief.md`
> 같은 지위(규약 소스 + 단위 끝 탐사자 지시서)가 된다. 산출물(발견 문서)은
> 착수 시 `m3-implementation-round12.md`로 신설.
> **이 파일이 무엇인가**: **[2026-08-31 신설, 같은 날 §0·§6 회신 완료 — 규약
> 확정]** M3(디스패치 엔진) 구현 구간의 규약이자 착수 문항지다. §0 세 문항과
> §6 첫 단위 계획이 전부 확정돼(회신 기록은 §0 바로 아래), 이 파일은 M2의
> `m2-implementation-round11-brief.md`같은 지위(규약 소스 + 단위 끝 탐사자
> 지시서)다. 산출물(발견 문서)은 `m3-implementation-round12.md`.
>
> **명명**: `mN-implementation-roundNN` 규약(2026-08-31 사용자 확정,
> `.claude/README.md` `qa-request/` 행이 소스) — 라운드 번호는 마일스톤을
@ -24,6 +24,12 @@
| **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 라운드로 승격하고, 잔손질까지 파일을 쪼개면 발견 흐름이 갈라진다 |
**⭐ [2026-08-31 회신 — 전량 확정]** 사용자가 대화형 선택지로 **Q1·Q2·Q3 전부
권고 (a)를 채택**했고, **§6 첫 단위(코어) 계획도 그대로 승인**했다("승인 —
이대로 착수" 선택; 세션은 사용자 지시 *"M3 를 작업 시작하자.
m3-implementation-round12 문서를 보면 돼"*로 열렸다). 이로써 이 파일이 M3
규약 소스다 — 발견 번호 `H-212`부터, M2 하자는 Q3 (a) 규칙.
**통보(문항 아님 — 규약·코드 배치라 여기 명시만)**: 발견 문서는 착수 시
`m3-implementation-round12.md` 신설, 번호 `H-212`부터. **mock 확장은 불필요**
M3 핸들러가 부르는 건 quad-base 자기 부기 API(`setLength` 등)뿐이고 엔진
@ -98,11 +104,33 @@ M2 §5를 그대로 쓰되 치환 셋: 대상 라운드 파일은
무효화 표)·`bind-system-plan.md`가 중심. `git stash` 금지·실행 우선·한 줄
대조·`grep -rn "TODO(H-"` 전수 확인은 동일.
## §6 첫 단위(코어) 작업 계획 — §0 회신 후 확정
## §6 첫 단위(코어) 작업 계획 — **[2026-08-31 사용자 확정]** ("승인 — 이대로 착수")
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-로컬
테스트 핸들러.
여기 적힌 것은 `base/`가 정하지 않은 **코드 배치·범위 절단**이라 이 계획이
소스다(M2 §6과 같은 지위) — 설계 결정이 아니다.
**소스 (`quad-base/src/`, 배치는 `architecture.md` 소스 트리 그대로)**
| 파일 | 내용 | 옮겨 적는 절 |
|---|---|---|
| `Dispatch/Handler.luau` | 계약 **타입만** 담는 잎 — `Handler` 타입(`isHandlable(inst,k,v): boolean` / `priority: number` / `process(inst,k,v,index) -> (any?) -> ()`). Dispatch를 되참조하지 않는다 | `dispatch-core-plan.md` "핸들러 계약" 절, "Dispatch는 프리미티브가 아니다" 절의 단방향 의존 |
| `Dispatch/init.luau` | `InitDispatch(module)` 팩토리(`module-lifecycle-plan.md` "New()의 내부 구성" 예시 그대로 — `H-174` (a)) — `module.Dispatch`에: `getHandler`(우선순위 스캔·첫 매치, 매치 실패는 `Brand`+`typeof(v)` 출력 + provider 안내 즉시 error, 실패 메시지는 클로저 지연 생성) / `process`(하강 diff (A)/(B) 의사코드 그대로 — retractor `nil` 반환 즉시 error 양쪽, (B) 점유 마커 선행, `chains:SetStrong``h.process` **전**, (A) 소비 직후 `NOOP` 교체) / 3-인자 `retractFrom`(꼬리 역순, 구멍이면 error) / `addHandler`(등록 시점 정렬, 동률 감지 print는 `module.debug`가 참일 때만) / `listHandlers`(항상 호출 가능, 반환만 하는 순수 조회) / `drive`(범위는 아래 행). `chains`는 별도 파일이 아니라 `InitDispatch`가 만드는 `Relate` **인스턴스별** 값. `HANDLER_PRIORITY_HIGH`/`_NORMAL`/`_LOW`/`_FALLBACK` 상수는 이 파일 정의 + `module.Dispatch`에 재노출(Handler.luau를 타입 전용 잎으로 유지) | "Dispatch 체인" 절 의사코드(`H-103` 주석 포함), "우선순위 동률/매치 실패 처리", `H-162`(NOOP = `Void`) |
| (범위 절단) `drive` | 이 단위에선 파이프라인 (b) **본체 단일 일반화 `for`만**(각 `(k,v)``process(inst,k,v,1)`). ⓪/⓪' 배치 Blocker 게이팅은 **단위 2**(`getBlocker`/`getBookkeeping`/`recompute`가 생기는 자리)에서 배선, (a) pre-pass/(c) `postRefList`**M8**(`PreRef`/`PostRef` 본체·소진 센티널이 생기는 자리). 정본과의 차이는 코드 헤더 주석에 명시 | `bind-system-plan.md` "`New(name)(props)` 파이프라인 의사코드" 절 |
| `quad-types/src/init.luau` | `Quad` 타입에 `Dispatch` 필드 + `Handler` 타입 재수출(`H-25` — 마일스톤마다 갱신 규칙의 M3 몫) | `quad-types-plan.md` "`Quad` 타입 — 확정된 표면" 절 |
| `init.luau`(최상위) | `module:RunInit(InitDispatch)` 추가 | `module-lifecycle-plan.md` |
**테스트 (`quad-base/test/`)** — 테스트 핸들러는 §0 통보대로 spec 파일 로컬
(실핸들러가 아직 없음). `inst`는 평범한 테이블(base 계약상 `inst`는 백엔드
재량이라 mock 확장 불필요).
| 파일 | 검증하는 계약 |
|---|---|
| `spec.dispatch.luau` | `getHandler` 우선순위 스캔·첫 매치 · 매치 실패 error 메시지(Brand/typeof/provider 안내) · (A) 분기: retractor가 **새 값**을 받고 아래 체인은 안 건드림, 같은 자리 클로저 교체 · (B) 분기: 그 자리부터 꼬리 역순 철거 후 재설치 · retractor 반환 생략 즉시 error((A)/(B) 모두) · `retractFrom` 꼬리 역순·항상 소비(`list[i]=nil`)·구멍 error · 재귀 위임 `index+1`/다른 키 위임 항상 `1` · 래핑 핸들러 2단 체인(같은 핸들러가 인덱스 N·N+1 — `State<State<T>>` 유사 구조를 spec 핸들러로) · `SetStrong` 선행(재귀 위임 시 하위 retractor 유실 없음 — 2026-08-13 감사 버그의 음성 대조) · 조건부 재위임 핸들러의 `retractFrom(index+1)` 직접 호출 경로(체크리스트 8) · `addHandler` 정렬·동률 경고가 `module.debug` 게이팅 · `listHandlers` 반환만 · `New()` 인스턴스 간 레지스트리/체인 격리 |
| `spec.drive.luau` | 단일 일반화 `for` 한 번으로 배열 파트 **전체**가 해시 파트보다 먼저 + 배열 안에서는 index 순서(`F-4-1` — 재작성 대기 스파이크 `01`이 물어야 했던 언어 동작 질문을 여기서 실측) · 모든 진입이 index 1 |
- 스파이크 `01` 재작성(`luau-test/rewrite-required/01-*`)은 **따로 안 한다**
`spec.drive.luau`가 같은 질문을 상시 회귀로 실측하므로. `STATUS.md`에 그
취지를 기록하고 재작성 대기 목록에서 정리(이 처분도 §0 회신에 묶임).
**커밋 단위**: M2와 같게 모듈마다 하나(구현 + spec + `base/` 정정이 있으면
같은 커밋), 단위 끝 절차는 §4.

View file

@ -1,6 +1,35 @@
# M3 구현 **12라운드** — 발견 원문 + 배치 문항지 (스텁)
# M3 구현 **12라운드** — 발견 원문 + 배치 문항지
> **[2026-08-31 스텁]** 규약 문항지(`m3-implementation-round12-brief.md`)의
> §0 회신이 아직이라 **비어 있다** — M3 착수와 함께 round11 파일과 같은
> 구조(요약 표 / 상세 / §4 배치 문항 / §5 이상 없음 / §6 남은 의심)로
> 채워진다. 발견 번호는 **`H-212`부터**(round11이 `H-211`까지 썼다).
> **이 파일이 무엇인가**: **[2026-08-31 신설]** M3 자율 구현 구간
> (`m3-implementation-round12-brief.md`가 규약, 같은 날 §0·§6 확정)에서 나온
> 발견 전부. 실제 코드를 옮기고 돌리다 나온 것이다. 번호는 **`H-212`부터**
> (11라운드가 `H-211`까지 썼다).
>
> **갈래 표기**(규약 §2): **①** 자율로 고침(같은 커밋에서 `base/`+코드) /
> **②** §4 표에 쌓아 배치 회신 대기 / **③** 즉시 중단·보고. M2 하자는
> 규약 §0 Q3 (a) — 경미하면 여기 ①, 설계 결정 규모면 그때
> `m2-implementation-round13`을 새로 연다.
>
> **상태의 소스는 이 파일 자신** — 요약 표의 상태 열이 최신.
## 요약 표
| 번호 | 갈래 | 단위 | 심각도 | 한 줄 | 상태 |
|---|---|---|---|---|---|
| (아직 없음) | | | | | |
## §4 배치 문항지 (사용자가 읽을 유일한 자리)
**[2026-08-31 기준] 열린 문항 없음.**
| 번호 | 무엇 | 선택지 | 권고 | 권고 근거 |
|---|---|---|---|---|
| (아직 없음) | | | | |
## §5 이상 없음 확인 (탐사자·구현이 확인만 하고 문제 없었던 자리)
(아직 없음)
## §6 남은 의심 (발견은 아니지만 다음 라운드가 파볼 자리)
(아직 없음)

View file

@ -23,10 +23,15 @@
개명(구현 중 문서라 옛 이름이 안 맞았음; 명명 규약 `mN-implementation-roundNN`
`.claude/README.md` `qa-request/` 행이 소스 — 라운드 번호는 마일스톤을 가로질러
단순 증가). M2 종료 보고도 전달 — **M2 종결.**
**다음 액션: M3(디스패치 엔진) 착수 — [2026-08-31] 규약 문항지
`qa-request/m3-implementation-round12-brief.md` 작성 완료, §0 표(문항 셋)
사용자 회신 대기.** 회신되면 그 파일이 M3 규약 소스가 되고 §6(첫 단위
계획) 확정 후 착수(2026-08-29 체크포인트의 "M3은 새 규약 문항" 이행).
**다음 액션 이행됨 — ⭐⭐⭐ [2026-08-31] M3(디스패치 엔진) 자율 구현 구간
착수.** 규약 문항지 `qa-request/m3-implementation-round12-brief.md`의 §0
세 문항(규약 재사용/단위 넷/M2 하자 혼입 규칙)이 **전부 권고 (a)로 사용자
확정**됐고 §6 첫 단위(코어) 계획도 승인됨("승인 — 이대로 착수") — 그
파일이 M3 규약 소스다(2026-08-29 체크포인트의 "M3은 새 규약 문항" 이행).
발견·배치 문항은 `-round12.md`(`H-212`부터), **진행 상태의 소스는
`ROADMAP.md` M3 체크박스** — 여기서 세지 않는다. 단위 넷: ① Handler
계약+디스패치 코어 → ② Length/Offset 부기 → ③ `None`+`NoneHandler`/
`NilHandler` → ④ Leaf+가드 등록+종합 테스트(brief §1이 소스).
아래는 착수 전(2026-08-26) 서술:
**[2026-08-26] 8라운드까지 전부 처리 완료 — M2 착수 게이트가 0이다.**

View file

@ -2,12 +2,14 @@
Roblox 엔진용 DOMless UI 렌더러 **quad**를 처음부터 다시 짜는 프로젝트.
**⭐ [2026-08-31 기준] M0(스파이크 검증)/M1(스캐폴딩)/M2(반응형 코어 —
Source/State/Store)까지 완료, 다음은 M3(디스패치 엔진)** — M2는 자율 구현
Source/State/Store)까지 완료, **M3(디스패치 엔진) 진행 중**** — M2는 자율 구현
구간(규약 `.claude/qa-request/m2-implementation-round11-brief.md`, 발견·배치
문항 `-round11.md`)으로 돌아 2026-08-28 착수~08-31 종결: 단위 넷 구현·감사·
리뷰·탐사 완료, `ROADMAP.md` M2 체크박스 전부 `[x]`, §4 문항·코드 마커 0.
**M3 착수 전에 새 자율 규약 문항을 사용자와 정할 것**(`.claude/todos.md`
00번이 소스). **⚠️ [2026-08-24] M2와 M3의
**M3도 같은 방식의 자율 구간** — 규약은
`.claude/qa-request/m3-implementation-round12-brief.md`(2026-08-31 §0·§6
사용자 확정, 단위 넷·발견 `H-212`부터 `-round12.md`), 진행 상태는
`.claude/todos.md` 00번이 소스. **⚠️ [2026-08-24] M2와 M3의
번호·순서가 맞바뀌었다** — 예전엔 M2=디스패치, M3=반응형이었는데 의존이
한 방향(디스패치 → 반응형)이라 반응형을 먼저 짓기로 확정했다. 그래서
**2026-08-24 이전에 쓰인 `session/`·`archive/`·`qa-request/` 문서의