code wiki / (root) / nx_glbnorm_gate.nx

nx_glbnorm_gate.nx

buildroot/runtime/nx_glbnorm_gate.nx

30706 B599 linesdepth 4pulls 10 transitivereach 0 importersview sourcekind gate/proof
docsdependenciesstructsconstsfunctions

about

nx_glbnorm_gate.nx -- proves that every NORMAL nx_gltf_export writes is a UNIT vector per glTF 2.0, and proves it BY DECODING THE ACTUAL binary32 BYTES OUT OF THE BIN CHUNK OF A FILE THE SUBJECT WROTE. WHY THIS GATE HAD TO EXIST. Until 2026-08-25 every .glb this estate published was invalid. The number came from OUTSIDE: KhronosGroup/glTF-Validator 2.0.0-dev.3.10 under node, over all 18 .glb files pulled from https://nishifamily.com by curl, uncapped -- files=18 clean=0 with_errors=18 threw=0 sum=18, and 33,682 errors, of which ACCESSOR_VECTOR3_NON_UNIT x 33,656. SIX of our own gates ran GREEN over that same code the whole time. They were not weak gates; they were gates that measured our code against our own expectations, and the expectation itself was the bug ("renderers re-normalise" -- a comment, never a measurement). This gate exists so the estate can see that class WITHOUT an external referee: it decodes the emitted bytes and applies a tolerance DERIVED FROM THE REFEREE'S OWN SOURCE LINE if (Math.abs(Math.sqrt(r) - 1) > 0.00674) -> ACCESSOR_VECTOR3_NON_UNIT as GN_TOL_FP. A green here is a claim about the SPEC, not about our taste. THE ANTI-VACUITY CONTROL IS THE WHOLE POINT. gg_prefix_f32 below is a VERBATIM TRANSCRIPTION of the emission this fix replaced. T2 shows it FAILS the identical predicate the fixed path passes, so the tooth can tell a fix from a no-op. T2b proves the transcription is faithful by sweeping it against the still-live gl_i2f32 rather than trusting that it was copied correctly. WHY THIS FILE IS ALL SMALL FUNCTIONS AND main() HOLDS ALMOST NOTHING. NOT STYLE -- A MEASURED LANDMINE. The first draft did the whole job inline in main(), which reached roughly 85 local bindings, and the compiler then MISCOMPILED SOME OF THEM WITH NO DIAGNOSTIC AT ALL. Measured, from that build's own output, with the constants and the inline product printed beside the binding: DUMP GG_NV = 145 ... GG_VEC3_F32_BYTES = 12 ... GG_NV * GG_VEC3_F32_BYTES inline = 1740 DUMP gg_pb = 1756 <- let gg_pb: i64 = GG_NV * GG_VEC3_F32_BYTES DUMP gg_nb = 5244 <- let gg_nb: i64 = GG_NV * GG_VEC3_F32_BYTES (the SAME expression) Two `let`s of one constant expression, in one function, disagreeing with each other AND with that expression evaluated inline one line away. Everything computed from a RUNTIME value in the same function (jlen 724, binoff 752, binlen 6384, fsz 7136) stayed correct and self-consistent throughout. The cost of that landmine was a full RED that looked exactly like a broken fix: the gate read the normal block 8 bytes late and reported 132 of 145 normals non-unit, while the writer had been correct all along -- the real block sat at 752+1740, exactly where it belongs. ***A MISCOMPILED LOCAL IS A SILENT WRONG ANSWER THAT INDICTS THE SUBJECT INSTEAD OF THE INSTRUMENT.*** So every function here stays small, and the BIN layout is derived ONCE, in gg_layout, from PARAMETERS rather than from constant-expression locals. THE GATE READS u32s WITH ITS OWN gg_ru32 AND ENCODES EXPECTED POSITIONS WITH vm_int_to_f32 RATHER THAN THE SUBJECT'S gl_i2f32 -- ON PURPOSE, and for the reason nx_vnormals_gate states: an oracle that borrows its subject's helpers agrees with it by construction and stops being able to detect a change in them. The side effect is a free measurement: T8 passing means gl_i2f32 and vm_int_to_f32(v,1) are the same

dependencies 6 imports · 0 importers

nx_syscalls.nx nx_gate_verdict.nx nx_vecmath.nx nx_vnormals_lib.nx nx_glbnorm_lib.nx nx_gltf_export.nx nx_glbnorm_gate.nx

imports: nx_syscalls.nxnx_gate_verdict.nxnx_vecmath.nxnx_vnormals_lib.nxnx_glbnorm_lib.nxnx_gltf_export.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main gv_ctr sys_mmap nxa_die sys_write sys_exit nxa_lock_take nxa_lock_addr sys_write ↻ nxa_lock_give nxa_lock_addr ↻ nxa_report_overrun sys_write ↻ nxa_dump_printable sys_write ↻ nxa_dump_sizes sys_write ↻ gv_head gv_puts sys_write ↻ sys_mkdir sys_mmap ↻ gg_build_verts gg_set3 gg_h gg_build_cols gg_set3 ↻ gv_check gv_puts ↻ gg_eq gg_build_faces gg_set3 ↻ gg_fixture vm_isqrt gn_unit_err vm_f32_to_int vm_abs vm_isqrt ↻ gg_prefix_f32 gg_distinct

structs

none

consts

61const GG_DIR_MODE: i64 = 493 // 0755, spelled in decimal because this dialect has no octal
62const GG_DIR: *u8 = "/tmp/nx_glbnorm_gate"
63const GG_PLAIN: *u8 = "/tmp/nx_glbnorm_gate/plain.glb"
64const GG_COLOR: *u8 = "/tmp/nx_glbnorm_gate/color.glb"
66const GG_V3: i64 = 3
67const GG_VEC3_F32_BYTES: i64 = 12
68const GG_U32_BYTES: i64 = 4
69const GG_TRI_I: i64 = 3
70const GG_ALPHA_OPAQUE: i64 = 255
71const GG_NO_COLOUR_BLOCK: i64 = 0 // write_glb has no COLOR_0 block between normals and indices
72const GG_HAS_COLOUR_BLOCK: i64 = 1 // write_glb_colored does
76const GG_GLB_HDR_BYTES: i64 = 12
77const GG_CHUNK_HDR_BYTES: i64 = 8
78const GG_OFF_MAGIC: i64 = 0
79const GG_OFF_VERSION: i64 = 4
80const GG_OFF_JSON_LEN: i64 = 12
81const GG_OFF_JSON_TYPE: i64 = 16
82const GG_MAGIC_GLTF: i64 = 0x46546C67
83const GG_MAGIC_JSON: i64 = 0x4E4F534A
84const GG_MAGIC_BIN: i64 = 0x004E4942
85const GG_GLB_VERSION: i64 = 2
86const GG_CONTAINER_CHECKS: i64 = 4
92const GG_N: i64 = 12
93const GG_STEP: i64 = 128
94const GG_NV_GRID: i64 = 144 // GG_N * GG_N
95const GG_NV: i64 = 145 // + the orphan
96const GG_ORPHAN: i64 = 144 // GG_NV - 1
97const GG_NF: i64 = 242 // 2 * (GG_N - 1)^2
102const GG_HA: i64 = 7
103const GG_HB: i64 = 13
104const GG_HC: i64 = 11
105const GG_HD: i64 = 37
106const GG_HE: i64 = 5
107const GG_HF: i64 = 29
108const GG_JX: i64 = 3
109const GG_JXS: i64 = 11
110const GG_JZ: i64 = 4
111const GG_JZS: i64 = 7
112const GG_COL_MOD: i64 = 256
113const GG_MIN_DISTINCT: i64 = 20 // a FLOOR on fixture variety; the measured value is printed
118const GG_RAW_LO: i64 = 995
119const GG_RAW_HI: i64 = 1000
121const GG_SWEEP_LO: i64 = 0 - 40000 // gl_i2f32 transcription sweep, wide enough to cross the sign,
122const GG_SWEEP_HI: i64 = 40000 // the 2^e boundaries and the fx1024 range positions live in
123const GG_OVER_ENVELOPE: i64 = 1048576 // 2^20, far outside GN_IN_MAX, to exercise gn_reduce
124const GG_RULER_OVER: i64 = 4096 // > GN_RULER_MAX, so the ruler must abstain rather than acquit
125const GG_EXP_OF_ONE: i64 = 104 // biased exponent of gn_f32(1) = 2^-23: 127 - 23. Underflow guard.
126const GG_EXP_SHIFT: i64 = 23
127const GG_EXP_MASK: i64 = 255
130const GG_R_BINOFF: i64 = 0
131const GG_R_NORMOFF: i64 = 1
132const GG_R_COLOFF: i64 = 2
133const GG_R_IDXOFF: i64 = 3
134const GG_R_BINLEN: i64 = 4
135const GG_R_CONT: i64 = 5
136const GG_R_WORST: i64 = 6
137const GG_R_BAD: i64 = 7
138const GG_R_UNMEAS: i64 = 8
139const GG_R_WORSTX: i64 = 9
140const GG_R_BADX: i64 = 10
141const GG_R_RT: i64 = 11
142const GG_R_N: i64 = 12
145const GG_F_RAWLO: i64 = 0
146const GG_F_RAWHI: i64 = 1
147const GG_F_DISTINCT: i64 = 2
148const GG_F_PREFAIL: i64 = 3
149const GG_F_N: i64 = 4
413const GG_KB_ONE: i64 = 1065353216
414const GG_KD_ONE: *u8 = "1"
415const GG_KB_HALF: i64 = 1056964608
416const GG_KD_HALF: *u8 = "0.5"
417const GG_KB_EIGHTH: i64 = 1040187392
418const GG_KD_EIGHTH: *u8 = "0.125"
419const GG_KB_DANCE: i64 = 1098776576
420const GG_KD_DANCE: *u8 = "15.875"
421const GG_KB_SEEDSAN: i64 = 3286131474
422const GG_KD_SEEDSAN: *u8 = "-444.77398681640625"
423const GG_KD_TRUNC: *u8 = "-444"
424const GG_KB_NEGONE: i64 = 3212836864
425const GG_KD_NEGONE: *u8 = "-1"
428const GG_KB_TINY: i64 = 869711765
429const GG_KD_TINY: *u8 = "0.00000010000000116860974230803549289703369140625"
430const GG_KB_HUGE: i64 = 2139095039
431const GG_KD_HUGE: *u8 = "340282346638528859811704183484516925440"
432const GG_KAT_COUNT: i64 = 8
433const GG_DEC_SWEEP_LO: i64 = 0 - 20000
434const GG_DEC_SWEEP_HI: i64 = 20000
435const GG_DEC_BUF: i64 = 384

functions

151func gg_pv(label: *u8, v: i64) -> i64 { gv_puts(label); gv_num(v); gv_puts("\n" as *u8); return 0 }
called by 1: main calls 2: gv_putsgv_num
152func gg_eq(a: i64, b: i64) -> i64 { if a == b { return 1 } return 0 }
called by 1: main
155func gg_both(a: i64, b: i64) -> i64 { if a == 1 { if b == 1 { return 1 } } return 0 }
called by 1: main
156func gg_ge(a: i64, b: i64) -> i64 { if a >= b { return 1 } return 0 }
called by 1: main
157func gg_le(a: i64, b: i64) -> i64 { if a <= b { return 1 } return 0 }
called by 1: main
161func gg_ru32(b: *u8, at: i64) -> i64
167func gg_prefix_f32(v: i64) -> i64
182func gg_h(i: i64, j: i64) -> i64 { return ((i*GG_HA + j*GG_HB) % GG_HC) * GG_HD - ((i*j) % GG_HE) * GG_HF }
called by 1: gg_build_verts
184func gg_set3(a: *i64, i: i64, x: i64, y: i64, z: i64) -> i64 { a[i*GG_V3+0]=x; a[i*GG_V3+1]=y; a[i*GG_V3+2]=z; return 0 }
186func gg_build_verts(v: *i64) -> i64
called by 1: main calls 2: gg_set3gg_h
201func gg_build_faces(f: *i64) -> i64
called by 1: main calls 1: gg_set3
218func gg_build_cols(c: *i64) -> i64
called by 1: main calls 1: gg_set3
231func gg_layout(glb: *u8, nv: i64, ncol: i64, out: *i64) -> i64
called by 1: main calls 1: gg_ru32
249func gg_expect_binlen(nv: i64, nf: i64, ncol: i64) -> i64
called by 1: main
255func gg_measure(glb: *u8, nv: i64, normoff: i64, out: *i64) -> i64
288func gg_pos_ok(glb: *u8, vbuf: *i64, nv: i64, binoff: i64) -> i64
called by 1: main calls 2: gg_ru32vm_int_to_f32
297func gg_idx_ok(glb: *u8, fbuf: *i64, nf: i64, idxoff: i64) -> i64
called by 1: main calls 1: gg_ru32
306func gg_col_ok(glb: *u8, cbuf: *i64, nv: i64, coloff: i64) -> i64
called by 1: main
320func gg_orphan_ok(glb: *u8, normoff: i64) -> i64
called by 1: main calls 2: gg_ru32gn_f32
328func gg_distinct(nrm: *i64, n: i64) -> i64
called by 1: gg_fixture
350func gg_fixture(nrm: *i64, nv: i64, out: *i64) -> i64
368func gg_transcription_ok() -> i64
called by 1: main calls 2: gg_prefix_f32gl_i2f32
378func gg_shifts(nrm: *i64, nv: i64, un: *i64) -> i64
called by 1: main calls 1: gn_unit3
389func gg_report(tag: *u8, r: *i64) -> i64
called by 1: main calls 2: gv_putsgv_num
404func gg_err_at(glb: *u8, normoff: i64) -> i64
called by 1: main calls 2: gn_unit_errgg_ru32
437func gg_dec_is(bits: i64, want: *u8, buf: *u8) -> i64
called by 2: gg_katsmain calls 1: gn_dec_f32
450func gg_kats(buf: *u8) -> i64
called by 1: main calls 1: gg_dec_is
469func gg_key_ok() -> i64
called by 1: main calls 2: gn_f32_keyvm_int_to_f32
478func gg_dec_int_ok(buf: *u8, ibuf: *u8) -> i64
called by 1: main calls 3: gn_dec_f32vm_int_to_f32gl_num
494func main() -> i64