=== 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