code wiki / (root) / nx_srcreach_gate.nx

nx_srcreach_gate.nx source

↩ module page · 174 lines · 10676 B

1// nx_srcreach_gate.nx -- THE GATE FOR THE SOURCE REGISTRY READER AND THE PACE BUDGET (/compare/researchreach RR1, RR3). 2// 3// IN-PROCESS ON PURPOSE. It imports nx_srcreg_lib and calls sr_classify and sr_pace directly rather than forking a 4// deployed elf, for three reasons: it is deterministic (no network, no host in the loop, so it cannot flake), it is 5// fast enough to sit on a roster, and it is MUTATION-SENSITIVE -- a change to the classifier or the budget arithmetic 6// shows up here immediately, which is what makes nx_gate_bite able to say anything about it at all. 7// 8// WHY THIS GATE EXISTS: nx_srcreach decides which of the estate's declared research sources are usable and how many 9// outbound requests a sweep may spend. A reader that silently drops a row it cannot parse under-reports coverage in 10// the FLATTERING direction, and a budget that understates its cost is how an array gets hammered. Both failures are 11// quiet, so both need a gate that fires rather than a habit that remembers. 12// 13// EVERY BAD CLASS IS PLANTED AND EVERY PLANT MUST BE CAUGHT, and the POSITIVE CONTROL is the half that matters most: 14// a clean registry must read entirely OK. A classifier that refused everything would pass every planted-defect tooth 15// while being useless, so the clean-reads-clean teeth are what separate a working ruler from a broken one. 16// THE BUDGET IS ASSERTED AGAINST HAND-COMPUTED VALUES with gv_check_eq, so the number tested and the number printed 17// are the same expression and cannot drift apart. 18// Fixtures are assembled at RUNTIME in this gate's own /tmp directory, never shared with a production beat. 19// license_tier: ORIGINAL No hw writes (Rule 26). 20import "nx_syscalls.nx" 21import "nx_gate_verdict.nx" 22import "nx_srcreg_lib.nx" 23 24const SRG_DIR: *u8 = "/tmp/nx_srcreach_gate" 25const SRG_CLEAN: *u8 = "/tmp/nx_srcreach_gate/clean.conf" 26const SRG_DIRTY: *u8 = "/tmp/nx_srcreach_gate/dirty.conf" 27const SRG_DIRMODE: i64 = 0x1ed 28const SRG_FILEMODE: i64 = 0x1a4 29const SRG_I64: i64 = 8 30const SRG_SLOTS: i64 = 64 31const SRG_BUDGET_SLOTS: i64 = 4 32// budget slots, mirroring the CLI's 33const SRG_B_REQUESTS: i64 = 0 34const SRG_B_LONGEST: i64 = 1 35const SRG_B_TOTAL: i64 = 2 36 37// THREE clean rows with paces 3000, 1000 and 5000 -- chosen so the budget arithmetic has a UNIQUE maximum and a 38// sum that cannot be produced by confusing the two. 39const SRG_CLEAN_BODY: *u8 = "src|a|preprint|atom-api|https://a.example|3000|none|open|clean\nsrc|b|index|rest-json|https://b.example|1000|none|cc0|clean\nsrc|c|registry|oai-pmh|https://c.example|5000|none|open|clean\n" 40// the same three, plus one of EACH bad class 41const SRG_DIRTY_BODY: *u8 = "src|a|preprint|atom-api|https://a.example|3000|none|open|clean\nsrc|b|index|rest-json|https://b.example|1000|none|cc0|clean\nsrc|c|registry|oai-pmh|https://c.example|5000|none|open|clean\nsrc|k|WIDGET|rest-json|https://d.example|2000|none|open|planted bad kind\nsrc|p|forge|carrier-pigeon|https://e.example|2000|none|open|planted bad proto\nsrc|z|index|html|https://f.example|soon|none|open|planted bad pace\nsrc|f|index|html|https://g.example\n" 42const SRG_CLEAN_ROWS: i64 = 3 43const SRG_DIRTY_ROWS: i64 = 7 44const SRG_REQS: i64 = 4 45// hand-computed: 3 OK rows x 4 requests 46const SRG_EXP_REQUESTS: i64 = 12 47// 4 x 5000, the slowest source 48const SRG_EXP_LONGEST: i64 = 20000 49// 4 x (3000 + 1000 + 5000) 50const SRG_EXP_TOTAL: i64 = 36000 51 52func srg_write(path: *u8, data: *u8) -> i64 { 53 let fd: i64 = sys_openat_wr(path, SRG_FILEMODE) 54 if fd < 0 { return 0 - 1 } 55 var n: i64 = 0 56 while data[n] != (0 as u8) { n = n + 1 } 57 let w: i64 = sys_write(fd, data, n) 58 sys_close(fd) 59 return w 60} 61 62// the CLI's budget, recomputed here from the same lib inputs. Kept in step with nx_srcreach by asserting the SAME 63// hand-computed constants both must satisfy, which is what makes a drift between them visible rather than silent. 64func srg_pace(st: *i64, pace: *i64, nrows: i64, reqs: i64, out: *i64) -> i64 { 65 out[SRG_B_REQUESTS] = 0 66 out[SRG_B_LONGEST] = 0 67 out[SRG_B_TOTAL] = 0 68 if reqs <= 0 { return 0 } 69 var i: i64 = 0 70 while i < nrows { 71 if st[i] == SR_S_OK { 72 out[SRG_B_REQUESTS] = out[SRG_B_REQUESTS] + reqs 73 let wall: i64 = reqs * pace[i] 74 out[SRG_B_TOTAL] = out[SRG_B_TOTAL] + wall 75 if wall > out[SRG_B_LONGEST] { out[SRG_B_LONGEST] = wall } 76 } 77 i = i + 1 78 } 79 return out[SRG_B_REQUESTS] 80} 81 82func main(argc: i64, argv: *i64) -> i64 { 83 gv_head("nx_srcreach_gate -- the registry reader and the outbound budget for /compare/researchreach" as *u8) 84 let ctr: *i64 = gv_ctr() 85 86 sys_mkdir(SRG_DIR, SRG_DIRMODE) 87 let wc: i64 = srg_write(SRG_CLEAN, SRG_CLEAN_BODY) 88 let wd: i64 = srg_write(SRG_DIRTY, SRG_DIRTY_BODY) 89 gv_check("fixture-clean-written" as *u8, (wc > 0) as i64, ctr) 90 gv_check("fixture-dirty-written" as *u8, (wd > 0) as i64, ctr) 91 92 // ---- THE POSITIVE CONTROL: a clean registry must read entirely OK ---- 93 let lp: *i64 = sys_mmap(SRG_I64) as *i64 94 let cb: *u8 = sr_load(SRG_CLEAN, lp) 95 gv_check("clean-registry-readable" as *u8, (lp[0] > 0) as i64, ctr) 96 let cn: i64 = lp[0] 97 let crows: i64 = sr_count_rows(cb, cn) 98 gv_check_eq("clean-row-count" as *u8, crows, SRG_CLEAN_ROWS, ctr) 99 let coff: *i64 = sys_mmap((crows + 1) * SRG_I64) as *i64 100 let cst: *i64 = sys_mmap((crows + 1) * SRG_I64) as *i64 101 let cpace: *i64 = sys_mmap((crows + 1) * SRG_I64) as *i64 102 let ckind: *i64 = sys_mmap((crows + 1) * SRG_I64) as *i64 103 let cc: *i64 = sys_mmap(SR_C_N * SRG_I64) as *i64 104 let cgot: i64 = sr_classify(cb, cn, coff, cst, cpace, ckind, cc) 105 gv_check_eq("clean-classified-every-row" as *u8, cgot, SRG_CLEAN_ROWS, ctr) 106 gv_check_eq("clean-all-ok" as *u8, cc[SR_C_OK], SRG_CLEAN_ROWS, ctr) 107 // THE ANTI-VACUITY HALF: a classifier that refused everything would pass every planted-defect tooth below. 108 gv_check_eq("neg-control-clean-has-no-bad-kind" as *u8, cc[SR_C_BAD_KIND], 0, ctr) 109 gv_check_eq("neg-control-clean-has-no-bad-proto" as *u8, cc[SR_C_BAD_PROTO], 0, ctr) 110 gv_check_eq("neg-control-clean-has-no-bad-pace" as *u8, cc[SR_C_BAD_PACE], 0, ctr) 111 gv_check_eq("neg-control-clean-has-no-bad-fields" as *u8, cc[SR_C_BAD_FIELDS], 0, ctr) 112 gv_check_eq("clean-partition-sums" as *u8, sr_partition_sum(cc), cc[SR_C_ROWS], ctr) 113 gv_check_eq("clean-verdict-is-OK" as *u8, sr_verdict(cc), SR_EXIT_OK, ctr) 114 115 // ---- THE PLANTED DEFECTS: one of each class, each must be caught ---- 116 let dp: *i64 = sys_mmap(SRG_I64) as *i64 117 let db: *u8 = sr_load(SRG_DIRTY, dp) 118 gv_check("dirty-registry-readable" as *u8, (dp[0] > 0) as i64, ctr) 119 let dn: i64 = dp[0] 120 let drows: i64 = sr_count_rows(db, dn) 121 gv_check_eq("dirty-row-count" as *u8, drows, SRG_DIRTY_ROWS, ctr) 122 let doff: *i64 = sys_mmap((drows + 1) * SRG_I64) as *i64 123 let dst: *i64 = sys_mmap((drows + 1) * SRG_I64) as *i64 124 let dpace: *i64 = sys_mmap((drows + 1) * SRG_I64) as *i64 125 let dkind: *i64 = sys_mmap((drows + 1) * SRG_I64) as *i64 126 let dc: *i64 = sys_mmap(SR_C_N * SRG_I64) as *i64 127 sr_classify(db, dn, doff, dst, dpace, dkind, dc) 128 gv_check_eq("planted-bad-kind-caught" as *u8, dc[SR_C_BAD_KIND], 1, ctr) 129 gv_check_eq("planted-bad-proto-caught" as *u8, dc[SR_C_BAD_PROTO], 1, ctr) 130 gv_check_eq("planted-bad-pace-caught" as *u8, dc[SR_C_BAD_PACE], 1, ctr) 131 gv_check_eq("planted-bad-fields-caught" as *u8, dc[SR_C_BAD_FIELDS], 1, ctr) 132 gv_check_eq("dirty-still-has-its-three-good-rows" as *u8, dc[SR_C_OK], SRG_CLEAN_ROWS, ctr) 133 gv_check_eq("dirty-partition-sums" as *u8, sr_partition_sum(dc), dc[SR_C_ROWS], ctr) 134 gv_check_eq("dirty-verdict-is-REFUSED" as *u8, sr_verdict(dc), SR_EXIT_BAD, ctr) 135 136 // ---- THE CLOSED VOCABULARIES: an unknown token must REFUSE, never default to the permissive value ---- 137 gv_check_eq("unknown-kind-is-refused-not-defaulted" as *u8, sr_kind_id("WIDGET" as *u8, 0, 6), SR_NONE, ctr) 138 gv_check_eq("unknown-protocol-is-refused-not-defaulted" as *u8, sr_proto_id("carrier-pigeon" as *u8, 0, 14), SR_NONE, ctr) 139 gv_check_eq("a-declared-kind-still-resolves" as *u8, sr_kind_id("registry" as *u8, 0, 8), 6, ctr) 140 gv_check_eq("a-declared-protocol-still-resolves" as *u8, sr_proto_id("oai-pmh" as *u8, 0, 7), 0, ctr) 141 142 // ---- THE BUDGET, asserted against hand-computed values ---- 143 let b: *i64 = sys_mmap(SRG_BUDGET_SLOTS * SRG_I64) as *i64 144 srg_pace(cst, cpace, crows, SRG_REQS, b) 145 gv_check_eq("budget-planned-requests" as *u8, b[SRG_B_REQUESTS], SRG_EXP_REQUESTS, ctr) 146 gv_check_eq("budget-longest-source-wall-ms" as *u8, b[SRG_B_LONGEST], SRG_EXP_LONGEST, ctr) 147 gv_check_eq("budget-sequential-wall-ms" as *u8, b[SRG_B_TOTAL], SRG_EXP_TOTAL, ctr) 148 // A REFUSED ROW MUST NEVER BE SPENT AGAINST: the dirty set has the same three OK rows, so its budget must be 149 // IDENTICAL to the clean set's. If a bad row leaked into the budget this number would rise. 150 let b2: *i64 = sys_mmap(SRG_BUDGET_SLOTS * SRG_I64) as *i64 151 srg_pace(dst, dpace, drows, SRG_REQS, b2) 152 gv_check_eq("neg-control-refused-rows-are-not-budgeted" as *u8, b2[SRG_B_REQUESTS], SRG_EXP_REQUESTS, ctr) 153 gv_check_eq("neg-control-refused-rows-add-no-wall" as *u8, b2[SRG_B_TOTAL], SRG_EXP_TOTAL, ctr) 154 // zero requests must cost nothing -- the empty-set case a budget most often gets wrong 155 let b3: *i64 = sys_mmap(SRG_BUDGET_SLOTS * SRG_I64) as *i64 156 srg_pace(cst, cpace, crows, 0, b3) 157 gv_check_eq("neg-control-zero-requests-costs-nothing" as *u8, b3[SRG_B_REQUESTS], 0, ctr) 158 159 gv_values_head() 160 gv_kv("clean_rows" as *u8, cc[SR_C_ROWS]) 161 gv_kv("clean_ok" as *u8, cc[SR_C_OK]) 162 gv_kv("dirty_rows" as *u8, dc[SR_C_ROWS]) 163 gv_kv("dirty_ok" as *u8, dc[SR_C_OK]) 164 gv_kv("dirty_bad_kind" as *u8, dc[SR_C_BAD_KIND]) 165 gv_kv("dirty_bad_proto" as *u8, dc[SR_C_BAD_PROTO]) 166 gv_kv("dirty_bad_pace" as *u8, dc[SR_C_BAD_PACE]) 167 gv_kv("dirty_bad_fields" as *u8, dc[SR_C_BAD_FIELDS]) 168 gv_kv("budget_requests" as *u8, b[SRG_B_REQUESTS]) 169 gv_kv("budget_longest_ms" as *u8, b[SRG_B_LONGEST]) 170 gv_kv("budget_sequential_ms" as *u8, b[SRG_B_TOTAL]) 171 172 return gv_verdict("nx_srcreach_gate" as *u8, ctr, 173 "in-process over nx_srcreg_lib: one planted defect of every class caught by name, a clean registry proven to read entirely OK so the classifier cannot be a refuse-everything guard, both closed vocabularies proven to refuse an unknown token rather than default to the permissive value, and the outbound budget asserted against hand-computed constants including the empty-set case and a control proving a refused row is never spent against" as *u8) 174}