code wiki / (root) / nx_nxwreap_lib.nx

nx_nxwreap_lib.nx

buildroot/runtime/nx_nxwreap_lib.nx

21486 B429 linesdepth 5pulls 5 transitivereach 2 importersview sourcekind library
docsdependenciesstructsconstsfunctions

about

nx_nxwreap_lib.nx -- THE CLASSIFIER for LEAKED WRITE-GUARD SCRATCH FILES, and the ONE place the decision to remove one is taken. No `main`: the CLI (nx_nxwreap) and the gate (nx_nxwreap_gate) both import THIS, so the reaper and its proof cannot disagree about what a scratch file is. --------------------------------------------------------------------------------------------- THE DEFECT, MEASURED 2026-08-25. nx_fs_write lands every atomic write through a temp named <path>.nxw<pid> and renames it away on success (nx_fsops_lib.fsx_write). BOTH of its failure paths -- a short write and a failed rename -- ALREADY unlink that temp, so an ordinary FAILED write leaves nothing behind. What is left is the single case in which no code of ours runs at all: a writer KILLED between the open and the rename. Eleven agents were killed mid-write on this estate today by spend/session/weekly limits, and `nx_shelltool glob \"*.nxw*\" buildroot/runtime` returned matches=192 corpus_complete=1. THE INFLOW FOR *FAILED* WRITES IS ALREADY CLOSED. THIS ORGAN EXISTS FOR THE *KILLED* WRITER, WHICH NO amount OF CLEANUP CODE IN THE WRITER CAN EVER REACH. THE HARM IS NOT THE DISK, IT IS THE CENSUS. A scratch file is a FULL COPY OF A SOURCE FILE lying beside that source file, so `nx_shelltool find <name> buildroot/runtime` returns the fossils -- `find nx_organ_ship` returned 9 rows of which 5 were .nxw* -- and any name or content scan that does not filter by extension can read PRESENT off a fossil after the real file was already fixed. A STALE FULL COPY BESIDE THE FILE IT COPIES IS A FALSE-NEGATIVE-ON-ABSENCE GENERATOR. BOUNDED HONESTLY, because the scope of a claim is part of the claim: the EXT-FILTERED path is NOT affected. `nx_absent <pattern> <dir> nx` cannot match `....nxw12848`, since that name does not end in `.nx`. The blast radius is every UNFILTERED name/content scan, and only those. --------------------------------------------------------------------------------------------- FAIL-SAFE BY CONSTRUCTION, INHERITED RATHER THAN RE-STATED. The predicate is nx_lock_reap_core.lr_should_reap -- reap iff the file EXISTS AND its owner is NOT alive AND it is older than the threshold; everything else is 0. It is NOT re-implemented here. This organ contributes exactly one thing the lock reaper cannot: the OWNER IS IN THE FILENAME. WHY /proc/<pid> AND NOT lr_owner_alive's CMDLINE NEEDLE. The lock reaper identifies an owner by scanning every /proc/<pid>/cmdline for a substring, because a lock file does not say who holds it. A write-guard scratch file DOES say: the pid is its own suffix. Testing /proc/<pid> directly is one stat instead of a whole-/proc walk, and it is exact rather than a substring guess. PID REUSE IS REAL, AND IT IS RESOLVED IN THE SAFE DIRECTION. A dead writer's pid can be recycled by an unrelated process, and nothing in the filename can distinguish that from the original writer still running. So: IF /proc/<pid> EXISTS WE DO NOT REAP, even though the true owner may be long dead. That leaves some litter -- the HARMLESS failure. The other direction unlinks the in-flight temp of a LIVE writer, destroying a write that was about to succeed -- the HARMFUL one.

dependencies 2 imports · 2 importers

nx_syscalls.nx nx_lock_reap_core.nx nx_nxwreap_lib.nx nx_nxwreap.nx nx_nxwreap_gate.nx

imports: nx_syscalls.nxnx_lock_reap_core.nx

imported by: nx_nxwreap.nxnx_nxwreap_gate.nx

structs

none

consts

80const NW_SUFFIX: *u8 = ".nxw" as *u8
81const NW_SUF_LEN: i64 = 4
82const NW_PROC: *u8 = "/proc/" as *u8
83const NW_SLASH: i64 = 47
84const NW_CH_ZERO: i64 = 48
85const NW_CH_NINE: i64 = 57
86const NW_B10: i64 = 10
89const NW_PID_MAX_DIGITS: i64 = 10
93const NW_PID_NOT_NXW: i64 = 0 - 1
94const NW_PID_MALFORMED: i64 = 0 - 2
97const NW_D_REAP: i64 = 0
98const NW_D_LIVE_OWNER: i64 = 1
99const NW_D_TOO_YOUNG: i64 = 2
100const NW_D_MALFORMED: i64 = 3
101const NW_D_VANISHED: i64 = 4
102const NW_D_NOT_REGULAR: i64 = 5
103const NW_D_PATHLONG: i64 = 6
104const NW_D_NOT_NXW: i64 = 7
110const NW_C_TOTAL: i64 = 0
111const NW_C_REAP: i64 = 1
112const NW_C_LIVE_OWNER: i64 = 2
113const NW_C_TOO_YOUNG: i64 = 3
114const NW_C_MALFORMED: i64 = 4
115const NW_C_VANISHED: i64 = 5
116const NW_C_NOT_REGULAR: i64 = 6
117const NW_C_PATHLONG: i64 = 7
118const NW_C_NOT_NXW: i64 = 8
119const NW_C_UNLINKED: i64 = 9
120const NW_C_UNLINK_FAIL: i64 = 10
121const NW_C_WOULD: i64 = 11
122const NW_C_DIRS: i64 = 12
123const NW_C_SLOTS: i64 = 13
126const NW_I_PID: i64 = 0
127const NW_I_AGE: i64 = 1
128const NW_I_ALIVE: i64 = 2
129const NW_I_SLOTS: i64 = 3
131const NW_I64_BYTES: i64 = 8
132const NW_DENTBUF: i64 = 65536
133const NW_PATHBUF: i64 = 4096
134const NW_PIDBUF: i64 = 64
135const NW_CONFBUF: i64 = 256
138const NW_SHIP_TIMEOUT_MS: i64 = 900000 // == nx_organ_ship.nx OS_TIMEOUT_MS, cited by name
139const NW_MS_PER_S: i64 = 1000
140const NW_DEFAULT_MAX_AGE_SEC: i64 = 3600 // == nx_jobclaim_lib.nx JR_DEFAULT_MAX_AGE_SEC
141const NW_MAXAGE_CONF: *u8 = "knowledge/status/nxwreap_maxage.conf" as *u8
142const NW_SRC_CONF: i64 = 0
143const NW_SRC_DEFAULT: i64 = 1

functions

145func nw_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
146func nw_num(v: i64) -> i64 { nxi_out(v); return 0 }
150func nw_ship_bound_s() -> i64 { return NW_SHIP_TIMEOUT_MS / NW_MS_PER_S }
called by 2: mainmain
154func nw_maxage(srcp: *i64) -> i64
168func nw_maxage_src_name(s: i64) -> *u8
called by 2: mainmain
173func nw_decision_name(d: i64) -> *u8
185func nw_decision_why(d: i64) -> *u8
197func nw_ctr() -> *i64
called by 2: mainmain calls 1: sys_mmap
208func nw_pid_of(name: *u8, nlen: i64) -> i64
called by 2: gt_pidnw_classify
242func nw_pid_alive(pid: i64, pbuf: *u8) -> i64
253func nw_classify(dir: *u8, name: *u8, nlen: i64, dtype: i64, now: i64, max_age_s: i64,
287func nw_bump(out: *i64, d: i64) -> i64
called by 1: nw_scan
299func nw_sum(out: *i64) -> i64
312func nw_axis_sum(out: *i64) -> i64
318func nw_report(path: *u8, info: *i64, apply: i64, out: *i64) -> i64
called by 1: nw_scan calls 3: nw_putsnw_numlr_unlink
349func nw_scan(dir: *u8, now: i64, max_age_s: i64, apply: i64, out: *i64) -> i64
389func nw_print_partition(out: *i64) -> i64