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}