code wiki / _hdl_build / nx_treediverge.nx
nx_treediverge.nx
buildroot/runtime/_hdl_build/nx_treediverge.nx
about
nx_treediverge.nx -- THE MISSING CROSS-TREE DIVERGENCE DETECTOR (debt 1785438829, sev-8).
THE GAP IT CLOSES, in that debt's own words: "nx_dup_source_check finds dups WITHIN buildroot but
there is NO laptop-vs-NAS divergence detector -- I did it BY HAND four times today. BUILD THAT: a
cross-tree census emitting per-file laptop_bytes / nas_bytes / delta / direction, so divergence is a
REPORT rather than an archaeology exercise; size alone would have caught all four of today's instances."
WHY IT MATTERS (not tidiness): /api/build compiles from buildroot, so a fix living only in the laptop
SSOT NEVER REACHES A RUNNING BINARY, and a fix living only in buildroot is DESTROYED by the next sync
from the SSOT. The divergence is BIDIRECTIONAL -- neither tree is a superset -- so a one-way sync in
EITHER direction silently loses work. You cannot merge safely without first knowing the direction
per file. That is exactly what this emits.
COMPOSES, DOES NOT DUPLICATE: nx_treediff already emits one tree's manifest as "<bytes> <relpath>"
per .nx file and says in its own usage that it is "for cross-tree comparison" -- it just never
performed the comparison. This is the missing half. Run nx_treediff on each tree, then:
nx_treediverge <manifestA> <manifestB> [labelA] [labelB]
VERDICTS, per file: A-ONLY / B-ONLY / A-AHEAD / B-AHEAD / SAME. "AHEAD" is BY BYTES, which is the
signal that caught all four historical instances; it is a FLOOR, not proof of content (equal size can
still differ -- see the same-size-rewrite caveat on expect=<size> CAS). Declared, never implied.
NON-VACUITY: an empty or unreadable manifest REFUSES (exit 3) instead of reporting "0 divergent",
because a comparator that reads nothing and prints GREEN is the self-ceiling defect this ecosystem
has banned repeatedly. A zero-divergence verdict is only emitted when BOTH sides actually had rows.
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
| 27 | const TV_MAGIC_5381: i64 = 5381 |
| 29 | const TV_HBUCKETS: i64 = 65536 // hash buckets; power of two so the mask is an AND |
| 30 | const TV_MAXENT: i64 = 200000 // per-tree entry ceiling (corpus is ~17.7k .nx today, 11x headroom) |
| 31 | const TV_BUFCAP: i64 = 16777216 // 16 MiB per manifest (17.7k rows x ~80B ~= 1.4 MiB, 11x headroom) |
functions
| 40 | func tv_puts(s: *u8) -> i64 |
| 46 | func tv_putn(v: i64) -> i64 |
| 61 | func tv_readall(path: *u8, outn: *i64) -> *u8 |
| 78 | func tv_hash(s: *u8) -> i64 |
| 84 | func tv_streq(a: *u8, b: *u8) -> i64 called by 1: tv_find |
| 95 | func tv_parse(buf: *u8, start: i64, end: i64, szout: *i64) -> *u8 |
| 117 | func tv_index(buf: *u8, n: i64) -> i64 |
| 144 | func tv_find(rel: *u8) -> i64 |
| 154 | func tv_emit(tag: *u8, rel: *u8, a: i64, b: i64) -> i64 |
| 163 | func main(argc: i64, argv: *i64) -> i64 |