code wiki / (root) / nx_degmode_lib.nx

nx_degmode_lib.nx source

↩ module page · 230 lines · 12097 B

1// nx_degmode_lib.nx -- GRACEFUL DEGRADATION AS A DECIDABLE FUNCTION, NOT A GROUND STOP. 2// 3// WHY THIS EXISTS (operator, 2026-09-03, after a day in which every build was refused): 4// "research as of september 2026 what estates do like the military when functionality is degraded to 5// still get the best they can get till hardware is avilable and then have it automatically recover". 6// 7// WHAT THE FIELD DOES, AND WHAT WE WERE DOING INSTEAD. The estate's admission is ONE load bar applied 8// to ALL work: `ba_verdict` returns GRANT or QUEUE and carries NO priority concept (grepped, absent). 9// So a one-line restore-capability fix and a 600-domain census sweep received the identical answer. 10// That is a GROUND STOP, and grounding for every defect is the exact failure mode the field's doctrine 11// exists to avoid: 12// - Safety-systems doctrine: graceful degradation means the priorities, triggers and behaviours are 13// designed UP FRONT and verified, so the degraded state is DELIBERATE AND AUDITABLE, not accidental. 14// Ours was accidental -- no declared class, no clock, no exercise. 15// - Aviation's Minimum Equipment List: an aircraft is DISPATCHED with named items inoperative under 16// named limitations, and every deferral carries a REPAIR CATEGORY WITH A CLOCK (A specified, B 3 17// days, C 10 days, D 120 days). Permitted dispatch becomes a CONTROLLED DEFERRAL; only an 18// impermissible one grounds the aircraft. Our defect ran ~a day with no category and nothing 19// counting, which is how a day passes without anyone deciding. 20// - Degraded-ops training doctrine: workarounds are learned in an exercise, not on the battlefield. 21// Our degraded path had never been exercised, which is why that day was archaeology. 22// 23// THE THREE DECISIONS THIS LIB MAKES, and each is DATA rather than a literal (rules 11 and 17): 24// dm_admit(class, health) -- shed by ESSENTIALITY instead of shutting the door on everyone 25// dm_deferral_state(age, limit) -- the MEL clock, so a degraded state cannot run silently forever 26// dm_recover(samples, ...) -- the automatic re-arm, with the flap guard the field insists on 27// 28// THE CLASS IS AN EXPLICIT DECLARATION, NEVER A NAME MATCH. This estate has been bitten repeatedly by 29// classifiers keyed on a name substring (a DAEMON read as a gate because of a `_gate` suffix; a gate 30// fleet invisible because it is declared `oracle`), and its own conclusion each time was that the fix is 31// an explicit declaration, never a rename. So dm_class_of reads a declaration table and an UNDECLARED 32// target gets DM_E3 -- the LEAST essential class -- and that default is ANNOUNCED by dm_class_declared 33// rather than silently applied. An unknown input must never resolve to the PERMISSIVE value: that is 34// exactly the live `pr_mode` defect, where a mistyped route mode silently downgrades fail-closed to open. 35// 36// UNOBSERVABLE ABSTAINS FROM TIGHTENING, IT DOES NOT ACQUIT AND IT DOES NOT BLOCK. 37// Most hosts have no flashcache at all, so treating IOADM_UNOBS as RED would refuse every build on every 38// machine that never had the fault -- a false-positive generator that everyone would disable within a 39// day. This axis therefore contributes NOTHING when it cannot see: dm_admit returns admit for every 40// class, and the CALLER'S EXISTING LOAD BAR IS UNCHANGED AND STILL APPLIES. The axis declining to 41// tighten is not the same as the system declining to refuse. 42// 43// PROVEN 13/13 GREEN 2026-09-03. Harness bite INCONCLUSIVE for a NAMED reason (the laptop nx_gate_bite 44// runs only operators 1/2a/2b and its comparison sites never reached dm_admit's decision line), so the 45// bite was done BY HAND instead: planting the ground-stop-removal defect -- RED admits every class -- 46// took the gate 13/13 GREEN to 11/13 RED with exactly two teeth failing, and the restore was byte- 47// identical by cmp. A harness INCONCLUSIVE is a fact about the tester, never evidence about the gate. 48// 49// license_tier: ORIGINAL No hw writes (Rule 26). LIB (no main). 50import "nx_syscalls.nx" 51 52// health inputs -- deliberately the SAME numbering ioa_dmcache returns, so no translation layer can 53// drift between the sensor and the policy that reads it. 54const DM_H_GREEN: i64 = 0 55const DM_H_RED: i64 = 1 56const DM_H_AMBER: i64 = 2 57const DM_H_UNOBS: i64 = 3 58 59// essentiality ladder. LOWER IS MORE ESSENTIAL. 60const DM_E1: i64 = 1 // restore-capability: fixes to the fault itself, safety fixes, the rollback path 61const DM_E2: i64 = 2 // in-flight work: the rung a seat is currently closing 62const DM_E3: i64 = 3 // bulk: censuses, sweeps, fleet campaigns 63const DM_E_UNDECLARED: i64 = DM_E3 // fail-safe: an undeclared target is the LEAST essential 64 65const DM_ADMIT: i64 = 1 66const DM_DEFER: i64 = 0 67 68const DM_CONF: *u8 = "knowledge/degmode.conf" 69const DM_CONF_ALT: *u8 = "../knowledge/degmode.conf" 70const DM_CONF_CAP: i64 = 65536 71const DM_NAMEMAX: i64 = 256 72 73// MEL repair categories, in seconds. Category A is operator-specified and therefore has no constant. 74const DM_CAT_B_S: i64 = 259200 // 3 days 75const DM_CAT_C_S: i64 = 864000 // 10 days 76const DM_CAT_D_S: i64 = 10368000 // 120 days 77 78// recovery guard. Both are POLICY, declared here and overridable from conf by the caller. 79const DM_RECOVER_CONSECUTIVE: i64 = 3 // consecutive clear samples required before re-arming 80const DM_RECOVER_MIN_SAMPLES: i64 = 4 // minimum observations before the question may be answered 81 82func dm_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 83 84// ---- ADMISSION BY ESSENTIALITY ----------------------------------------------------------------- 85// The whole point: keep the most important work moving instead of stopping everything. 86func dm_admit(class: i64, health: i64) -> i64 { 87 // The axis cannot see -> it contributes nothing. The caller's load bar still decides. 88 if health == DM_H_UNOBS { return DM_ADMIT } 89 if health == DM_H_GREEN { return DM_ADMIT } 90 if health == DM_H_AMBER { 91 if class <= DM_E2 { return DM_ADMIT } 92 return DM_DEFER 93 } 94 // RED: caching is off and every write hits the array. Only restore-capability work proceeds -- 95 // which deliberately includes the build of the organ that diagnoses the fault. 96 if class <= DM_E1 { return DM_ADMIT } 97 return DM_DEFER 98} 99 100// ---- CLASS RESOLUTION: DECLARATION ONLY -------------------------------------------------------- 101// A row is `class|<exact-target-name>|<E1|E2|E3>`. Exact match on the WHOLE name, never a substring: 102// a substring rule would make nx_cachewatch_gate inherit nx_cachewatch's class by accident. 103func dm_conf_read(buf: *u8, cap: i64) -> i64 { 104 var fd: i64 = sys_openat_rd(DM_CONF) 105 if fd < 0 { fd = sys_openat_rd(DM_CONF_ALT) } 106 if fd < 0 { return 0 - 1 } 107 var got: i64 = 0 108 var go: i64 = 1 109 while go == 1 { 110 if got >= cap { go = 0 } else { 111 let r: i64 = sys_read(fd, (buf as i64 + got) as *u8, cap - got) 112 if r <= 0 { go = 0 } else { got = got + r } 113 } 114 } 115 sys_close(fd) 116 return got 117} 118// PLAIN prefix test -- no terminator required. Used for the row marker `class|`, where the very next 119// byte is the target name rather than a separator. 120// THE FIRST DRAFT USED dm_field_eq FOR THIS AND NO ROW EVER MATCHED: that helper demands a field 121// terminator after the match, which is right for the NAME and wrong for a prefix. Every lookup then 122// fell through to the undeclared default -- and because that default is E3, the failure was SILENT AND 123// SAFE-LOOKING: everything simply became least-essential. Caught only by T7 asserting a declared class 124// reads back as declared. A parser whose failure mode is the conservative default is the hardest kind 125// to notice. 126func dm_starts(buf: *u8, n: i64, at: i64, s: *u8) -> i64 { 127 let m: i64 = dm_slen(s) 128 if at + m > n { return 0 } 129 var i: i64 = 0 130 while i < m { 131 if buf[at + i] != s[i] { return 0 } 132 i = i + 1 133 } 134 return 1 135} 136// does buf[at..] begin with `s` and end exactly at a field separator or newline? 137func dm_field_eq(buf: *u8, n: i64, at: i64, s: *u8) -> i64 { 138 let m: i64 = dm_slen(s) 139 if at + m > n { return 0 } 140 var i: i64 = 0 141 while i < m { 142 if buf[at + i] != s[i] { return 0 } 143 i = i + 1 144 } 145 let nxt: i64 = at + m 146 if nxt >= n { return 1 } 147 let c: i64 = buf[nxt] as i64 148 if c == 124 { return 1 } // '|' 149 if c == 10 { return 1 } // newline 150 if c == 13 { return 1 } 151 return 0 152} 153// Returns the declared class, or 0 when the target is UNDECLARED. 0 is distinguishable from every 154// real class on purpose: the caller must be able to SAY that it defaulted. 155func dm_class_declared(buf: *u8, n: i64, target: *u8) -> i64 { 156 var i: i64 = 0 157 var found: i64 = 0 158 while i < n { 159 var sol: i64 = 0 160 if i == 0 { sol = 1 } else { if buf[i - 1] == (10 as u8) { sol = 1 } } 161 if sol == 1 { 162 if found == 0 { 163 if dm_starts(buf, n, i, "class|" as *u8) == 1 { 164 let np: i64 = i + 6 165 if dm_field_eq(buf, n, np, target) == 1 { 166 let cp: i64 = np + dm_slen(target) + 1 167 if cp < n { 168 if dm_field_eq(buf, n, cp, "E1" as *u8) == 1 { found = DM_E1 } 169 if dm_field_eq(buf, n, cp, "E2" as *u8) == 1 { found = DM_E2 } 170 if dm_field_eq(buf, n, cp, "E3" as *u8) == 1 { found = DM_E3 } 171 } 172 } 173 } 174 } 175 } 176 i = i + 1 177 } 178 return found 179} 180// The resolving wrapper. UNDECLARED -> least essential, and the caller learns which happened by 181// calling dm_class_declared itself. Never returns the permissive value for an unknown input. 182func dm_class_of(buf: *u8, n: i64, target: *u8) -> i64 { 183 let d: i64 = dm_class_declared(buf, n, target) 184 if d == 0 { return DM_E_UNDECLARED } 185 return d 186} 187 188// ---- THE MEL CLOCK ----------------------------------------------------------------------------- 189// A deferral without an expiry is how a degraded state runs for a day with nobody deciding. `limit_s` 190// comes from the declared repair category; 0 means Category A (operator-specified) and is reported 191// UNSET rather than treated as infinite. 192const DM_CLOCK_UNSET: i64 = 0 - 1 193const DM_CLOCK_LIVE: i64 = 0 194const DM_CLOCK_EXPIRED: i64 = 1 195func dm_deferral_state(age_s: i64, limit_s: i64) -> i64 { 196 if limit_s <= 0 { return DM_CLOCK_UNSET } 197 if age_s < 0 { return DM_CLOCK_UNSET } 198 if age_s >= limit_s { return DM_CLOCK_EXPIRED } 199 return DM_CLOCK_LIVE 200} 201 202// ---- AUTOMATIC RECOVERY, WITH THE GUARD THE FIELD INSISTS ON ----------------------------------- 203// The estate's own record is emphatic that automated action on a measured signal is DANGEROUS: in the 204// Oct-2025 us-east-1 event, health checks alternating between failing and healthy drove automatic 205// failover that removed HEALTHY capacity, and the fix that worked was disabling the automation. 206// So re-arming requires all four of: 207// (a) enough observations to answer at all -- the empty-set denominator 208// (b) the most recent `need` samples ALL clear -- the short window, so it cannot latch on one blip 209// (c) at least one NON-clear sample before them -- proof there was a fault to recover FROM, so a 210// steady-GREEN host never fires a spurious "recovery" 211// (d) no clear/not-clear alternation inside the window -- the flap guard 212// samples[] holds the most recent `n` health readings in chronological order, oldest first. 213func dm_recover(samples: *i64, n: i64, need: i64, min_n: i64) -> i64 { 214 if need <= 0 { return 0 } 215 if n < min_n { return 0 } 216 if n < need + 1 { return 0 } 217 var i: i64 = n - need 218 while i < n { 219 if samples[i] != DM_H_GREEN { return 0 } 220 i = i + 1 221 } 222 var saw_fault: i64 = 0 223 var j: i64 = 0 224 while j < n - need { 225 if samples[j] != DM_H_GREEN { saw_fault = 1 } 226 j = j + 1 227 } 228 if saw_fault == 0 { return 0 } 229 return 1 230}