design: 게이트 통과/유보 미구분으로 단순화 + 새 노드 두 맵 비대칭 초기화 확정
1) 게이트는 통과와 유보를 구분하지 않는다. 상류 emit이 오면 정책 실행 전에
무조건 withheld[source] = true 로 넣고, 정책이 emit()을 부르면 게이트가
자기를 출처로 전파한 뒤(동기) table.clear 한다. 그냥 통과시킬 때도 상류
출처를 넘기지 않고 언제나 자기를 낸다 — 하류가 보는 차이는 집합 원소가
하나냐 여럿이냐뿐이고 판정 규칙은 같다. 그래서 직전 라운드에 넣었던
"정책이 그 자리에서 emit()을 불렀는지 노드가 되짚는다"는 감지 로직이
통째로 불필요해졌다.
2) 새 노드의 두 맵은 비대칭으로 초기화한다.
- sourceEmitMap: 비운다. nil ~= source.count 라 어떤 emit도 "처음 보는
것"으로 걸리고, 새 노드는 실제로 emit을 받아본 적이 없으므로 그게 맞다.
- sourceCountMap: 상류에서 전부 끌어와 실제 count로 채우고 rawInvalid를
true로 둔다. 순회가 훑을 목록이 곧 이 맵이라 비워두면 "훑을 게 없으니
유효하다"로 오판한다 — 여기는 lazy할 수 없고 "내가 뭘 추적하는가"가
필요하다.
그래서 :With 병합 규칙은 필요 없어졌다(생성 시점 라이브 count로 통일되므로
두 상류가 같은 소스에 다른 count를 들 일이 없다). /code-review Med-3이
열어둔 (b)/(c)가 이걸로 전부 닫혔다.
처리 전량은 round5-followup.md의 R절. 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
356a308ce0
commit
930e45bfad
6 changed files with 104 additions and 44 deletions
|
|
@ -126,12 +126,18 @@ end)
|
||||||
**확정 기제**(사용자 안, 에이전트가 냈던 (a) `nil` 전체 확인 / (b) 소스마다
|
**확정 기제**(사용자 안, 에이전트가 냈던 (a) `nil` 전체 확인 / (b) 소스마다
|
||||||
개별 emit은 기각 — 각각 O(1) 판정을 깨거나 `Blocker`의 "정확히 1회"를 깬다):
|
개별 emit은 기각 — 각각 O(1) 판정을 깨거나 `Blocker`의 "정확히 1회"를 깬다):
|
||||||
|
|
||||||
- `GateNode`가 **자기가 흡수한 소스 집합**을 들고 있는다 —
|
- `GateNode`가 **자기를 거쳐간 소스 집합**을 들고 있는다 —
|
||||||
`withheld : { [source] : true }`. 정책이 통과시키지 **않은** 상류 emit의
|
`withheld : { [source] : true }`.
|
||||||
출처가 여기 쌓인다.
|
- **⭐ [2026-08-21 단순화] 통과와 유보를 구분하지 않는다.** 상류 emit이
|
||||||
- 유보를 풀 때 게이트는 **자기 자신을 출처로 실어** 하류에 emit 한다.
|
오면 **정책을 실행하기 전에 무조건** 그 출처를 `withheld`에 넣고, 그
|
||||||
전파는 **동기**이므로, 그 emit이 반환된 **뒤에** `table.clear(withheld)`
|
다음 정책을 실행한다. 정책이 `emit()`을 부르면 게이트가 **자기 자신을
|
||||||
하면 하류 전원이 집합을 온전히 본다.
|
출처로** 하류에 전파하고, 전파는 **동기**이므로 반환된 **뒤에**
|
||||||
|
`table.clear(withheld)` 한다. 정책이 안 부르면 집합에 그대로 쌓인다.
|
||||||
|
- **그래서 게이트는 언제나 자기를 출처로 낸다** — 그냥 통과시킬 때도 상류
|
||||||
|
출처를 그대로 넘기지 않는다. 사용자: *"후행 노드들은 한개가 지연된거로
|
||||||
|
생각이 될 수 있겠지만, 사실 여기서 지연과 비지연을 구분할 이유가
|
||||||
|
없습니다."* 하류가 보는 차이는 집합의 원소가 하나냐 여럿이냐뿐이고 판정
|
||||||
|
규칙은 완전히 같다.
|
||||||
- 하류는 출처가 `GateNode`면 그 집합을 순회하며 각 소스에 평소 규칙(1~3)을
|
- 하류는 출처가 `GateNode`면 그 집합을 순회하며 각 소스에 평소 규칙(1~3)을
|
||||||
적용하고, 하나라도 걸리면 **받은 출처를 그대로** 더 아래로 넘긴다
|
적용하고, 하나라도 걸리면 **받은 출처를 그대로** 더 아래로 넘긴다
|
||||||
(`state-epoch-plan.md` §2).
|
(`state-epoch-plan.md` §2).
|
||||||
|
|
@ -139,11 +145,10 @@ end)
|
||||||
`sourceEmitMap`이 뒤에 남지만, 그 소스의 다음 진짜 emit이 규칙 1/2로
|
`sourceEmitMap`이 뒤에 남지만, 그 소스의 다음 진짜 emit이 규칙 1/2로
|
||||||
걸려 스스로 낫는다.
|
걸려 스스로 낫는다.
|
||||||
|
|
||||||
**⭐ 그래서 `setup` 시그니처는 안 바뀐다.** 흡수 집합을 채우는 건 정책이
|
**⭐ 그래서 `setup` 시그니처는 안 바뀐다.** 집합을 채우는 건 정책이 아니라
|
||||||
아니라 **노드**다 — 노드가 `onUpstreamEmit()`을 부르기 전후로 "정책이 그
|
**노드**이고, 노드는 정책이 뭘 하는지 들여다볼 필요조차 없다(위 단순화).
|
||||||
자리에서 `emit()`을 불렀는가"만 보면 통과/유보를 알 수 있고, 유보였으면
|
정책은 소스를 몰라도 되고, `Throttle`처럼 나중에 타이머에서 `emit()`을
|
||||||
그 출처를 `withheld`에 넣는다. 정책은 소스를 몰라도 되고, `Throttle`처럼
|
부르는 경우도 그대로 동작한다 — 그때 쌓여 있던 집합이 그대로 나간다.
|
||||||
나중에 타이머에서 `emit()`을 부르는 경우도 그대로 동작한다.
|
|
||||||
|
|
||||||
5. **생명주기.** 게이트 노드가 잡는 자원(타이머/플래그)이 언제 죽는가 —
|
5. **생명주기.** 게이트 노드가 잡는 자원(타이머/플래그)이 언제 죽는가 —
|
||||||
지금 설계대로면 다운스트림이 다 죽으면 GC(팩토리는 weak 추적,
|
지금 설계대로면 다운스트림이 다 죽으면 GC(팩토리는 weak 추적,
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,20 @@ State
|
||||||
-- "재계산이 필요하다"는 확정 플래그
|
-- "재계산이 필요하다"는 확정 플래그
|
||||||
```
|
```
|
||||||
|
|
||||||
노드가 이 두 맵을 **언제 어떻게 갖게 되는지**(생성 시 상류에서 복사 vs 첫
|
**⭐ [2026-08-21 확정] 노드가 생길 때의 초기값은 두 맵이 서로 다르다.**
|
||||||
재계산 때 구성)는 §5의 7번 — 관측 가능한 차이는 거의 없지만 아직 안 못박았다.
|
|
||||||
|
- **`sourceEmitMap`은 비운 채로 시작한다.** `nil ~= source.count`라 어떤 emit이
|
||||||
|
와도 "처음 보는 것"으로 걸린다 — 그리고 그게 맞다. 사용자: *"새로 생성된
|
||||||
|
노드에서 들어온 emit 은, 개념적으로 해당 노드가 한번도 받아본적 없는
|
||||||
|
emit 입니다."*
|
||||||
|
- **`sourceCountMap`은 반대로 상류에서 전부 끌어와 실제 count로 채우고,
|
||||||
|
`rawInvalid = true`로 시작한다.** 이쪽은 비워두면 안 된다 — 순회가 훑을
|
||||||
|
대상 목록이 곧 이 맵이라, 비어 있으면 **"훑을 게 없으니 유효하다"**로
|
||||||
|
오판한다. 사용자: *"이건 상류가 주는대로 lazy 할 순 없는게, '내가 뭘
|
||||||
|
추적하고 있나' 가 필요하죠. 따라서 다음을 제안합니다: 전부 가져와서, 실제
|
||||||
|
count 로 둡니다. 그러고 `rawInvalid` 를 true 로 두세요."*
|
||||||
|
- 그래서 **`:With`에서 두 상류가 같은 소스에 다른 count를 들고 있을 때의 병합
|
||||||
|
규칙도 필요 없다** — 어차피 생성 시점의 라이브 count로 통일된다.
|
||||||
|
|
||||||
**⭐ 대원칙 — 무효화를 결정하는 건 언제나 count 비교지 emit의 도착이 아니다.**
|
**⭐ 대원칙 — 무효화를 결정하는 건 언제나 count 비교지 emit의 도착이 아니다.**
|
||||||
emit은 **"이 원천을 확인해봐"** 라는 요청일 뿐이다. 그래서 emit이 통과해도
|
emit은 **"이 원천을 확인해봐"** 라는 요청일 뿐이다. 그래서 emit이 통과해도
|
||||||
|
|
@ -76,8 +88,9 @@ count가 이미 최신이면 **캐시는 유효한 채로 남는다**(아래 2
|
||||||
- **`GateNode`** — 그 게이트가 **흡수해뒀던 소스 집합**을 확인하라
|
- **`GateNode`** — 그 게이트가 **흡수해뒀던 소스 집합**을 확인하라
|
||||||
(`base/gate-plan.md`의 4번). 게이트가 `blocker:Off()` 등으로 유보를 풀 때
|
(`base/gate-plan.md`의 4번). 게이트가 `blocker:Off()` 등으로 유보를 풀 때
|
||||||
쓴다.
|
쓴다.
|
||||||
**출처는 전파 도중 바뀌지 않는다** — 중간 노드는 자기를 끼워넣지 않고 받은
|
**평범한 노드는 출처를 안 바꾼다** — 자기를 끼워넣지 않고 받은 출처를 그대로
|
||||||
출처를 그대로 아래로 넘긴다(소스 emit이 원래 그러듯이).
|
아래로 넘긴다. **`GateNode`만 예외로 언제나 자기 자신을 출처로 새로 낸다**
|
||||||
|
(`base/gate-plan.md`의 4번).
|
||||||
- **emit을 받았을 때** — 출처가 `Source`면 판정은 O(1)이다, 그 항목 하나만 본다:
|
- **emit을 받았을 때** — 출처가 `Source`면 판정은 O(1)이다, 그 항목 하나만 본다:
|
||||||
1. `sourceCountMap[source] ~= source.count` → 둘 다 `source.count`로 갱신하고
|
1. `sourceCountMap[source] ~= source.count` → 둘 다 `source.count`로 갱신하고
|
||||||
`rawInvalid = true`를 세운 다음 **뒤로 emit** 한다.
|
`rawInvalid = true`를 세운 다음 **뒤로 emit** 한다.
|
||||||
|
|
@ -251,31 +264,21 @@ count가 이미 최신이면 **캐시는 유효한 채로 남는다**(아래 2
|
||||||
`base/source-state-plan.md`의 전파 모델 절은 **채택과 함께 그렇게 다시
|
`base/source-state-plan.md`의 전파 모델 절은 **채택과 함께 그렇게 다시
|
||||||
썼다.**
|
썼다.**
|
||||||
|
|
||||||
7. **[2026-08-21 — (a)는 해소, (b)/(c)만 남음] 두 맵의 초기값·병합·재계산 시
|
7. **[2026-08-21 전량 해소] 두 맵의 초기값·병합·재계산 시 갱신 범위.**
|
||||||
갱신 범위.**
|
- **(a) 재계산 후 `sourceCountMap` 갱신 범위** — **자기가 읽은 상류 전부를
|
||||||
- **(a) 재계산 후 `sourceCountMap` 갱신 범위 — 해소.** **자기가 읽은 상류
|
갱신한다**(사용자: *"invalid 에 대한 계산을 위한 count 테이블은 단순히
|
||||||
전부를 갱신한다**(사용자: *"invalid 에 대한 계산을 위한 count 테이블은
|
전부 업데이트 하는건 맞아보입니다"*). §2에 반영.
|
||||||
단순히 전부 업데이트 하는건 맞아보입니다"*). §2에 반영 완료.
|
|
||||||
- ⚠️ 이 항목을 제기할 때 든 근거("`A:Set(); Z:Set()`이면 같은 값을 두 번
|
- ⚠️ 이 항목을 제기할 때 든 근거("`A:Set(); Z:Set()`이면 같은 값을 두 번
|
||||||
계산한다")는 **틀렸었다.** 전파는 동기라 `A:Set()`의 파동이 **완전히
|
계산한다")는 **틀렸었다.** 전파는 동기라 `A:Set()`의 파동이 **완전히
|
||||||
끝난 뒤에** `Z:Set()`이 시작되므로, 그 사이 재계산은 `Z`의 옛 값을 읽는
|
끝난 뒤에** `Z:Set()`이 시작되므로, 그 사이 재계산은 `Z`의 옛 값을 읽는
|
||||||
게 맞고 통지가 두 번 나는 것도 맞다(사용자 정정: *"싱크라 set 의 emit 이
|
게 맞고 통지가 두 번 나는 것도 맞다(사용자 정정: *"싱크라 set 의 emit 이
|
||||||
전부 전파 된 다음 z:set 이라 두번 나는게 맞긴 해요"*). 전부 갱신이
|
전부 전파 된 다음 z:set 이라 두번 나는게 맞긴 해요"*). 전부 갱신이
|
||||||
실제로 값을 하는 자리는 **게이트가 붙들고 있는 동안 하류가 `Get()`으로
|
실제로 값을 하는 자리는 **게이트가 붙들고 있는 동안 하류가 `Get()`으로
|
||||||
앞당겨 읽는 경우**뿐이다 — §2의 재계산 항목이 소스.
|
앞당겨 읽는 경우**뿐이다.
|
||||||
- **(b) 새 노드의 두 맵 초기값 — 열림(낮은 위험).** 원안은 "상류에서 복사".
|
- **(b) 새 노드의 두 맵 초기값** — `sourceEmitMap`은 **비우고**,
|
||||||
대안은 "첫 재계산 때 자기가 읽은 상류들의 맵을 합쳐 구성". **동기 전파
|
`sourceCountMap`은 **전부 끌어와 실제 count로 채운 뒤 `rawInvalid = true`**.
|
||||||
덕분에 둘의 차이가 나타나는 경우는 하나뿐**이다 — 게이트가 붙들고 있는
|
§2의 "노드가 생길 때의 초기값" 문단이 소스.
|
||||||
동안 파생 노드가 새로 생기는 경우. 그때 복사본은 상류의 "아직 안 던진"
|
- **(c) `:With` 병합 규칙** — (b)로 인해 **필요 없어졌다.**
|
||||||
지연분을 물려받아 해제 시 통지를 한 번 더 받고(무해), 첫-재계산본은 이미
|
|
||||||
최신이라 삼킨다(이것도 무해 — 새 노드의 Observer는 등록 즉시 1회 관측으로
|
|
||||||
현재 값을 이미 봤다). **에이전트 권고: 첫 재계산 때 구성** — (c)가 자동으로
|
|
||||||
사라지고 "값을 계산한 시점의 스냅샷"이라는 맵의 뜻과 일치한다.
|
|
||||||
- **(c) `:With` 병합에서 두 상류가 같은 소스에 다른 count를 들 때 — (b)에
|
|
||||||
종속.** (b)에서 "첫 재계산 때 구성"을 택하면 그 시점 라이브 count로
|
|
||||||
통일돼 병합 규칙 자체가 필요 없다. "복사"를 택하면 명시 규칙이 필요하다
|
|
||||||
(`sourceCountMap`은 더 큰 쪽, `sourceEmitMap`은 **더 작은 쪽** — 안 던진
|
|
||||||
게 하나라도 있으면 안 던진 것으로 봐야 통지가 안 죽는다).
|
|
||||||
|
|
||||||
## 6. 곁가지 — 폴링용 sugar
|
## 6. 곁가지 — 폴링용 sugar
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1077,3 +1077,40 @@ Observer가 이제 변경당 **1회**만 울어야 하므로 핵심 assert가
|
||||||
재계산 때 구성)과 그에 종속된 `:With` 병합 규칙. 동기 전파 덕에 둘의 차이가
|
재계산 때 구성)과 그에 종속된 `:With` 병합 규칙. 동기 전파 덕에 둘의 차이가
|
||||||
나는 경우는 **게이트 유보 중 파생 노드가 새로 생길 때** 하나뿐이고 어느
|
나는 경우는 **게이트 유보 중 파생 노드가 새로 생길 때** 하나뿐이고 어느
|
||||||
쪽이든 무해하다. §5 7번.
|
쪽이든 무해하다. §5 7번.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# R절 — 두 건 더 단순해짐 (2026-08-21, Q절 직후)
|
||||||
|
|
||||||
|
## R-1. 게이트는 통과/유보를 구분하지 않는다
|
||||||
|
|
||||||
|
Q절은 "노드가 정책이 그 자리에서 `emit()`을 불렀는지 되짚어 유보만
|
||||||
|
`withheld`에 넣는다"였는데, 사용자가 그 감지 자체를 없앴다:
|
||||||
|
|
||||||
|
> *"사실 gate 는 상태가 어떻든 항상 유보그룹에 우선 넣고, (정책이 emit 을
|
||||||
|
> 부르든 말든, 정책 실행 전에 그냥 넣음) 그런 다음 정책을 실행하면 emit 이
|
||||||
|
> 그냥 뒤로 gate 자신을 전파해버리면 됩니다. 후행 노드들은 한개가 지연된거로
|
||||||
|
> 생각이 될 수 있겠지만, 사실 여기서 지연과 비지연을 구분할 이유가 없습니다."*
|
||||||
|
|
||||||
|
- 상류 emit → **정책 실행 전에 무조건** `withheld[source] = true` → 정책 실행.
|
||||||
|
- 정책이 `emit()`을 부르면 게이트가 **자기를 출처로** 전파하고, 동기 전파라
|
||||||
|
반환 뒤 `table.clear(withheld)`.
|
||||||
|
- **게이트는 언제나 자기를 출처로 낸다** — 그냥 통과시킬 때도 상류 출처를
|
||||||
|
넘기지 않는다. 하류가 보는 차이는 집합 원소가 하나냐 여럿이냐뿐.
|
||||||
|
|
||||||
|
## R-2. 새 노드의 두 맵 — 비대칭 초기화 (P절 Med-3 해소)
|
||||||
|
|
||||||
|
> *"emit 은 그냥 비어있어도 됩니다. nil 자체도 변경으로 보아도 돼요. …
|
||||||
|
> 새로 생성된 노드에서 들어온 emit 은, 개념적으로 해당 노드가 한번도 받아본적
|
||||||
|
> 없는 emit 입니다. … 이건 상류가 주는대로 lazy 할 순 없는게, '내가 뭘 추적하고
|
||||||
|
> 있나' 가 필요하죠. 따라서 다음을 제안합니다: 전부 가져와서, 실제 count 로
|
||||||
|
> 둡니다. 그러고 rawInvalid 를 true 로 두세요."*
|
||||||
|
|
||||||
|
| 맵 | 초기값 | 왜 |
|
||||||
|
|---|---|---|
|
||||||
|
| `sourceEmitMap` | **비움** | `nil ~= source.count`라 어떤 emit도 "처음 보는 것"으로 걸린다 — 새 노드는 실제로 받아본 적이 없다 |
|
||||||
|
| `sourceCountMap` | **전부 끌어와 실제 count**, + `rawInvalid = true` | 순회가 훑을 목록이 곧 이 맵이라, 비워두면 "훑을 게 없으니 유효하다"로 오판한다 |
|
||||||
|
|
||||||
|
그래서 **`:With` 병합 규칙은 필요 없어졌다** — 생성 시점 라이브 count로
|
||||||
|
통일되므로 두 상류가 다른 count를 들 일이 없다. P절 Med-3이 열어둔 (b)/(c)가
|
||||||
|
이걸로 전부 닫혔다.
|
||||||
|
|
|
||||||
|
|
@ -213,13 +213,13 @@
|
||||||
`table.clear`한다. 하류는 출처가 게이트면 그 집합의 소스들에 평소 규칙을
|
`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 에포크 — 새 노드의 두 맵 초기값(복사 vs 첫
|
- **[해소, 2026-08-21 같은 날] State 에포크 — 새 노드의 두 맵 초기값과
|
||||||
재계산 때 구성)과 그에 종속된 `:With` 병합 규칙.** 재계산 시 갱신 범위(전부
|
`:With` 병합.** `sourceEmitMap`은 **비우고**(어떤 emit이 와도 "처음 보는
|
||||||
갱신)는 같은 날 **확정**됐고, 그걸 제기할 때 든 근거는 **동기 전파를 놓친
|
것"으로 걸리는 게 맞다 — 새 노드는 개념적으로 emit을 받아본 적이 없다),
|
||||||
것이라 사용자가 정정**했다. 남은 (b)/(c)는 **동기 전파 덕에 차이가 나는
|
`sourceCountMap`은 **전부 끌어와 실제 count로 채운 뒤 `rawInvalid = true`**
|
||||||
경우가 게이트 유보 중 새 노드가 생길 때 하나뿐**이고 어느 쪽이든 무해하다 —
|
(비워두면 순회가 훑을 목록 자체가 없어 "유효하다"로 오판한다 — *"'내가 뭘
|
||||||
권고는 "첫 재계산 때 구성". M3 구현 시 정하면 된다.
|
추적하고 있나' 가 필요하죠"*). 그래서 `:With` 병합 규칙은 **필요 없어졌다.**
|
||||||
`base/state-epoch-plan.md`의 §5 7번.
|
재계산 시 갱신 범위(전부 갱신)도 확정. `base/state-epoch-plan.md`의 §2·§5 7번.
|
||||||
- **[해소, 2026-08-21] 공용 게이트 노드의 이름과 표면 — `state:Gate(setup)`
|
- **[해소, 2026-08-21] 공용 게이트 노드의 이름과 표면 — `state:Gate(setup)`
|
||||||
메소드 + `GateNode`로 확정.** 탑레벨 프리미티브는 안 만들고, `Blocker`는
|
메소드 + `GateNode`로 확정.** 탑레벨 프리미티브는 안 만들고, `Blocker`는
|
||||||
`state:Block(blocker)` 안에서 그 배선을 쓴다(사용자: *"Gate 는 따로
|
`state:Block(blocker)` 안에서 그 배선을 쓴다(사용자: *"Gate 는 따로
|
||||||
|
|
|
||||||
|
|
@ -309,3 +309,17 @@ O절 커밋 직후 사용자가 돌린 리뷰에서 12건이 나왔고 전부
|
||||||
`Z:Set()`이 시작되므로 통지가 두 번 나는 건 중복이 아니라 맞는 동작이다.
|
`Z:Set()`이 시작되므로 통지가 두 번 나는 건 중복이 아니라 맞는 동작이다.
|
||||||
그 과정에서 대원칙 하나가 명문화됐다: **무효화를 결정하는 건 언제나 count
|
그 과정에서 대원칙 하나가 명문화됐다: **무효화를 결정하는 건 언제나 count
|
||||||
비교지 emit의 도착이 아니다.** 전량은 followup의 Q절.
|
비교지 emit의 도착이 아니다.** 전량은 followup의 Q절.
|
||||||
|
|
||||||
|
## 14. 마지막 단순화 두 건 — 게이트 통과/유보 미구분, 새 노드 맵 비대칭 초기화
|
||||||
|
|
||||||
|
사용자가 Q절 기제를 한 번 더 줄였다. 게이트는 **정책 실행 전에 무조건**
|
||||||
|
출처를 `withheld`에 넣고, 통과시킬 때조차 **자기를 출처로** 전파한다 —
|
||||||
|
"지연과 비지연을 구분할 이유가 없다". 그래서 Q절이 넣었던 "정책이 emit을
|
||||||
|
불렀는지 노드가 되짚는다"는 감지 로직이 통째로 사라졌다.
|
||||||
|
|
||||||
|
새 노드의 두 맵은 **비대칭**으로 초기화한다: `sourceEmitMap`은 비우고
|
||||||
|
(새 노드는 개념적으로 emit을 받아본 적이 없으므로 `nil`이 곧 "변경"),
|
||||||
|
`sourceCountMap`은 상류에서 전부 끌어와 실제 count로 채운 뒤
|
||||||
|
`rawInvalid = true`(순회가 훑을 목록이 곧 이 맵이라 비워두면 "유효"로
|
||||||
|
오판). 이걸로 `:With` 병합 규칙이 필요 없어지며 `/code-review` Med-3이
|
||||||
|
닫혔다. 전량은 followup의 R절.
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,10 @@
|
||||||
내보내는 emit이 어느 출처를 싣는지"가 안 정해진 걸 잡아 한때 M2 항목으로
|
내보내는 emit이 어느 출처를 싣는지"가 안 정해진 걸 잡아 한때 M2 항목으로
|
||||||
되돌아갔으나, **사용자가 그 자리에서 `emit(self)` + 흡수 집합으로
|
되돌아갔으나, **사용자가 그 자리에서 `emit(self)` + 흡수 집합으로
|
||||||
확정**했다(`setup` 시그니처는 안 바뀜 — `base/gate-plan.md` 4번). 같이
|
확정**했다(`setup` 시그니처는 안 바뀜 — `base/gate-plan.md` 4번). 같이
|
||||||
제기됐던 에포크 쪽 세 자리 중 "재계산 시 count 전부 갱신"도 확정,
|
제기됐던 에포크 쪽 세 자리도 **전량 확정**됐다(재계산 시 count 전부 갱신 /
|
||||||
나머지 둘(새 노드 맵 초기값 / `:With` 병합)은 **M3 구현 시 정하면 되는
|
새 노드는 `sourceEmitMap`은 비우고 `sourceCountMap`은 실제 count로 채운 뒤
|
||||||
낮은 위험 항목**으로 남았다(`state-epoch-plan.md` §5 7번).
|
`rawInvalid = true` / 그래서 `:With` 병합 규칙은 불필요) —
|
||||||
|
`state-epoch-plan.md` §5 7번.
|
||||||
그 외 남은 것은 판단이 아니라 구현 시 정할 것들 — `Gate`의
|
그 외 남은 것은 판단이 아니라 구현 시 정할 것들 — `Gate`의
|
||||||
생명주기·재진입 계약, M2에 `Blocker`까지 넣을지, 스파이크 `05` 재작성
|
생명주기·재진입 계약, M2에 `Blocker`까지 넣을지, 스파이크 `05` 재작성
|
||||||
(`luau-test/STATUS.md`).
|
(`luau-test/STATUS.md`).
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue