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}