nx_provcheck.nx
buildroot/runtime/nx_provcheck.nx
about
nx_provcheck.nx -- ASK THE ARTIFACT WHAT IT WAS BUILT FROM, THEN ASK THE TREE (2026-08-07).
This is the question the treecanon manifest exists to approximate, answered from facts instead:
"is the deployed binary built from the sources that are in the tree right now?"
The manifest answers a DIFFERENT question and answers it backwards. It is generated from the LAPTOP
mirror, pushed to the NAS, and used to judge the NAS tree -- while edits land on the NAS through
nx_fs_write and builds compile FROM the NAS. So it compares truth against a stale copy of a mirror and
reports truth as a fork. Measured 2026-08-07: four different hashes for one header inside ten minutes,
builds blocked by my own newer edit, and a manifest push that lost a file-lock race and simply did not
land. Every one of those is the architecture, not a bug in the guards.
★★★★★★A MANIFEST IS A CLAIM ABOUT A TREE AT A PAST INSTANT; A CLOSURE HASH IS A FACT ABOUT THE BINARY
IN YOUR HAND. `<target>.provenance` records the closure the build actually read; this recomputes the
closure from the tree as it stands and compares. No push, no watermark, no census, nothing that can go
stale between the write and the read, and no second tree required to have an opinion.
VERDICTS -- each its own bucket because each has a different remedy:
CURRENT recorded closure == tree closure. The artifact IS its sources.
DRIFTED they differ. Something in the import closure changed since the build.
UNRECORDED the sidecar has no closure_sha256 (built before this existed, or by the async path).
*NOT A FAILURE AND NOT A PASS* -- it is "I could not look", and it must never be
reported as either. A guard that turns absence into a verdict is the one that gets
switched off after it lies once.
NOSIDECAR no .provenance at all.
nx_provcheck <target> [root] root default "." (run from the buildroot's parent)
exit 0 CURRENT | 1 DRIFTED | 2 UNRECORDED/NOSIDECAR | 3 usage
license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
dependencies 2 imports · 0 importers
imports: nx_tool_run.nxnx_buildecho.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
| 33 | const PC_CAP: i64 = 262144 |
| 34 | const PC_TMO: i64 = 90000 |
functions
| 36 | func pp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } called by 1: main |
| 37 | func pe(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(2,s,n); return 0 } called by 1: main |
| 38 | func pcat(d: *u8, o: i64, s: *u8) -> i64 { var x: i64=o; var i: i64=0; while s[i]!=(0 as u8){d[x]=s[i];x=x+1;i=i+1} return x } called by 1: main |
| 39 | func psame64(a: *u8, b: *u8) -> i64 { var i: i64=0; while i<64 { if a[i]!=b[i] { return 0 } i=i+1 } return 1 } called by 1: main |
| 41 | func main(argc: i64, argv: *i64) -> i64 |