code wiki / (root) / nx_print_runtime_monitor_test.nx

nx_print_runtime_monitor_test.nx source

↩ module page · 97 lines · 4955 B

1// nx_print_runtime_monitor_test.nx -- exercise the runtime spaghetti 2// monitor against synthetic telemetry sequences. 3// 4// Closed-form invariants: 5// (a) Null/bad constructor inputs -> null monitor 6// (b) First event primes state; no issue 7// (c) Normal layer progression (Z advancing every ~expected_time): 8// NO issues raised 9// (d) STUCK_LAYER: same Z for > expected × multiple ms -> fires 10// (e) FLOW_ANOMALY: extruder advances but XY doesn't, Z static -> fires 11// (f) EXTRUDER_RUNAWAY: e advances WAY more than xy -> fires 12// (g) After issue fires, n_issues_total increments 13// 14// expect_exit: 0 15// license_tier: ORIGINAL 16 17import "nx_syscalls.nx" 18import "nx_print_runtime_monitor.nx" 19 20const Q14: i64 = 16384 21 22func main() -> i64 { 23 // ===== (a) Bad inputs ===== 24 let m_bad: *NxRuntimeMonitor = nx_runtime_monitor_new(0, 3, Q14, Q14) 25 if (m_bad as i64) != 0 { return 10 } 26 let m_bad2: *NxRuntimeMonitor = nx_runtime_monitor_new(1000, 1, Q14, Q14) 27 if (m_bad2 as i64) != 0 { return 11 } 28 29 // ===== Build a monitor: expect 5s per layer, alarm at 3× (15s). 30 // Flow anomaly: e > 5mm advance + xy < 2mm + same Z -> alarm. 31 let m: *NxRuntimeMonitor = nx_runtime_monitor_new( 32 5000, // expected_layer_time_ms 33 3, // stuck_layer_multiple 34 5 * Q14, // flow_anomaly_e_mm_q14 35 2 * Q14) // flow_anomaly_xy_mm_q14 36 if (m as i64) == 0 { return 20 } 37 38 // ===== (b) First event: no issue ===== 39 let v0: i64 = nx_runtime_monitor_step(m, 200 * Q14 / 1000, 0, 0, 0) // z=0.2mm, t=0 40 if v0 != NX_RT_ISSUE_NONE { return 30 } 41 42 // ===== (c) Normal layer progression: NO issues ===== 43 // 5 layers, each advancing Z by 0.2mm at 5s intervals 44 let v1: i64 = nx_runtime_monitor_step(m, 400 * Q14 / 1000, 10 * Q14, 50 * Q14, 5000) 45 if v1 != NX_RT_ISSUE_NONE { return 40 } 46 let v2: i64 = nx_runtime_monitor_step(m, 600 * Q14 / 1000, 20 * Q14, 50 * Q14, 10000) 47 if v2 != NX_RT_ISSUE_NONE { return 41 } 48 let v3: i64 = nx_runtime_monitor_step(m, 800 * Q14 / 1000, 30 * Q14, 50 * Q14, 15000) 49 if v3 != NX_RT_ISSUE_NONE { return 42 } 50 if m.n_issues_total != 0 { return 43 } 51 52 // ===== (d) STUCK_LAYER: stay on same Z for > 15s (3 × 5s) ===== 53 // Same Z=0.8mm but big time advance (16s past last layer change). 54 let v_stuck: i64 = nx_runtime_monitor_step(m, 800 * Q14 / 1000, 55 35 * Q14, // small extrusion 56 1 * Q14, // small XY 57 15000 + 16000) // 16s past last layer 58 if v_stuck != NX_RT_ISSUE_STUCK_LAYER { return 50 } 59 if nx_runtime_monitor_last_issue(m) != NX_RT_ISSUE_STUCK_LAYER { return 51 } 60 if m.n_issues_total != 1 { return 52 } 61 62 // ===== (e) FLOW_ANOMALY: extruder advances but XY barely, Z same ===== 63 // Fresh monitor for clean test. 64 let m2: *NxRuntimeMonitor = nx_runtime_monitor_new(5000, 3, 5 * Q14, 2 * Q14) 65 nx_runtime_monitor_step(m2, 200 * Q14 / 1000, 0, 0, 0) 66 // Same Z; e advanced 10mm (> 5mm threshold); xy advanced 1mm (< 2mm threshold) 67 let v_flow: i64 = nx_runtime_monitor_step(m2, 200 * Q14 / 1000, 68 10 * Q14, // big e 69 1 * Q14, // small XY 70 100) 71 if v_flow != NX_RT_ISSUE_FLOW_ANOMALY { return 60 } 72 73 // ===== (f) EXTRUDER_RUNAWAY: e advances >10× XY ===== 74 let m3: *NxRuntimeMonitor = nx_runtime_monitor_new(5000, 3, 5 * Q14, 2 * Q14) 75 nx_runtime_monitor_step(m3, 200 * Q14 / 1000, 0, 0, 0) 76 // Z advances (so STUCK_LAYER doesn't fire; FLOW_ANOMALY needs dz=0). 77 // XY accumulates only 5mm across this step, but e advanced 100mm. 78 // Ratio = 100/5 = 20× > 10× threshold. 79 // BUT the per-layer reset on Z change wipes cumulative_xy_q14 to 0 80 // before runaway check. So the test must advance Z FIRST (resets 81 // cumulative xy), THEN have e shoot up at the same Z. 82 nx_runtime_monitor_step(m3, 400 * Q14 / 1000, 10 * Q14, 50 * Q14, 5000) // normal layer 83 // Now at z=0.4mm. Stay on this layer, accumulate XY=5mm + huge e=100mm. 84 let v_runaway: i64 = nx_runtime_monitor_step(m3, 400 * Q14 / 1000, 85 110 * Q14, // e jumps by 100mm 86 5 * Q14, // XY only 5mm 87 6000) 88 // FLOW_ANOMALY would fire first (de=100 > 5, xy=5 > 2 threshold so NOT 89 // FLOW; check runaway logic). de=100, xy_total=5 (since last Z change), 90 // 10*xy=50; de(100) > 50 + de > Q14 -> RUNAWAY. 91 if v_runaway != NX_RT_ISSUE_EXTRUDER_RUNAWAY { return 70 } 92 93 // ===== (g) n_issues_total increments per issue ===== 94 if m3.n_issues_total != 1 { return 80 } 95 96 return 0 97}