quad/.claude/session/2026-08-19-01-new-initxxx-composition-relate-guard.md
qwreey-agent-selene 4be9373124
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>
2026-08-19 01:16:26 +09:00

115 lines
7.7 KiB
Markdown

# 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`에 사후 추가할지, 아예 공백으로
인정하고 넘어갈지 등 — 이 문서 자체가 그 판단의 근거 자료).