=== t1_diamond ===
초기 D:Get() =	110
Observer 발화 횟수:	1	| 관측값:	220
D 재계산 횟수:	2	| B:	2	| C:	2
2회차 후 발화:	2	| 관측값:	220,330
=== t2_error ===
-- A:Set(2) (전파 중 O_bad가 error) --
Set이 던졌는가:	true	|	./t2_error.luau:7: 사용자 콜백 실패
O_bad 발화:	1	| O_good 발화:	0	| 관측:	
C의 값은 자가치유되는가: C:Get() =	2	(정상)
하지만 O_good은 이 변경에 대해 영원히 안 울었다:	0
-- 이후 A:Set(3)은 정상인가 --
두 번째 Set도 같은 자리에서 던짐:	true	| O_good 발화:	0
-- O_bad를 제거하고(구독 해제 없이 새 파동) --
O_good 발화:	1	| 관측:	4
→ 2와 3에 대한 통지는 영영 오지 않았다. 마지막 값만 보임
=== t3_gate_error ===
=== (a) blocker:Off() 순회 중 한 핸들이 error ===
보류 중 — g1.withheld 비었나:	false	| g2.withheld 비었나:	false
Off()가 던졌는가:	true	|	./t3_gate_error.luau:11: g1 하류에서 실패
blocker.IsBlocked:	false	(이미 false — Off는 상태부터 바꾼다)
g2가 아직 붙들고 있나(비었으면 flush됨):	false	| o2 발화:	0
→ g2는 IsBlocked=false 인데도 밀린 통지를 못 내보냄. b:Off()를 다시 불러도:
   두 번째 Off도 같은 자리에서 던짐:	false	| o2 발화:	1

=== (b) flush 도중 error → 떼어낸 배치가 소멸 ===
보류됨. withheld 비었나:	false
flush 진입 후 withheld 비었나(스왑됨):	true	| flush 횟수:	1
gate.emitEpochMap은 이미 Sync됨 → 같은 리비전은 이제 규칙 3으로 삼켜진다
같은 리비전 재도착 후 o 발화:	1	| 관측:	
→ 배치는 사라졌고 재도착도 삼켜져, 그 변경에 대한 통지가 영영 안 나감
   (값은 살아있다: g:Get() =	2	)
=== t4_throttle ===
=== variant = localpending ===
  타이머 살아있는 개수(idle이면 0):	0
  통과:	t=0.00 v=1 | t=1.00 v=2 | t=3.00 v=3
  최종 통과:	t=0.00 v=1 | t=1.00 v=2 | t=3.00 v=3
  t=5까지 살아있는 타이머:	0

=== variant = nopending ===
  타이머 살아있는 개수(idle이면 0):	1
  통과:	t=0.00 v=1 | t=1.00 v=2
  최종 통과:	t=0.00 v=1 | t=1.00 v=2 | t=4.00 v=3
  t=5까지 살아있는 타이머:	1
=== t5_recompute_race ===
D:Get() =	2	(A=1로 계산됨)
A의 실제 값:	99
다시 D:Get() =	2	  ← 기대값 198
D 재계산 횟수:	1
로그:	fn이 읽은 A = 1

-- 이후 A를 또 바꾸면 회복되는가 --
D:Get() =	10	(회복됨)
=== t5b_fix ===
D:Get() =	2
다시 D:Get() =	198	  ← 198이면 고쳐진 것
재계산 횟수:	2
=== t6_effect_gate ===
blocker ON — 이 구간의 변경은 gated 쪽에서 유보되어야 한다
fn 실행 기록:	run(gated=2, plain=2)
gated가 아직 붙들고 있나:	true
Off() 이후 fn 실행 기록:	run(gated=2, plain=2)
gated observer 발화 횟수:	1	| plain observer:	1
=== t7_poisoned ===
-- 정상 배치 --
recompute 횟수:	1	| blocker.IsOn():	false
-- 두 번째 배치에서 사용자 코드가 error --
drive가 던졌는가:	true	| blocker.IsOn():	true	← 영구 On
-- 이후 런타임 :Add() 등이 부르는 setLength --
recompute가 몇 번 돌았나:	0	(0이면 그 owner는 영영 재계산 안 됨)
-- 새 배치를 열어도 --
blocker.IsOn():	false	| 총 recompute:	2
=== t8_reentrant ===
관측 순서:	220,330
Observer 발화:	2	| D 재계산:	3
최종 D:Get() =	330	(A=3이므로 330이어야 함)
=== t9_gate_chain ===
[상류 먼저] 유보 중 g1=true g2=false | 발화 0
  b1:Off 후 g1=false g2=true 발화=0
  최종 발화 1 | v=5, batch=2
[하류 먼저] 유보 중 g1=true g2=false | 발화 0
  b2:Off 후 g1=true g2=false 발화=0
  최종 발화 1 | v=5, batch=2
=== t10_subscribe_gc ===
Observer 발화:	0	  ← 공개 계약("예외 없이 그냥 계속 돎")대로면 1
A의 구독자 수:	0	  ← 중간 State가 수거됐으면 0
Observer는 레지스트리에 살아있다:	true	| 그러나 다시는 안 울린다
=== d1_basic ===
offsets:	0	1	2	| 다음 자리:	3
recompute 횟수:	1
=== d2_slots ===
초기: s1.Offset =	0	| s2.Offset =	1	| recompute:	1
-- 런타임에 Slot1이 3개가 됨 (s1.Length:Set(3)) --
s1.Offset =	0	| s2.Offset =	4	(기대 4) | recompute:	2
-- Slot2도 2개가 됨 --
s2.Offset =	4	(기대 4) | 4번 자리 offset =	6	(기대 6)
-- Slot1이 다시 0개 --
s2.Offset =	1	(기대 1) | 4번 자리 =	3	(기대 3)
=== d4_reentrant ===
초기 owner.Length =	0	| s2.Offset =	0
-- s1.Length:Set(2) --
owner.Length =	2	| 실제 합계 =	3	| N =	3	| recompute:	3
s2.Offset =	2	(기대 2) | 3번 자리 offset =	2	(기대 2)
  ❌ owner.Length가 실제 합계와 다르다
=== d5_chain_error ===
-- 백엔드 미주입 상태에서 Attribute 한 번 --
던졌는가:	true	|	./d5_chain_error.luau:8: quad: setAttribute op이 주입되지 않았습니다(백엔드 팩토리 미설치)
claim 남았는가:	true
체인 슬롯:	있음(retractor=function: 0x000055f521ddcb70)
-- 이제 백엔드를 붙이고 정상적으로 다시 시도 --
성공했는가:	false	|	./d5_chain_error.luau:16: attribute "Score" is already bound by another owner
-- 명시적 철거로 회수되는가 --
철거 후 claim 남았는가:	true
철거 후 재시도 성공?:	false	|	./d5_chain_error.luau:16: attribute "Score" is already bound by another owner
=== d7_splice_fix ===
[확정 설계 그대로] s3.Offset = 1 (기대 5) | invalidAfter = 2
[위치 재조정함] s3.Offset = 5 (기대 5) | invalidAfter = 2
=== d9_hole2 ===
setOffsetSource에서 터지는가:	true
메시지:	./dispatch.luau:46: attempt to perform arithmetic (add) on number and nil
=== e1_errlevel ===
level 기본(1):	./e1_errlevel.luau:5: Slot:Add — index가 범위 밖(1..3): 9
level 2      :	./e1_errlevel.luau:12: Slot:Add — index가 범위 밖(1..3): 9
