code wiki / _hdl_build / nx_resmon_gate.nx

nx_resmon_gate.nx source

↩ module page · 229 lines · 16495 B

1// nx_resmon_gate.nx -- referee for nx_resmon's two policy predicates (debt seq1005). 2// 3// It gates the SAME functions the organ runs (nx_resmon_lib.nx), not a reimplementation, and it needs 4// no /proc and no fixtures on disk -- every input is synthetic, so the result is deterministic. 5// 6// T2 AND T4 ARE THE TEETH THAT MATTER: 7// T2 is the NON-VACUITY control: with thresholds set unreachably high, measurements that trip RED 8// under real thresholds must return GREEN. If T2 ever fails, T1 is passing for free. 9// T4 pins the EXACT false positive this instrument made on its first live run: a process with a huge 10// RESERVED VmData but almost nothing committed reported a worst case of 40.6 GiB on a 36.9 GB box. 11// A leaker is judged on rss+swap, never on reserved address space. That regression cannot return 12// silently now. 13// 14// license_tier: ORIGINAL expect_exit: 0 15import "nx_gate.nx" 16import "nx_gate_verdict.nx" 17import "nx_resmon_lib.nx" 18 19// The age this leak axis ACTUALLY reported on 2026-08-21: 7.2 h against a 900 s freshness bound, i.e. 20// ~43 consecutive missed 600 s beats, while the pressure axis sat amber at swap 754 permil. 21// ★NAMED FOR ITS PURPOSE -- "an observed age far past the bound" -- never for its digits, which is the 22// distinction the magic-number ratchet's own refusal text draws and which nx_magic's auto-hoist 23// (K_MAGIC_27259) cannot make for you. ★KEPT AT THE MEASURED VALUE so T8 regresses against the real 24// incident rather than against a round number somebody chose afterwards. 25const RG_STALE_AGE_OBSERVED_S: i64 = 27259 26 27// The blind-alarm fixtures below are DERIVED from the bound and the lib's OWN multiplier, never written 28// as digits: if RM_BLIND_ALARM_WINDOWS is ever retuned, these fixtures move with it and the test cannot 29// silently stop testing the threshold it names. A literal 1800 here would be a second copy of the policy's 30// shape, and the two drift the moment one side changes -- the same defect as a hand-counted length beside 31// a string literal. 32const RG_MAX_AGE_S: i64 = 900 // the declared memvel freshness bound 33const RG_BLIND_ALARM_AGE_S: i64 = RG_MAX_AGE_S * RM_BLIND_ALARM_WINDOWS // DERIVED: exactly at the alarm 34const RG_BLIND_UNDER_ALARM_S: i64 = RG_BLIND_ALARM_AGE_S - 1 // DERIVED: one second short of it 35 36// (rg_row removed 2026-08-14: the shared base class renders the check rows now. A hand-rolled row 37// printer beside gv_check is the duplicate-ruler defect, and leaving it defined-but-uncalled would 38// show up as a fresh nx_unwired hit.) 39 40func main() -> i64 { 41 // ---- T1: the verdict ladder moves with the thresholds (data-driven, not hardcoded) ---- 42 // same measurement (swap 934 permil, the real reading from the incident), three threshold sets. 43 var t1: i64 = 0 44 let g: i64 = rm_verdict(934, 500, 0, 1, 940, 990, 250, 100, 3, 6) // below amber -> GREEN 45 let a: i64 = rm_verdict(934, 500, 0, 1, 700, 990, 250, 100, 3, 6) // over amber only -> AMBER 46 let r: i64 = rm_verdict(934, 500, 0, 1, 700, 850, 250, 100, 3, 6) // over red -> RED 47 if g == 0 { if a == 1 { if r == 2 { t1 = 1 } } } 48 49 // ---- T2 NON-VACUITY: unreachable thresholds must NOT flip the verdict ---- 50 // 934 permil swap, 23 leakers -- catastrophic in reality -- but no threshold can be crossed. 51 var t2: i64 = 0 52 if rm_verdict(934, 500, 23, 1, 9999, 9999, 0 - 1, 0 - 1, 9999, 9999) == 0 { t2 = 1 } 53 54 // ---- T3: EACH axis can raise the verdict on its own ---- 55 var t3: i64 = 0 56 let byswap: i64 = rm_verdict(900, 900, 0, 1, 700, 850, 250, 100, 3, 6) // swap alone -> RED 57 let byavail: i64 = rm_verdict(0, 50, 0, 1, 700, 850, 250, 100, 3, 6) // avail alone -> RED 58 let byleak: i64 = rm_verdict(0, 900, 7, 1, 700, 850, 250, 100, 3, 6) // leakers alone -> RED 59 if byswap == 2 { if byavail == 2 { if byleak == 2 { t3 = 1 } } } 60 61 // ---- T4: RESERVED-but-untouched is NOT a leak; COMMITTED is ---- 62 // (a) the real first-run false positive: 40.6 GiB reserved, ~1 MiB committed -> NOT a leaker. 63 // (b) a genuine leaker: monotonic address space AND 3.02 GiB actually committed -> IS a leaker. 64 // (c) monotonic but small -> below the floor -> NOT a leaker. 65 // (d) big and committed but VmSize != VmPeak (it has shrunk) -> NOT the fingerprint. 66 var t4: i64 = 0 67 let fp: i64 = rm_is_leaker(42581844, 42581844, 1024, 0, 262144) 68 let real: i64 = rm_is_leaker(6903268, 6903268, 161228, 2111640, 262144) 69 let small: i64 = rm_is_leaker(2668, 2668, 600, 0, 262144) 70 let shrunk: i64 = rm_is_leaker(1000000, 4000000, 500000, 500000, 262144) 71 if fp == 0 { if real == 1 { if small == 0 { if shrunk == 0 { t4 = 1 } } } } 72 73 // ---- T5: rm_field parses both shapes it must serve, and reports absence honestly ---- 74 var t5: i64 = 0 75 let b: *u8 = sys_mmap(512) 76 let s: *u8 = "Name:\tnx_hub_gw.elf\nVmPeak:\t 6903268 kB\nVmSize:\t 6903268 kB\nVmRSS:\t 161228 kB\nleak-min-kb = 262144\n" as *u8 77 var i: i64 = 0 78 while s[i] != (0 as u8) { b[i] = s[i]; i = i + 1 } 79 b[i] = 0 as u8 80 let vpk: i64 = rm_field(b, i, "VmPeak:" as *u8) 81 let vrs: i64 = rm_field(b, i, "VmRSS:" as *u8) 82 let cfg: i64 = rm_field(b, i, "leak-min-kb" as *u8) 83 let miss: i64 = rm_field(b, i, "VmSwap:" as *u8) 84 if vpk == 6903268 { if vrs == 161228 { if cfg == 262144 { if miss == 0 - 1 { t5 = 1 } } } } 85 86 // ---- T6: an UNOBSERVABLE leak axis contributes NOTHING, and the ONLY variable is that one bit ---- 87 // Same measurement, same thresholds, one flag apart. A rm_verdict that ignored leak_observed would 88 // return RED for BOTH of these and fail here. ★TWO ARMS ONE VARIABLE APART IS WHAT MAKES A RESULT 89 // ATTRIBUTABLE -- two tests that each isolate one signal do not prove discrimination between them. 90 var t6: i64 = 0 91 let seen: i64 = rm_verdict(0, 900, 7, 1, 700, 850, 250, 100, 3, 6) // 7 growers OBSERVED -> RED 92 let unseen: i64 = rm_verdict(0, 900, 7, 0, 700, 850, 250, 100, 3, 6) // the SAME 7, unobserved -> GREEN 93 if seen == 2 { if unseen == 0 { t6 = 1 } } 94 95 // ---- T7 neg-control-unobservable-is-not-a-green-vote ---- 96 // ★★★★★AN AXIS THAT CANNOT SEE MUST ABSTAIN, NOT ACQUIT. With the leak axis blind AND swap over 97 // its red threshold, the verdict must still be RED: the other axes are levels, a snapshot measures 98 // them exactly, and they still decide. A naive implementation that short-circuited to GREEN the 99 // moment the leak axis went unobservable would pass T6 and fail ONLY here -- which is the point. 100 var t7: i64 = 0 101 if rm_verdict(900, 900, 7, 0, 700, 850, 250, 100, 3, 6) == 2 { t7 = 1 } 102 103 // MIGRATED onto nx_gate_verdict (D001) 2026-08-14, in the FULL form -- deliberately NOT the 104 // generator's minimal form. nx_gate_dry_apply offered `ctr[0]=green; ctr[1]=1`, which makes the 105 // verdict readable but collapses FIVE teeth into ONE boolean: it reports passed 1/1, and a tooth 106 // that silently stopped running would still read GREEN. That is exactly the defect gv_ctr exists 107 // to prevent -- DECLARED MUST EQUAL EXECUTED BY CONSTRUCTION -- so the counter is driven per tooth 108 // by gv_check instead. ★★★★★★A ONE-STATE JUDGE CANNOT SEE A DROPPED CONJUNCT: nx_gate_green would 109 // have accepted the minimal form, because it only ever reads the verdict line. Reading the 110 // candidate is what caught it. This also retires the hardcoded /5 denominator, a magic number 111 // pinned to the tooth count that silently lies the moment a sixth tooth is added. 112 // ---- T8: the blind CLASSIFIER separates two states with OPPOSITE remedies ---- 113 // ★A beat that RAN AND WAS REFUSED and a beat that IS DEAD are indistinguishable from outside, and 114 // that indistinguishability IS the defect this closes. REFUSING -> shed load, the axis recovers by 115 // itself. DEAD -> the beat is broken, go fix it. Collapsing them into one word sent four lanes at 116 // four different mechanisms for the same symptom on 2026-08-21. 117 var t8: i64 = 0 118 let notblind: i64 = rm_blind_class(1, 232, 900) // measurement fresh -> not blind at all 119 let refusing: i64 = rm_blind_class(0, 232, 900) // no measurement, FRESH refusal stamp 120 let deadnostamp: i64 = rm_blind_class(0, 0 - 1, 900) // no refusal stamp has ever been written 121 let deadstale: i64 = rm_blind_class(0, RG_STALE_AGE_OBSERVED_S, 900) // the REAL 7.2 h reading, far past the bound 122 if notblind == 0 { if refusing == 1 { if deadnostamp == 2 { if deadstale == 2 { t8 = 1 } } } } 123 124 // ---- T9 ANTI-VACUITY: leak_observed DOMINATES, so this is not merely an age comparison ---- 125 // ★★★★★TWO ARMS ONE VARIABLE APART IS WHAT MAKES A RESULT ATTRIBUTABLE. An implementation that 126 // ignored leak_observed and only compared the age would pass every arm of T8 and fail ONLY here. 127 var t9: i64 = 0 128 let dom_a: i64 = rm_blind_class(1, 0 - 1, 900) // fresh measurement, NO stamp -> still NOT blind 129 let dom_b: i64 = rm_blind_class(0, 0 - 1, 900) // identical age, measurement gone -> DEAD 130 if dom_a == 0 { if dom_b == 2 { t9 = 1 } } 131 132 // ---- T10 neg-control-clock-skew-and-the-bound-pinned-on-both-sides ---- 133 // ★A NEGATIVE AGE IS CLOCK SKEW, NOT FRESHNESS: a future-stamped file must never read REFUSING, or 134 // it reads fresh forever -- the stale-fixture defect wearing a clock. The bound is pinned on BOTH 135 // sides so a later >= / > slip cannot pass silently. 136 var t10: i64 = 0 137 let skew: i64 = rm_blind_class(0, 0 - 5, 900) // future stamp -> DEAD, never REFUSING 138 let atbound: i64 = rm_blind_class(0, 900, 900) // exactly at the bound -> still counts as fresh 139 let overbound: i64 = rm_blind_class(0, 901, 900) // one second past -> DEAD 140 if skew == 2 { if atbound == 1 { if overbound == 2 { t10 = 1 } } } 141 142 // ---- T11: THE ALARM AN ABSTAINING AXIS OWES ---- 143 // ★Abstention is SAFE for the verdict and INVISIBLE to the operator, so a detector that goes blind 144 // raises nothing anywhere. rm_verdict is RIGHT to let UNOBSERVABLE cast no vote; rm_verdict_blind adds 145 // the missing half -- an alarm on the BLINDNESS ITSELF, never a leak claim about something unmeasured. 146 // TWO ARMS ONE VARIABLE APART: identical records, only the axis visibility differs. 147 var t11: i64 = 0 148 let quiet_seen: i64 = rm_verdict_blind(0, 900, 0, 1, 700, 850, 250, 100, 3, 6, 0, RG_MAX_AGE_S) 149 let quiet_blind: i64 = rm_verdict_blind(0, 900, 0, 0, 700, 850, 250, 100, 3, 6, RG_BLIND_ALARM_AGE_S, RG_MAX_AGE_S) 150 if quiet_seen == 0 { if quiet_blind == 1 { t11 = 1 } } 151 152 // ---- T12 neg-control-one-stale-window-is-still-only-abstention ---- 153 // ★max_age is already sized to absorb one FULL missed beat, so a single stale window is the transient 154 // miss the abstention already covers. Alarming there would leave the detector permanently amber on a 155 // healthy box, and a permanently-amber detector is one everyone learns to ignore. The bound is pinned 156 // on BOTH sides so a later >= / > slip cannot pass silently. 157 var t12: i64 = 0 158 let justunder: i64 = rm_verdict_blind(0, 900, 0, 0, 700, 850, 250, 100, 3, 6, RG_BLIND_UNDER_ALARM_S, RG_MAX_AGE_S) 159 let atalarm: i64 = rm_verdict_blind(0, 900, 0, 0, 700, 850, 250, 100, 3, 6, RG_BLIND_ALARM_AGE_S, RG_MAX_AGE_S) 160 if justunder == 0 { if atalarm == 1 { t12 = 1 } } 161 162 // ---- T13 neg-control-a-blind-axis-must-never-LOWER-a-verdict ---- 163 // ★The alarm may only RAISE. If it could lower, a dark LEADING axis would mask a red PRESSURE axis -- 164 // precisely the inversion that makes the safest verdict the most flattering one. Second arm pins clock 165 // skew: an unusable age IS a blindness and must alarm, not read as fresh forever. 166 var t13: i64 = 0 167 let redblind: i64 = rm_verdict_blind(900, 900, 0, 0, 700, 850, 250, 100, 3, 6, RG_BLIND_ALARM_AGE_S, RG_MAX_AGE_S) 168 let skewblind: i64 = rm_verdict_blind(0, 900, 0, 0, 700, 850, 250, 100, 3, 6, 0 - 5, RG_MAX_AGE_S) 169 if redblind == 2 { if skewblind == 1 { t13 = 1 } } 170 171 // ---- T14: THE TREND READER KEEPS THE TAIL OF AN OVER-CAP LOG (2026-09-02) ---- 172 // THE ONE TOOTH HERE THAT TOUCHES DISK, deliberately: the property under test IS file geometry (a log 173 // larger than the read cap), and no synthetic input can express it. Fixture assembled at RUNTIME under 174 // /tmp/nx_resmon_gate/ (the fixture-ratchet law), never a source literal. Planted: 3,000 rows whose 175 // worst= is an OLD process, then ONE final row whose worst= is NEWEST_ROW; cap = well under a quarter 176 // of the file. The head-bounded reader this replaces (measured live 2026-09-02: 65 frozen UNOBSERVABLE 177 // beats after resmon.log crossed 1 MiB) returned a window whose last line was a TORN old row. 178 var t14: i64 = 0 179 sys_mkdir("/tmp/nx_resmon_gate" as *u8, 493) 180 let fxp: *u8 = "/tmp/nx_resmon_gate/overcap.log" as *u8 181 let ffd: i64 = sys_openat_wr(fxp, 420) 182 if ffd >= 0 { 183 let row: *u8 = "RESMON swap_used_permil=900 mem_avail_permil=500 load1_centi=1500 worst_committed_kb=1000000 worst=old_row_process\n" as *u8 184 var rn: i64 = 0 185 while rn < 3000 { sys_write(ffd, row, rm_slen(row)); rn = rn + 1 } 186 let last: *u8 = "RESMON swap_used_permil=900 mem_avail_permil=500 load1_centi=1500 worst_committed_kb=2000000 worst=NEWEST_ROW\n" as *u8 187 sys_write(ffd, last, rm_slen(last)) 188 sys_close(ffd) 189 let fcap: i64 = 32768 190 let fbuf: *u8 = sys_mmap(fcap) 191 let fenv: *i64 = sys_mmap(64) as *i64 192 let fn: i64 = rm_trend_read_tail(fxp, fbuf, fcap, fenv) 193 // the retained window must END with the newest row, DECLARE truncation, report the true file size, 194 // and START on a record boundary (the torn first record trimmed) -- four conjuncts, one tooth. 195 var tailok: i64 = 0 196 if fn > 0 { if fenv[3] == 1 { if fenv[0] > fcap { 197 let needle: *u8 = "worst=NEWEST_ROW\n" as *u8 198 let nl: i64 = rm_slen(needle) 199 var m: i64 = 1 200 var k: i64 = 0 201 while k < nl { if fbuf[fn - nl + k] != needle[k] { m = 0 } k = k + 1 } 202 if m == 1 { if fbuf[0] == (82 as u8) { tailok = 1 } } 203 } } } 204 t14 = tailok 205 } 206 207 let ctr: *i64 = gv_ctr() 208 gv_head("nx_resmon_gate -- pressure + leak-census predicates (seq1005)" as *u8) 209 gv_check("T1-verdict-ladder-is-threshold-driven" as *u8, t1, ctr) 210 gv_check("T2-NONVACUITY-unreachable-stays-GREEN" as *u8, t2, ctr) 211 gv_check("T3-each-axis-can-raise-alone" as *u8, t3, ctr) 212 gv_check("T4-reserved-not-leak-committed-is" as *u8, t4, ctr) 213 gv_check("T5-field-parse-status-conf-and-absent" as *u8, t5, ctr) 214 gv_check("T6-unobservable-leak-axis-casts-no-vote" as *u8, t6, ctr) 215 gv_check("T7-neg-control-unobservable-is-not-a-green-vote" as *u8, t7, ctr) 216 gv_check("T8-blind-classifier-separates-REFUSING-from-DEAD" as *u8, t8, ctr) 217 gv_check("T9-ANTIVACUITY-leak-observed-dominates-not-just-age" as *u8, t9, ctr) 218 gv_check("T10-neg-control-clock-skew-is-DEAD-and-bound-pinned-both-sides" as *u8, t10, ctr) 219 gv_check("T11-a-blind-LEADING-axis-raises-an-alarm-of-its-own" as *u8, t11, ctr) 220 gv_check("T12-neg-control-one-stale-window-is-still-only-abstention" as *u8, t12, ctr) 221 gv_check("T13-neg-control-blindness-may-only-RAISE-never-lower-a-verdict" as *u8, t13, ctr) 222 gv_check("T14-trend-reader-keeps-the-TAIL-of-an-over-cap-log-and-declares-truncation" as *u8, t14, ctr) 223 // CANONICAL ANCHOR, LAST LINE, POSITIONAL (seq585). gv_last_line reads only the FINAL line, so the 224 // rich domain row above is preserved untouched and the machine-readable verdict rides alone here. 225 // ★FIX THE EMITTER, NEVER WIDEN THE READER -- widening is how an estate ends up with two readers 226 // and two spellings of success. Without this tail nothing can judge the gate: /api/promote refuses 227 // it as D001 and nx_gate_green cannot read its outcome, so flake and erosion stay invisible. 228 return gv_verdict("RESMON-GATE" as *u8, ctr, "the policy predicates in nx_resmon_lib, gated as PURE functions on synthetic inputs -- no /proc, no fixture, no clock. Each tooth states its own claim above; this note deliberately does NOT recite them, because a note that enumerates teeth goes stale the moment one is added and drifts toward understatement, which is the direction nobody audits" as *u8) 229}