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}