code wiki / _hdl_build / nx_gltf_load_gate.nx

nx_gltf_load_gate.nx source

↩ module page · 267 lines · 14006 B

1// nx_gltf_load_gate.nx -- ★NATIVE sovereign glTF viewer gate: load our exported nishi_being.glb back into the Nishi 2// renderer and render it (round-trip on OUR OWN stack), AND ★D1 FAIL-CLOSED teeth (debt 1785902685, 2026-08-12): 3// T5-T10 feed malformed/unsupported glbs assembled AT RUNTIME in /tmp -> the loader must REFUSE with the exact NAMED 4// reason, never segfault. T7 is the POSITIVE CONTROL (a valid minimal Khronos-shaped glb with u16 indices MUST load) 5// so a refuse-everything guard cannot pass. gv-migrated (D001): verdict comes from nx_gate_verdict, exit carries it. 6// license_tier: ORIGINAL expect_exit: 0 7import "nx_syscalls.nx" 8import "nx_png.nx" 9import "nx_trimesh.nx" 10import "nx_gltf_load.nx" 11import "nx_gate_verdict.nx" 12 13func clearfb(fb: *i64, n: i64, c: i64) -> i64 { var i: i64=0; while i<n { fb[i]=c; i=i+1 } return 0 } 14func filled(fb: *i64, n: i64, bg: i64) -> i64 { var c: i64=0; var i: i64=0; while i<n { if fb[i]!=bg { c=c+1 } i=i+1 } return c } 15 16// exact string equality (asserts WHICH refusal rule fired -- a suite that only asks "was it refused?" is blind) 17func gstreq(a: *u8, b: *u8) -> i64 { 18 var i: i64 = 0 19 var r: i64 = 0-1 20 while r < 0 { 21 let ca: i64 = a[i] as i64 22 let cb: i64 = b[i] as i64 23 if ca != cb { r = 0 } else { if ca == 0 { r = 1 } else { i = i + 1 } } 24 } 25 return r 26} 27// fixture emitter: write a buffer to a file 28func gwfile(path: *u8, b: *u8, n: i64) -> i64 { 29 let fd: i64 = sys_openat_wr(path, 0x1a4) 30 if fd < 0 { return 0 } 31 sys_write(fd, b, n) 32 sys_close(fd) 33 return 1 34} 35func gw32(b: *u8, at: i64, v: i64) -> i64 { 36 b[at] = (v & 0xff) as u8 37 b[at+1] = ((v>>8) & 0xff) as u8 38 b[at+2] = ((v>>16) & 0xff) as u8 39 b[at+3] = ((v>>24) & 0xff) as u8 40 return 0 41} 42func gw16(b: *u8, at: i64, v: i64) -> i64 { 43 b[at] = (v & 0xff) as u8 44 b[at+1] = ((v>>8) & 0xff) as u8 45 return 0 46} 47func gputs(b: *u8, at: i64, s: *u8) -> i64 { 48 var i: i64 = 0 49 while s[i] != (0 as u8) { b[at+i] = s[i]; i = i + 1 } 50 return at + i 51} 52func gputn(b: *u8, at: i64, v: i64) -> i64 { 53 if v == 0 { b[at] = 48 as u8; return at + 1 } 54 let tmp: *u8 = sys_mmap(32) as *u8 55 var x: i64 = v 56 var n: i64 = 0 57 while x > 0 { tmp[n] = (48 + x%10) as u8; x = x/10; n = n + 1 } 58 var i: i64 = 0 59 while i < n { b[at+i] = tmp[n-1-i]; i = i + 1 } 60 return at + n 61} 62// assemble a minimal Khronos-shaped .glb (3 verts / 1 tri) with parameterized index componentType, 63// index bufferView byteOffset, and index values -- the refusal fixtures AND the positive control. 64func mkglb(path: *u8, ct: i64, io: i64, ia: i64, ibb: i64, ic: i64) -> i64 { 65 let js: *u8 = sys_mmap(2048) as *u8 66 var p: i64 = 0 67 p = gputs(js, p, "{\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0},\"indices\":1}]}],\"accessors\":[{\"bufferView\":0,\"componentType\":5126,\"count\":3},{\"bufferView\":1,\"componentType\":" as *u8) 68 p = gputn(js, p, ct) 69 p = gputs(js, p, ",\"count\":3}],\"bufferViews\":[{\"byteOffset\":0,\"byteLength\":36},{\"byteOffset\":" as *u8) 70 p = gputn(js, p, io) 71 p = gputs(js, p, ",\"byteLength\":6}]}" as *u8) 72 while p % 4 != 0 { js[p] = 32 as u8; p = p + 1 } 73 let jlen: i64 = p 74 let binlen: i64 = 44 75 let total: i64 = 28 + jlen + binlen 76 let b: *u8 = sys_mmap(total + 64) as *u8 77 b[0] = 103 as u8; b[1] = 108 as u8; b[2] = 84 as u8; b[3] = 70 as u8 78 gw32(b, 4, 2) 79 gw32(b, 8, total) 80 gw32(b, 12, jlen) 81 b[16] = 74 as u8; b[17] = 83 as u8; b[18] = 79 as u8; b[19] = 78 as u8 82 var i: i64 = 0 83 while i < jlen { b[20+i] = js[i]; i = i + 1 } 84 gw32(b, 20+jlen, binlen) 85 b[24+jlen] = 66 as u8; b[25+jlen] = 73 as u8; b[26+jlen] = 78 as u8; b[27+jlen] = 0 as u8 86 let bo: i64 = 28 + jlen 87 var k: i64 = 0 88 while k < 44 { b[bo+k] = 0 as u8; k = k + 1 } 89 gw32(b, bo+12, 1065353216) 90 gw32(b, bo+28, 1065353216) 91 gw16(b, bo+36, ia) 92 gw16(b, bo+38, ibb) 93 gw16(b, bo+40, ic) 94 return gwfile(path, b, total) 95} 96// one refusal tooth: load `path` via the std loader; pass iff refused(0) with the EXACT reason `want`. 97// prints the observed values on mismatch (a boolean cannot say why). 98func refuse_tooth(path: *u8, want: *u8) -> i64 { 99 let ok: i64 = gltf_load_std(path, 900) 100 let why: *u8 = gltf_load_why() 101 var pass: i64 = 0 102 if ok == 0 { if gstreq(why, want) == 1 { pass = 1 } } 103 if pass == 0 { 104 gv_puts(" detail: ok=" as *u8); gv_num(ok) 105 gv_puts(" why=" as *u8); gv_puts(why) 106 gv_puts(" want=" as *u8); gv_puts(want) 107 gv_puts("\n" as *u8) 108 } 109 return pass 110} 111 112// ★D2 fixture: 2 meshes / 3 primitives (9 verts, 3 tris), third primitive uses u32 indices -- 113// proves the multi-mesh walk, the per-mesh primitives array, the concat base offsets, and both index widths 114func mk2glb(path: *u8) -> i64 { 115 let jb: *u8 = sys_mmap(2048) as *u8 116 var p: i64 = gputs(jb, 0, "{\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0},\"indices\":1},{\"attributes\":{\"POSITION\":2},\"indices\":3}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4},\"indices\":5}]}],\"accessors\":[{\"bufferView\":0,\"componentType\":5126,\"count\":3},{\"bufferView\":1,\"componentType\":5123,\"count\":3},{\"bufferView\":2,\"componentType\":5126,\"count\":3},{\"bufferView\":3,\"componentType\":5123,\"count\":3},{\"bufferView\":4,\"componentType\":5126,\"count\":3},{\"bufferView\":5,\"componentType\":5125,\"count\":3}],\"bufferViews\":[{\"byteOffset\":0,\"byteLength\":36},{\"byteOffset\":108,\"byteLength\":6},{\"byteOffset\":36,\"byteLength\":36},{\"byteOffset\":116,\"byteLength\":6},{\"byteOffset\":72,\"byteLength\":36},{\"byteOffset\":124,\"byteLength\":12}]}" as *u8) 117 while p % 4 != 0 { jb[p] = 32 as u8; p = p + 1 } 118 let jlen: i64 = p 119 let binlen: i64 = 136 120 let total: i64 = 28 + jlen + binlen 121 let b: *u8 = sys_mmap(total + 64) as *u8 122 b[0] = 103 as u8; b[1] = 108 as u8; b[2] = 84 as u8; b[3] = 70 as u8 123 gw32(b, 4, 2) 124 gw32(b, 8, total) 125 gw32(b, 12, jlen) 126 b[16] = 74 as u8; b[17] = 83 as u8; b[18] = 79 as u8; b[19] = 78 as u8 127 var i: i64 = 0 128 while i < jlen { b[20+i] = jb[i]; i = i + 1 } 129 gw32(b, 20+jlen, binlen) 130 b[24+jlen] = 66 as u8; b[25+jlen] = 73 as u8; b[26+jlen] = 78 as u8; b[27+jlen] = 0 as u8 131 let bo: i64 = 28 + jlen 132 var k: i64 = 0 133 while k < binlen { b[bo+k] = 0 as u8; k = k + 1 } 134 // prim0 verts @0: (0,0,0)(1,0,0)(0,1,0) 1.0f=1065353216 2.0f=1073741824 3.0f=1077936128 135 gw32(b, bo+12, 1065353216) 136 gw32(b, bo+28, 1065353216) 137 // prim1 verts @36: (2,0,0)(3,0,0)(2,1,0) 138 gw32(b, bo+36, 1073741824) 139 gw32(b, bo+48, 1077936128) 140 gw32(b, bo+60, 1073741824) 141 gw32(b, bo+64, 1065353216) 142 // prim2 verts @72: (0,2,0)(1,2,0)(0,3,0) 143 gw32(b, bo+76, 1073741824) 144 gw32(b, bo+84, 1065353216) 145 gw32(b, bo+88, 1073741824) 146 gw32(b, bo+100, 1077936128) 147 // indices: u16 @108 (0,1,2) + u16 @116 (0,1,2) + u32 @124 (0,1,2) 148 gw16(b, bo+110, 1) 149 gw16(b, bo+112, 2) 150 gw16(b, bo+118, 1) 151 gw16(b, bo+120, 2) 152 gw32(b, bo+128, 1) 153 gw32(b, bo+132, 2) 154 return gwfile(path, b, total) 155} 156 157const BG: i64 = 24 + 26*256 + 34*65536 158const W: i64 = 300 159const H: i64 = 460 160 161func main() -> i64 { 162 let ctr: *i64 = gv_ctr() 163 gv_head("nx_gltf_load_gate -- sovereign .glb loader: round-trip render + D1 fail-closed named refusals (debt 1785902685)" as *u8) 164 165 // precondition: the exported being fixture (round-trip half). Refusal teeth need no fixture. 166 var havebeing: i64 = 0 167 let bfd: i64 = sys_openat_rd("knowledge/nishi_being.glb" as *u8) 168 if bfd >= 0 { havebeing = 1; sys_close(bfd) } 169 if gv_need("knowledge/nishi_being.glb" as *u8, havebeing, ctr) == 1 { 170 let ok: i64 = gltf_load("knowledge/nishi_being.glb" as *u8) 171 let nv: i64 = tm_nv() 172 let nt: i64 = tm_nt() 173 gv_puts(" loaded: ok=" as *u8); gv_num(ok); gv_puts(" verts=" as *u8); gv_num(nv); gv_puts(" tris=" as *u8); gv_num(nt); gv_puts(" overflow=" as *u8); gv_num(tm_ovf()); gv_puts("\n" as *u8) 174 var t1: i64 = 0 175 if ok == 1 { if nv > 1000 { if tm_ovf() == 0 { t1 = 1 } } } 176 if t1 == 0 { gv_puts(" detail: why=" as *u8); gv_puts(gltf_load_why()); gv_puts("\n" as *u8) } 177 gv_check("T1 parses our exported .glb into the native renderer" as *u8, t1, ctr) 178 // T2: loaded counts equal the file's OWN declared accessor counts (two readers of one 179 // declaration -- catches silent truncation, and never goes stale when the export evolves; 180 // the old tooth hardcoded 7954/15912 and went RED when the being export grew to 8180/16360) 181 let szp2: *i64 = sys_mmap(16) as *i64 182 let fbuf: *u8 = sys_read_file("knowledge/nishi_being.glb" as *u8, szp2) 183 let jl2: i64 = gll_ru32(fbuf, 12) 184 let dNV: i64 = gll_nth_num(fbuf, 20, 20+jl2, "\"count\":" as *u8, 1) 185 let dNI: i64 = gll_nth_num(fbuf, 20, 20+jl2, "\"count\":" as *u8, 4) 186 gv_puts(" declared: NV=" as *u8); gv_num(dNV); gv_puts(" NI=" as *u8); gv_num(dNI); gv_puts("\n" as *u8) 187 var t2: i64 = 0 188 if nv == dNV { if nt*3 == dNI { t2 = 1 } } 189 gv_check("T2 loaded counts equal the file's declared accessor counts" as *u8, t2, ctr) 190 let npx: i64 = W*H 191 let fb: *i64 = sys_mmap(npx*8) as *i64 192 let zb: *i64 = sys_mmap(npx*8) as *i64 193 clearfb(fb, npx, BG); trimesh_zclear(zb, npx); trimesh_render(fb, zb, W, H, 2400, 0-200, 2600, 520, 2) 194 let fil: i64 = filled(fb, npx, BG) 195 gv_puts(" render: filled=" as *u8); gv_num(fil); gv_puts("\n" as *u8) 196 var t3: i64 = 0 197 if fil > npx/12 { t3 = 1 } 198 gv_check("T3 loaded .glb renders on our stack (filled > 1/12 of frame)" as *u8, t3, ctr) 199 // turntable artifact: 3 views of the loaded model 200 let yaws: *i64 = sys_mmap(3*8) as *i64 201 yaws[0]=1400; yaws[1]=3200; yaws[2]=5600 202 let GWD: i64 = W*3 203 let gal: *i64 = sys_mmap(GWD*H*8) as *i64 204 clearfb(gal, GWD*H, BG) 205 let cell: *i64 = sys_mmap(npx*8) as *i64 206 var v: i64 = 0 207 while v < 3 { 208 clearfb(cell, npx, BG); trimesh_zclear(zb, npx); trimesh_render(cell, zb, W, H, yaws[v], 0-200, 2600, 520, 2) 209 var y: i64 = 0 210 while y < H { var x: i64=0; while x<W { gal[y*GWD+v*W+x]=cell[y*W+x]; x=x+1 } y=y+1 } 211 v = v + 1 212 } 213 write_png(gal, GWD, H, "knowledge/nx_gltf_view.png" as *u8) 214 gv_puts(" turntable artifact -> knowledge/nx_gltf_view.png (loaded .glb, 3 views)\n" as *u8) 215 } 216 217 // ===== ★D1 refusal teeth: fixtures assembled at runtime, reasons asserted EXACTLY ===== 218 let p5: *u8 = "/tmp/gllg_trunc.bin" as *u8 219 let tb: *u8 = sys_mmap(16) as *u8 220 var q: i64 = 0 221 while q < 10 { tb[q] = 88 as u8; q = q + 1 } 222 gwfile(p5, tb, 10) 223 gv_check("T5 neg-control-truncated-file refused named file-too-short" as *u8, refuse_tooth(p5, "file-too-short" as *u8), ctr) 224 var t5b: i64 = 0 225 if gltf_load(p5) == 0 { if gstreq(gltf_load_why(), "file-too-short" as *u8) == 1 { t5b = 1 } } 226 if t5b == 0 { gv_puts(" detail: legacy why=" as *u8); gv_puts(gltf_load_why()); gv_puts("\n" as *u8) } 227 gv_check("T5b neg-control-legacy-entry refused named file-too-short" as *u8, t5b, ctr) 228 let p6: *u8 = "/tmp/gllg_jsonoob.glb" as *u8 229 let hb: *u8 = sys_mmap(32) as *u8 230 hb[0] = 103 as u8; hb[1] = 108 as u8; hb[2] = 84 as u8; hb[3] = 70 as u8 231 gw32(hb, 4, 2) 232 gw32(hb, 8, 24) 233 gw32(hb, 12, 999999) 234 hb[16] = 74 as u8; hb[17] = 83 as u8; hb[18] = 79 as u8; hb[19] = 78 as u8 235 gw32(hb, 20, 0) 236 gwfile(p6, hb, 24) 237 gv_check("T6 neg-control-json-oob refused named json-chunk-oob" as *u8, refuse_tooth(p6, "json-chunk-oob" as *u8), ctr) 238 // T7 POSITIVE CONTROL: a valid minimal Khronos-shaped glb (u16 indices) MUST load -- refuse-everything dies here 239 let p7: *u8 = "/tmp/gllg_ok.glb" as *u8 240 mkglb(p7, 5123, 36, 0, 1, 2) 241 var t7: i64 = 0 242 if gltf_load_std(p7, 900) == 1 { if tm_nv() == 3 { if tm_nt() == 1 { t7 = 1 } } } 243 if t7 == 0 { gv_puts(" detail: why=" as *u8); gv_puts(gltf_load_why()); gv_puts(" nv=" as *u8); gv_num(tm_nv()); gv_puts(" nt=" as *u8); gv_num(tm_nt()); gv_puts("\n" as *u8) } 244 gv_check("T7 positive-control minimal std glb loads (u16 indices, 3v/1t)" as *u8, t7, ctr) 245 let p8: *u8 = "/tmp/gllg_idxoob.glb" as *u8 246 mkglb(p8, 5123, 900000, 0, 1, 2) 247 gv_check("T8 neg-control-index-oob refused named index-accessor-oob" as *u8, refuse_tooth(p8, "index-accessor-oob" as *u8), ctr) 248 let p9: *u8 = "/tmp/gllg_u8idx.glb" as *u8 249 mkglb(p9, 5121, 36, 0, 1, 2) 250 gv_check("T9 neg-control-index-ctype refused named index-componentType-unsupported" as *u8, refuse_tooth(p9, "index-componentType-unsupported" as *u8), ctr) 251 let p10: *u8 = "/tmp/gllg_idxrange.glb" as *u8 252 mkglb(p10, 5123, 36, 0, 1, 7) 253 gv_check("T10 neg-control-index-range refused named index-out-of-range" as *u8, refuse_tooth(p10, "index-out-of-range" as *u8), ctr) 254 255 // ===== ★D2 (debt 1786545740): multi-mesh/multi-primitive concat, mechanism proven exactly ===== 256 let p12: *u8 = "/tmp/gllg_multi.glb" as *u8 257 mk2glb(p12) 258 var t12: i64 = 0 259 if gltf_load_all(p12, 900) == 1 { if tm_nv() == 9 { if tm_nt() == 3 { t12 = 1 } } } 260 if t12 == 0 { gv_puts(" detail: why=" as *u8); gv_puts(gltf_load_why()); gv_puts(" nv=" as *u8); gv_num(tm_nv()); gv_puts(" nt=" as *u8); gv_num(tm_nt()); gv_puts("\n" as *u8) } 261 gv_check("T12 D2 concat: 2 meshes / 3 primitives load as 9 verts / 3 tris (u16 AND u32 indices)" as *u8, t12, ctr) 262 gv_puts(" NOTE donor seed_san.vrm ABSENT estate-wide (measured 2026-08-12, corpus_complete=1) -- D2 donor acceptance awaits re-acquisition; mechanism proven on the synthetic multi-prim fixture above\n" as *u8) 263 264 let rc: i64 = gv_verdict("GLTF-LOAD-GATE" as *u8, ctr, "loader is fail-closed with named reasons; round-trip + positive control + D2 concat intact" as *u8) 265 sys_exit(rc) 266 return rc 267}