code wiki / _hdl_build / nx_treediff.nx
nx_treediff.nx
buildroot/runtime/_hdl_build/nx_treediff.nx
about
nx_treediff.nx -- CROSS-TREE SOURCE DIVERGENCE CENSUS (laptop SSOT vs NAS buildroot).
THE GAP IT CLOSES (filed seq1429, hit FOUR times in one session 2026-07-30):
seq768 the build-admission enforcement was in NEITHER tree
seq1393 five compiler defects existed ONLY in the buildroot copy
seq1419 the deployed compiler was fine; the buildroot copy was the divergent one
seq1429 nx_office_daemon/nx_survey_daemon were stale in buildroot while the SSOT was migrated
nx_dup_source_check finds duplicate basenames WITHIN buildroot. NOTHING compared the buildroot
against the laptop SSOT, so every one of those was found by hand, by accident, after the damage.
WHY IT MATTERS BEYOND TIDINESS: /api/build compiles from BUILDROOT. A fix that lives only in the
SSOT never reaches a running binary; a fix that lives only in buildroot is destroyed by the next
sync from the SSOT. BOTH DIRECTIONS SILENTLY LOSE WORK, which is why divergence must be a REPORT,
not an archaeology exercise.
DESIGN: this half runs ON THE NAS and emits a manifest of `<bytes> <relpath>` for one tree, in a
stable sorted-by-path order. The caller diffs two manifests (one per tree). Byte SIZE is a
deliberately cheap discriminator -- it caught all four of today's instances -- and it needs no hash
primitive on either side. A size match is NOT proof of identity; it is a screen that turns an
unbounded search into a short candidate list, and it says so in its own output rather than implying
certainty it does not have.
FAIL-CLOSED + HONEST ENVELOPE: every cap is declared in-band (files scanned, cap hit, depth). A
scanner that silently truncates its own coverage is the self-ceiling defect (law L011) -- so if a
cap is reached the verdict SAYS SO and reports PARTIAL rather than presenting a floor as a total.
DIALECT: plain-if, no empty literals, <=6 params, consts above use.
dependencies 1 imports · 0 importers
imports: nx_syscalls.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 29 | const TD_MAX_FILES: i64 = 40000 // upper bound on emitted rows; declared, never silent |
| 30 | const TD_MAX_DEPTH: i64 = 8 // recursion depth cap |
| 31 | const TD_PATH_CAP: i64 = 1024 |
| 32 | const TD_NAME_CAP: i64 = 256 |
| 33 | const TD_DIRENT_BUF: i64 = 65536 |
| 35 | const TD_OUTBUF: i64 = 4194304 // 4 MiB manifest buffer (~19.8k rows x ~60B, with headroom) |
functions
| 48 | func td_puts(s: *u8) -> i64 |
| 54 | func td_putn(v: i64) -> i64 |
| 67 | func td_cat(d: *u8, o: i64, s: *u8) -> i64 called by 1: td_walk |
| 74 | func td_ends_nx(nm: *u8) -> i64 called by 1: td_walk |
| 84 | func td_size(path: *u8) -> i64 |
| 94 | func td_row(sz: i64, rel: *u8) -> i64 |
| 123 | func td_walk(dir: *u8, rel: *u8, depth: i64) -> i64 called by 2: td_walkmain calls 12: sys_openat_rdsys_mmapsys_getdents64dirent_reclendirent_typedirent_name+6 |
| 171 | func main(argc: i64, argv: *i64) -> i64 |