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}