nx_nxwreap_lib.nx
buildroot/runtime/nx_nxwreap_lib.nx
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
imports: nx_syscalls.nxnx_lock_reap_core.nx
imported by: nx_nxwreap.nxnx_nxwreap_gate.nx
structs
| none |
consts
| 80 | const NW_SUFFIX: *u8 = ".nxw" as *u8 |
| 81 | const NW_SUF_LEN: i64 = 4 |
| 82 | const NW_PROC: *u8 = "/proc/" as *u8 |
| 83 | const NW_SLASH: i64 = 47 |
| 84 | const NW_CH_ZERO: i64 = 48 |
| 85 | const NW_CH_NINE: i64 = 57 |
| 86 | const NW_B10: i64 = 10 |
| 89 | const NW_PID_MAX_DIGITS: i64 = 10 |
| 93 | const NW_PID_NOT_NXW: i64 = 0 - 1 |
| 94 | const NW_PID_MALFORMED: i64 = 0 - 2 |
| 97 | const NW_D_REAP: i64 = 0 |
| 98 | const NW_D_LIVE_OWNER: i64 = 1 |
| 99 | const NW_D_TOO_YOUNG: i64 = 2 |
| 100 | const NW_D_MALFORMED: i64 = 3 |
| 101 | const NW_D_VANISHED: i64 = 4 |
| 102 | const NW_D_NOT_REGULAR: i64 = 5 |
| 103 | const NW_D_PATHLONG: i64 = 6 |
| 104 | const NW_D_NOT_NXW: i64 = 7 |
| 110 | const NW_C_TOTAL: i64 = 0 |
| 111 | const NW_C_REAP: i64 = 1 |
| 112 | const NW_C_LIVE_OWNER: i64 = 2 |
| 113 | const NW_C_TOO_YOUNG: i64 = 3 |
| 114 | const NW_C_MALFORMED: i64 = 4 |
| 115 | const NW_C_VANISHED: i64 = 5 |
| 116 | const NW_C_NOT_REGULAR: i64 = 6 |
| 117 | const NW_C_PATHLONG: i64 = 7 |
| 118 | const NW_C_NOT_NXW: i64 = 8 |
| 119 | const NW_C_UNLINKED: i64 = 9 |
| 120 | const NW_C_UNLINK_FAIL: i64 = 10 |
| 121 | const NW_C_WOULD: i64 = 11 |
| 122 | const NW_C_DIRS: i64 = 12 |
| 123 | const NW_C_SLOTS: i64 = 13 |
| 126 | const NW_I_PID: i64 = 0 |
| 127 | const NW_I_AGE: i64 = 1 |
| 128 | const NW_I_ALIVE: i64 = 2 |
| 129 | const NW_I_SLOTS: i64 = 3 |
| 131 | const NW_I64_BYTES: i64 = 8 |
| 132 | const NW_DENTBUF: i64 = 65536 |
| 133 | const NW_PATHBUF: i64 = 4096 |
| 134 | const NW_PIDBUF: i64 = 64 |
| 135 | const NW_CONFBUF: i64 = 256 |
| 138 | const NW_SHIP_TIMEOUT_MS: i64 = 900000 // == nx_organ_ship.nx OS_TIMEOUT_MS, cited by name |
| 139 | const NW_MS_PER_S: i64 = 1000 |
| 140 | const NW_DEFAULT_MAX_AGE_SEC: i64 = 3600 // == nx_jobclaim_lib.nx JR_DEFAULT_MAX_AGE_SEC |
| 141 | const NW_MAXAGE_CONF: *u8 = "knowledge/status/nxwreap_maxage.conf" as *u8 |
| 142 | const NW_SRC_CONF: i64 = 0 |
| 143 | const NW_SRC_DEFAULT: i64 = 1 |
functions
| 145 | func 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 } |
| 146 | func nw_num(v: i64) -> i64 { nxi_out(v); return 0 } |
| 150 | func nw_ship_bound_s() -> i64 { return NW_SHIP_TIMEOUT_MS / NW_MS_PER_S } |
| 154 | func nw_maxage(srcp: *i64) -> i64 |
| 168 | func nw_maxage_src_name(s: i64) -> *u8 |
| 173 | func nw_decision_name(d: i64) -> *u8 |
| 185 | func nw_decision_why(d: i64) -> *u8 |
| 197 | func nw_ctr() -> *i64 |
| 208 | func nw_pid_of(name: *u8, nlen: i64) -> i64 |
| 242 | func nw_pid_alive(pid: i64, pbuf: *u8) -> i64 |
| 253 | func nw_classify(dir: *u8, name: *u8, nlen: i64, dtype: i64, now: i64, max_age_s: i64, |
| 287 | func nw_bump(out: *i64, d: i64) -> i64 called by 1: nw_scan |
| 299 | func nw_sum(out: *i64) -> i64 |
| 312 | func nw_axis_sum(out: *i64) -> i64 |
| 318 | func nw_report(path: *u8, info: *i64, apply: i64, out: *i64) -> i64 |
| 349 | func nw_scan(dir: *u8, now: i64, max_age_s: i64, apply: i64, out: *i64) -> i64 called by 2: mainmain calls 12: sys_openat_rdsys_mmapsys_getdents64dirent_reclendirent_nameccz_slen+6 |
| 389 | func nw_print_partition(out: *i64) -> i64 |