code wiki / (root) / nx_stalesweep.nx

nx_stalesweep.nx source

↩ module page · 218 lines · 11233 B

1// nx_stalesweep.nx -- SOVEREIGN replacement for nx_stale_sweep.cron.sh (2026-08-07). 2// 3// WHAT IT MEASURES: an organ whose LIVE elf is older than its buildroot SOURCE is a stale mirror -- the 4// class that was previously found by injury (Jul-19 clock elf; argecho 81h) rather than measured. 5// 6// THE PROPERTY THAT MUST SURVIVE THE PORT, and it is the reason this file exists rather than a swap: 7// the script files ONE ROLLUP debt with CONSTANT text, never one row per stale organ. Its own comment 8// names the debt that taught it: 1785525470, `a beat that files one row per instance converts a metric 9// into a backlog`. 10// (STAR)A RECURRING BEAT THAT FILES ONE ROW PER INSTANCE CONVERTS A METRIC INTO A BACKLOG -- FILE ONE 11// ROLLUP ROW WITH CONSTANT TEXT AND KEEP THE INSTANCE LIST IN A REGENERATED FILE. 12// The ledger row is the POINTER; knowledge/status/stale_mirror.worklist is the TRUTH. 13// 14// TWO MORE PROPERTIES A CARELESS PORT WOULD DESTROY: 15// - SOURCE RESOLUTION ORDER. Prefer buildroot/runtime/_hdl_build/<b>.nx, and only then 16// buildroot/runtime/<b>.nx. buildrun compiles the _hdl_build twin when BOTH exist, so checking the 17// runtime twin would verify the WRONG elf and report a stale mirror that is not stale. 18// - THE DOCTRINE SENTENCE. source-newer is AMBIGUOUS (pending upgrade vs uncommitted WIP), so the debt 19// says TRIAGE and explicitly forbids blanket-rebuild. Drop that line and this beat stops being a 20// triage signal and becomes a rebuild trigger that ships half-work. 21// 22// nx_stalesweep [stale-hours] (no args on the clock; conf then 72) 23// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 24import "nx_syscalls.nx" 25const SS_MAGIC_3600: i64 = 3600 26const SS_MAGIC_1024: i64 = 1024 27 28const SS_CONF: *u8 = "knowledge/status/stalesweep.conf" 29const SS_WORKTMP: *u8 = "knowledge/status/.stale_mirror.worklist.tmp" 30const SS_WORKLIST: *u8 = "knowledge/status/stale_mirror.worklist" 31const SS_HDL: *u8 = "buildroot/runtime/_hdl_build/" 32const SS_RT: *u8 = "buildroot/runtime/" 33const SS_DEBT: *u8 = "/volume1/homes/elderwesto/nishihost/nx_debt.elf" 34const SS_DIRBUF: i64 = 262144 35const SS_NAMEW: i64 = 256 36const SS_MAXELF: i64 = 4096 37const SS_MODE: i64 = 0x1a4 38const SS_DEF_TH: i64 = 72 39const SS_STATBUF: i64 = 256 40const SS_MTIME_OFF: i64 = 88 41const SS_OUTCAP: i64 = 1048576 42 43func ss_o(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 44func ss_cat(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 } 45func ss_num(d: *u8, o: i64, v: i64) -> i64 { var x: i64=o; var mm: i64=v; if mm<0{d[x]=45 as u8;x=x+1;mm=0-mm} if mm==0{d[x]=48 as u8;return x+1} let t:*u8=sys_mmap(24); var k:i64=0; while mm>0{t[k]=(48+(mm%10)) as u8;mm=mm/10;k=k+1} var j:i64=0; while j<k{d[x]=t[k-1-j];x=x+1;j=j+1} return x } 46func ss_len(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 47func ss_slot(b: *u8, i: i64) -> *u8 { return ((b as i64) + i*SS_NAMEW) as *u8 } 48func ss_atoi(s: *u8) -> i64 { var v: i64=0; var i: i64=0; while s[i]!=(0 as u8){ if s[i]<(48 as u8){return v} if s[i]>(57 as u8){return v} v=v*10+((s[i]-(48 as u8)) as i64); i=i+1 } return v } 49func ss_opendir(p: *u8) -> i64 { return __syscall(257, 0-100, p as i64, 0x10000, 0, 0, 0) } 50 51// st_mtime SECONDS -- the CANONICAL channel, LIFTED from gv_mtime in nx_gate_verdict_lib.nx rather than 52// re-derived (nx_gatebuilt_gate.nx records doing exactly the same, and the offset is proven by 53// _freshness_gate T5). Returns -1 when unstattable: FAIL-CLOSED, never 0-means-brand-new -- a 0 here 54// would make every unstattable path look infinitely stale and flood the rollup. 55func ss_mtime(path: *u8) -> i64 { 56 let sb: *u8 = sys_mmap(SS_STATBUF) 57 if sys_fstatat(path, sb) != 0 { return 0 - 1 } 58 let mp: *i64 = ((sb as i64) + SS_MTIME_OFF) as *i64 59 return mp[0] 60} 61 62func ss_ends_elf(nm: *u8) -> i64 { 63 let n: i64 = ss_len(nm) 64 if n <= 4 { return 0 } 65 if nm[n-4] != (46 as u8) { return 0 } 66 if nm[n-3] != (101 as u8) { return 0 } 67 if nm[n-2] != (108 as u8) { return 0 } 68 if nm[n-1] != (102 as u8) { return 0 } 69 return 1 70} 71 72func main(argc: i64, argv: *i64) -> i64 { 73 var th: i64 = SS_DEF_TH 74 let cp: *i64 = sys_mmap(8) as *i64 75 let cd: *u8 = sys_read_file(SS_CONF, cp) 76 if (cd as i64) != 0 { 77 let cn: i64 = cp[0] 78 var i: i64 = 0 79 var seen: i64 = 0 80 while i < cn { 81 if seen == 0 { 82 if cd[i] == (61 as u8) { seen = 1 } 83 } else { 84 if cd[i] >= (48 as u8) { if cd[i] <= (57 as u8) { var v: i64 = 0 85 while i < cn { if cd[i] >= (48 as u8) { if cd[i] <= (57 as u8) { v = v*10 + ((cd[i]-(48 as u8)) as i64); i = i + 1 } else { i = cn } } else { i = cn } } 86 if v > 0 { th = v } } } 87 seen = 2 88 } 89 i = i + 1 90 } 91 } 92 if argc >= 2 { let a: i64 = ss_atoi(argv[1] as *u8); if a > 0 { th = a } } 93 94 let names: *u8 = sys_mmap(SS_MAXELF * SS_NAMEW) 95 var ne: i64 = 0 96 let dfd: i64 = ss_opendir("." as *u8) 97 if dfd < 0 { ss_o("STALESWEEP FAIL cannot open nishihost\\n" as *u8); sys_exit(1); return 1 } 98 let dbuf: *u8 = sys_mmap(SS_DIRBUF) 99 var more: i64 = 1 100 while more == 1 { 101 let nb: i64 = sys_getdents64(dfd, dbuf, SS_DIRBUF) 102 if nb <= 0 { more = 0 } else { 103 var p: i64 = 0 104 while p < nb { 105 let reclen: i64 = (dbuf[p+16] as i64) + ((dbuf[p+17] as i64) * 256) 106 if reclen <= 0 { p = nb } else { 107 let nmp: *u8 = ((dbuf as i64) + p + 19) as *u8 108 if ss_ends_elf(nmp) == 1 { if ne < SS_MAXELF { 109 let dst: *u8 = ss_slot(names, ne) 110 var c: i64 = 0 111 while c < SS_NAMEW-1 { if nmp[c]==(0 as u8){dst[c]=0 as u8;c=SS_NAMEW} else {dst[c]=nmp[c];c=c+1} } 112 if c == SS_NAMEW-1 { dst[c] = 0 as u8 } 113 ne = ne + 1 114 } } 115 p = p + reclen 116 } 117 } 118 } 119 } 120 sys_close(dfd) 121 122 let wl: *u8 = sys_mmap(SS_OUTCAP) 123 var wo: i64 = 0 124 var cand: i64 = 0 125 var over: i64 = 0 126 var worsth: i64 = 0 127 let worst: *u8 = sys_mmap(SS_NAMEW) 128 worst[0] = 0 as u8 129 let sp: *u8 = sys_mmap(SS_NAMEW * 2) 130 var i2: i64 = 0 131 while i2 < ne { 132 let nm: *u8 = ss_slot(names, i2) 133 let nl: i64 = ss_len(nm) 134 // basename b = name minus the trailing ".elf" 135 var so: i64 = ss_cat(sp, 0, SS_HDL) 136 var k: i64 = 0 137 while k < nl - 4 { sp[so] = nm[k]; so = so + 1; k = k + 1 } 138 so = ss_cat(sp, so, ".nx" as *u8) 139 sp[so] = 0 as u8 140 var st: i64 = ss_mtime(sp) 141 if st < 0 { 142 // SECOND choice only -- _hdl_build wins when both exist, because buildrun compiles THAT twin. 143 so = ss_cat(sp, 0, SS_RT) 144 k = 0 145 while k < nl - 4 { sp[so] = nm[k]; so = so + 1; k = k + 1 } 146 so = ss_cat(sp, so, ".nx" as *u8) 147 sp[so] = 0 as u8 148 st = ss_mtime(sp) 149 } 150 if st >= 0 { 151 let et: i64 = ss_mtime(nm) 152 if et >= 0 { if st > et { 153 cand = cand + 1 154 let ageh: i64 = (st - et) / SS_MAGIC_3600 155 if ageh > worsth { worsth = ageh 156 var q: i64 = 0 157 while q < nl - 4 { if q < SS_NAMEW-1 { worst[q] = nm[q] } q = q + 1 } 158 if nl - 4 < SS_NAMEW { worst[nl-4] = 0 as u8 } else { worst[SS_NAMEW-1] = 0 as u8 } 159 } 160 if ageh >= th { 161 over = over + 1 162 var b2: i64 = 0 163 while b2 < nl - 4 { wl[wo] = nm[b2]; wo = wo + 1; b2 = b2 + 1 } 164 wl[wo] = 58 as u8; wo = wo + 1 165 wo = ss_num(wl, wo, ageh) 166 wl[wo] = 10 as u8; wo = wo + 1 167 } 168 } } 169 } 170 i2 = i2 + 1 171 } 172 173 if over > 0 { 174 // temp BESIDE the target so the rename is same-device and therefore genuinely atomic 175 // (the EXDEV trap nx_lmexport exposed in the mv-based originals today). 176 let fd: i64 = sys_openat_wr(SS_WORKTMP, SS_MODE) 177 if fd >= 0 { sys_write(fd, wl, wo); sys_close(fd); sys_renameat(SS_WORKTMP, SS_WORKLIST) } 178 // ONE rollup row, CONSTANT text -- nx_debt content-idempotence collapses re-files. 179 let pid: i64 = sys_fork() 180 if pid == 0 { 181 let av: *i64 = sys_mmap(64) as *i64 182 av[0] = SS_DEBT as i64 183 av[1] = "add" as *u8 as i64 184 av[2] = "5" as *u8 as i64 185 av[3] = "stale-mirror" as *u8 as i64 186 av[4] = "STALE-MIRROR ROLLUP (auto-filed by nx_stalesweep; ONE row for the whole class, idempotent by constant text): organs whose live elf is a threshold-deep window behind buildroot source. CURRENT names+ages regenerated every sweep in knowledge/status/stale_mirror.worklist -- the ledger row is the POINTER, the worklist file is the TRUTH. source-newer is AMBIGUOUS (pending upgrade vs uncommitted WIP). OWNER lane per organ: rebuild (source good) or park/revert (uncommitted WIP); NEVER blanket-rebuild (ships half-work)." as *u8 as i64 187 av[5] = 0 188 let ev: *i64 = sys_mmap(32) as *i64 189 ev[0] = "PATH=/usr/bin:/bin" as *u8 as i64; ev[1] = 0 190 sys_execve(SS_DEBT, av, ev) 191 sys_exit(127) 192 } 193 if pid > 0 { let stb: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, stb, 0) } 194 } 195 196 let msg: *u8 = sys_mmap(SS_MAGIC_1024) 197 var mo: i64 = 0 198 mo = ss_cat(msg, mo, "STALESWEEP elfs=" as *u8); mo = ss_num(msg, mo, ne) 199 mo = ss_cat(msg, mo, " candidates=" as *u8); mo = ss_num(msg, mo, cand) 200 mo = ss_cat(msg, mo, " over_thresh=" as *u8); mo = ss_num(msg, mo, over) 201 mo = ss_cat(msg, mo, " thresh_h=" as *u8); mo = ss_num(msg, mo, th) 202 mo = ss_cat(msg, mo, " worst=" as *u8) 203 if worst[0] == (0 as u8) { mo = ss_cat(msg, mo, "none" as *u8) } else { mo = ss_cat(msg, mo, worst) } 204 mo = ss_cat(msg, mo, " worst_h=" as *u8); mo = ss_num(msg, mo, worsth) 205 // FORKS IS ONE-OR-ZERO, NOT THE OVER COUNT (2026-08-07). v1 printed `forks=649` by reusing `over`, 206 // which is simply false: the walk and every stat are IN-PROCESS, and the ONLY fork this organ makes is 207 // the single nx_debt rollup add. A reader comparing this against nx_segsweep forks=0 would conclude 208 // the sweeper was fork-storming when it makes at most one. 209 // (STAR)A METRIC THAT REUSES ANOTHER METRIC VARIABLE IS A LIE WITH A CORRECT-LOOKING SHAPE -- it moves, 210 // it is plausible, and nothing about the output reveals that the label and the value disagree. 211 var nfork: i64 = 0 212 if over > 0 { nfork = 1 } 213 mo = ss_cat(msg, mo, " forks=" as *u8); mo = ss_num(msg, mo, nfork) 214 mo = ss_cat(msg, mo, " ts=" as *u8); mo = ss_num(msg, mo, sys_now_realtime_sec()) 215 msg[mo] = 10 as u8; mo = mo + 1 216 sys_write(1, msg, mo) 217 sys_exit(0) 218 return 0 219}