code wiki / (root) / nx_roundtrip.nx

nx_roundtrip.nx

buildroot/runtime/nx_roundtrip.nx

16524 B398 linesdepth 5pulls 5 transitivereach 0 importersview sourcekind tool
docsdependenciesstructsconstsfunctions

about

nx_roundtrip.nx -- THE SELF-ORACLE: nishi -> glTF -> nishi, and NAME WHAT THE TRIP LOSES. WHY THIS EXISTS. Every other fidelity oracle in this estate is currently blocked on ground truth: the rigged reference corpus was measured 2026-08-22 and is DEGENERATE (eleven .nxa files byte-identical in geometry), and D:\rigs is empty. A ROUND TRIP needs none of that. It compares our own ingest against our own export, so it is available today, it carries no licensing question, and it measures the one thing an external corpus can never tell us: what OUR OWN PIPELINE destroys. IT COMPOSES, IT DOES NOT REIMPLEMENT. It forks nx_mesh2glb (NXMSH2 -> glb) then nx_gltf2mesh (glb -> NXMSH2) and compares the input with the output. There is exactly one glTF writer and one glTF reader in the estate and this organ is neither of them. WHAT "IDENTICAL" MEANS HERE, AND WHY NOT BYTE IDENTITY. glTF is JSON plus a binary blob; key order, float formatting and accessor packing are all free to change without meaning changing. Byte-comparing the containers would report LOSSY on a lossless trip. So the assertion is SEMANTIC: triangle count, layer count, layer NAMES, and vertex POSITIONS. THE POSITION TOLERANCE IS ZERO, AND THAT IS DERIVED, NOT CHOSEN. nx_mesh2glb's own header states positions "PASS THROUGH as raw f32 bits (zero re-quantisation)", and its code copies the 4-byte word with mg_w32 without decoding it. A pass-through has no error term, so the correct tolerance is EXACT BIT EQUALITY. Picking an epsilon would have hidden a real requantisation bug behind a number nobody derived. If positions ever stop matching bit-for-bit, that is a REGRESSION IN THE WRITER, not rounding. NORMALS AND COLOURS ARE KNOWN-LOSSY BY DESIGN and are deliberately NOT asserted: the writer transcodes per-vertex normals f32 -> normalized i16 and per-tri colour f32 -> u8. Asserting on them would make this organ permanently RED for a documented, intended conversion, and a detector that is permanently red is one everyone learns to ignore. They are REPORTED, never scored. EXITS: 0 IDENTICAL | 1 LOSSY | 2 usage | 3 UNOBSERVABLE 3 IS NOT A SOFTER 1. A missing tool, a fork that returns 127, an empty output, or an unreadable container means the trip WAS NOT OBSERVED -- reporting that as LOSSY would blame the format for a harness failure. This estate has been bitten by exactly that confusion, so the two are kept structurally apart. license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0

dependencies 2 imports · 0 importers

nx_syscalls.nx nx_tool_run.nx nx_roundtrip.nx

imports: nx_syscalls.nxnx_tool_run.nx

imported by: nobody (leaf or entry point)

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

main rt_usage rt_out sys_write sys_exit rt_check 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 ↻ rt_out ↻ rt_join sys_unlinkat sys_read_file sys_openat_rd sys_lseek sys_mmap ↻ sys_read sys_munmap sys_close rt_hdr rt_u32 rt_say rt_bputs rt_bputnum sys_write ↻ rt_run2 sys_mmap ↻ tr_run_capture

structs

none

consts

38const RT_EXIT_IDENTICAL: i64 = 0
39const RT_EXIT_LOSSY: i64 = 1
40const RT_EXIT_USAGE: i64 = 2
41const RT_EXIT_UNOBSERVABLE: i64 = 3
46const RT_MAGIC_N: i64 = 78 // 'N' at offset 0
47const RT_MAGIC_2: i64 = 50 // '2' at offset 5
48const RT_MAGIC_2_OFF: i64 = 5
49const RT_NLAY_OFF: i64 = 8 // u32 layer count
50const RT_NTRI_OFF: i64 = 12 // u32 triangle count
51const RT_HDR_BASE: i64 = 16 // first layer record
52const RT_LAYER_STRIDE: i64 = 24 // name[16] + u32 off + u32 count
53const RT_LAYER_NAME_LEN: i64 = 16
54const RT_LAYER_OFF_FLD: i64 = 16
55const RT_LAYER_CNT_FLD: i64 = 20
56const RT_TRI_STRIDE: i64 = 84 // 36 position + 36 normal + 12 colour
57const RT_POS_BYTES: i64 = 36 // the only bytes asserted; see header
58const RT_MIN_CONTAINER: i64 = 44 // the smallest readable NXMSH2, per the writer's own guard
60const RT_WORD: i64 = 8
61const RT_U32_BYTES: i64 = 4
62const RT_BYTE_MASK: i64 = 255
63const RT_STDOUT: i64 = 1
64const RT_PATH_CAP: i64 = 4096
65const RT_CAP_CAP: i64 = 262144 // capture buffer for a forked tool's stdout
66const RT_ARGV_SLOTS: i64 = 8
67const RT_SCRATCH: i64 = 64
68const RT_DECIMAL: i64 = 10
69const RT_ASCII_ZERO: i64 = 48
70const RT_ASCII_MINUS: i64 = 45
71const RT_ASCII_NL: i64 = 10
72const RT_ASCII_SLASH: i64 = 47
73const RT_EXEC_NOT_FOUND: i64 = 127 // execve failure surfaces here; NOT a lossy trip
74const RT_VERB_CHECK: i64 = 99 // 'c'
78const RT_NAME_REPORT_MAX: i64 = 12
80const RT_M2G_DEFAULT: *u8 = "/volume1/homes/elderwesto/nishihost/_offc/nx_mesh2glb.elf"
81const RT_G2M_DEFAULT: *u8 = "/volume1/homes/elderwesto/nishihost/_offc/nx_gltf2mesh.elf"
82const RT_MID_NAME: *u8 = "rt_mid.glb"
83const RT_BACK_NAME: *u8 = "rt_back.nxmesh"

functions

85func rt_out(s: *u8) -> i64
called by 2: rt_usagert_check calls 1: sys_write
91func rt_u32(b: *u8, o: i64) -> i64
called by 1: rt_hdr
94func rt_bputs(buf: *u8, off: i64, s: *u8) -> i64
called by 1: rt_say
100func rt_bputnum(buf: *u8, off: i64, v: i64, scratch: *u8) -> i64
called by 1: rt_say
115func rt_say(label: *u8, v: i64, scratch: *u8, line: *u8) -> i64
124func rt_join(dst: *u8, dir: *u8, name: *u8) -> i64
called by 1: rt_check
145func rt_run2(tool: *u8, a1: *u8, a2: *u8, cap: *u8, olen: *i64) -> i64
called by 1: rt_check calls 2: sys_mmaptr_run_capture
154func rt_hdr(b: *u8, n: i64, out: *i64) -> i64
called by 1: rt_check calls 1: rt_u32
171func rt_name_eq(a: *u8, ao: i64, b: *u8, bo: i64) -> i64
called by 1: rt_check
179func rt_print_name(b: *u8, off: i64) -> i64
called by 1: rt_check calls 1: sys_write
189func rt_usage() -> i64
called by 1: main calls 1: rt_out
199func rt_check(inp: *u8, scratch_dir: *u8, m2g: *u8, g2m: *u8) -> i64
377func main(argc: i64, argv: *i64) -> i64