code wiki / (root) / nx_artifactdrift.nx

nx_artifactdrift.nx

buildroot/runtime/nx_artifactdrift.nx

96790 B1487 linesdepth 8pulls 15 transitivereach 0 importersview sourcekind tool
docsdependenciesstructsconstsfunctions

about

nx_artifactdrift.nx -- IS THE BINARY WE ARE SERVING THE ONE THE LAST BUILD PRODUCED? ⚠THIS ORGAN WAS NAMED WRONG TWICE, AND BOTH GUARDS WERE RIGHT. It shipped as `nx_promotestale` and nx_job_run's launch guard refused it: that guard splits the name on '_' and denies any SEGMENT STARTING WITH a control-plane stem, so "promotestale" reads as promote. Renamed to `nx_servedrift`, /api/promote then refused it as a DAEMON and nx_job_run refused it again -- "servedrift" starts with "serve", and that guard's header states it chose stem-prefix DELIBERATELY so `nx_server` could never escape, calling an escaped server "the brick". -- BOTH REFUSALS WERE CORRECT. A launch guard must be wrong in the direction of REFUSING, and a name that starts with `serve` genuinely looks like a server. The tempting fix -- patch an allow-path into a never-brick guard so it consults organ_kind.conf -- would trade a real safety property for a bad name. -- SO THE NAME MOVED, NOT THE GUARD: this measures DRIFT BETWEEN THE BUILT AND SERVED ARTIFACT, which `artifactdrift` says exactly and claims to be no kind of server. ★★AN ORGAN'S NAME IS PART OF ITS INTERFACE, BECAUSE THE ESTATE'S OWN SAFETY RULES READ IT -- and when a guard and a name disagree, the guard is the thing with a proof behind it. WHY IT EXISTS, MEASURED 2026-08-14: two organs were found SERVING STALE CODE purely because a human happened to notice nx_catalog's BUILT and PROMOTED columns disagree -- nx_vizsla_digest (47,402 served vs 47,596 built) and nx_vizsla_plan (176,882 served vs 217,561 built: ~40 KB, a FIFTH of the organ, missing from the running binary). Both were invisible to every health check the estate runs. -- A RUNNING BINARY THAT IS NOT WHAT ITS SOURCE BUILT IS A SILENT CORRECTNESS AND SECURITY DEFECT: every fix, every audit and every gate verdict then describes code that is not the code being executed. -- SPOTTING IT BY EYE DOES NOT SCALE. nx_catalog answers this one NAME at a time; this sweeps. nx_artifactdrift [judge] [registry] [buildroot] [srcroot_primary] [srcroot_secondary] [declare_conf] [trend_log] THE OWNER-SIGNAL AXIS (DM5 ps_owner_scan, 2026-08-20). Every BEHIND row carries an OWNER SIGNAL, so a promote list built from this census can never omit the check. BEHIND alone is NECESSARY BUT NOT SUFFICIENT for "promote me": a BEHIND row can be ANOTHER SEAT'S WORK IN FLIGHT -- measured live 2026-08-15 on nx_oo_extract_gate, where the only thing that stopped the promote was a human looking. STATES, a partition over the BEHIND rows and NOTHING ELSE: DECLARED a row in the declaration conf claims the target -- a STATEMENT, so it outranks the inferences below and is the mechanism for the standing "declare any build you do not promote" law IN-FLIGHT-SUSPECT scratch siblings <target>.nx.* beside the source, or a same-day source touch SRC-UNRESOLVED no source under either root -- the axis ABSTAINS; it does not acquit UNDECLARED no claim and no signal: the ONLY class eligible to be CONSIDERED, never an order ⚠IT IS A SEPARATE AXIS, exactly like the INERT exec-bit axis and for the same reason -- folding owner states into the IDENTICAL/STALE/NO-BUILD/NO-SERVED/STAGED-POINTER partition would break the reconciliation that makes that partition worth trusting. It reconciles against BEHIND on its own, and

dependencies 3 imports · 0 importers

nx_syscalls.nx nx_heavyio_lib.nx nx_stubmain_lib.nx nx_artifactdrift.nx

imports: nx_syscalls.nxnx_heavyio_lib.nxnx_stubmain_lib.nx

imported by: nobody (leaf or entry point)

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

main ps_streq 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 ↻ hio_admit sys_mmap ↻ hio_root sys_mmap ↻ hio_cat sys_openat_rd sys_close hio_cat ↻ hio_admit_conf_root sys_mmap ↻ hio_conf_read sys_openat_rd ↻ sys_mmap ↻ sys_read sys_close ↻ hio_eol hio_keyis hio_slot hio_atoi hio_running ioa_count_comm ioa_count_comm_mode ioa_slen

structs

none

consts

88const PS_MAXROW: i64 = 4096
89const PS_NAMEMAX: i64 = 256
90const PS_STAT_SIZE_OFF: i64 = 48
93const PS_STAT_MODE_OFF: i64 = 24
94const PS_MODE_OWNER_X: i64 = 64
98const PS_ASCII_v: i64 = 118 // 'v' -- first byte of the ruler's `verdict=` token, a cheap prefilter
99const PS_BYTE_RADIX: i64 = 256 // combining two little-endian bytes of st_mode
100const PS_BIT_SET: i64 = 2 // `% 2` on a shifted mode = is that permission bit set
101const PS_I64_BYTES: i64 = 8 // sizeof(i64) -- the row tables hold i64 handles, not bytes
102const PS_MODE_0644: i64 = 420 // 0644 in decimal, the estate's standard file mode
103const PS_EXIT_NOTFOUND: i64 = 127 // exec convention: command not found
104const PS_ASCII_SLASH: i64 = 47 // '/' -- path separator, for finding a basename
105const PS_ASCII_HASH: i64 = 35 // the comment byte that opens a skipped line in every conf this organ reads
106const PS_STATBUF_BYTES: i64 = 160 // struct stat is 144 B on x86-64; 160 is the rounded buffer three stat helpers share
107const PS_DEFAULT_REG: *u8 = "tool_allowlist.conf"
108const PS_DEFAULT_BROOT: *u8 = "buildroot/_build/"
111const PS_JUDGE_TMP: *u8 = "/tmp/nx_artifactdrift_judge.tmp"
112const PS_TAB: i64 = 9
113const PS_NL: i64 = 10
114const PS_LOGLINE_CAP: i64 = 1536 // the durable trend row's buffer -- named because it grew when the owner axis landed, and RAISED AGAIN when the fork-root axis added five fields. Raised BEFORE those fields were appended, deliberately: a trend row that overruns its buffer corrupts the one durable record this census leaves behind.
121const PS_SRCROOT_A: *u8 = "buildroot/runtime/_hdl_build/"
122const PS_SRCROOT_B: *u8 = "buildroot/runtime/"
123const PS_SRC_EXT: *u8 = ".nx"
127const PS_DECLARE_CONF: *u8 = "knowledge/status/drift_owner_declare.conf"
128const PS_DRIFT_LOG: *u8 = "knowledge/status/artifactdrift.log"
152const PS_FORKROOT: *u8 = "buildroot/_offc/"
155const PS_FORK_MAX: i64 = 1024
162const PS_SCRATCH_MARK: *u8 = ".nx."
163const PS_SCRATCH_MAX: i64 = 8192 // >10x the measured 762; the loader ANNOUNCES if it ever fills (no silent cap)
164const PS_OWN_DIRBUF: i64 = 65536 // getdents read window, the estate's standard directory buffer
165const PS_OWN_NAMES_SHOWN: i64 = 4 // scratch names printed per row; the COUNT is always exact and says PREFIX above this
166const PS_SECS_PER_DAY: i64 = 86400 // a DEFINITION, not a tunable: the UTC day the mtime is bucketed into
167const PS_STAT_MTIME_OFF: i64 = 88 // st_mtime.tv_sec at byte 88 of x86-64 struct stat (size 48, blksize 56, blocks 64, atime 72)
170const PS_OWN_DECLARED: i64 = 0
171const PS_OWN_INFLIGHT: i64 = 1
172const PS_OWN_UNDECLARED: i64 = 2
173const PS_OWN_UNRESOLVED: i64 = 3
190const PS_REF_FRESH: i64 = 0
191const PS_REF_FOSSIL: i64 = 1
192const PS_REF_UNKNOWN: i64 = 2

functions

194func ps_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
199func ps_endswith(s: *u8, slen: i64, sfx: *u8) -> i64
called by 2: ps_dir_elfsmain calls 2: ps_lenps_streq_n
204func ps_puts(s: *u8) -> i64 { sys_write(1, s, ps_len(s)); return 0 }
205func ps_pn(v: i64) -> i64
219func ps_size(path: *u8) -> i64
called by 1: main calls 2: sys_mmapsys_fstatat
236func ps_execbit(path: *u8) -> i64
called by 1: main calls 2: sys_mmapsys_fstatat
249func ps_srcpath(root: *u8, elf: *u8, bs: i64, te: i64, out: *u8) -> i64
called by 1: ps_srcclass
265func ps_srcclass(srca: *u8, srcb: *u8, elf: *u8, bs: i64, te: i64) -> i64
275func ad_cat(d: *u8, o: i64, s: *u8) -> i64 { var p: i64 = o; var i: i64 = 0; while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } return p }
called by 2: ps_owner_scanmain
276func ad_catn(d: *u8, o: i64, v: i64) -> i64
called by 1: main calls 1: sys_mmap
288func ps_streq(a: *u8, b: *u8) -> i64
called by 1: main
300func ps_same(a: *u8, b: *u8) -> i64
called by 1: main calls 2: sys_mmapsys_read_file
328func ps_line_at(b: *u8, n: i64, key: *u8, klen: i64) -> i64
called by 1: ps_explain calls 1: ps_streq_n
348func ps_val_in_line(b: *u8, n: i64, ls: i64, key: *u8, klen: i64) -> i64
called by 1: ps_explain calls 1: ps_streq_n
383func ps_explain(tmp: *u8, out: *i64) -> i64
448func ps_judge(live: *u8, built: *u8, tmp: *u8) -> i64
486func ps_streq_n(a: *u8, b: *u8, n: i64) -> i64
494func ps_contains(s: *u8, sub: *u8) -> i64
called by 1: ps_load_scratch calls 2: ps_lenps_streq_n
505func ps_startswith(s: *u8, pfx: *u8) -> i64
called by 1: ps_scratch_count calls 2: ps_lenps_streq_n
519func ps_load_scratch(dir: *u8, tab: *i64, cap: i64, full: *i64) -> i64
564func ps_dir_elfs(dir: *u8, tab: *i64, cap: i64, full: *i64) -> i64
600func ps_mtime(path: *u8) -> i64
610func ps_decl_has(b: *u8, n: i64, name: *u8) -> i64
called by 1: ps_owner_scan calls 2: ps_lenps_streq_n
642func ps_scratch_count(tab: *i64, ntab: i64, pfx: *u8, show: i64) -> i64
663func ps_owner_scan(stm: *u8, srca: *u8, srcb: *u8, tab: *i64, ntab: i64, declb: *u8, decln: i64, now: i64, out: *i64) -> i64
697func main(argc: i64, argv: *i64) -> i64