code wiki / (root) / nx_store_janitor_gate.nx

nx_store_janitor_gate.nx source

↩ module page · 239 lines · 12792 B

1// nx_store_janitor_gate.nx -- THE JANITOR GATE: the seg-store's most destructive standing beat (it moves 2// files nobody can reach, on every plane, every beat) had NO gate. Born 2026-08-18 from two live incidents 3// in two days: nx_store_janitor swept a segment being BORN (files land before the manifest line, id above the 4// manifest max), then its race repair restored only the .docs -- comparewatch-seg-1786828803 (08-16/17) and 5// debt-seg-1787064612 (08-18) both read as "lossy load"/SHORTFALL to every reader, and one seat's debt row was 6// overwritten during the hand repair. Subject: ./nx_store_janitor.elf (argv[1] overrides the path so a STAGED 7// build can be bitten before promote). Fixture assembled at RUNTIME under /tmp/janitor_gate/ (a detector that 8// scans source would find its own fixture) and rebuilt from scratch on every run (idempotent by construction). 9// Teeth, each printed with its values: superseded segment moved (the sweep still sweeps -- the anti-vacuity 10// tooth), birth in flight left alone, live segment untouched, heal restores EVERY sidecar, heal never clobbers a 11// live file, empty manifest REFUSES and touches nothing. RED against the pre-08-18 binary by construction (it 12// moves the birth and knows no heal verb); GREEN only when both fixes are in the forked binary. 13// license_tier: ORIGINAL No hw writes (Rule 26). 14import "nx_gate_verdict.nx" 15import "nx_tool_run.nx" 16 17const JG_OUT: i64 = 65536 18const JG_PATH: i64 = 512 19const JG_STAT: i64 = 256 20const JG_STAT_SIZE_OFF: i64 = 48 21const JG_AV: i64 = 64 22const JG_I64: i64 = 8 23const JG_EXIT_REFUSED: i64 = 3 // nx_store_janitor's own REFUSED exit code (its header contract) 24// fixture strings are LOCALS in main and threaded as parameters -- a const *u8 indexed by position is the 25// banked CONST[i] landmine (nx_store_janitor_beat header), so none is declared here 26 27func jg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 28func jg_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; var p: i64 = o; while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } return p } 29// file size via fstatat, -1 if absent 30func jg_size(path: *u8) -> i64 { 31 let st: *u8 = sys_mmap(JG_STAT) 32 if sys_fstatat(path, st) != 0 { sys_munmap(st, JG_STAT); return 0 - 1 } 33 let p: *i64 = (st as i64 + JG_STAT_SIZE_OFF) as *i64 34 let v: i64 = p[0] 35 sys_munmap(st, JG_STAT) 36 return v 37} 38func jg_exists(path: *u8) -> i64 { if jg_size(path) >= 0 { return 1 } return 0 } 39func jg_w(path: *u8, content: *u8) -> i64 { 40 let fd: i64 = sys_openat_wr(path, MODE_0644) 41 if fd < 0 { return 0 - 1 } 42 let n: i64 = jg_slen(content) 43 if n > 0 { sys_write(fd, content, n) } 44 sys_close(fd) 45 return 0 46} 47func jg_has(hay: *u8, hn: i64, needle: *u8) -> i64 { 48 var i: i64 = 0 49 let nl: i64 = jg_slen(needle) 50 if nl == 0 { return 0 } 51 while i + nl <= hn { 52 var j: i64 = 0 53 var ok: i64 = 1 54 while j < nl { if hay[i+j] != needle[j] { ok = 0; j = nl } else { j = j + 1 } } 55 if ok == 1 { return 1 } 56 i = i + 1 57 } 58 return 0 59} 60// fixture file paths: <root>/jg-seg-<id>.<ext> and <root>/retired/jg-seg-<id>.<ext> 61func jg_live(dst: *u8, pfx: *u8, id: *u8, ext: *u8) -> i64 { 62 var o: i64 = jg_cat(dst, 0, pfx) 63 o = jg_cat(dst, o, "seg-" as *u8) 64 o = jg_cat(dst, o, id) 65 o = jg_cat(dst, o, ext) 66 dst[o] = 0 as u8 67 return o 68} 69func jg_retired(dst: *u8, ret: *u8, id: *u8, ext: *u8) -> i64 { 70 var o: i64 = jg_cat(dst, 0, ret) 71 o = jg_cat(dst, o, "/jg-seg-" as *u8) 72 o = jg_cat(dst, o, id) 73 o = jg_cat(dst, o, ext) 74 dst[o] = 0 as u8 75 return o 76} 77// count how many of the four segment files of <id> exist in the live dir (loc=0) or retired/ (loc=1) 78func jg_count4(pfx: *u8, ret: *u8, id: *u8, loc: i64) -> i64 { 79 let p: *u8 = sys_mmap(JG_PATH) 80 var n: i64 = 0 81 let exts: *i64 = sys_mmap(JG_AV) as *i64 82 exts[0] = ".docs" as *u8 as i64 83 exts[1] = ".idx" as *u8 as i64 84 exts[2] = ".pos" as *u8 as i64 85 exts[3] = ".imp" as *u8 as i64 86 var i: i64 = 0 87 while i < 4 { 88 if loc == 0 { jg_live(p, pfx, id, exts[i] as *u8) } else { jg_retired(p, ret, id, exts[i] as *u8) } 89 n = n + jg_exists(p) 90 i = i + 1 91 } 92 sys_munmap(p, JG_PATH) 93 return n 94} 95// unlink both locations of all four files of <id> (idempotent setup) 96func jg_clear(pfx: *u8, ret: *u8, id: *u8) -> i64 { 97 let p: *u8 = sys_mmap(JG_PATH) 98 let exts: *i64 = sys_mmap(JG_AV) as *i64 99 exts[0] = ".docs" as *u8 as i64 100 exts[1] = ".idx" as *u8 as i64 101 exts[2] = ".pos" as *u8 as i64 102 exts[3] = ".imp" as *u8 as i64 103 var i: i64 = 0 104 while i < 4 { 105 jg_live(p, pfx, id, exts[i] as *u8); sys_unlinkat(p) 106 jg_retired(p, ret, id, exts[i] as *u8); sys_unlinkat(p) 107 i = i + 1 108 } 109 sys_munmap(p, JG_PATH) 110 return 0 111} 112// write all four files of <id> into live (loc=0) or retired (loc=1) 113func jg_make4(pfx: *u8, ret: *u8, id: *u8, loc: i64, body: *u8) -> i64 { 114 let p: *u8 = sys_mmap(JG_PATH) 115 let exts: *i64 = sys_mmap(JG_AV) as *i64 116 exts[0] = ".docs" as *u8 as i64 117 exts[1] = ".idx" as *u8 as i64 118 exts[2] = ".pos" as *u8 as i64 119 exts[3] = ".imp" as *u8 as i64 120 var i: i64 = 0 121 while i < 4 { 122 if loc == 0 { jg_live(p, pfx, id, exts[i] as *u8) } else { jg_retired(p, ret, id, exts[i] as *u8) } 123 jg_w(p, body) 124 i = i + 1 125 } 126 sys_munmap(p, JG_PATH) 127 return 0 128} 129// fork the janitor: <elf> <prefix> <verb>; returns rc, out/olen filled 130func jg_run(elf: *u8, pfx: *u8, verb: *u8, out: *u8, olen: *i64) -> i64 { 131 let av: *i64 = sys_mmap(JG_AV) as *i64 132 av[0] = elf as i64 133 av[1] = pfx as i64 134 av[2] = verb as i64 135 av[3] = 0 136 olen[0] = 0 137 let rc: i64 = tr_run_capture(elf, av, out, JG_OUT - 1, olen) 138 sys_munmap(av as *u8, JG_AV) 139 return rc 140} 141 142func main(argc: i64, argv: *i64) -> i64 { 143 let ctr: *i64 = gv_ctr() 144 gv_head("nx_store_janitor_gate -- birth-in-flight rule, whole-segment heal, refuse-on-unknown-live-set" as *u8) 145 let root: *u8 = "/tmp/janitor_gate" as *u8 146 let ret: *u8 = "/tmp/janitor_gate/retired" as *u8 147 let pfx: *u8 = "/tmp/janitor_gate/jg-" as *u8 148 let mani: *u8 = "/tmp/janitor_gate/jg-manifest.txt" as *u8 149 var elf: *u8 = "./nx_store_janitor.elf" as *u8 150 if argc >= 2 { elf = argv[1] as *u8 } 151 gv_puts(" subject: " as *u8); gv_puts(elf); gv_puts("\n" as *u8) 152 if gv_need("janitor-elf-present" as *u8, jg_exists(elf), ctr) == 0 { 153 return gv_verdict("storejanitor" as *u8, ctr, "subject binary absent; pass its path as argv[1]" as *u8) 154 } 155 156 // ---- SETUP, idempotent: rebuild the fixture plane from scratch every run 157 sys_mkdir(root, MODE_0755) 158 sys_mkdir(ret, MODE_0755) 159 jg_clear(pfx, ret, "99" as *u8); jg_clear(pfx, ret, "100" as *u8); jg_clear(pfx, ret, "101" as *u8); jg_clear(pfx, ret, "102" as *u8) 160 sys_unlinkat(mani) 161 jg_w(mani, "seg-100\nseg-101\n" as *u8) 162 jg_make4(pfx, ret, "99" as *u8, 0, "superseded generation\n" as *u8) // below max, unlisted -> must be MOVED 163 jg_make4(pfx, ret, "100" as *u8, 0, "live" as *u8) // listed -> untouched 164 let p: *u8 = sys_mmap(JG_PATH) 165 jg_live(p, pfx, "101" as *u8, ".docs" as *u8); jg_w(p, "live record whose index was swept\n" as *u8) 166 jg_retired(p, ret, "101" as *u8, ".idx" as *u8); jg_w(p, "idx" as *u8) // listed, sidecars in retired/ 167 jg_retired(p, ret, "101" as *u8, ".pos" as *u8); jg_w(p, "pos" as *u8) // (the 08-16/08-18 damage shape) 168 jg_retired(p, ret, "101" as *u8, ".imp" as *u8); jg_w(p, "imp" as *u8) 169 jg_retired(p, ret, "100" as *u8, ".idx" as *u8); jg_w(p, "decoy" as *u8) // a stale twin of a LIVE file: heal must NOT clobber 170 jg_make4(pfx, ret, "102" as *u8, 0, "birth in flight\n" as *u8) // above max, unlisted -> must be LEFT ALONE 171 // assert the fixture reached its intended state before asserting outcomes (a fixture that never 172 // reached the condition would pass every tooth vacuously) 173 let fix_ok: i64 = ((jg_count4(pfx, ret, "99" as *u8, 0) == 4) as i64) & ((jg_count4(pfx, ret, "100" as *u8, 0) == 4) as i64) & ((jg_count4(pfx, ret, "101" as *u8, 1) == 3) as i64) & ((jg_count4(pfx, ret, "102" as *u8, 0) == 4) as i64) 174 if gv_need("fixture-assembled" as *u8, fix_ok, ctr) == 0 { 175 return gv_verdict("storejanitor" as *u8, ctr, "could not assemble /tmp/janitor_gate fixture" as *u8) 176 } 177 178 // ---- RUN 1: apply 179 let out: *u8 = sys_mmap(JG_OUT) 180 let olen: *i64 = sys_mmap(JG_I64) as *i64 181 let rc1: i64 = jg_run(elf, pfx, "apply" as *u8, out, olen) 182 gv_puts(" apply rc=" as *u8); gv_num(rc1); gv_puts(" out=" as *u8); sys_write(1, out, olen[0]) 183 let l99: i64 = jg_count4(pfx, ret, "99" as *u8, 0) 184 let r99: i64 = jg_count4(pfx, ret, "99" as *u8, 1) 185 let l100: i64 = jg_count4(pfx, ret, "100" as *u8, 0) 186 let l102: i64 = jg_count4(pfx, ret, "102" as *u8, 0) 187 gv_puts(" values: seg99 live=" as *u8); gv_num(l99); gv_puts(" retired=" as *u8); gv_num(r99) 188 gv_puts(" seg100 live=" as *u8); gv_num(l100) 189 gv_puts(" seg102 live=" as *u8); gv_num(l102); gv_puts("\n" as *u8) 190 let moved_ok: i64 = ((l99 == 0) as i64) & ((r99 == 4) as i64) & (jg_has(out, olen[0], "MOVED=4" as *u8)) 191 gv_check("superseded-below-max-moved-to-retired-all-four-files" as *u8, moved_ok, ctr) 192 let birth_ok: i64 = ((l102 == 4) as i64) & (jg_has(out, olen[0], "inflight_files=4" as *u8)) 193 gv_check("birth-in-flight-above-max-left-alone-and-counted" as *u8, birth_ok, ctr) 194 gv_check("live-segment-untouched-by-apply" as *u8, (l100 == 4) as i64, ctr) 195 let quiet_ok: i64 = ((rc1 == 0) as i64) & ((1 - jg_has(out, olen[0], "LOST-LIVE" as *u8)) as i64) 196 gv_check("apply-exit-0-and-no-live-segment-lost" as *u8, quiet_ok, ctr) 197 // the discriminating pair as one bite: fires on the superseded (moved), silent on the birth (kept) 198 var birth_moved: i64 = 0 199 if l102 < 4 { birth_moved = 1 } 200 var sup_moved: i64 = 0 201 if l99 == 0 { sup_moved = 1 } 202 gv_bite("neg-control-sweep-discriminates-superseded-from-birth" as *u8, sup_moved, birth_moved, ctr) 203 204 // ---- RUN 2: heal 205 let rc2: i64 = jg_run(elf, pfx, "heal" as *u8, out, olen) 206 gv_puts(" heal rc=" as *u8); gv_num(rc2); gv_puts(" out=" as *u8); sys_write(1, out, olen[0]) 207 let l101: i64 = jg_count4(pfx, ret, "101" as *u8, 0) 208 let r101: i64 = jg_count4(pfx, ret, "101" as *u8, 1) 209 jg_live(p, pfx, "100" as *u8, ".idx" as *u8) 210 let sz100idx: i64 = jg_size(p) 211 jg_retired(p, ret, "100" as *u8, ".idx" as *u8) 212 let decoy: i64 = jg_exists(p) 213 gv_puts(" values: seg101 live=" as *u8); gv_num(l101); gv_puts(" retired=" as *u8); gv_num(r101) 214 gv_puts(" seg100.idx bytes=" as *u8); gv_num(sz100idx); gv_puts(" decoy-still-retired=" as *u8); gv_num(decoy); gv_puts("\n" as *u8) 215 let heal_ok: i64 = ((l101 == 4) as i64) & ((r101 == 0) as i64) & (jg_has(out, olen[0], "healed=3" as *u8)) & ((rc2 == 0) as i64) 216 gv_check("heal-restores-every-sidecar-of-a-live-segment" as *u8, heal_ok, ctr) 217 // live 100.idx holds "live" (4 bytes); the retired decoy holds "decoy" (5). Unchanged size + decoy still there = no clobber. 218 let noclob: i64 = ((sz100idx == 4) as i64) & ((decoy == 1) as i64) 219 gv_check("heal-never-clobbers-a-present-live-file" as *u8, noclob, ctr) 220 221 // ---- RUN 3: neg-control -- an EMPTY manifest is an unknown live set: refuse, touch nothing. 222 // Measured as a DELTA (live counts before == after) so this tooth judges only "moved nothing", whatever 223 // state the earlier teeth left the fixture in. 224 let l100a: i64 = jg_count4(pfx, ret, "100" as *u8, 0) 225 let l101a: i64 = jg_count4(pfx, ret, "101" as *u8, 0) 226 let l102a: i64 = jg_count4(pfx, ret, "102" as *u8, 0) 227 jg_w(mani, "" as *u8) 228 let rc3: i64 = jg_run(elf, pfx, "apply" as *u8, out, olen) 229 gv_puts(" empty-manifest apply rc=" as *u8); gv_num(rc3); gv_puts(" out=" as *u8); sys_write(1, out, olen[0]) 230 let l100b: i64 = jg_count4(pfx, ret, "100" as *u8, 0) 231 let l101b: i64 = jg_count4(pfx, ret, "101" as *u8, 0) 232 let l102b: i64 = jg_count4(pfx, ret, "102" as *u8, 0) 233 gv_puts(" values: live files before=" as *u8); gv_num(l100a + l101a + l102a); gv_puts(" after=" as *u8); gv_num(l100b + l101b + l102b); gv_puts(" 234" as *u8) 235 let refuse_ok: i64 = ((rc3 == JG_EXIT_REFUSED) as i64) & (jg_has(out, olen[0], "REFUSED" as *u8)) & ((l100b == l100a) as i64) & ((l101b == l101a) as i64) & ((l102b == l102a) as i64) & ((l100a + l101a + l102a > 0) as i64) 236 gv_check("neg-control-empty-manifest-refuses-and-moves-nothing" as *u8, refuse_ok, ctr) 237 238 return gv_verdict("storejanitor" as *u8, ctr, "each tooth above states itself; the subject is the binary named on the subject line" as *u8) 239}