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}