code wiki / _hdl_build / nx_loop_monitor.nx

nx_loop_monitor.nx source

↩ module page · 41 lines · 2224 B

1// nx_loop_monitor.nx -- the MONITOR/HANDLER organ: the "someone on the team watching the loop and 2// handling its output" that was MISSING (operator caught it: the overnight loop ran 484 beats banking 3// 0 wins on a DRY vein, with nobody noticing or re-tasking). This organ consumes the beat stream and 4// classifies the loop's PRODUCTIVITY, then HANDLES it -- continue / re-task to a new opportunity / 5// restart a stalled process. It is the feedback that turns "motion" into "progress". license_tier: 6// ORIGINAL Feeds nx_opportunity_loop (re-task -> re-scan) and nx_spec_ingest (productive -> spec). 7 8import "nx_syscalls.nx" 9 10const LM_PRODUCTIVE: i64 = 1 // banking new wins recently -> keep going 11const LM_DRY: i64 = 2 // log advancing but 0 wins for a long streak -> the vein is exhausted 12const LM_STALL: i64 = 3 // log NOT advancing -> the process is hung/blocked 13 14const LM_CONTINUE: i64 = 1 15const LM_RETASK: i64 = 2 // hand back to the opportunity loop to pick a different space 16const LM_RESTART: i64 = 3 // kill + relaunch the worker 17 18// classify: did the loop make progress, exhaust the vein, or stall? 19// recent_wins = wins banked in the recent window 20// advancing = 1 if the beat counter moved since last check (else the process is stuck) 21// zero_streak = consecutive beats with 0 wins 22// dry_threshold = how many zero-win beats before we call the vein dry 23func lm_classify(recent_wins: i64, advancing: i64, zero_streak: i64, dry_threshold: i64) -> i64 { 24 if advancing == 0 { return LM_STALL } 25 if recent_wins > 0 { return LM_PRODUCTIVE } 26 if zero_streak >= dry_threshold { return LM_DRY } 27 return LM_PRODUCTIVE // early zeros are normal; not yet dry 28} 29 30// HANDLE: every verdict maps to an action -- output is never just logged-and-ignored. 31func lm_action(verdict: i64) -> i64 { 32 if verdict == LM_STALL { return LM_RESTART } 33 if verdict == LM_DRY { return LM_RETASK } 34 return LM_CONTINUE 35} 36 37// how many beats of compute were WASTED past the point the vein should have been called dry. 38func lm_wasted_beats(zero_streak: i64, dry_threshold: i64) -> i64 { 39 if zero_streak <= dry_threshold { return 0 } 40 return zero_streak - dry_threshold 41}