# 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 기준] 확인 대기.**