fix: "Gate 재진입 계약"은 잘못 옮긴 서술 — 열린 항목에서 제거, emit=flush로 정정
사용자 반문으로 에이전트 서술 오류 둘을 정정. 결론은 안 바뀌었고 근거와 열린 항목 목록만 정리됐다. 1) gate-plan.md 6번의 "onUpstreamEmit 안에서 같은 게이트의 emit()을 재귀적으로 부르는 경우"는 blocker-plan.md의 재진입 절을 잘못 옮긴 것이다. 그 절은 같은 Blocker 인스턴스를 중첩해 On()/Off() 하는 것을 말하고 정책의 emit() 호출과 무관하며, 정책이 flush를 부르는 건 재귀가 아니라 평범한 통과 경로다. 계약 셋으로 정리: 끝나지 않는 되먹임은 UB(dispatch-core-plan.md의 2026-08-04 확정 원칙), 유한한 재진입은 지원(debounce-throttle-plan.md의 onWindowEnd 주석이 이미 대비), 같은 인스턴스 중첩 금지는 Blocker 규칙 그대로. 그래서 question.md의 사용자 판단 항목에서 재진입을 뺐다. 2) 정책이 받는 emit은 "이 값을 내보내라"가 아니라 "쌓인 걸 지금 흘려보내라" (flush)이고, debounce-throttle-plan.md가 이미 gate:passThrough()로 부르던 것이다. 배치를 떼어내는 것도 그 핸들 안에서 일어나므로, 직전 커밋이 "재진입 위험"이라 부른 것은 에이전트가 적은 "전파 후 table.clear" 의사코드의 결함이지 모델의 구멍이 아니었다. 수정(flush 진입 시 스왑)은 그대로 유효하고 서술만 그렇게 고쳤다. Gate에 남은 사용자 판단은 빈 배치 emit 하나뿐. 처리 전량은 U절. doc-check.py ERROR 0. Co-authored-by: qwreey <me@qwreey.moe> Claude-Session: https://claude.ai/code/session_01TiW21rnti9SbLgF6twtn6D
This commit is contained in:
parent
3b46d5ef68
commit
46287ee393
4 changed files with 115 additions and 21 deletions
|
|
@ -5,7 +5,7 @@
|
||||||
없이 `state:Gate( (emit) -> ()->() )` 처럼 선언되고 마치 Compute 처럼
|
없이 `state:Gate( (emit) -> ()->() )` 처럼 선언되고 마치 Compute 처럼
|
||||||
GateNode(ComputeNode 처럼) 생성된다 그리고 Blocker 는 해당 내부 배선을 따른다
|
GateNode(ComputeNode 처럼) 생성된다 그리고 Blocker 는 해당 내부 배선을 따른다
|
||||||
← 동의합니다 해당 방법대로 확정하면 됩니다."* 구현은 **M2**("게이팅 먼저"
|
← 동의합니다 해당 방법대로 확정하면 됩니다."* 구현은 **M2**("게이팅 먼저"
|
||||||
결정, `ROADMAP.md`). **남은 것은 아래 "아직 안 정한 것"의 생명주기·재진입 계약과 M2
|
결정, `ROADMAP.md`). **남은 것은 아래 "아직 안 정한 것"의 생명주기·빈 배치 emit·M2
|
||||||
범위뿐** — `/code-review high`가 잡았던 4번(유보된 emit이 싣는 출처)은 같은
|
범위뿐** — `/code-review high`가 잡았던 4번(유보된 emit이 싣는 출처)은 같은
|
||||||
날 `emit(self)` + 흡수 집합으로 닫혔고, **`setup` 시그니처는 안 바뀌었다.**
|
날 `emit(self)` + 흡수 집합으로 닫혔고, **`setup` 시그니처는 안 바뀌었다.**
|
||||||
|
|
||||||
|
|
@ -141,20 +141,28 @@ end)
|
||||||
번에 정책이 두 번 돌아, `Throttle`의 leading 통과 직후 두 번째 emit이
|
번에 정책이 두 번 돌아, `Throttle`의 leading 통과 직후 두 번째 emit이
|
||||||
`pending`을 세워 **이미 전달한 변경에 대한 유령 trailing emit**이
|
`pending`을 세워 **이미 전달한 변경에 대한 유령 trailing emit**이
|
||||||
나간다.
|
나간다.
|
||||||
- **⭐⭐ [2026-08-21 `/code-review high` — 재진입 안전] 전파 페이로드는
|
- **⭐⭐ 정책이 받는 `emit`은 "이 값을 내보내라"가 아니라 "쌓인 걸 지금
|
||||||
`withheld` 자체가 아니라 그 자리에서 떼어낸 스냅샷이다.** "전파가 반환된
|
흘려보내라"(flush)** — 페이로드를 정책이 정하지 않는다. 그래서 배치를
|
||||||
뒤에 `table.clear`"는 **재진입이 없을 때만** 성립한다 — `G`가 두 갈래로
|
떼어내는 것도 **그 핸들 안**에서 일어난다.
|
||||||
전파하다 첫 갈래의 Observer가 `B:Set()`을 부르면(quad는 Observer 안
|
`base/debounce-throttle-plan.md`가 이미 같은 것을 `gate:passThrough()`
|
||||||
`Set`을 허용) 그 파동이 `G`에 다시 도달해 중첩 전파가 끝나며 `clear`가
|
("invalid 세팅 + 아래로 1회 전파")로 부르고 있다.
|
||||||
돌고, **바깥 전파의 남은 갈래는 빈 집합을 받아** 원래 변경을 영영 못
|
- **전파 페이로드는 `withheld` 자체가 아니라 flush 진입 시점에 떼어낸
|
||||||
받는다. 그래서 전파 직전에 **스왑**한다:
|
스냅샷이다.** **[2026-08-21 정정]** 여기 한때 "전파가 반환된 뒤에
|
||||||
|
`table.clear`"라고 적었는데 그게 틀렸다 — 전파가 스택에 남아 있는 동안
|
||||||
|
제어가 같은 게이트로 되돌아오면(하류 Observer가 상류를 `:Set()`,
|
||||||
|
`debounce-throttle-plan.md`의 `onWindowEnd` 주석이 이미 대비하는 경우)
|
||||||
|
중첩 flush의 `clear`가 돌아 **바깥 전파의 남은 갈래가 빈 집합**을 받는다.
|
||||||
|
**모델이 아니라 그 의사코드가 문제였다** — `emit()`이 flush인 이상 들어가는
|
||||||
|
순간 떼어내는 게 원래 모양이고, 그러면 그 경로 자체가 없다:
|
||||||
```
|
```
|
||||||
local batch = self._withheld
|
local batch = self._withheld
|
||||||
self._withheld = {} -- 새 테이블. clear가 아니다
|
self._withheld = {} -- 새 테이블. clear가 아니다
|
||||||
emitDownstream(self, batch) -- 떼어낸 batch를 페이로드로 넘긴다
|
emitDownstream(self, batch) -- 떼어낸 batch를 페이로드로 넘긴다
|
||||||
```
|
```
|
||||||
하류가 순회하는 것은 `gate._withheld`가 아니라 **받은 `batch`** 다.
|
하류가 순회하는 것은 `gate._withheld`가 아니라 **받은 `batch`** 다.
|
||||||
재진입이 나도 그 파동은 새 테이블에 쌓이므로 바깥 전파와 안 섞인다.
|
중첩 파동은 새 테이블에 쌓이므로 바깥 전파와 안 섞인다. 같은 에포크가
|
||||||
|
중첩으로 두 번 도달하는 경우는 애초에 문제가 아니다 — 하류 count가 이미
|
||||||
|
최신이라 규칙 3으로 삼켜진다.
|
||||||
- **그래서 게이트는 언제나 자기(와 그 배치)를 출처로 낸다** — 그냥
|
- **그래서 게이트는 언제나 자기(와 그 배치)를 출처로 낸다** — 그냥
|
||||||
통과시킬 때도 상류 출처를 그대로 넘기지 않는다. 사용자: *"후행 노드들은 한개가 지연된거로
|
통과시킬 때도 상류 출처를 그대로 넘기지 않는다. 사용자: *"후행 노드들은 한개가 지연된거로
|
||||||
생각이 될 수 있겠지만, 사실 여기서 지연과 비지연을 구분할 이유가
|
생각이 될 수 있겠지만, 사실 여기서 지연과 비지연을 구분할 이유가
|
||||||
|
|
@ -166,9 +174,9 @@ end)
|
||||||
- **⭐ [2026-08-21 신설] 하류가 또 다른 게이트면 — 받은 집합을 풀어
|
- **⭐ [2026-08-21 신설] 하류가 또 다른 게이트면 — 받은 집합을 풀어
|
||||||
자기 `withheld`에 합친다.** 게이트가 게이트 emit을 받는 경우가 정의돼
|
자기 `withheld`에 합친다.** 게이트가 게이트 emit을 받는 경우가 정의돼
|
||||||
있지 않던 구멍이었다(사용자 발견). **출처를 그대로 넘기면 안 된다** —
|
있지 않던 구멍이었다(사용자 발견). **출처를 그대로 넘기면 안 된다** —
|
||||||
상류 게이트는 자기 전파가 끝나자마자 `table.clear` 하므로, 하류 게이트가
|
상류 게이트가 넘기는 배치는 **그 전파에만 쓰이는 일회성 스냅샷**이라,
|
||||||
유보했다가 나중에 풀면 그때는 **빈 집합**을 내보내게 되어 변경이 통째로
|
하류 게이트가 그 참조만 들고 유보했다가 나중에 풀면 이미 지나간 배치를
|
||||||
증발한다. 그래서 수신 시점에 **풀어서 옮겨 담아야** 한다:
|
내보내게 된다. 그래서 수신 시점에 **풀어서 옮겨 담아야** 한다:
|
||||||
```
|
```
|
||||||
-- 출처가 Source면 그 하나를, 게이트 배치면 그 배치 전부를 편다
|
-- 출처가 Source면 그 하나를, 게이트 배치면 그 배치 전부를 편다
|
||||||
for source in unfold(origin) do
|
for source in unfold(origin) do
|
||||||
|
|
@ -201,9 +209,21 @@ end)
|
||||||
지금 설계대로면 다운스트림이 다 죽으면 GC(팩토리는 weak 추적,
|
지금 설계대로면 다운스트림이 다 죽으면 GC(팩토리는 weak 추적,
|
||||||
`debounce-throttle-plan.md` 5-4). `Gate` 자체에 `Flush`/`Cancel` 같은 표면을
|
`debounce-throttle-plan.md` 5-4). `Gate` 자체에 `Flush`/`Cancel` 같은 표면을
|
||||||
둘지, 그건 정책(Debounce)만의 것으로 둘지.
|
둘지, 그건 정책(Debounce)만의 것으로 둘지.
|
||||||
6. **재진입.** `Blocker`의 "재진입 의도적 미지원"(`blocker-plan.md`)이 `Gate`
|
6. **[2026-08-21 정리 — 열린 항목 아님] 재진입.** 여기 한때 *"`onUpstreamEmit`
|
||||||
레벨의 계약으로 올라가는지 — 즉 `onUpstreamEmit` 안에서 같은 게이트의
|
안에서 같은 게이트의 `emit()`을 재귀적으로 부르는 경우"*라고 적혀 있었는데
|
||||||
`emit()`을 재귀적으로 부르는 경우.
|
**잘못 옮긴 서술이었다**(사용자 지적). `blocker-plan.md`의 "재진입(네스팅)"
|
||||||
|
절이 말하는 건 **같은 `Blocker` 인스턴스를 중첩해 `On()`/`Off()` 하는 것**
|
||||||
|
이고, 정책이 `emit()`을 호출하는 것과는 무관하다 — 애초에 정책이 flush를
|
||||||
|
부르는 건 재귀가 아니라 **평범한 통과 경로**다. 지금 계약은 셋으로 정리된다:
|
||||||
|
- **끝나지 않는 되먹임은 UB.** `base/dispatch-core-plan.md`의 2026-08-04
|
||||||
|
확정 원칙 그대로 — *"일반적인 재진입/무한루프는 방어 안 함,
|
||||||
|
provider/사용자 코드 버그로 간주"*. 게이트가 따로 가드를 두지 않는다.
|
||||||
|
- **유한한 재진입은 지원한다.** 전파 도중 소비자가 동기적으로 상류를
|
||||||
|
`:Set()`하는 건 이미 대비된 경우이고(`debounce-throttle-plan.md`의
|
||||||
|
`onWindowEnd` 주석), 게이트 쪽에서 그걸 안전하게 만드는 장치가 위 4번의
|
||||||
|
**flush 진입 시 스왑**이다.
|
||||||
|
- **같은 게이트/`Blocker` 인스턴스를 중첩해 쓰지 않는다** — `Blocker`의
|
||||||
|
기존 규칙이 그대로 적용된다(겹치는 배치는 새 인스턴스).
|
||||||
7. **⭐ 소비자가 하나 더 있다 — `Effect(fn, ...deps)`의 최초 1회 억제.**
|
7. **⭐ 소비자가 하나 더 있다 — `Effect(fn, ...deps)`의 최초 1회 억제.**
|
||||||
2026-08-21 5라운드 `C-6`에서 확정된 다중 의존성 `Effect`는, 의존성마다 구독을
|
2026-08-21 5라운드 `C-6`에서 확정된 다중 의존성 `Effect`는, 의존성마다 구독을
|
||||||
걸면 각 구독의 "등록 즉시 1회 실행"이 N번 발화하므로 **설치 구간 동안 발화를
|
걸면 각 구독의 "등록 즉시 1회 실행"이 N번 발화하므로 **설치 구간 동안 발화를
|
||||||
|
|
|
||||||
|
|
@ -1168,7 +1168,7 @@ end
|
||||||
## T-2. 수정한 나머지 3건
|
## T-2. 수정한 나머지 3건
|
||||||
|
|
||||||
- **Medium**: "무조건 `withheld`에 넣는다"가 "수신 규칙 1~3을 건너뛴다"로 읽히던 것 → **"정책의 통과/유보와 무관하게"라는 뜻**이고 규칙 3으로 삼켜진 emit은 정책도 안 돌고 집합에도 안 들어간다고 명시. 안 그러면 다이아몬드에서 `Throttle` 정책이 두 번 돌아 **유령 trailing emit**이 나간다.
|
- **Medium**: "무조건 `withheld`에 넣는다"가 "수신 규칙 1~3을 건너뛴다"로 읽히던 것 → **"정책의 통과/유보와 무관하게"라는 뜻**이고 규칙 3으로 삼켜진 emit은 정책도 안 돌고 집합에도 안 들어간다고 명시. 안 그러면 다이아몬드에서 `Throttle` 정책이 두 번 돌아 **유령 trailing emit**이 나간다.
|
||||||
- **Medium**: `luau-test/STATUS.md`의 "런타임 12개"가 이미 나간 `04`/`10`/`19`를 포함한 옛 총계에서 이어져 온 수라 실제(9건)와 안 맞던 것.
|
- **Medium**: `luau-test/STATUS.md`에 있던 `런타임 12개`라는 수가 이미 나간 `04`/`10`/`19`를 포함한 옛 총계에서 이어져 온 수라 실제(9건)와 안 맞던 것.
|
||||||
- **Medium**: 이 문서 D절 색인 표가 삭제된 `research/` 두 문서를 **현재형**으로 서술하던 것 → 당시 상태임을 못박고 승격 사실을 배너로.
|
- **Medium**: 이 문서 D절 색인 표가 삭제된 `research/` 두 문서를 **현재형**으로 서술하던 것 → 당시 상태임을 못박고 승격 사실을 배너로.
|
||||||
|
|
||||||
## T-3. 열린 항목으로 승격한 2건
|
## T-3. 열린 항목으로 승격한 2건
|
||||||
|
|
@ -1184,3 +1184,50 @@ end
|
||||||
|
|
||||||
`question.md`가 "남은 것은 사용자 판단이 아니다"라고 닫아뒀던 것도 이 둘 때문에
|
`question.md`가 "남은 것은 사용자 판단이 아니다"라고 닫아뒀던 것도 이 둘 때문에
|
||||||
정정했다(리뷰 Low-7이 지적한 `question.md`↔`gate-plan.md` 불일치).
|
정정했다(리뷰 Low-7이 지적한 `question.md`↔`gate-plan.md` 불일치).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# U절 — T절 두 건에 대한 사용자 반문 (2026-08-21)
|
||||||
|
|
||||||
|
사용자가 T절의 `/code-review` 발견 둘을 되짚어 **에이전트 서술의 오류 둘**을
|
||||||
|
잡아냈다. 결론이 바뀐 건 없지만 근거와 열린 항목 목록이 정리됐다.
|
||||||
|
|
||||||
|
## U-1. "재진입 계약"은 열린 항목이 아니었다 — 잘못 옮긴 서술
|
||||||
|
|
||||||
|
`gate-plan.md` 6번이 `blocker-plan.md`의 "재진입" 절을 인용하며
|
||||||
|
*"`onUpstreamEmit` 안에서 같은 게이트의 `emit()`을 재귀적으로 부르는 경우"*
|
||||||
|
라고 적어뒀는데, **그 절이 말하는 건 같은 `Blocker` 인스턴스를 중첩해
|
||||||
|
`On()`/`Off()` 하는 것**이고 정책의 `emit()` 호출과는 무관하다. 애초에 정책이
|
||||||
|
flush를 부르는 건 재귀가 아니라 **평범한 통과 경로**다(사용자: *"정책 안에서
|
||||||
|
emit 을 재귀호출 한다는게 무슨 말인가요?"*).
|
||||||
|
|
||||||
|
정리된 계약 셋(열린 항목 아님) — `gate-plan.md` 6번:
|
||||||
|
- **끝나지 않는 되먹임은 UB.** 사용자 지적(*"옵져버가 Set을 불러 자신이
|
||||||
|
무한반복 되게 만드는거 UB아닌가요?"*)이 맞고, 근거는 이미 있다 —
|
||||||
|
`dispatch-core-plan.md`의 2026-08-04 확정 원칙 *"일반적인 재진입/무한루프는
|
||||||
|
방어 안 함, provider/사용자 코드 버그로 간주"*.
|
||||||
|
- **유한한 재진입은 지원한다.** `debounce-throttle-plan.md`의 `onWindowEnd`
|
||||||
|
주석이 이미 *"전파 도중 소비자가 동기적으로 상류를 `:Set()`해서 재진입해도"*
|
||||||
|
를 대비해 상태 정리를 전파보다 먼저 둔다.
|
||||||
|
- **같은 인스턴스 중첩 금지**는 `Blocker` 규칙 그대로.
|
||||||
|
|
||||||
|
## U-2. `emit`은 flush다 — H-1은 모델이 아니라 의사코드의 결함이었다
|
||||||
|
|
||||||
|
사용자 지적: *"Gate 정책이 받는 emit 은 정확히는 triggerEmit 같은 것으로,
|
||||||
|
쌓여 있어서, 실제로는 `emitDownstream(self, batch)` 가 자동으로 된 다음
|
||||||
|
내려가지 않아요?"* — 맞다. 정책은 페이로드를 정하지 않고 **"쌓인 걸 지금
|
||||||
|
흘려보내라"**만 부른다(`debounce-throttle-plan.md`가 이미 `gate:passThrough()`
|
||||||
|
로 부르던 것). 그러면 배치를 떼어내는 것도 **그 핸들 안**에서 일어나므로,
|
||||||
|
T절이 "재진입 위험"이라 부른 것은 **에이전트가 적은 "전파 후 `table.clear`"
|
||||||
|
의사코드의 결함**이지 사용자 모델의 구멍이 아니었다. 수정 자체(flush 진입 시
|
||||||
|
스왑)는 그대로 유효하고, 서술만 그렇게 고쳤다.
|
||||||
|
|
||||||
|
부수로 사용자가 짚은 *"이미 하류들은 count 가 최신이라 emit 이 먹어질텐데요"*
|
||||||
|
도 맞다 — 같은 에포크가 중첩으로 두 번 도달하는 건 규칙 3으로 삼켜진다.
|
||||||
|
문제는 중복 통지가 아니라 **바깥 전파가 빈 배치를 보게 되는 것**이었다.
|
||||||
|
|
||||||
|
## U-3. 그래서 `Gate`에 남은 사용자 판단은 하나뿐
|
||||||
|
|
||||||
|
**빈 배치 emit**(소스 없는 flush)을 무조건 통지로 볼 것인가 —
|
||||||
|
`gate-plan.md` 8번, `question.md` 3번. 나머지(생명주기, M2 범위)는 구현 시
|
||||||
|
정하면 된다.
|
||||||
|
|
|
||||||
|
|
@ -209,8 +209,8 @@
|
||||||
할지, 아니면 실측 전엔 그냥 둘지 판단 필요.
|
할지, 아니면 실측 전엔 그냥 둘지 판단 필요.
|
||||||
- **[해소, 2026-08-21 같은 날] 게이트가 유보했다 내보내는 emit이 싣는 출처 —
|
- **[해소, 2026-08-21 같은 날] 게이트가 유보했다 내보내는 emit이 싣는 출처 —
|
||||||
`emit(self)` + 흡수 집합.** `GateNode`가 흡수한 소스를 `withheld` 집합에
|
`emit(self)` + 흡수 집합.** `GateNode`가 흡수한 소스를 `withheld` 집합에
|
||||||
들고 있다가, 풀 때 **자기를 출처로** 하류에 emit 하고 (동기 전파라) 반환 뒤
|
들고 있다가, 풀 때(=flush) **집합을 그 자리에서 떼어내 새 테이블로 스왑하고**
|
||||||
`table.clear`한다. 하류는 출처가 게이트면 그 집합의 소스들에 평소 규칙을
|
자기를 출처로 그 배치를 하류에 넘긴다. 하류는 출처가 게이트면 그 집합의 소스들에 평소 규칙을
|
||||||
적용한다. **`setup` 시그니처는 안 바뀐다** — 집합을 채우는 건 정책이 아니라
|
적용한다. **`setup` 시그니처는 안 바뀐다** — 집합을 채우는 건 정책이 아니라
|
||||||
노드이기 때문. `base/gate-plan.md`의 4번, `base/state-epoch-plan.md` §2.
|
노드이기 때문. `base/gate-plan.md`의 4번, `base/state-epoch-plan.md` §2.
|
||||||
- **[해소, 2026-08-21 같은 날] State 에포크 — 새 노드의 두 맵 초기값과
|
- **[해소, 2026-08-21 같은 날] State 에포크 — 새 노드의 두 맵 초기값과
|
||||||
|
|
@ -220,14 +220,26 @@
|
||||||
(비워두면 순회가 훑을 목록 자체가 없어 "유효하다"로 오판한다 — *"'내가 뭘
|
(비워두면 순회가 훑을 목록 자체가 없어 "유효하다"로 오판한다 — *"'내가 뭘
|
||||||
추적하고 있나' 가 필요하죠"*). 그래서 `:With` 병합 규칙은 **필요 없어졌다.**
|
추적하고 있나' 가 필요하죠"*). 그래서 `:With` 병합 규칙은 **필요 없어졌다.**
|
||||||
재계산 시 갱신 범위(전부 갱신)도 확정. `base/state-epoch-plan.md`의 §2·§5 7번.
|
재계산 시 갱신 범위(전부 갱신)도 확정. `base/state-epoch-plan.md`의 §2·§5 7번.
|
||||||
|
- **⭐ [신설, 2026-08-21 두 번째 `/code-review high`] `Gate` — 소스 없는
|
||||||
|
emit(빈 배치)을 어떻게 다루나. M2 착수 전.** 정책이 상류 신호와 무관하게
|
||||||
|
`emit()`(=flush)을 부르면 **빈 배치**가 나가 하류가 조용히 삼킨다.
|
||||||
|
`Effect(fn, ...deps)`의 설치 구간 억제가 정확히 이 모양(어떤 소스 에포크와도
|
||||||
|
무관한 발화를 마지막에 한 번)이라 그 용례가 직접 걸린다. 권고는 **"빈 배치 =
|
||||||
|
무조건 통지"**(명령형 통지라 접을 근거가 없음). 상세는 `base/gate-plan.md`의
|
||||||
|
8번.
|
||||||
|
- **같이 제기됐던 "재진입 계약"은 열린 항목이 아니었다**(사용자 지적으로
|
||||||
|
2026-08-21 정리) — `blocker-plan.md`의 재진입은 **같은 인스턴스 중첩**을
|
||||||
|
말하는 것이지 정책의 `emit()` 호출과 무관하고, 끝나지 않는 되먹임은
|
||||||
|
2026-08-04 확정 원칙대로 **UB**이며, 유한한 재진입은 flush 진입 시 스왑으로
|
||||||
|
이미 안전하다. `gate-plan.md`의 6번.
|
||||||
- **[해소, 2026-08-21] 공용 게이트 노드의 이름과 표면 — `state:Gate(setup)`
|
- **[해소, 2026-08-21] 공용 게이트 노드의 이름과 표면 — `state:Gate(setup)`
|
||||||
메소드 + `GateNode`로 확정.** 탑레벨 프리미티브는 안 만들고, `Blocker`는
|
메소드 + `GateNode`로 확정.** 탑레벨 프리미티브는 안 만들고, `Blocker`는
|
||||||
`state:Block(blocker)` 안에서 그 배선을 쓴다(사용자: *"Gate 는 따로
|
`state:Block(blocker)` 안에서 그 배선을 쓴다(사용자: *"Gate 는 따로
|
||||||
프리미티브 없이 state:Gate( (emit) -> ()->() ) 처럼 선언되고 마치 Compute
|
프리미티브 없이 state:Gate( (emit) -> ()->() ) 처럼 선언되고 마치 Compute
|
||||||
처럼 GateNode(ComputeNode 처럼) 생성된다"*). `Get()`엔 영향 없음(통지만
|
처럼 GateNode(ComputeNode 처럼) 생성된다"*). `Get()`엔 영향 없음(통지만
|
||||||
막음)까지 확정. **[2026-08-21 정정]** 여기 "남은 것은 사용자 판단이 아니라
|
막음)까지 확정. **[2026-08-21 정정]** 여기 "남은 것은 사용자 판단이 아니라
|
||||||
구현 시 정할 것들"이라 적었으나, 두 번째 `/code-review high`가 **재진입
|
구현 시 정할 것들"이라 적었으나, 두 번째 `/code-review high`가 **빈 배치
|
||||||
계약과 빈 배치 emit을 사용자 판단 항목으로 되돌렸다**(바로 위 항목). 구현 시
|
emit을 사용자 판단 항목으로 되돌렸다**(바로 위 항목). 구현 시
|
||||||
정하면 되는 건 생명주기와 M2 범위뿐 — `base/gate-plan.md`가
|
정하면 되는 건 생명주기와 M2 범위뿐 — `base/gate-plan.md`가
|
||||||
소스. 아래는 열려 있던 시점의 서술: 위 항목의 결정("게이팅 먼저")에 따라 base에 만들 것이
|
소스. 아래는 열려 있던 시점의 서술: 위 항목의 결정("게이팅 먼저")에 따라 base에 만들 것이
|
||||||
`Blocker`가 아니라 **상류 emit을 가로채 정책이 통과 여부를 정하는 공용 게이트
|
`Blocker`가 아니라 **상류 emit을 가로채 정책이 통과 여부를 정하는 공용 게이트
|
||||||
|
|
@ -236,7 +248,7 @@
|
||||||
**공개 API로 낸다**(사용자: *"이 API가 비공개일 이유는 없어보인다"*). 남은 것 —
|
**공개 API로 낸다**(사용자: *"이 API가 비공개일 이유는 없어보인다"*). 남은 것 —
|
||||||
(a) **이름**(사용자: *"프리미티브 명을 Gater? 뭔가 이상하게 들어간다는게 약간의
|
(a) **이름**(사용자: *"프리미티브 명을 Gater? 뭔가 이상하게 들어간다는게 약간의
|
||||||
문제"*, 에이전트 권고는 `Gate` 그대로 — `gate`는 이미 장치를 가리키는 명사),
|
문제"*, 에이전트 권고는 `Gate` 그대로 — `gate`는 이미 장치를 가리키는 명사),
|
||||||
(b) M2에 `Gate`만 넣을지 `Blocker`까지 넣을지, 그리고 생명주기/재진입 계약.
|
(b) M2에 `Gate`만 넣을지 `Blocker`까지 넣을지, 그리고 생명주기 계약.
|
||||||
**[2026-08-21 해소]** 여기 있던 "`:Apply` 팩토리인가"와 "`Blocker`가 그 위에
|
**[2026-08-21 해소]** 여기 있던 "`:Apply` 팩토리인가"와 "`Blocker`가 그 위에
|
||||||
어떻게 얹히는가"는 닫혔다 — **사용자 확정으로 `Gate`는 `:Apply`가 아니라
|
어떻게 얹히는가"는 닫혔다 — **사용자 확정으로 `Gate`는 `:Apply`가 아니라
|
||||||
`:With`류 State 메소드**(*"state 의 전파를 손대는 작업이라 with 처럼 다른
|
`:With`류 State 메소드**(*"state 의 전파를 손대는 작업이라 with 처럼 다른
|
||||||
|
|
|
||||||
|
|
@ -348,3 +348,18 @@ O절 커밋 직후 사용자가 돌린 리뷰에서 12건이 나왔고 전부
|
||||||
followup D절의 옛 `research/` 현재형 서술을 고쳤다. 재진입 계약과 "소스 없는
|
followup D절의 옛 `research/` 현재형 서술을 고쳤다. 재진입 계약과 "소스 없는
|
||||||
emit(빈 배치)"은 사용자 판단 항목으로 승격 — 후자는 `Effect(fn, ...deps)`
|
emit(빈 배치)"은 사용자 판단 항목으로 승격 — 후자는 `Effect(fn, ...deps)`
|
||||||
설치 구간 억제 용례에 직접 걸린다. 전량은 T절.
|
설치 구간 억제 용례에 직접 걸린다. 전량은 T절.
|
||||||
|
|
||||||
|
## 17. 사용자 반문 — "재진입 계약"은 없던 항목, `emit`은 flush
|
||||||
|
|
||||||
|
사용자가 T절을 되짚어 에이전트 서술 오류 둘을 잡았다. (1) `gate-plan.md`
|
||||||
|
6번의 "정책 안에서 `emit()` 재귀호출"은 `blocker-plan.md`의 재진입 절을
|
||||||
|
**잘못 옮긴 것** — 그 절은 같은 인스턴스 중첩(`On()`/`Off()`)을 말하고,
|
||||||
|
정책이 flush를 부르는 건 평범한 통과 경로다. 무한 되먹임은 2026-08-04
|
||||||
|
확정 원칙대로 UB이고 유한 재진입은 이미 지원(`debounce-throttle-plan.md`의
|
||||||
|
`onWindowEnd` 주석)이라, 이 항목은 열린 게 아니라 **정리 대상**이었다.
|
||||||
|
(2) 정책이 받는 `emit`은 페이로드를 정하지 않는 **flush 트리거**라 배치
|
||||||
|
스왑이 그 핸들 안에서 일어난다 — T절의 H-1은 모델의 구멍이 아니라
|
||||||
|
에이전트가 적은 "전파 후 `table.clear`" 의사코드의 결함이었다. 수정은
|
||||||
|
그대로 유효하고 서술만 고쳤다.
|
||||||
|
|
||||||
|
그래서 `Gate`에 남은 **사용자 판단은 빈 배치 emit 하나뿐**이다. 전량은 U절.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue