code wiki / _hdl_build / nx_treecanon_gate.nx

nx_treecanon_gate.nx

buildroot/runtime/_hdl_build/nx_treecanon_gate.nx

11911 B288 linesdepth 3pulls 3 transitivereach 0 importersview sourcekind gate/proof
docsdependenciesstructsconstsfunctions

about

nx_treecanon_gate.nx -- THE DIVERGENCE GATE THAT REFUSES (debt 1785622769, operator directive 2026-08-01: "ONE canonical tree per generation with a lineage manifest ... a divergence gate that REFUSES a build when the deploying tree's copy diverges from canonical"). MEASURED 2026-08-03, and it is why this exists: NAS buildroot vs laptop nxc2 diverge on 8,258 files -- 3,705 NAS-newer, 1,838 laptop-newer, 739 NAS-only, 1,976 laptop-only. NEITHER TREE IS A SUPERSET IN EITHER DIRECTION. A name-level diff saw only 969 of those, because the dangerous class is files present in BOTH with DIFFERENT BYTES (5,543 of them). ⇒ ★A NAME-LEVEL TREE DIFF IS NOT A DIVERGENCE CHECK. It cannot see the failure that actually bites -- editing a file in one tree and compiling the other copy, which is precisely how the unfreed-mmap fix had to be applied twice (the incident that opened this debt). SCOPE, DELIBERATE AND STATED: this gate does NOT try to reconcile the fork. Blocking on all 8,258 would block every build, and mass-merging on a size screen would be DESTRUCTIVE -- byte size is a SCREEN, not proof of newer (banked law: newer mtime + FEWER bytes = REVERT). It enforces a CANON LIST from knowledge/tree_canon.conf (rule 11: the policy is DATA), starting at the crown jewels and growing by measurement. Stopping the bleeding beats an unfinished cleanup. T0 LOADED both manifests parse and index (non-vacuity floor on the inputs) T1 CANON READ the canon list loads and is non-empty (an empty list would pass vacuously) T2 CANON CLEAN every canon path is present in BOTH trees and byte-identical -- REFUSES otherwise T3 BITE the detector fires on a REAL divergent path and stays silent on a REAL identical one, both discovered from the manifests at runtime (no hardcoded fixture) license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0

dependencies 2 imports · 0 importers

nx_syscalls.nx nx_gate_verdict.nx nx_treecanon_gate.nx

imports: nx_syscalls.nxnx_gate_verdict.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 gv_head gv_puts sys_write gv_puts ↻ sys_mmap ↻ tc_readall sys_openat_rd sys_mmap ↻ sys_read sys_close tc_index sys_mmap ↻ tc_parse tc_hash gv_num sys_mmap ↻ sys_write ↻ sys_munmap gv_check gv_puts ↻ tc_lookup tc_hash ↻ tc_streq tc_diverges tc_lookup ↻ gv_bite gv_puts ↻ gv_verdict gv_puts ↻ gv_num ↻ gv_journal sys_openat_append sys_mmap ↻ gv_catn sys_mmap ↻ sys_munmap ↻ sys_now_realtime_sec

structs

none

consts

28const TC_HBUCKETS: i64 = 65536
29const TC_MAXENT: i64 = 200000
30const TC_BUFCAP: i64 = 16777216
31const TC_CONFCAP: i64 = 262144
32const TC_HASH_SEED: i64 = 5381
33const TC_SPACE: i64 = 32
34const TC_NL: i64 = 10
35const TC_CR: i64 = 13
36const TC_HASHCH: i64 = 35
37const TC_BANG: i64 = 33 // '!' row prefix: the BUILD LANE freezes every build while that row
40const TC_D0: i64 = 48
41const TC_D9: i64 = 57

functions

53func tc_readall(path: *u8, outn: *i64, cap: i64) -> *u8
70func tc_hash(s: *u8) -> i64
called by 2: tc_indextc_lookup
76func tc_streq(a: *u8, b: *u8) -> i64
called by 1: tc_lookup
84func tc_parse(buf: *u8, start: i64, end: i64, szout: *i64) -> *u8
called by 1: tc_index
106func tc_index(buf: *u8, n: i64, htab: *i64, keys: *i64, sizes: *i64) -> i64
called by 1: main calls 3: sys_mmaptc_parsetc_hash
144func tc_lookup(rel: *u8, htab: *i64, keys: *i64, sizes: *i64) -> i64
called by 2: tc_divergesmain calls 2: tc_hashtc_streq
159func tc_diverges(rel: *u8) -> i64
called by 1: main calls 1: tc_lookup
168func main(argc: i64, argv: *i64) -> i64