code wiki / _hdl_build / nx_envelope_audit_gate.nx

nx_envelope_audit_gate.nx source

↩ module page · 306 lines · 17355 B

1// nx_envelope_audit_gate.nx -- TEETH FOR THE SILENT-CAP DETECTOR, because on 2026-08-20 it HAD ONE. 2// 3// WHY THIS GATE EXISTS. nx_envelope_audit is the estate's enforcer of the scale-law ("every tool DECLARES 4// its envelope IN ITS OUTPUT -- silent capping is forbidden BY CONSTRUCTION"). It shipped for weeks with a 5// row-cap gate wrapping its whole per-row body and a row counter that only incremented INSIDE that gate, so 6// every allowlist row past the cap was dropped with no counter and no marker -- and its dogfood line then 7// printed the cap as a HAND-TYPED literal, which reads as a population. Measured: it reported rows=512 8// against a tool_allowlist.conf whose true data-row count is over a thousand. 9// ***THE ENFORCER COMMITTED THE DEFECT IT ENFORCES, AND ITS OWN OUTPUT WAS THE ALIBI.*** 10// A green that never had a corresponding red is unverified, so every tooth below is paired with the input 11// that must make it fail. 12// 13// HERMETIC BY CONSTRUCTION. The subject resolves its probe dirs (buildroot/runtime/_hdl_build, then 14// buildroot/runtime) RELATIVE TO CWD, so this gate builds a complete throwaway probe tree under 15// /tmp/nx_envelope_audit_gate/ and chdirs into it. Nothing here touches a production path, nothing shares a 16// fixture with a beat, and the fixtures are rebuilt every run so the gate is idempotent -- a gate that is 17// not idempotent reports on its first run and lies about every run after. 18// The fixture SOURCES are assembled at RUNTIME, never stored as files in the tree, because a detector that 19// scans source will otherwise find its own test fixture -- and writing the pattern in a comment re-arms 20// that trap, since prose is source bytes too. 21// 22// SUBJECT: the DEPLOYED nx_envelope_audit elf (serving root, then _offc, then a local _build). If none 23// resolves the gate SKIPs via gv_need -- "I could not look" is not "it is broken". 24// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 25import "nx_syscalls.nx" 26import "nx_gate_verdict.nx" 27import "nx_gatekit_lib.nx" 28 29const EG_DIR: *u8 = "/tmp/nx_envelope_audit_gate" 30const EG_BR: *u8 = "/tmp/nx_envelope_audit_gate/buildroot" 31const EG_RT: *u8 = "/tmp/nx_envelope_audit_gate/buildroot/runtime" 32const EG_HDL: *u8 = "/tmp/nx_envelope_audit_gate/buildroot/runtime/_hdl_build" 33const EG_CONF: *u8 = "/tmp/nx_envelope_audit_gate/f.conf" 34const EG_SMALL: *u8 = "/tmp/nx_envelope_audit_gate/small.conf" 35const EG_HUGE: *u8 = "/tmp/nx_envelope_audit_gate/huge.conf" 36const EG_O1: *u8 = "/tmp/nx_envelope_audit_gate/o1.log" 37const EG_O2: *u8 = "/tmp/nx_envelope_audit_gate/o2.log" 38const EG_O3: *u8 = "/tmp/nx_envelope_audit_gate/o3.log" 39 40const EG_S1: *u8 = "/tmp/nx_envelope_audit_gate/buildroot/runtime/_hdl_build/egsilent.nx" 41const EG_S2: *u8 = "/tmp/nx_envelope_audit_gate/buildroot/runtime/_hdl_build/egdecl.nx" 42const EG_S3: *u8 = "/tmp/nx_envelope_audit_gate/buildroot/runtime/_hdl_build/egcmt.nx" 43const EG_S4: *u8 = "/tmp/nx_envelope_audit_gate/buildroot/runtime/_hdl_build/egplain.nx" 44 45const EG_SUBJ1: *u8 = "/volume1/homes/elderwesto/nishihost/nx_envelope_audit.elf" 46const EG_SUBJ2: *u8 = "/volume1/homes/elderwesto/nishihost/_offc/nx_envelope_audit.elf" 47const EG_SUBJ3: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/_build/nx_envelope_audit.sov.elf" 48 49// FIXTURE SHAPE -- the expected counts are DERIVED from these, never re-typed beside them, because a 50// hand-counted expectation beside a generator is a second copy of the generator's shape and the two drift. 51// ⚠ THE FIXTURE SIZE *IS* THE STRENGTH OF THE ROW-CAP TOOTH, AND IT WAS WRONG ON THE FIRST TRY. 52// Measured 2026-08-20: with 100 silent rows this gate went GREEN 12/12 against a mutant that had the row 53// cap RESTORED -- because 117 rows never reached a cap of 512. A fixture the defect cannot fail is not a 54// test, and the green it produces is indistinguishable from a green earned. The count below is therefore 55// larger than the LIVE tool_allowlist.conf row count, so the tooth proves "no fixed row cap at or below 56// this fixture's size binds" -- which is a BOUND, and it is stated here rather than implied. 57// It is deliberately NOT written as "512 + margin": a hand-typed copy of a cap that has been DELETED is 58// still a second copy of that cap's shape, and it would silently stop covering a smaller future cap. 59const EG_N_SILENT: i64 = 1200 60const EG_N_DECL: i64 = 7 61const EG_N_CMT: i64 = 5 62const EG_N_PLAIN: i64 = 3 63const EG_N_MISS: i64 = 2 64// Rows in the SMALL conf: deliberately fewer than the subject's list cap so the prefix marker must be 65// ABSENT -- the good half of the bite. Two, so the tooth is not testing an empty set. 66const EG_N_SMALL: i64 = 2 67// Enough rows to push the allowlist past the subject's own EA_ALLOWCAP and force its PARTIAL path. 68const EG_N_HUGE: i64 = 14000 69 70const EG_CAPBUF: i64 = 1048576 71const EG_CONFBUF: i64 = 2097152 72const EG_PATHB: i64 = 512 73const EG_TAB: i64 = 9 74const EG_NL: i64 = 10 75const EG_HASH: i64 = 35 76 77func eg_wr(path: *u8, buf: *u8, n: i64) -> i64 { 78 let fd: i64 = sys_openat_wr(path, GV_MODE_644) 79 if fd < 0 { return 0 - 1 } 80 gk_write_all(fd, buf, n) 81 sys_close(fd) 82 return n 83} 84// one allowlist row: <name><TAB>/x/<base>.elf<TAB>GREEN<NL>. TAB and NL are CONSTRUCTED as bytes: a bare 85// control character inside a string literal is ambiguous to the nx lexer, and the '#' below cannot appear 86// in a literal at all. 87func eg_row(b: *u8, o: i64, nm: *u8, idx: i64, base: *u8) -> i64 { 88 var p: i64 = gk_cat(b, o, nm) 89 p = gk_catn(b, p, idx) 90 b[p] = EG_TAB as u8; p = p + 1 91 p = gk_cat(b, p, "/x/" as *u8) 92 p = gk_cat(b, p, base) 93 p = gk_cat(b, p, ".elf" as *u8) 94 b[p] = EG_TAB as u8; p = p + 1 95 p = gk_cat(b, p, "GREEN" as *u8) 96 b[p] = EG_NL as u8; p = p + 1 97 return p 98} 99func eg_rows(b: *u8, o: i64, nm: *u8, base: *u8, cnt: i64) -> i64 { 100 var p: i64 = o 101 var i: i64 = 0 102 while i < cnt { p = eg_row(b, p, nm, i + 1, base); i = i + 1 } 103 return p 104} 105// a comment row the subject must NOT count 106func eg_hashrow(b: *u8, o: i64) -> i64 { 107 var p: i64 = o 108 b[p] = EG_HASH as u8; p = p + 1 109 p = gk_cat(b, p, " a comment row that must never be counted" as *u8) 110 b[p] = EG_NL as u8; p = p + 1 111 return p 112} 113// first integer following an ANCHORED needle. Anchors carry their punctuation so a field name repeated in 114// prose or in the partition line cannot be read as the answer -- a parser that matches the DATA instead of 115// the REPORT LINE is how a census reports verdicts its own organ cannot emit. 116func eg_num_after(buf: *u8, n: i64, needle: *u8) -> i64 { 117 let p: i64 = gk_out_pos(buf, n, needle) 118 if p < 0 { return 0 - 1 } 119 var i: i64 = p + gk_len(needle) 120 var v: i64 = 0 121 var got: i64 = 0 122 while i < n { 123 let c: i64 = buf[i] as i64 124 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); got = 1; i = i + 1 } else { i = n } } else { i = n } 125 } 126 if got == 0 { return 0 - 1 } 127 return v 128} 129// LAST non-empty line, by POSITION. Positional anchoring beats textual matching wherever the output is 130// untrusted: the subject quotes field names in its own prose, so any textual anchor can be matched by data. 131// Separate cursor, explicit flag: a loop that exits by writing a sentinel INTO the variable it is 132// searching for erases the answer, and that idiom is exactly what nx_srclint hunts. 133func eg_last_line_is(buf: *u8, n: i64, want: *u8) -> i64 { 134 var e: i64 = n 135 var go: i64 = 1 136 while go == 1 { 137 if e <= 0 { go = 0 } else { if buf[e-1] == (EG_NL as u8) { e = e - 1 } else { go = 0 } } 138 } 139 if e <= 0 { return 0 } 140 var s: i64 = e 141 var go2: i64 = 1 142 while go2 == 1 { 143 if s <= 0 { go2 = 0 } else { if buf[s-1] == (EG_NL as u8) { go2 = 0 } else { s = s - 1 } } 144 } 145 let m: i64 = gk_len(want) 146 if e - s < m { return 0 } 147 var j: i64 = 0 148 var ok: i64 = 1 149 while j < m { if buf[s+j] != want[j] { ok = 0; j = m } else { j = j + 1 } } 150 return ok 151} 152func main(argc: i64, argv: *i64) -> i64 { 153 let ctr: *i64 = gv_ctr() 154 gv_head("=== nx_envelope_audit_gate -- the silent-cap detector must not have a silent cap ===" as *u8) 155 156 // ---- SUBJECT RESOLUTION (probe, never assume; an absent artifact is indistinguishable from a dead 157 // server unless you stat the binary you are about to fork) 158 let subj: *u8 = sys_mmap(EG_PATHB) 159 var have: i64 = 0 160 if gk_exists(EG_SUBJ1) == 1 { gk_cat(subj, 0, EG_SUBJ1); have = 1 } 161 if have == 0 { if gk_exists(EG_SUBJ2) == 1 { gk_cat(subj, 0, EG_SUBJ2); have = 1 } } 162 if have == 0 { if gk_exists(EG_SUBJ3) == 1 { gk_cat(subj, 0, EG_SUBJ3); have = 1 } } 163 if gv_need("a deployed nx_envelope_audit elf to fork" as *u8, have, ctr) == 0 { 164 return gv_verdict("nx_envelope_audit_gate" as *u8, ctr, "SKIPPED: no deployed subject to fork -- I could not look, which is not a finding about the subject" as *u8) 165 } 166 167 // ---- FIXTURE TREE (rebuilt every run: idempotent by construction) 168 gk_mkdir(EG_DIR); gk_mkdir(EG_BR); gk_mkdir(EG_RT); gk_mkdir(EG_HDL) 169 // a BOUNDED source with no declaration marker anywhere -> SILENT-CAP CANDIDATE 170 gk_write(EG_S1, "const Z_CAP: i64 = 4096\nfunc f() -> i64 { return Z_CAP }\n" as *u8) 171 // a BOUNDED source that EMITS a declaration marker in code -> DECLARING 172 gk_write(EG_S2, "const Z_CAP: i64 = 4096\nfunc f() -> i64 { puts(\"scanned=\") return Z_CAP }\n" as *u8) 173 // a BOUNDED source whose ONLY declaration marker sits in a COMMENT -> must stay a CANDIDATE 174 gk_write(EG_S3, "const Z_CAP: i64 = 4096\n// envelope: prose documents a bound, it does not emit one\nfunc f() -> i64 { return Z_CAP }\n" as *u8) 175 // no bound consts at all -> UNBOUNDED-OR-NA 176 gk_write(EG_S4, "func f() -> i64 { return 1 }\n" as *u8) 177 178 let cb: *u8 = sys_mmap(EG_CONFBUF) 179 var p: i64 = eg_hashrow(cb, 0) 180 p = eg_rows(cb, p, "s" as *u8, "egsilent" as *u8, EG_N_SILENT) 181 p = eg_rows(cb, p, "d" as *u8, "egdecl" as *u8, EG_N_DECL) 182 p = eg_rows(cb, p, "c" as *u8, "egcmt" as *u8, EG_N_CMT) 183 p = eg_rows(cb, p, "p" as *u8, "egplain" as *u8, EG_N_PLAIN) 184 p = eg_rows(cb, p, "m" as *u8, "egnosuch" as *u8, EG_N_MISS) 185 eg_wr(EG_CONF, cb, p) 186 let ps: i64 = eg_rows(cb, 0, "s" as *u8, "egsilent" as *u8, EG_N_SMALL) 187 eg_wr(EG_SMALL, cb, ps) 188 let ph: i64 = eg_rows(cb, 0, "z" as *u8, "egplain" as *u8, EG_N_HUGE) 189 eg_wr(EG_HUGE, cb, ph) 190 191 // The subject resolves its probe dirs relative to CWD, so become the fixture tree. 192 sys_chdir(EG_DIR) 193 194 let o1: *u8 = sys_mmap(EG_CAPBUF) 195 let o2: *u8 = sys_mmap(EG_CAPBUF) 196 let o3: *u8 = sys_mmap(EG_CAPBUF) 197 let n1: *i64 = sys_mmap(GV_CTR_BYTES) 198 let n2: *i64 = sys_mmap(GV_CTR_BYTES) 199 let n3: *i64 = sys_mmap(GV_CTR_BYTES) 200 // gk_run tests each optional arg against NULL, not against an empty string -- passing "" would hand 201 // the subject two empty argv elements it never asked for. 202 let rc1: i64 = gk_run_capture(subj, EG_CONF, EG_O1, 0 as *u8, 0 as *u8, o1, EG_CAPBUF, n1) 203 let rc2: i64 = gk_run_capture(subj, EG_SMALL, EG_O2, 0 as *u8, 0 as *u8, o2, EG_CAPBUF, n2) 204 let rc3: i64 = gk_run_capture(subj, EG_HUGE, EG_O3, 0 as *u8, 0 as *u8, o3, EG_CAPBUF, n3) 205 let c1: i64 = n1[0] 206 let c2: i64 = n2[0] 207 let c3: i64 = n3[0] 208 209 // ---- T1 ANTI-VACUITY, FIRST. A census that produced nothing has failed, not passed -- and every 210 // assertion below is read out of this capture, so a green here is the precondition for the rest 211 // meaning anything at all. 212 var t1: i64 = 0 213 if c1 > 0 { if gk_out_has(o1, c1, "ENVELOPE-AUDIT (F227 scale-law sweep) rows=" as *u8) == 1 { t1 = 1 } } 214 gv_check("anti-vacuity-subject-ran-and-emitted-its-report-header" as *u8, t1, ctr) 215 216 let rows: i64 = eg_num_after(o1, c1, ") rows=" as *u8) 217 let decl: i64 = eg_num_after(o1, c1, " declaring=" as *u8) 218 let sil: i64 = eg_num_after(o1, c1, " silent_cap_candidates=" as *u8) 219 let una: i64 = eg_num_after(o1, c1, " unbounded_or_na=" as *u8) 220 let mis: i64 = eg_num_after(o1, c1, " name_probe_miss=" as *u8) 221 222 // PRINT THE VALUES, NOT JUST PASS/FAIL: a gate that reports a boolean cannot say why, and both 223 // vacuous teeth ever found in this estate were caught by a diagnostic dump, never by the verdict 224 // vector. The fixture expectation is printed beside the observation so the BOUND of the row-cap 225 // claim is visible to the reader without opening this source. 226 gv_puts(" [diag] fixture rows=" as *u8); gv_num(EG_N_SILENT + EG_N_DECL + EG_N_CMT + EG_N_PLAIN + EG_N_MISS) 227 gv_puts(" observed rows=" as *u8); gv_num(rows) 228 gv_puts(" declaring=" as *u8); gv_num(decl) 229 gv_puts(" silent=" as *u8); gv_num(sil) 230 gv_puts(" unbounded=" as *u8); gv_num(una) 231 gv_puts(" miss=" as *u8); gv_num(mis) 232 gv_puts(" rc1=" as *u8); gv_num(rc1) 233 gv_puts(" rc3=" as *u8); gv_num(rc3) 234 gv_puts("\n" as *u8) 235 236 // ---- T2 THE ROW-CAP REGRESSION TOOTH. The fixture is deliberately larger than the cap that used to 237 // bind, so a reinstated row cap reports its own cap here instead of the population. 238 let want_rows: i64 = EG_N_SILENT + EG_N_DECL + EG_N_CMT + EG_N_PLAIN + EG_N_MISS 239 var t2: i64 = 0 240 if rows == want_rows { t2 = 1 } 241 gv_check("every-data-row-is-scanned--rows-equals-the-population-not-a-cap" as *u8, t2, ctr) 242 243 // ---- T3 the hash row must not be counted. The conf carries exactly one, so a subject that counted 244 // comment rows would read one too many and this tooth alone would catch it. 245 var t3: i64 = 0 246 if rows == want_rows { if c2 > 0 { if eg_num_after(o2, c2, ") rows=" as *u8) == EG_N_SMALL { t3 = 1 } } } 247 gv_check("neg-control-a-hash-comment-row-is-NOT-counted-as-a-tool" as *u8, t3, ctr) 248 249 // ---- T4 the partition must sum, and the subject must SAY it sums. A partition you cannot reconcile 250 // is a leak, not a measurement. 251 var t4: i64 = 0 252 if decl + sil + una + mis == rows { if gk_out_has(o1, c1, "RECONCILES" as *u8) == 1 { t4 = 1 } } 253 gv_check("partition-sums-to-rows-and-the-subject-declares-it" as *u8, t4, ctr) 254 255 // ---- T5 the comment-only-marker source must land in CANDIDATES, not DECLARING. This is the tooth 256 // that keeps ea_has_code honest: a marker in a comment DOCUMENTS an envelope, it does not EMIT one. 257 var t5: i64 = 0 258 if decl == EG_N_DECL { if sil == EG_N_SILENT + EG_N_CMT { t5 = 1 } } 259 gv_check("neg-control-a-declaration-marker-inside-a-COMMENT-does-NOT-count-as-declaring" as *u8, t5, ctr) 260 261 // ---- T6 the unbounded and missing classes are not swept into a neighbour 262 var t6: i64 = 0 263 if una == EG_N_PLAIN { if mis == EG_N_MISS { t6 = 1 } } 264 gv_check("unbounded-and-name-probe-miss-are-their-own-buckets" as *u8, t6, ctr) 265 266 // ---- T7 BITE on the prefix marker: it must FIRE when the list is a prefix of its count, and stay 267 // SILENT when the list is complete. A marker that fires on everything discriminates nothing. 268 let pm: *u8 = "PREFIX OF ITS OWN COUNT" as *u8 269 var fired_bad: i64 = 0 270 var fired_good: i64 = 0 271 if gk_out_has(o1, c1, pm) == 1 { fired_bad = 1 } 272 if c2 > 0 { if gk_out_has(o2, c2, pm) == 1 { fired_good = 1 } } 273 gv_bite("prefix-of-its-own-count-marker" as *u8, fired_bad, fired_good, ctr) 274 275 // ---- T8 an allowlist larger than the subject's own read cap must REFUSE to publish a confident 276 // distribution: non-zero exit AND the word PARTIAL. A zero from an incomplete scan is still a floor. 277 var t8: i64 = 0 278 if rc3 != 0 { if gk_out_has(o3, c3, "verdict=PARTIAL" as *u8) == 1 { t8 = 1 } } 279 gv_check("oversize-allowlist-exits-NON-ZERO-and-declares-PARTIAL" as *u8, t8, ctr) 280 281 // ---- T9 the positive control for T8. Without it, a subject that refused EVERYTHING would score full 282 // marks on T8: a guard that refuses everything passes every negative test. 283 var t9: i64 = 0 284 if rc1 == 0 { if gk_out_has(o1, c1, "verdict=COMPLETE" as *u8) == 1 { t9 = 1 } } 285 gv_check("positive-control-a-COVERED-run-exits-ZERO-and-declares-COMPLETE" as *u8, t9, ctr) 286 287 // ---- T10 the coverage verdict must be the LAST line, because every positional reader in the estate 288 // takes the final line and the subject quotes its own field names in prose above it. 289 var t10: i64 = 0 290 if eg_last_line_is(o1, c1, "ENVELOPE-AUDIT COVERAGE" as *u8) == 1 { t10 = 1 } 291 gv_check("coverage-verdict-is-the-LAST-line-by-position" as *u8, t10, ctr) 292 293 // ---- T11 the declared caps must be DERIVED from the consts they bound. A hand-typed copy of a cap is 294 // a second copy of that cap's shape, and the two drift silently. 295 var t11: i64 = 0 296 if gk_out_has(o1, c1, "allow_cap=" as *u8) == 1 { if gk_out_has(o1, c1, "coverage_complete=" as *u8) == 1 { if gk_out_has(o1, c1, "list_cap=" as *u8) == 1 { t11 = 1 } } } 297 gv_check("envelope-declares-allow_cap-coverage_complete-and-list_cap" as *u8, t11, ctr) 298 299 // ---- T12 rc2 is the small-conf control: it must also run clean, so T3 and T7's good half rest on a 300 // run that actually happened rather than on an empty capture. 301 var t12: i64 = 0 302 if rc2 == 0 { if c2 > 0 { t12 = 1 } } 303 gv_check("fixture-reached-its-condition-the-small-conf-run-produced-output" as *u8, t12, ctr) 304 305 return gv_verdict("nx_envelope_audit_gate" as *u8, ctr, "hermetic probe tree under /tmp; every expected count DERIVED from the fixture constants that generate it" as *u8) 306}