diff --git a/.claude/base/debounce-throttle-plan.md b/.claude/base/debounce-throttle-plan.md index 89a2414..e364df2 100644 --- a/.claude/base/debounce-throttle-plan.md +++ b/.claude/base/debounce-throttle-plan.md @@ -201,7 +201,7 @@ leading/trailing/통과 후 창 재개방은 **완전히 동일**. 그래서 공 생겼으니 이름 붙여 꺼내는 것뿐. **[2026-08-21 실현 — 이 권고가 확정됐다]** 그 노드는 `state:Gate(setup)`가 -만드는 **`GateNode`**이고 **M2**에서 구현된다(`base/gate-plan.md` — +만드는 **`GateNode`**이고 **M2**에서 구현됐다(**[2026-08-29]** 단위 4, `quad-base/src/State.luau`의 `:Gate`; `base/gate-plan.md` — **[2026-08-24]** 2026-08-22엔 디스패치 쪽이었다가 마일스톤 순서 교체로 반응형 코어로 돌아왔다). 다만 "내부 공용"은 아니게 됐다 — **공개 표면**이다. `Debounce`/`Throttle` 쪽 @@ -1244,7 +1244,7 @@ additional-primitives-plan.md`가 원래 "안 만들어도 된다"고 판단했 **M8**(`Ref`)에서 확정되는 것들이라 그 이후 언제든 얹을 수 있다. 2026-08-22엔 `Blocker.luau`가 디스패치 쪽으로 앞당겨져 있어서 "게이트/`Blocker`는 다른 마일스톤"이라고 적었으나, 2026-08-24 마일스톤 순서 교체로 되돌아왔다. 그 -"게이트 노드를 공용으로 빼는" 작업도 같은 M2에서 State 코어와 함께 한다 — +"게이트 노드를 공용으로 빼는" 작업도 같은 M2에서 State 코어와 함께 했다(**[2026-08-29]** 완료) — 사용자 결정 "게이팅 먼저"(`Dispatch.drive`의 배치 등록이 이미 그 게이팅에 의존하므로)는 그대로 지켜진다. 1절에서 봤듯 같은 노드를 공유하므로 따로 하면 같은 걸 두 번 설계하게 되는 것도 그대로다. 표면/이름은 `base/gate-plan.md`가 소스(이 문서의 1절이 그 일반화를 처음 diff --git a/.claude/base/gate-plan.md b/.claude/base/gate-plan.md index a71376d..ad5ebed 100644 --- a/.claude/base/gate-plan.md +++ b/.claude/base/gate-plan.md @@ -337,7 +337,8 @@ function GateNode:_receive(from) -- (2) 통과한 것만 흡수 집합에 합친다. `from`이 집합이면 unfold해서 합친다 -- — 게이트-게이트 중첩에서 중복이 저절로 접힌다(집합이라서). - if isEpochSet(from) then + if isEpochSet(from) then -- (의사 술어 — 실제 코드는 `isEpoch(from)`의 반대 분기, + -- `state-epoch-plan.md` §5 "런타임 분기는 `isEpoch`로"; 단위 4) for epoch in from do self._withheld[epoch] = true end else self._withheld[from] = true diff --git a/.claude/base/source-state-plan.md b/.claude/base/source-state-plan.md index 33f3ac3..e17e204 100644 --- a/.claude/base/source-state-plan.md +++ b/.claude/base/source-state-plan.md @@ -1121,9 +1121,12 @@ then return factory(self) else return factory:__apply(self) end end` — 즉 - **함수와 콜러블의 유니온으로 여는 안은 기각** — 필드로 받으면 유니온도 캐스트도 필요 없다. 필드 이름은 **`__apply`**(**[2026-08-28 10라운드 `H-158` 사용자 확정]** *"키는 __apply 로 하기로 했던거로 기억중임"* — - `base/blocker-plan.md` 배너), 시그니처는 **[2026-08-28 M2 단위 2 확정]** 메소드형 - `__apply: (self: any, state: State) -> U` — `quad-types/src/init.luau`의 `State.Apply` - 파라미터 타입과 `State.luau`의 `(factory :: any):__apply(self)` 호출이 소스. + `base/blocker-plan.md` 배너), 시그니처는 **[2026-08-28 M2 단위 2 확정, 2026-08-29 단위 4 + `H-179` 정정]** 메소드형 `__apply: (self: any, state: any) -> any` — 호출은 `State.luau`의 + `(factory :: any):__apply(self)`. `State.Apply`의 파라미터 타입은 **교집합 오버로드** + (함수 팩토리는 제네릭 `U`, 객체 팩토리는 `any` 반환 → 호출부가 결과를 명시)이고 그 + 정확한 표기와 근거는 `base/typing-limits.md` §1②가 소스 — 한때 여기 `(self: any, state: + State) -> U`라 적었는데 그 유니온 표기는 `Blocker`처럼 필드가 더 있는 객체를 못 받는다. - **구현 비용 거의 0**: Modifier와 달리 State/Source는 제네릭 `__index`로 필드 setter를 즉석 합성하는 메커니즘이 없어서(고정된 메소드 표면만 존재), Modifier의 `Apply`처럼 "필드 이름으로 예약해야 하는" 충돌 diff --git a/.claude/todos.md b/.claude/todos.md index 3f1f60b..a94f79e 100644 --- a/.claude/todos.md +++ b/.claude/todos.md @@ -422,7 +422,7 @@ 실제로 quad-base에 새 코어 메커니즘을 추가하지 않는 **순수 슈가**로 확인돼(같은 절), 위 항목들과 우선순위는 다시 같아짐 — M0/M2를 막지 않고, **그 게이티드 노드는 [2026-08-21] `state:Gate`로 확정돼 M2에서 - 만들어진다**(`base/gate-plan.md`) — `Debounce`/`Throttle`은 그 위의 + 만들어졌다**(`base/gate-plan.md`, **[2026-08-29]** 단위 4로 완료) — `Debounce`/`Throttle`은 그 위의 정책으로 얹으면 되고, 같은 설계를 두 번 할 일은 없어졌다. 주입 op 2개(`setTimeout`/`clearTimeout`)가 백엔드 팩토리 표면에 추가될 예정이라는 것도 M1 설계 시 인지. 남은 열린 질문 없음(구