nx_nxa_texm_gate.nx source
↩ module page · 342 lines · 15578 B
1// nx_nxa_texm_gate.nx -- THE GATE FOR THE TEXM WRITER.
2//
3// SUBJECT: the nx_nxa_texm ELF, forked for real. The organ's contract is an EXIT CODE plus an
4// ADDITIVE container rewrite, and /api/gate_run derives its verdict from the exit code -- so a
5// gate that only read stdout would test the least load-bearing half. Every tooth asserts either an
6// exit code or a byte read back out of the rewritten container.
7//
8// THE DANGEROUS FAILURE THIS GATE EXISTS TO CATCH is not "TEXM missing". It is TEXM PRESENT AND A
9// PRE-EXISTING SECTION GONE. The floor score would RISE while the asset silently lost its rig,
10// garments or hair -- a regression wearing a win, and exactly what an unverified section-append
11// produces. T3 therefore enumerates ALL THIRTEEN pre-existing tags by name rather than spot-
12// checking, and asserts the section count arithmetic closes.
13//
14// FIXTURES AT RUNTIME, IN /tmp/nx_nxa_texm_gate/, and every subject-created output is UNLINKED at
15// SETUP. A gate that is not idempotent reports on its first run and lies about every run after --
16// a sibling gate hit exactly that today, where a conf left by an earlier run made correct
17// behaviour read as FAIL. Setup also asserts the unlink WORKED before anything is measured.
18//
19// THE REAL ASSET IS READ, NEVER WRITTEN. Input is the shipped character; every output goes to
20// /tmp. The organ never modifies its input, which is what makes an end-to-end gate on production
21// data safe here.
22//
23// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
24import "nx_syscalls.nx"
25import "nx_gate_verdict.nx"
26import "nx_tool_run.nx"
27
28const TG_SUBJECT_DEFAULT: *u8 = "_offc/nx_nxa_texm.elf"
29// ABSOLUTE ON PURPOSE. nx_sov_build_run anchors CWD to buildroot/ before forking, so a
30// nishihost-relative path resolves to buildroot/sites/... and the read returns nothing -- which
31// this gate reported as sections=-1 and a RED across every content tooth, blaming the subject for
32// a harness path error. A gate's own working directory is part of its fixture.
33// AND IT IS THE BANKED PRE-TEXM ARTIFACT, NOT THE SERVED ONE. This gate used to read the LIVE
34// shipped asset, which worked exactly until the capability it tests SHIPPED: once TEXM was written
35// into the served character, "TEXM absent before" could never be true again, and the bite pair
36// honestly reported FALSE-POSITIVE (fired on good input) -- the gate declaring it could no longer
37// discriminate. A gate whose fixture is the production artifact measures its own success into
38// vacuity. The banked pre-TEXM asset is a real artifact (13 sections, TEXC present, TEXM absent),
39// so the ABSENT half of the bite is testable forever.
40const TG_ASSET: *u8 = "/volume1/homes/elderwesto/nishihost/knowledge/bank/ref9d.nxa.pretexm-20260823"
41
42// the organ's exit contract, restated so a change to it BREAKS THIS GATE loudly
43const TG_EXIT_OK: i64 = 0
44const TG_EXIT_BAD: i64 = 3
45const TG_EXIT_NOSEC: i64 = 4
46
47// NXA layout
48const TG_HDR: i64 = 32
49const TG_TOCE: i64 = 32
50const TG_OFF_FIELD: i64 = 8
51const TG_LEN_FIELD: i64 = 16
52const TG_NSEC: i64 = 16
53const TG_TAGB: i64 = 4
54const TG_WORD: i64 = 8
55const TG_RADIX: i64 = 256
56const TG_MASK: i64 = 255
57const TG_NXA_VER: i64 = 1
58
59// THE SECTION COUNTS ARE DERIVED FROM THE INPUT, NEVER DECLARED. This gate used to assert
60// "13 carried + 1 appended = 14" as two literals. That is a picked count describing the subject's
61// SHAPE, and it went RED the moment the asset legitimately GREW: the FACE and MORF sections landed
62// (a capability RISE) and the gate reported a failure. An instrument that cannot tell growth from
63// regression will call every improvement a defect, and raising the literal to 16 would only move
64// the breakage to whoever lands section 17.
65// carried = the input's own section count, read from its header
66// appended = 1 when the input lacks TEXM, 0 when it already has one (replace, not duplicate)
67// so the arithmetic closes for ANY input, and the tooth still catches a dropped or doubled section.
68
69// a resolution small enough that the gate finishes inside a caller deadline. This is a GATE
70// RUNTIME budget, not a quality bar -- the shipping default is read from
71// knowledge/asset_texture_floor.conf by the organ itself and is deliberately NOT restated here,
72// because a threshold copied into a second file is a duplicate ruler that drifts.
73const TG_GATE_RES: *u8 = "128"
74const TG_MIN_TEXM_WORDS: i64 = 8 // a TEXM smaller than its own header cannot carry a map
75
76const TG_CAPCAP: i64 = 262144
77const TG_ARGVN: i64 = 8
78const TG_MODEDIR: i64 = 493
79
80const TG_DIR: *u8 = "/tmp/nx_nxa_texm_gate"
81const TG_OUT1: *u8 = "/tmp/nx_nxa_texm_gate/o1.nxa"
82const TG_OUT2: *u8 = "/tmp/nx_nxa_texm_gate/o2.nxa"
83const TG_NOTEXC: *u8 = "/tmp/nx_nxa_texm_gate/notexc.nxa"
84const TG_OUT3: *u8 = "/tmp/nx_nxa_texm_gate/o3.nxa"
85
86func tg_rd64(b: *u8, off: i64) -> i64 {
87 var v: i64 = 0
88 var i: i64 = TG_WORD - 1
89 while i >= 0 { v = v*TG_RADIX + ((b[off + i] & TG_MASK) as i64); i = i - 1 }
90 return v
91}
92func tg_wr64(b: *u8, off: i64, v: i64) -> i64 {
93 var n: i64 = v
94 var i: i64 = 0
95 while i < TG_WORD { let q: i64 = n / TG_RADIX; b[off + i] = (n - q*TG_RADIX) as u8; n = q; i = i + 1 }
96 return 0
97}
98func tg_tageq(b: *u8, off: i64, t: *u8) -> i64 {
99 var i: i64 = 0
100 while i < TG_TAGB { if b[off + i] != t[i] { return 0 } i = i + 1 }
101 return 1
102}
103// section wordlen by tag, or -1 when absent. Walks the WHOLE table.
104func tg_find_len(b: *u8, ns: i64, t: *u8) -> i64 {
105 var s: i64 = 0
106 while s < ns {
107 let e: i64 = TG_HDR + s*TG_TOCE
108 if tg_tageq(b, e, t) == 1 { return tg_rd64(b, e + TG_LEN_FIELD) }
109 s = s + 1
110 }
111 return 0 - 1
112}
113func tg_nsec(path: *u8, lenout: *i64) -> i64 {
114 let lp: *i64 = sys_mmap(TG_WORD*2) as *i64
115 let b: *u8 = sys_read_file(path, lp)
116 if (b as i64) == 0 { lenout[0] = 0; return 0 - 1 }
117 lenout[0] = lp[0]
118 lenout[1] = b as i64
119 return tg_rd64(b, TG_NSEC)
120}
121func tg_run(subject: *u8, a1: *u8, a2: *u8, a3: *u8, out: *u8, olen: *i64) -> i64 {
122 let av: *i64 = sys_mmap(TG_WORD*TG_ARGVN) as *i64
123 av[0] = subject as i64
124 av[1] = a1 as i64
125 av[2] = a2 as i64
126 av[3] = a3 as i64
127 av[4] = 0
128 return tr_run_capture(subject, av, out, TG_CAPCAP, olen)
129}
130func tg_exists(path: *u8) -> i64 {
131 let lp: *i64 = sys_mmap(TG_WORD*2) as *i64
132 let b: *u8 = sys_read_file(path, lp)
133 if (b as i64) == 0 { return 0 }
134 return 1
135}
136// a structurally valid NXA carrying VERT+SKEL but NO TEXC -- the negative control for the
137// prerequisite check. Built at RUNTIME so no detector can find this pattern in source.
138func tg_write_notexc(path: *u8) -> i64 {
139 let nsec: i64 = 2
140 let total: i64 = TG_HDR + nsec*TG_TOCE + nsec*TG_WORD
141 let b: *u8 = sys_mmap(total + 64)
142 var i: i64 = 0
143 while i < total { b[i] = 0 as u8; i = i + 1 }
144 let mg: *u8 = "NXANIM01" as *u8
145 var k: i64 = 0
146 while k < TG_WORD { b[k] = mg[k]; k = k + 1 }
147 tg_wr64(b, TG_WORD, TG_NXA_VER)
148 tg_wr64(b, TG_NSEC, nsec)
149 let data: i64 = TG_HDR + nsec*TG_TOCE
150 let h0: i64 = TG_HDR
151 let h1: i64 = TG_HDR + TG_TOCE
152 var c: i64 = 0
153 let tv: *u8 = "VERT" as *u8
154 while c < TG_TAGB { b[h0 + c] = tv[c]; c = c + 1 }
155 tg_wr64(b, h0 + TG_OFF_FIELD, data)
156 tg_wr64(b, h0 + TG_LEN_FIELD, 1)
157 var c2: i64 = 0
158 let ts: *u8 = "SKEL" as *u8
159 while c2 < TG_TAGB { b[h1 + c2] = ts[c2]; c2 = c2 + 1 }
160 tg_wr64(b, h1 + TG_OFF_FIELD, data + TG_WORD)
161 tg_wr64(b, h1 + TG_LEN_FIELD, 1)
162 tg_wr64(b, data, 1)
163 tg_wr64(b, data + TG_WORD, 1)
164 let fd: i64 = sys_openat_wr(path, MODE_0644)
165 if fd < 0 { return 0 - 1 }
166 let wr: i64 = sys_write(fd, b, total)
167 sys_close(fd)
168 if wr != total { return 0 - 1 }
169 return total
170}
171
172func main(argc: i64, argv: *i64) -> i64 {
173 let ctr: *i64 = gv_ctr()
174 gv_head("nx_nxa_texm gate -- the PBR map set is written INTO the asset, additively" as *u8)
175 var subject: *u8 = TG_SUBJECT_DEFAULT
176 if argc >= 2 { subject = argv[1] as *u8 }
177 gv_puts(" subject: " as *u8)
178 gv_puts(subject)
179 gv_puts("\n\n" as *u8)
180
181 // ---- SETUP: create scratch, then REMOVE every output the subject might create.
182 sys_mkdir(TG_DIR, TG_MODEDIR)
183 sys_unlinkat(TG_OUT1)
184 sys_unlinkat(TG_OUT2)
185 sys_unlinkat(TG_OUT3)
186 sys_unlinkat(TG_NOTEXC)
187 var clean: i64 = 0
188 if tg_exists(TG_OUT1) == 0 { if tg_exists(TG_OUT2) == 0 { if tg_exists(TG_OUT3) == 0 { clean = 1 } } }
189 gv_check("setup-outputs-absent-before-measuring (gate is idempotent)" as *u8, clean, ctr)
190
191 let cap: *u8 = sys_mmap(TG_CAPCAP)
192 let olen: *i64 = sys_mmap(TG_WORD*2) as *i64
193 let meta: *i64 = sys_mmap(TG_WORD*4) as *i64
194
195 // ---- BEFORE: the shipped asset must NOT already carry TEXM, or every tooth below is vacuous.
196 let ns_in: i64 = tg_nsec(TG_ASSET, meta)
197 let bin: *u8 = meta[1] as *u8
198 gv_puts(" input sections=" as *u8)
199 gv_num(ns_in)
200 gv_puts(" bytes=" as *u8)
201 gv_num(meta[0])
202 gv_puts("\n" as *u8)
203 var pre_ok: i64 = 0
204 if ns_in > 0 { pre_ok = 1 }
205 gv_check("input-carries-sections-to-carry (count bound in the condition, an empty input cannot pass)" as *u8, pre_ok, ctr)
206 var texm_before: i64 = 0
207 if tg_find_len(bin, ns_in, "TEXM" as *u8) >= 0 { texm_before = 1 }
208
209 // ---- T1: write TEXM ----
210 let rc1: i64 = tg_run(subject, TG_ASSET, TG_OUT1, TG_GATE_RES, cap, olen)
211 gv_puts(" [T1] write rc=" as *u8)
212 gv_num(rc1)
213 gv_puts("\n" as *u8)
214 var t1: i64 = 0
215 if rc1 == TG_EXIT_OK { t1 = 1 }
216 gv_check("texm-write-exits-OK" as *u8, t1, ctr)
217
218 let ns_out: i64 = tg_nsec(TG_OUT1, meta)
219 let bout: *u8 = meta[1] as *u8
220 gv_puts(" output sections=" as *u8)
221 gv_num(ns_out)
222 gv_puts(" bytes=" as *u8)
223 gv_num(meta[0])
224 gv_puts("\n" as *u8)
225
226 // ---- T2: ANTI-VACUITY. A TEXM whose length is header-only would still be "PRESENT". Assert
227 // the fixture reached the condition: a real map set was baked and carries real bytes.
228 let tl: i64 = tg_find_len(bout, ns_out, "TEXM" as *u8)
229 gv_puts(" [T2] TEXM wordlen=" as *u8)
230 gv_num(tl)
231 gv_puts("\n" as *u8)
232 var t2: i64 = 0
233 if tl > TG_MIN_TEXM_WORDS { t2 = 1 }
234 gv_check("anti-vacuity-TEXM-carries-more-than-its-own-header" as *u8, t2, ctr)
235
236 // ---- T3: EVERY pre-existing tag survives. THE REGRESSION TOOTH.
237 // Enumerated from the INPUT'S OWN TOC, not from a hand-written tag list: the old version named
238 // thirteen tags, so it could only ever notice a regression among those thirteen and was blind
239 // to any section added later (it would have carried FACE and MORF away silently). Reading the
240 // input's table means the tooth covers whatever the asset actually holds, forever.
241 var kept: i64 = 0
242 var ki: i64 = 0
243 while ki < ns_in {
244 let ke: i64 = TG_HDR + ki*TG_TOCE
245 if tg_find_len(bout, ns_out, ((bin as i64) + ke) as *u8) >= 0 { kept = kept + 1 }
246 ki = ki + 1
247 }
248 gv_puts(" [T3] pre-existing tags surviving=" as *u8)
249 gv_num(kept)
250 gv_puts(" of " as *u8)
251 gv_num(ns_in)
252 gv_puts("\n" as *u8)
253 var t3: i64 = 0
254 if ns_in > 0 { if kept == ns_in { t3 = 1 } }
255 gv_check("additive-only-every-pre-existing-section-survives (denominator is the input's own count)" as *u8, t3, ctr)
256
257 // ---- T4: the count arithmetic closes, DERIVED. carried = the input's own count; appended = 1
258 // only when the input lacked TEXM (a second apply REPLACES). Nothing dropped, nothing doubled,
259 // and the tooth holds for an asset of any size.
260 var expect_after: i64 = ns_in + 1
261 if texm_before == 1 { expect_after = ns_in }
262 gv_puts(" [T4] carried=" as *u8)
263 gv_num(ns_in)
264 gv_puts(" texm_already_present=" as *u8)
265 gv_num(texm_before)
266 gv_puts(" expected=" as *u8)
267 gv_num(expect_after)
268 gv_puts(" got=" as *u8)
269 gv_num(ns_out)
270 gv_puts("\n" as *u8)
271 var t4: i64 = 0
272 if ns_in > 0 { if ns_out == expect_after { t4 = 1 } }
273 gv_check("section-count-arithmetic-closes (carried + appended, both derived from the input)" as *u8, t4, ctr)
274
275 // ---- T5: SECTION LENGTHS ARE UNCHANGED, not merely present. A section can survive by name
276 // and be truncated; only comparing its wordlen catches that.
277 // BIND THE ASSERTION TO ITS DENOMINATOR. The first version of this tooth passed on ns_in=-1,
278 // i.e. it compared ZERO sections and reported success -- a tooth that passes on the empty set
279 // is not a tooth, and it passed in the same run where every other content tooth went RED.
280 var samelen: i64 = 0
281 var compared: i64 = 0
282 var si: i64 = 0
283 while si < ns_in {
284 let e: i64 = TG_HDR + si*TG_TOCE
285 let want: i64 = tg_rd64(bin, e + TG_LEN_FIELD)
286 let got: i64 = tg_find_len(bout, ns_out, ((bin as i64) + e) as *u8)
287 if got == want { compared = compared + 1 }
288 si = si + 1
289 }
290 gv_puts(" [T5] sections compared with identical wordlen=" as *u8)
291 gv_num(compared)
292 gv_puts(" of " as *u8)
293 gv_num(ns_in)
294 gv_puts("\n" as *u8)
295 if ns_in > 0 { if compared == ns_in { samelen = 1 } }
296 gv_check("every-carried-section-keeps-its-exact-wordlen (denominator is the input's own count)" as *u8, samelen, ctr)
297
298 // ---- T6/T7: THE BITE PAIR. TEXM absent before, present after. A writer that reported success
299 // for everything would pass a present-test alone; the ABSENT half is what catches it.
300 var fired_bad: i64 = 0
301 if tl >= 0 { fired_bad = 1 }
302 var fired_good: i64 = 0
303 if texm_before == 1 { fired_good = 1 }
304 gv_bite("neg-control-TEXM-absent-before-and-present-after" as *u8, fired_bad, fired_good, ctr)
305
306 // ---- T8: IDEMPOTENCY. A second apply must REPLACE, never append a second TEXM.
307 let rc2: i64 = tg_run(subject, TG_OUT1, TG_OUT2, TG_GATE_RES, cap, olen)
308 let ns2: i64 = tg_nsec(TG_OUT2, meta)
309 gv_puts(" [T8] second-apply rc=" as *u8)
310 gv_num(rc2)
311 gv_puts(" sections=" as *u8)
312 gv_num(ns2)
313 gv_puts("\n" as *u8)
314 // the second apply runs on an output that ALREADY carries TEXM, so a correct writer replaces it
315 // and the count must not move at all: expected == the first output's own count, derived.
316 var t8: i64 = 0
317 if rc2 == TG_EXIT_OK { if ns_out > 0 { if ns2 == ns_out { t8 = 1 } } }
318 gv_check("idempotent-second-apply-replaces-rather-than-appends (count must not move)" as *u8, t8, ctr)
319
320 // ---- T9: the TEXC PREREQUISITE is enforced. An asset with no UVs has nothing to bake into,
321 // and fabricating a map for it would be inventing data.
322 let wn: i64 = tg_write_notexc(TG_NOTEXC)
323 gv_check("setup-no-texc-fixture-written" as *u8, tg_exists(TG_NOTEXC), ctr)
324 let rc3: i64 = tg_run(subject, TG_NOTEXC, TG_OUT3, TG_GATE_RES, cap, olen)
325 gv_puts(" [T9] no-TEXC input rc=" as *u8)
326 gv_num(rc3)
327 gv_puts("\n" as *u8)
328 var t9: i64 = 0
329 if rc3 == TG_EXIT_NOSEC { if tg_exists(TG_OUT3) == 0 { t9 = 1 } }
330 gv_check("missing-TEXC-refused-by-name-AND-writes-no-output" as *u8, t9, ctr)
331
332 // ---- T10: the subject actually RAN. A negative sentinel or 127 would make every exit-code
333 // tooth above compare against a number the subject never produced.
334 var ran: i64 = 1
335 if rc1 < 0 { ran = 0 }
336 if rc1 == 127 { ran = 0 }
337 gv_check("neg-control-subject-actually-executed (not 127, not a harness sentinel)" as *u8, ran, ctr)
338
339 let rc: i64 = gv_verdict("NXA-TEXM" as *u8, ctr, "the map set is carried inside the asset and every prior section survives byte-for-byte" as *u8)
340 sys_exit(rc)
341 return rc
342}