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}