design: New()의 내부 구성 확정 — InitXxx 팩토리 체이닝 + Relate 기반 멱등 Init 가드

InitRoblox(Module) backend 주입 패턴을 quad-base 자기 내부(Dispatch 등)에도
대칭 적용 — 각 서브시스템이 InitXxx(module)로 module을 뮤테이션. 서브시스템
간 호출 순서 문제는 각 InitXxx 파일 톱레벨에 Relate() 하나를 두고 module을
weak key 삼아 인스턴스별 완료 여부를 기록해 require처럼 멱등하게 만들어
해소(relate-plan.md 체크리스트에도 용례 추가). module-lifecycle-plan.md에
"New()의 내부 구성" 절 신설, architecture.md/dispatch-core-plan.md/
ROADMAP.md(M1 체크리스트)에서 상호 참조.

핸드오버 감사 루프 4라운드(무발견 1회로 수렴) — 라운드 1~2는 절 인용
사각지대·상호참조 누락·SetWeak/SetStrong 일관성을 잡았고, 라운드 3~4는 그
수정 자체가 남긴 커밋 개수/날짜 오기, 원문 인용 파라프레이즈 등을 추가로
잡음. 부수로 session/ 기록 공백(2026-08-18/19 다수 커밋에 원문 누락)을
발견해 이번 세션분만 session/2026-08-19-01-*.md로 남김 — 과거 공백 처리는
사용자 확인 대기.

Co-authored-by: qwreey <me@qwreey.moe>
This commit is contained in:
qwreey-agent-selene 2026-08-19 01:16:26 +09:00
parent 96c8c2eaa1
commit 4be9373124
No known key found for this signature in database
8 changed files with 279 additions and 7 deletions

File diff suppressed because one or more lines are too long

View file

@ -154,11 +154,18 @@ quad는 이제 "스크립트"가 아니라 **라이브러리**다. DOMless Roblo
인자로 받도록 **손을 대야** 한다 — `New()`가 실제로 호출되면(위 opt-in
경로) 그 순간 만들어지는 새 `BaseModule` 테이블에 대해 이 손질이 필요.
**지금은 `New()` 자체가 노출 안 된 싱글톤 단계라 `Quad.Dispatch`
바로 접근**한다.
- **M0 스캐폴딩에 주는 함의**: 레지스트리를 module-level upvalue로
직접 잡아두면 나중에 다중 인스턴스화할 때 전면 수정이 된다. 지금
싱글톤으로 가되, **그 참조 형태를 나중에 인자 하나 받는 걸로 바꾸기
쉬운 모양으로 둘지**를 M0에서 정할 것.
바로 접근**한다. `New()` 자신이 내부적으로 어떤 형태로 조립되는지(v1
스타일 `InitXxx(module)` 팩토리 체이닝, 타입 재익스포트)는
`module-lifecycle-plan.md`의 "New()의 내부 구성" 절 참고.
- **M0 스캐폴딩에 주는 함의 — [2026-08-19] 정해짐, 실제로는 M0가 아니라
`ROADMAP.md` M1(실제 스캐폴딩)에 적용됨.** 레지스트리를 module-level
upvalue로 직접 잡아두면 나중에 다중 인스턴스화할 때 전면 수정이
된다는 우려가 있었는데, 바로 위에서 가리키는 InitXxx 패턴(각
`InitXxx(module)``module`을 upvalue가 아니라 **파라미터로 받아**
뮤테이션)이 처음부터 그 형태다 — 나중에 바꿀 일 자체가 없게 M1
스캐폴딩부터 이 모양으로 짠다. M0는 독립 스파이크 파일로 개별
가설만 검증하는 단계라 이 구조 자체를 아직 안 씀(`ROADMAP.md`의
"M0 — 스켈레톤 + 기술검증" 절 참고).
14. **pluggable 초기화는 팩토리 함수로.** rbvm처럼 네임스페이스 하나하나 수동
init 하는 방식(`base/lifecycle-pattern.md` 5번 항목 참고)은 피하고,
`InitRoblox(Module)` 같은 팩토리 함수가 생성된 모듈을 뮤테이션하는 도구를

View file

@ -623,7 +623,12 @@ end
state를 참조하는 코드들이 모듈 인스턴스를 인자로 받도록
(`InitModule(module)` 류) 손을 봐야 한다(`base/architecture.md` "확정된
결정" 13번). 지금은 `New()` 자체가 노출 안 된 싱글톤 단계라
`Quad.Dispatch`로 바로 접근한다.
`Quad.Dispatch`로 바로 접근한다. **[2026-08-19 추가]** 이 문단이 말하는
"`InitModule(module)` 류"의 정확한 형태(각 서브시스템별 `InitXxx(module)`
팩토리 체이닝 + `Relate` 기반 인스턴스별 멱등 가드)가
`module-lifecycle-plan.md`의 "New()의 내부 구성" 절에 구체화됨 —
`Dispatch/init.luau`도 그 패턴을 따르는 `InitDispatch(module)` 하나로
구현된다.
### base가 소유하는 핸들러와 주입되는 엔진 op (2026-08-13 열네 번째 세션 신설)

View file

@ -30,6 +30,123 @@ RBVM처럼 `init namespace` 하나하나 부르는 방식은 별로(`base/lifecy
주고 사용자가 호출하도록. `base/architecture.md` 14번 항목과 동일한 결정 —
여기서는 "왜"만 보강.
## New()의 내부 구성 — InitXxx 팩토리 체이닝 (2026-08-19 신설)
바로 위 절이 확정한 `InitRoblox(Module)` 패턴(팩토리가 모듈 테이블을
뮤테이션)은 지금까지 서술상 **backend 주입**에만 적용되는 것처럼 보였는데,
`New()` **자신**이 quad-base 내부 서브시스템(Dispatch 등)을 구성하는
방식도 대칭적으로 같은 패턴을 쓴다 — 새 설계가 아니라 이미 확정된 원칙을
quad-base 자기 자신에도 적용한 구체화. 논의 원문은
`session/2026-08-19-01-new-initxxx-composition-relate-guard.md`.
**사용자 제안 원문 요지**(2026-08-19): *"생성형식 자체는 비싱글톤이고,
Dispatch 같은것도 `Init(module)` 을 받는 함수로써 ... `module.Dispatch = ...`
형식들로 구현되고 ... 재익스포트식으로 구현하겠다는 이야기였음. 처음부터
`InitModuleName` 식으로 구현하여 팩토리를 쌓아 모듈을 리턴하는 방식으로,
quad v1 의 방식을 가져와봄직 하다."*
**형태**(각 서브시스템 파일이 `Init` 함수를 export하고, 타입도 재익스포트):
```lua
-- Dispatch/init.luau
local function Init(module)
local ... -- 여기서 레지스트리/릴레이션 생성
module.Dispatch = ...
end
export type Dispatch = ...
return Init
```
```lua
-- 최상위 init.luau
local InitDispatch = require(...)
type Dispatch = InitDispatch.Dispatch -- 재익스포트
local function New(): { Dispatch: Dispatch, New: typeof(New), ... }
local module = { New = New }
InitDispatch(module)
-- 서브시스템 개수만큼 InitXxx(module) 을 순서대로 쌓음
return module
end
return New()
```
`module = {New = New}` 자기참조는 `base/architecture.md` "확정된 결정"
13번이 이미 확정해둔 것과 정확히 같은 형태 — 별도 결정이 아니라 그 결정이
실제로 어떻게 코드로 나오는지를 구체화한 것뿐.
**타입 재익스포트는 실측 확인됨**(2026-08-19, 사용자: "그거 타입 익스포트
잘 됨") — `type Dispatch = InitDispatch.Dispatch` 형태로 서브모듈의
export 타입을 최상위에서 그대로 재노출하는 게 Luau에서 문제없이 동작한다.
`base/typing-limits.md`가 우려하는 "명시 바인딩 필요" 케이스와는 다른
자리라는 뜻 — 거긴 재귀 제네릭이 자기를 다른 타입 인자로 반환하는 게
문제였고, 여긴 단순 alias라 그 한계에 안 걸린다.
**순서 의존성은 각 `InitXxx``require`처럼 멱등하게 만들어서 해소한다**
(2026-08-19, 사용자 제안) — 서브시스템 간 호출 순서를 최상위 `New()`
직접 관리할 필요가 없다: 각 `InitXxx` 파일이 자기 톱레벨(함수 클로저
**밖**, 파일 스코프)에 `local relate = Relate()`를 하나 두고, `module`
weak key 삼아 "이 `module` 인스턴스에 이미 Init됐는지"를 기록한다. 이미
됐으면 그대로 스킵, 아니면 실제 작업을 한 번만 수행 — Lua의 `require`
캐시와 같은 발상이지만, `require` 캐시는 **파일** 단위(Init 함수 자체는
한 번만 로드)인 반면 `New()`는 여러 번 호출돼 서로 다른 `module` 테이블을
여러 개 만들 수 있어서, "이 particular 인스턴스에" 멱등하려면 파일 스코프
캐시로는 부족하고 `module`을 키로 하는 이 `Relate`가 따로 필요하다.
```lua
-- Dispatch/init.luau
local Relate = require(...)
local relate = Relate() -- 파일 스코프, 클로저 밖 — 이 Init 전체가 공유하는 단 하나의 인스턴스
local function Init(module)
if relate:GetStrong(module, INITED) then
return -- 이미 이 module 인스턴스엔 Init됨, no-op
end
relate:SetStrong(module, INITED, true) -- 실제 작업 전에 먼저 표시(순환 의존 대비, 아래 참고)
-- 자신의 의존성도 그냥 require+호출 — 상대도 멱등하므로 중복/순서 걱정 없음
-- 예: InitLifetime(module)
local ...
module.Dispatch = ...
end
return Init
```
이렇게 하면 **의존하는 쪽이 자기 의존성을 직접 호출**하면 되고(`require`가
의존 그래프를 알아서 풀어주는 것과 같은 감각), 최상위 `New()`는 순서를
신경 쓰지 않고 아는 `InitXxx(module)`을 전부 호출해도 된다 — 이미 누가
먼저 채웠으면 알아서 스킵된다.
- **GC와도 자연히 맞물림**: `relate-plan.md`의 "API" 절에 따르면 `Relate`
**첫 인자(`inst`, 여기선 `module`)는 항상 weak**다(선택의 여지가 없는
고정 동작 — `Weak`/`Strong` 구분은 오직 `value` 쪽 보관 방식만 가리킴).
그래서 `value` 쪽을 `SetWeak`으로 두든 `SetStrong`으로 두든 상관없이,
어떤 `Quad` 인스턴스(전체 `module` 테이블)가 더 이상 참조되지 않아
수거되면 이 Init-완료 기록도 같이 사라진다 — 별도 정리 로직 불필요.
`relate-plan.md`가 이미 확정해둔 "각 모듈이 자기 톱레벨에 `Relate()`
하나를 두고 재사용" 관례를 그대로 쓰는 것이라 새 메커니즘 아님.
(`relate-plan.md`가 별도로 명시한 "명시적으로 만든 기록은 명시적으로
지울 것" 원칙과 충돌하는 게 아니라 — 이 경우는 기록의 키 자체가 죽으면
그 기록을 다시 조회할 주체 자체가 사라지므로 지울 대상이 없어지는,
원칙이 애초에 상정하지 않은 자리다.)
- **`value``SetStrong`으로 통일**: 위 문단대로 GC 결과엔 차이가 없지만
(boolean 리터럴은 애초에 GC 대상이 아님), `relate-plan.md`의 일반 규칙
"다른 곳에서 안전하게 유지되는 것은 항상 `SetWeak`" 기준으로는 이 `true`
플래그를 다른 어디도 붙잡고 있지 않으므로 `SetStrong`이 그 규칙에 맞는
선택이다.
- **`_initializedBy` 가드(아래 "Bind는 누가, 어떻게 구현하는가" 절, 실제
정의는 `base/bind-system-plan.md`)와는 다른 층위** — 그건 backend
팩토리가 유일 슬롯을 채웠는지 **누가** 채웠는지까지 구분해야 하는 공개
계약(같은 팩토리 재호출=no-op, 다른 팩토리=에러)이고, 이건 quad-base
내부 서브시스템 각각이 **한 번만** 도는지만 보면 되는 사적 구현
디테일이라 "다른 호출자면 에러" 같은 분기 자체가 없다. 이름이 겹치지
않게 구분해서 쓸 것.
- **플래그를 실제 작업 전에 먼저 세우는 이유**: 나중에 `InitA`↔`InitB`처럼
상호 의존이 생기면([2026-08-19 기준] 지금은 없음, 대비만), 먼저
표시해두지 않으면 무한 재귀에 빠진다 — `require`가 순환 참조 시
미완성 exports를 돌려주는 것과 같은 이유로, 실제 작업 시작 전에 먼저
"완료"로 표시해둔다.
## Bind는 누가, 어떻게 구현하는가
인터페이스 상 `bind`를 두고 이것도 pluggable하게 할지 고민 — 단 **1개만 존재할

View file

@ -166,6 +166,11 @@ Handler 계약이 "`process`가 자기 retract 클로저를 반환"으로 바뀌
- **소유권/멤버십 전역 판정**`Slot``elementOwner`.
- **"언제까지 실행돼도 되는가"** — `bindLifetime`/`canExecute`
(`base/lifecycle-pattern.md`). 애초에 클로저 수명과 무관한 질문.
- **"이 인스턴스에 이미 했는가"류 인스턴스별 멱등 가드**(2026-08-19
신설) — `New()`가 만드는 각 `module` 인스턴스별로 `InitXxx(module)`
이미 실행됐는지 기록하는 것도 여러 호출 지점(다른 `InitXxx`가 자기
의존성으로 호출하는 경우 포함)을 가로질러야 해서 클로저 캡처로 대체
불가 — `base/module-lifecycle-plan.md`의 "New()의 내부 구성" 절.
**쓸 때 같이 지킬 것**:
- **정리 조건을 실제 정리와 묶을 것.** `Relate` 엔트리를 지우는 코드가

View file

@ -1485,3 +1485,22 @@ Store의 lazy `__index`와 충돌 / `PopOnly` 홀드 중 키가 사라지면 파
중단했음. **그래서 사용자 지침으로 감사 절차 자체를 바꿨다** — 병렬 금지(한
턴에 하나), 범위는 diff로 좁히고 라운드마다 각도를 바꿈, 종료 조건은 무발견
1회(옛 "2연속"은 병렬 전제라 완화). `conventions.md`의 감사 루프 절이 소스.
## 2026-08-19 — `New()` 내부 구성(InitXxx + Relate 멱등 가드) 확정, 세션 기록 공백 발견
원문: `session/2026-08-19-01-new-initxxx-composition-relate-guard.md`
사용자가 `New()`를 v1 스타일 `InitXxx(module)` 팩토리 체이닝으로 짜자고
제안(이미 확정된 `InitRoblox(Module)` backend 주입 패턴을 quad-base 자기
내부에도 대칭 적용) → 채택, `module-lifecycle-plan.md`에 "New()의 내부
구성" 절 신설. 이어서 서브시스템 간 호출 순서 문제를 "Init을 `require`처럼
멱등하게"(각 `InitXxx` 파일 톱레벨에 `Relate()` 하나 두고 `module`을 weak
key로 완료 여부 기록) 방식으로 직접 해소하는 아이디어도 제안·반영 —
`relate-plan.md`의 기존 확정 API/관례와 정확히 부합함을 확인. 핸드오버
감사 2라운드를 거치며 라운드 1의 수정 자체가 절 인용 사각지대를 새로
만든 걸 라운드 2가 잡는 등 실제로 반복 라운드가 필요함을 다시 확인.
**부수 발견 — session/ 기록 공백**: 2026-08-18에 커밋 10개(QA 1~2라운드
포함)가 있었는데 그날 session/ 파일은 1개뿐, 2026-08-19는 이 세션 전까지
(QA 3라운드 커밋 1개가 있었음에도) 0개였음. 과거 대화 트랜스크립트에 접근 불가라 그 공백을 사후 재구성하는 건
허위 기록 위험이 있어 보류 — 처리 방침은 사용자 확인 대기.

View file

@ -0,0 +1,115 @@
# 2026-08-19 — `New()`의 내부 구성: InitXxx 팩토리 체이닝 + `Relate` 기반 멱등 Init 가드
**요청**: `Quad.New()`가 실제로 어떻게 구현돼야 하는지에 대한 사용자
아이디어 검토 요청으로 시작 — 결론까지 나서 `base/`에 반영, 이어서
핸드오버 감사 루프와 세션 기록 공백 점검까지 같은 세션에서 처리.
## 1. 제안 — `New()`를 InitXxx 팩토리 체이닝으로
사용자 원문: *"New() 가 실행되면 Quad 를 만드는 함수가 있는것으로 처음부터
구현하는게 맞음. ... New 결과 안에 .New 함수를 넣어줌. 즉, 생성형식 자체는
비싱글톤이고, Dispatch 같은것도 Init(module) 을 받는 함수로써 ...
module.Dispatch = ... 형식들로 구현되고 ... 재익스포트식으로 구현하겠다는
이야기였음. 처음부터 InitModuleName 식으로 구현하여 팩토리를 쌓아 모듈을
리턴하는 방식으로, quad v1 의 방식을 가져와봄직 하다는것."*
**조사**: 기존 `base/architecture.md` 13번("모듈은 기본 싱글톤, `New()`
추가 인스턴스가 필요할 때만")과 14번("pluggable 초기화는 팩토리 함수로"),
`module-lifecycle-plan.md`가 이미 `InitRoblox(Module)` 형태의 backend 주입
패턴을 확정해뒀다는 걸 확인 — 이번 제안은 그 패턴을 quad-base **자기
자신의 내부 구성**(Dispatch 등)에도 대칭 적용하자는 것이라 새 설계가
아니라 기존 원칙의 자연스러운 확장으로 판단. `lifecycle-pattern.md`
거부한 rbvm `InitNamespace` 패턴(소비자가 라이브러리마다 수동으로 init을
부르는 것)과도 안 겹침 — 여기선 `New()` 하나만 외부에 노출되고 내부에서만
`InitXxx(module)`를 부름.
**결론**: 채택 추천 — `module = {New = New}` 자기참조도 이미 확정된 결정과
정확히 일치, `type Dispatch = InitDispatch.Dispatch` 재익스포트만 실제
Luau 동작 확인 필요하다고 남겨둠.
**사용자 확인**: "그거 타입 익스포트 잘 됨. 구체화 반영해줘." → 실측
확인됐다는 뜻으로 받아 `module-lifecycle-plan.md`에 "New()의 내부 구성"
절 신설, `architecture.md` 13번에서 포인터 연결.
## 2. 정제 — Init을 `require`처럼 멱등하게
사용자 원문: *"Init 은 require 처럼 생각 가능한듯. Init 여러번은 한번만
작동하게 자신 모듈 최상단에 Relate 를 (함수 안 아님. 클로저 바깥) 놓고,
자신 모듈의 init 여부를 저장해. 그리고 한번만 작동하도록 두고, 자신 init
에선 필요한것들을 init 해줘. 디펜던시 느낌인거지. ... 맨 바깥 quad-base
진입점의 New 에선 모든 Init 을 그냥 실행해도 돼."*
이게 1절 문서화 때 "구현 단계에서 정할 것"으로 남겨뒀던 "서브시스템 간
`InitXxx` 호출 순서 의존성" 문제를 실제로 푼다 — 각 `InitXxx` 파일이 자기
톱레벨(클로저 밖)에 `local relate = Relate()`를 두고 `module`을 weak key로
"이미 이 인스턴스에 Init됐는지"를 기록하면, 의존하는 쪽이 자기 의존성을
직접 호출해도 중복/순서 걱정이 없어짐(멱등) — `require`가 파일 단위로 하는
캐싱을, `New()`가 여러 `module` 인스턴스를 만들 수 있다는 차이 때문에
인스턴스 단위로 다시 구현하는 것.
`relate-plan.md`의 확정 API(`Relate()`/`SetWeak`/`GetWeak`/`SetStrong`/
`GetStrong`, "각 모듈이 자기 톱레벨에 `Relate()` 하나 재사용" 관례)와
정확히 부합함을 확인 — 새 메커니즘이 아니라 기존 프리미티브의 정확한
용례. `module-lifecycle-plan.md`에 반영, 순환 의존 대비를 위해 플래그를
실제 작업 전에 먼저 세우는 규칙도 같이 명문화.
## 3. 핸드오버 감사 루프 (2라운드, `conventions.md`의 "핸드오버 준비하고
커밋해" 절차)
바뀐 파일: `base/architecture.md`, `base/module-lifecycle-plan.md`,
`base/dispatch-core-plan.md`, `README.md`, `ROADMAP.md`.
**라운드 1**(`quad-doc-auditor`, agentId `ad95c24230306ab0f`) — 확실 3건 +
의심 3건 + 사용자판단 1건:
- 확실: `architecture.md`의 "M0 스캐폴딩에 주는 함의" 불릿이 이미 InitXxx
절이 답한 질문을 여전히 미결정으로 서술 / `README.md` 색인에 새 절 요약
누락 / `module-lifecycle-plan.md`의 "지금은 없음"이 날짜 없는 시한부
주장.
- 의심: `_initializedBy` 상호 참조가 정의를 못 찾게 함(`bind-system-plan.md`
누락) / GC 인과 서술이 `relate-plan.md`의 "`inst`는 항상 weak" 규칙과
어긋나게 읽힘 / `dispatch-core-plan.md`가 새 절을 안 가리켜 상호참조 누락.
- 사용자판단(문서만으론 못 정함, 이번엔 직접 판단해 처리): InitXxx 구조가
M0/M1 중 어느 마일스톤부터인지 → `ROADMAP.md`의 "M0 — 스켈레톤 +
기술검증" 절 실제 내용(스파이크 전용, "진짜 마일스톤 아님")을 근거로
**M1**로 확정, `ROADMAP.md` M1 체크리스트에 항목 신설.
전부 반영(위 6곳 수정 + M1 체크박스 추가).
**라운드 2**(agentId `a1d60d10fc36621ed`) — 라운드 1 수정 자체가 새 stale
2건을 만든 걸 발견:
- `architecture.md`가 인용하던 "M0 스캐폴딩에 주는 함의"라는 절 제목
문구를 라운드 1 수정이 지워버려 절 인용 규약 사각지대(파일명 없는 같은
문서 내 인용이라 `doc-check.py`가 안 잡음) 발생 → 원래 제목 문구를 불릿
맨 앞에 복원하면서 내용만 정정.
- "위 'M0 — 스켈레톤 + 기술검증' 절 참고"가 실제로는 `ROADMAP.md` 안의
절인데 파일명이 빠져 같은 문서 안인 것처럼 읽힘 → `ROADMAP.md`의 명시.
- 추가로 "확실": 이 새 절 자체가 사용자 발언 3건을 인용하면서
`session/2026-08-19-*.md` 포인터가 없음(이 문서가 그 포인터).
- 의심: `relate-plan.md`의 "언제 Relate를 쓰는가" 체크리스트에 새 용례가
안 실림 → 다섯 번째 불릿 추가.
- 사용자판단: Init-완료 플래그 값(`true`)을 `SetWeak`/`SetStrong` 중 뭘로
적을지가 문서 간 안 맞음 → boolean은 GC 대상이 아니라 실질 차이는 없지만
`relate-plan.md`의 일반 규칙("다른 곳에서 안 붙잡는 값은 Strong") 기준
**`SetStrong`으로 통일**.
전부 반영. 라운드 3은 이 문서 작성 이후 진행 예정(아래 미해결 참고).
## 4. 세션 기록 공백 발견 (사용자가 감사 진행 중 별도로 제기)
사용자 질문: *"세션 기록들 요즘 왜 안 적어? ... 18일 자가 하나 뿐이네."*
확인 결과 — `git log`엔 2026-08-18에 커밋 10개(QA 1~2라운드, 감사 루프
재설계, GitHub co-author 정책, git 원격 정책 등), 2026-08-19에 커밋 1개
(QA 3라운드)가 있는데, `session/`엔 2026-08-18 파일이 `pre-implementation-qa-applied.md`
**하나뿐**이고 2026-08-19 파일은 이 문서 이전엔 **0개**였다. 즉 QA
2라운드/3라운드(`todos.md` 00번이 상세히 서술하는, RC-1/RC-3/RC-4를 실제로
찾아 해결한 세션들)와 tooling/research 커밋 다수가 session/ 원문 없이
커밋됨 — 실제 공백.
**한계**: 이 세션은 그 과거 대화의 실제 트랜스크립트에 접근할 수 없다(커밋
메시지와 현재 파일 상태만 볼 수 있음) — `session/`의 정의 자체가 "시행착오
포함 원문"이라, 원문을 못 본 채로 "raw log"를 지어내면 오히려 그 자체가
허위 기록이 된다. 그래서 이 문서는 **이번 세션분만** 원문으로 채웠고,
과거 공백(08-18 QA 2/3라운드 등)을 어떻게 처리할지는 사용자에게 별도로
물어야 함(요약만 `session-summary.md`에 사후 추가할지, 아예 공백으로
인정하고 넘어갈지 등 — 이 문서 자체가 그 판단의 근거 자료).

View file

@ -85,6 +85,10 @@ Luau 코드로 부딪혀본 적 없는 세 가지**를 던지는 코드로 검
소스 트리 구조 확정" 절 그대로)
- [ ] quad-base용 최소 mock 테스트 하네스(Vide `test/mock.luau` 선례, 순수
`luau` CLI, `architecture.md` "테스트 전략" 절 참고)
- [ ] 최상위 `New()`/`InitXxx(module)` 팩토리 체이닝 골격 — 각 서브시스템
Init이 `module`을 파라미터로 받아 뮤테이션, `Relate` 기반 인스턴스별
멱등 가드(`base/module-lifecycle-plan.md`의 "New()의 내부 구성" 절
그대로, 2026-08-19 확정)
- [ ] 이 시점부터 `.claude/qa-request/`/`.claude/archive/` 폴더 실사용 시작
## M2 — 디스패치 엔진