nx_regfix_gate.nx source
↩ module page · 85 lines · 4188 B
1// nx_regfix_gate.nx -- ISOLATED proof of the reg_put next-segid fix (registration persistence past
2// the seg-store's cap). Writes REG_TEST_N records to a FRESH /tmp store (never the shared toolreg):
3// with the OLD ss_manifest cap, records beyond it collide onto one segment and are LOST; with
4// reg_next_segid (uncapped max+1) ALL persist + read back. rule-11 clean: every threshold is a NAMED
5// const (no bare literals). Runner must clean /tmp/regfix first. Exit 0 only on all-PASS.
6// license_tier: ORIGINAL expect_exit: 0
7import "nx_syscalls.nx"
8import "nx_registry.nx"
9
10const REG_TEST_N: i64 = 300 // records to write -- chosen ABOVE the old cap so the tail exercises it
11const OLD_MANIFEST_CAP: i64 = 256 // the seg-store cap this fix eliminates (documented in nx_seg_store)
12const KEY_CH: i64 = 107 // ASCII 'k' (id prefix)
13const VAL_CH: i64 = 118 // ASCII 'v' (value prefix)
14const ASCII_0: i64 = 48
15const DIR_MODE: i64 = 0x1ed // 0755
16const GATE_CHECKS: i64 = 3 // number of PASS conditions below (all must be GREEN)
17
18func g_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
19func g_putn(v: i64) -> i64 {
20 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 }
21 var m: i64 = v; if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
22 let d: *u8 = sys_mmap(24); var k: i64 = 0
23 while m > 0 { d[k] = (ASCII_0 + (m % 10)) as u8; m = m / 10; k = k + 1 }
24 let o: *u8 = sys_mmap(24); var i: i64 = 0
25 while i < k { o[i] = d[k-1-i]; i = i + 1 } sys_write(1, o, k)
26 return 0
27}
28// build <c><i> (e.g. "k42") into buf, NUL-terminated; return length
29func g_id(buf: *u8, c: i64, i: i64) -> i64 {
30 buf[0] = c as u8
31 var o: i64 = 1; var m: i64 = i
32 if m == 0 { buf[o] = ASCII_0 as u8; o = o + 1; buf[o] = 0 as u8; return o }
33 let t: *u8 = sys_mmap(24); var k: i64 = 0
34 while m > 0 { t[k] = (ASCII_0 + (m % 10)) as u8; m = m / 10; k = k + 1 }
35 while k > 0 { buf[o] = t[k-1]; o = o + 1; k = k - 1 }
36 buf[o] = 0 as u8
37 return o
38}
39
40func main(argc: i64, argv: *i64) -> i64 {
41 let pass: *i64 = sys_mmap(16) as *i64
42 pass[0] = 0
43 sys_mkdir("/tmp/regfix" as *u8, DIR_MODE)
44 let prefix: *u8 = "/tmp/regfix/rf-" as *u8
45 let idbuf: *u8 = sys_mmap(64)
46 let recbuf: *u8 = sys_mmap(64)
47
48 // write REG_TEST_N records (the tail is beyond OLD_MANIFEST_CAP)
49 var w: i64 = 0
50 while w < REG_TEST_N {
51 g_id(idbuf, KEY_CH, w)
52 let rl: i64 = g_id(recbuf, VAL_CH, w)
53 reg_put(prefix, "t:" as *u8, "__idx__" as *u8, idbuf, recbuf, rl)
54 w = w + 1
55 }
56
57 // every record must read back (the old cap loses everything beyond OLD_MANIFEST_CAP)
58 let po: *i64 = sys_mmap(16) as *i64
59 let lo: *i64 = sys_mmap(16) as *i64
60 var found: i64 = 0
61 var i: i64 = 0
62 while i < REG_TEST_N { g_id(idbuf, KEY_CH, i); if reg_get(prefix, "t:" as *u8, idbuf, po, lo) == 1 { found = found + 1 } i = i + 1 }
63 g_puts("T all-persist found=" as *u8); g_putn(found); g_puts("/" as *u8); g_putn(REG_TEST_N)
64 if found == REG_TEST_N { g_puts(" PASS\n" as *u8); pass[0] = pass[0] + 1 } else { g_puts(" FAIL (old cap loses the tail)\n" as *u8) }
65
66 // the LAST record (well past OLD_MANIFEST_CAP) present
67 g_id(idbuf, KEY_CH, REG_TEST_N - 1)
68 var oklast: i64 = 0
69 if reg_get(prefix, "t:" as *u8, idbuf, po, lo) == 1 { oklast = 1 }
70 g_puts("T last-record-present got=" as *u8); g_putn(oklast)
71 if oklast == 1 { g_puts(" PASS\n" as *u8); pass[0] = pass[0] + 1 } else { g_puts(" FAIL\n" as *u8) }
72
73 // next-segid uncapped (>= REG_TEST_N), NOT stuck at OLD_MANIFEST_CAP
74 let nseg: i64 = reg_next_segid(prefix)
75 g_puts("T next-segid-uncapped nseg=" as *u8); g_putn(nseg)
76 var okseg: i64 = 0
77 if nseg >= REG_TEST_N { okseg = 1 }
78 if okseg == 1 { g_puts(" PASS (uncapped)\n" as *u8); pass[0] = pass[0] + 1 } else { g_puts(" FAIL (still capped)\n" as *u8) }
79
80 let total: i64 = GATE_CHECKS
81 g_puts("REGFIX-GATE pass=" as *u8); g_putn(pass[0]); g_puts("/" as *u8); g_putn(total); g_puts(" verdict=" as *u8)
82 if pass[0] == total { g_puts("GREEN\n" as *u8); return 0 }
83 g_puts("RED\n" as *u8)
84 return 1
85}