--[[ Source — the writable root value. Structurally satisfies `State` (all derived methods come from `State.luau`'s impl through `__index`) and is itself an `Epoch` (`Revision`), so it is registered in BOTH `SourceBrand` and `EpochBrand` (multi-tagging, `brand-plan.md`) — never in `StateBrand`: `isState = isSource or StateBrand` is composed in the predicate, not by double registration. Sources, as-is: - `.claude/base/source-state-plan.md` "State는 쓰기 대상이 아님 — 확정, Source는 독립 공개 프리미티브로 격상" (`Source(default)`), "`Source:Set(v)`는 동일값이어도 항상 갱신하고 emit한다" (`H-68`), "Source 값을 직접 mutate한 뒤 전파 — `:Emit()`" (root only), "따름정리 — `Store`/`Source`의 `T`는 Modifier가 될 수 없음". - `.claude/base/modifier-plan.md` 7번: `isModifier` guard at the constructor and at `:Set` (the constructor also covers `store:Of`). - `.claude/base/state-epoch-plan.md` §2: `Revision` bump is `bit32.bnot(-rev)`; `Set`/`Emit` push the Source itself as the emit payload ("출처" only — no value, no revision). Assembly (`H-174`): `InitSource(module)` — needs the per-instance State impl for its `__index` chain, and pulls it in itself via `module:RunInit(State.Init)` (idempotent), so `New()` order is irrelevant. ]] local Brand = require("./Brand") local State = require("./State") local QuadTypes = require("../roblox_packages/quad_types") export type Source = QuadTypes.Source local SourceBrand = Brand.SourceBrand local EpochBrand = Brand.EpochBrand local isModifier = Brand.isModifier local WEAK_KEY_MT = { __mode = "k" } local function Init(module: any) -- Pull our dependency ourselves, `require`-style (`module-lifecycle-plan.md` -- "순서 의존성은 각 `InitXxx`를 `require`처럼 멱등하게 만들어서 해소한다") — -- `RunInit` is idempotent, so `New()` need not order us after `State.Init`. module:RunInit(State.Init) local StateImpl = State.implFor(module) local emitDown = StateImpl._emitDown local Impl = setmetatable({}, { __index = StateImpl }) Impl.__index = Impl function Impl.Get(self: any): any return self._value end -- In-place mutation was done by the caller; only the signal is sent. -- Root Sources only — derived States have no such concept ("하드 경계"). function Impl.Emit(self: any): any self.Revision = bit32.bnot(-self.Revision) emitDown(self, self) -- payload = the source epoch itself return self end -- `H-68`: same value still bumps the revision and emits — dedup is the -- downstream's job (EpochMap judgement, gates), and `==` would silently -- drop in-place table mutations. function Impl.Set(self: any, value: any): any if isModifier(value) then error("Source: cannot Set a Modifier as a Source value", 2) end self._value = value -- `H-207`: one copy of the bump-and-emit tail. Direct call, not colon -- delegation — same type, same impl table, no subtype override to hit. return Impl.Emit(self) end function Impl._track(self: any, map: any) map:Sync(self) -- a Source IS an Epoch: it goes into the map directly end local function Source(default: any): any if isModifier(default) then error("Source: cannot hold a Modifier as a Source value", 2) end local self = setmetatable({ _value = default, Revision = 0, _subs = setmetatable({}, WEAK_KEY_MT), -- weak-key subscribers (downstream) }, Impl) SourceBrand:register(self) EpochBrand:register(self) return self end module.Source = Source end return Init