docs: 감사 5라운드 반영 — lifecycle-pattern 원 확정 문단에 '평평한 = 모듈 인스턴스 필드' 정정, 깨진 절 인용 둘, 브랜드 개수 리터럴 제거

Co-authored-by: qwreey <me@qwreey.moe>
This commit is contained in:
qwreey 2026-08-28 18:40:24 +09:00
parent 197ea881ed
commit c685dffaa0
Signed by: qwreey
GPG key ID: D28DB79297A214BD
3 changed files with 12 additions and 6 deletions

View file

@ -182,7 +182,13 @@ GC에 묶이지 않음 — v1이 여기저기서 `PropertyChangedSignal`에 연
`canBound`/`canExecute`/`unbindLifetime`는 `isState`/`isObserver`처럼
핸들러 작성자가 직접 호출하는 **1급 프리미티브 연산**이라
`LifetimeHandle.bind(...)`류로 감싸면 안 됨 — `LifetimeHandle.luau` 파일
안에 있어도 되지만 export는 평평한 함수:
안에 있어도 되지만 export는 평평한 함수. **[2026-08-28 정정, M2 첫 단위]
"평평한"은 모듈 인스턴스의 필드라는 뜻이다** — `quad.bindLifetime(inst, v)`처럼
`isState`와 같은 자리에 놓이는 것이고, 파일 `LifetimeHandle.luau` 자신이 이
넷을 return하는 게 아니다(파일은 `InitLifetimeHandle(module)`을 return하고, 그
팩토리가 `module.bindLifetime = …` 에러 스텁 4종을 심는다 — 백엔드가 같은 필드를
덮어쓴다, 아래 "`Connected` 체크는 rbvm 패턴을 그대로 베끼는 게 아니라" 절).
아래 시그니처의 이름은 그 필드 이름이다:
```lua
bindLifetime(inst: any, value: any): () -- inst가 필요한 건 이것 하나뿐
@ -738,7 +744,7 @@ quad-roblox 구현 단계에서 실측 확인 대상 — 문제가 되면 gcconn
첫 단위]** 다만 그 실 구현을 갖는 건 base가 아니라 **백엔드**다 — quad-base의
`LifetimeHandle.luau``InitLifetimeHandle(module)`이 에러 스텁 4종을 모듈
인스턴스에 설치하는 인터페이스뿐이고 `Relate`를 require하지 않는다(아래
"base가 인터페이스로만 내보내는 것" 절, `base/architecture.md` 소스 트리).
"`Connected` 체크는 rbvm 패턴을 그대로 베끼는 게 아니라" 절, `base/architecture.md` 소스 트리).
여기 한때 *"둘 다 base가 제공하는 범용 유틸로 확정"*이라 적혀 있었으나 그건
`Relate` 쪽에만 맞는 말이다.
@ -766,7 +772,7 @@ store-plan.md`가 예전에 "state 옵저빙 결과로 slot을 조작할 때 생
Destroy 시 모든 커넥션을 즉시 끊어주지만, 다른 엔진에서도 라이프사이클을
확인할 수 있어야 하므로 base는 "이 바인드가 아직 유효한가"를 묻는 람다/인터페이스만
정의하고, quad-roblox가 그 구현을 Roblox의 실제 `Connected`로 채워넣는다(구현
주입 방식은 아래 "base 유틸은 인터페이스, 구현은 백엔드 팩토리" 절 참고). 이게
주입 방식은 아래 "`Connected` 체크는 rbvm 패턴을 그대로 베끼는 게 아니라" 절 참고). 이게
필요한 이유: rbvm처럼 GC 트릭으로 라이프사이클을 연결하면 GC가 즉발이 아니라서
중간에 죽은 참조가 남아있을 수 있고, 그 시점에 store에 새 값이 들어오면 죽은
대상에 처리를 시도하다 터질 수 있음 — 그래서 처리 직전에 유효성을 확인.

View file

@ -130,7 +130,7 @@
| 파일 | 내용 | 옮겨 적는 절 |
|---|---|---|
| `Brand.luau` | `Brand()` 생성자 + **브랜드 인스턴스 열다섯을 이 잎 파일에**(`brand-plan.md` 스니펫이 한 자리에 선언하는 그대로 — `EpochBrand``Source`/`Ref`/`GateNode`가 공유하므로 타입 모듈마다 두면 순환 require) + M2 타입의 `is*`(`isEpoch`/`isSource`/`isState`/`isStore`/`isObserver`/`isEffect`/`isBlocker`/`isRef`/`isPreRef`/`isPostRef`/`isModifier`). `isTag`/`isAttribute*`/`isTween`/`isSlot`은 그 타입의 마일스톤에서 | `base/brand-plan.md` "구현 — 인스턴스 브랜드" / `isRef` 계층 절 |
| `Brand.luau` | `Brand()` 생성자 + **브랜드 인스턴스 전부를 이 잎 파일에**(개수는 그 파일이 소스)(`brand-plan.md` 스니펫이 한 자리에 선언하는 그대로 — `EpochBrand``Source`/`Ref`/`GateNode`가 공유하므로 타입 모듈마다 두면 순환 require) + M2 타입의 `is*`(`isEpoch`/`isSource`/`isState`/`isStore`/`isObserver`/`isEffect`/`isBlocker`/`isRef`/`isPreRef`/`isPostRef`/`isModifier`). `isTag`/`isAttribute*`/`isTween`/`isSlot`은 그 타입의 마일스톤에서 | `base/brand-plan.md` "구현 — 인스턴스 브랜드" / `isRef` 계층 절 |
| `Relate.luau` | **기존 파일**(M1). 코드 변경 없음 — `base/relate-plan.md` "API"/"실제 구조" 대조 + 테스트만 | `base/relate-plan.md` |
| `LifetimeHandle.luau` | 4종 타입 시그니처 + **미주입 에러 스텁**(영어, `error(…, 2)`) + 공유 술어 `isBoundAlive`는 백엔드 몫이라 여기 없음 | `base/lifecycle-pattern.md` "확정" 절, `module-lifecycle-plan.md` 주입 절 |
| `Ref.luau` | 최소형 — `.Value`/`.Revision`/`:Set`/`:Callback`/`:WeakCallback`/`:Uncallback`, `Callbacks`(강) + `WeakCallbacks`(weak-key), `:Set` 순서 값→리비전(`bit32.bnot(-rev)`)→스냅샷 순회·함수키 dedup·thread 소진, `EpochBrand`+`RefBrand` 등록 | `base/ref-plan.md` "`Ref`는 `Epoch`를 만족한다" 절 + `H-128` |

View file

@ -272,7 +272,7 @@ Luau 코드로 부딪혀본 적 없는 세 가지**를 던지는 코드로 검
> 여기 있는 것 전부 State-free이자 dispatch-free라 어느 쪽에도 안 걸립니다.
> 이 절이 끝나야 아래 반응형 본체를 짤 수 있습니다.
- [x] **[2026-08-28 완료 — `quad-base/src/Brand.luau` + `test/spec.brand.luau`, 브랜드 인스턴스 15개와 M2 `is*` 11개가 이 잎 파일에]** `Brand.luau`(**[2026-08-21 재작성]** 인스턴스 브랜드 — `Brand()`
- [x] **[2026-08-28 완료 — `quad-base/src/Brand.luau` + `test/spec.brand.luau`, 브랜드 인스턴스 전부와 M2 `is*`가 이 잎 파일에 — 개수는 그 파일이 소스]** `Brand.luau`(**[2026-08-21 재작성]** 인스턴스 브랜드 — `Brand()`
브랜드마다 weak-key 집합 하나를 들고 `:register(x)`/`:is(x)`,
**다중 태깅 허용**(`Source`가 `SourceBrand`이면서 동시에 `EpochBrand`).
옛 공유 레지스트리 + `Brand.get(x) -> tag`
@ -629,7 +629,7 @@ Luau 코드로 부딪혀본 적 없는 세 가지**를 던지는 코드로 검
호출하므로(`base/gate-plan.md` 9번이 소스 — Blocker 인스턴스를 lazy
조회하는 `getBlocker(ownerKey)`는 Blocker 메서드가 아니라 Dispatch
쪽 헬퍼다) **최소한 그 셋이 도는 형태까지는 M3(디스패치)가 요구**
- [ ] **[2026-08-28 부분 — 첫 단위분(`Relate`/`Void`/`Ref`/`is*` 11개/생명주기 4종)은 `quad-types` `Quad`에 추가됨, `Source`/`Store`/`Effect`/`Blocker`는 각 단위에서]** **[2026-08-24 `H-25` 파생, 2026-08-25 `H-80`으로 목록 확장]**
- [ ] **[2026-08-28 부분 — 첫 단위분(`Relate`/`Void`/`Ref`/`is*`/생명주기 4종)은 `quad-types` `Quad`에 추가됨, `Source`/`Store`/`Effect`/`Blocker`는 각 단위에서]** **[2026-08-24 `H-25` 파생, 2026-08-25 `H-80`으로 목록 확장]**
`quad-types``Quad`**이 마일스톤이 얹는 탑레벨 값 전부** 추가 —
`Source` / `Store` / `Effect` / `Blocker` / `Relate` / **`Void`**(단일 no-op 함수 export — no-op 클로저를 돌려주는 자리는 새 클로저 대신 이것, **[2026-08-28 `H-162`]**) / **`Ref`**(최소형,
2026-08-27 `H-128`) /