/code-review high가 잡은 3건에 대한 사용자 회신 반영.
1) 게이트가 유보했다 내보내는 emit — (c) 채택, 다만 에이전트 안보다 단순한
형태로. 게이트에 자체 count를 주는 대신 흡수한 소스 집합
withheld : {[source]=true} 만 들고 있다가, 풀 때 자기를 출처로 하류에
emit 하고 전파가 동기이므로 반환 뒤 table.clear 한다. 하류는 출처가
GateNode면 그 집합의 소스들에 평소 규칙(1~3)을 적용하고 받은 출처를
그대로 더 아래로 넘긴다. OffWithoutEmit도 안전(다음 진짜 emit이 스스로
낫게 함). 그래서 emit의 출처는 Source | GateNode 둘 다가 된다.
⭐ setup 시그니처는 안 바뀐다 — 흡수 집합을 채우는 건 정책이 아니라
노드이기 때문(노드가 onUpstreamEmit 전후로 정책이 그 자리에서 emit()을
불렀는지만 보면 됨). P절이 "M2 표면에 영향"이라 적은 건 기우였다.
2) 재계산 후 sourceCountMap은 자기가 읽은 상류 전부를 갱신한다(확정).
다만 이걸 제기한 에이전트 근거("A:Set(); Z:Set()이면 같은 값을 두 번
계산")는 사용자가 반증 — 전파가 동기라 A 파동이 완전히 끝난 뒤 Z:Set()이
시작되므로 통지가 두 번 나는 건 중복이 아니라 맞는 동작이다. 전부 갱신이
실제로 값을 하는 자리는 게이트 유보 중 하류가 Get()으로 앞당겨 읽는
경우뿐이고, 그때 해제 통지가 규칙 2(통지만)로 떨어져 재계산을 안 한다.
3) 같이 명문화한 대원칙: 무효화를 결정하는 건 언제나 count 비교지 emit의
도착이 아니다. emit은 "이 원천을 확인해봐"라는 요청일 뿐이라, 통과해도
count가 최신이면 캐시는 유효한 채로 남는다.
남은 열린 항목은 새 노드의 두 맵 초기값(복사 vs 첫 재계산 때 구성)과 그에
종속된 :With 병합 규칙뿐이고, 동기 전파 덕에 차이가 나는 경우가 게이트 유보
중 파생 노드가 생길 때 하나뿐이라 어느 쪽이든 무해 — M3 구현 시 결정.
처리 전량은 round5-followup.md의 Q절. doc-check.py ERROR 0.
Co-authored-by: qwreey <me@qwreey.moe>
Claude-Session: https://claude.ai/code/session_01TiW21rnti9SbLgF6twtn6D