code wiki / _hdl_build / nx_browser_profile_gate.nx

nx_browser_profile_gate.nx source

↩ module page · 132 lines · 6342 B

1// nx_browser_profile_gate.nx -- gate for the browser PERSISTENT PROFILE STORE (R4 of the comms-parity 2// ladder). Proves on FRESH /tmp fixtures: (T1) contact roundtrip byte-identical, (T2) setting last-wins, 3// (T3) chat multi-key, (T4) ★THE SPLIT: clearing the CACHE family (delete every cache-prefix file = the 4// history-clear) leaves the PROFILE family byte-identical -- the operator's "different cache than the 5// history-clearing cache" requirement, proven mechanically, (T5) tombstone-delete misses, (T6) NEG bogus 6// key misses (liar-kill), (T7) re-put after tombstone works (additive law: current view correct). 7// expect_exit: 0 license_tier: ORIGINAL 8import "nx_browser_profile_store.nx" 9 10const GP: *u8 = "/tmp/bp_gate_profile-" 11const GC: *u8 = "/tmp/bp_gate_cache-" 12 13func g_unlink(path: *u8) -> i64 { __syscall(263, AT_FDCWD, path, 0, 0, 0, 0) return 0 } 14func g_pw(s: *u8) -> i64 { sys_write(1, s, bp_len(s)); return 0 } 15func g_pn(v: i64) -> i64 { 16 let b: *u8=sys_mmap(28); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m} 17 let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} 18 var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 19func g_eq(a: *u8, alen: i64, b: *u8, blen: i64) -> i64 { 20 if alen != blen { return 0 } 21 var i: i64=0; while i<alen { if a[i]!=b[i] { return 0 } i=i+1 } 22 return 1 } 23 24// delete every file in /tmp whose name starts with `stem` (e.g. "bp_gate_cache-"). Returns count. 25func g_clear_family(stem: *u8) -> i64 { 26 let dfd: i64 = sys_openat_rd("/tmp" as *u8) 27 if dfd < 0 { return 0 - 1 } 28 let buf: *u8 = sys_mmap(65536) 29 let full: *u8 = sys_mmap(4096) 30 var killed: i64 = 0 31 var go: i64 = 1 32 while go == 1 { 33 let n: i64 = sys_getdents64(dfd, buf, 65536) 34 if n <= 0 { go = 0 } else { 35 var off: i64 = 0 36 while off < n { 37 let reclen: i64 = (buf[off+16] as i64) + ((buf[off+17] as i64) * 256) 38 let name: *u8 = buf + off + 19 39 // prefix match name against stem 40 var m: i64 = 1 41 var i: i64 = 0 42 while stem[i] != (0 as u8) { if name[i] != stem[i] { m = 0; i = bp_len(stem) } else { i = i + 1 } } 43 if m == 1 { 44 var o: i64 = 0 45 let t: *u8 = "/tmp/\x00" as *u8 46 var j: i64 = 0 47 while t[j] != (0 as u8) { full[o] = t[j]; o = o + 1; j = j + 1 } 48 j = 0 49 while name[j] != (0 as u8) { full[o] = name[j]; o = o + 1; j = j + 1 } 50 full[o] = 0 as u8 51 g_unlink(full) 52 killed = killed + 1 53 } 54 off = off + reclen 55 } 56 } 57 } 58 sys_close(dfd) 59 return killed 60} 61 62func chk(name: *u8, ok: i64, pass: *i64) -> i64 { 63 g_pw(" " as *u8) 64 if ok==1 { g_pw("PASS " as *u8); pass[0]=pass[0]+1 } else { g_pw("FAIL " as *u8) } 65 g_pw(name); g_pw("\n" as *u8) 66 return 0 } 67 68func main() -> i64 { 69 g_pw("=== nx_browser_profile_gate: persistent profile store + cache-split (R4) ===\n" as *u8) 70 // fresh fixtures per run: clear BOTH families first (gate-only /tmp artifacts) 71 g_clear_family("bp_gate_profile-" as *u8) 72 g_clear_family("bp_gate_cache-" as *u8) 73 let pass: *i64 = sys_mmap(16) as *i64 74 pass[0] = 0 75 let out: *u8 = sys_mmap(65536) 76 77 // T1 contact roundtrip 78 let alice: *u8 = "Alice West;pub=ab12cd34;tel=+1-555-0100" 79 bp_put(GP, "contact:alice" as *u8, alice, bp_len(alice)) 80 var n: i64 = bp_get(GP, "contact:alice" as *u8, out, 65536) 81 chk("T1 contact roundtrip byte-identical " as *u8, g_eq(out, n, alice, bp_len(alice)), pass) 82 83 // T2 setting last-wins 84 bp_put(GP, "setting:theme" as *u8, "dark" as *u8, 4) 85 bp_put(GP, "setting:theme" as *u8, "light" as *u8, 5) 86 n = bp_get(GP, "setting:theme" as *u8, out, 65536) 87 chk("T2 setting overwrite last-wins " as *u8, g_eq(out, n, "light" as *u8, 5), pass) 88 89 // T3 chat multi-key (two messages, distinct ts keys, one commit via bp_put2 = the batch seam) 90 bp_put2(GP, "chat:family:1000" as *u8, "hello room" as *u8, 10, "chat:family:2000" as *u8, "second msg" as *u8, 10) 91 n = bp_get(GP, "chat:family:1000" as *u8, out, 65536) 92 var t3: i64 = g_eq(out, n, "hello room" as *u8, 10) 93 n = bp_get(GP, "chat:family:2000" as *u8, out, 65536) 94 if g_eq(out, n, "second msg" as *u8, 10) == 0 { t3 = 0 } 95 chk("T3 chat multi-key (batched single commit) " as *u8, t3, pass) 96 97 // T4 ★ THE SPLIT: cache write -> history-clear (delete cache family) -> profile INTACT 98 bp_put(GC, "cache:page1" as *u8, "<html>stub</html>" as *u8, 17) 99 n = bp_get(GC, "cache:page1" as *u8, out, 65536) 100 var t4: i64 = 0 101 if n > 0 { 102 let killed: i64 = g_clear_family("bp_gate_cache-" as *u8) 103 g_pw(" (history-clear removed " as *u8); g_pn(killed); g_pw(" cache files)\n" as *u8) 104 let cgone: i64 = bp_get(GC, "cache:page1" as *u8, out, 65536) 105 n = bp_get(GP, "contact:alice" as *u8, out, 65536) 106 if cgone < 0 { if g_eq(out, n, alice, bp_len(alice)) == 1 { t4 = 1 } } 107 } 108 chk("T4 SPLIT: cache cleared, profile intact " as *u8, t4, pass) 109 110 // T5 tombstone-delete misses 111 bp_del(GP, "contact:alice" as *u8) 112 n = bp_get(GP, "contact:alice" as *u8, out, 65536) 113 var t5: i64 = 0 114 if n < 0 { t5 = 1 } 115 chk("T5 tombstone-delete: current view misses " as *u8, t5, pass) 116 117 // T6 NEG bogus key 118 n = bp_get(GP, "contact:nobody_zz" as *u8, out, 65536) 119 var t6: i64 = 0 120 if n < 0 { t6 = 1 } 121 chk("T6 NEG bogus key misses (no fabrication) " as *u8, t6, pass) 122 123 // T7 re-put after tombstone (additive: history kept, current view correct) 124 bp_put(GP, "contact:alice" as *u8, "Alice West;pub=NEWKEY99" as *u8, 23) 125 n = bp_get(GP, "contact:alice" as *u8, out, 65536) 126 chk("T7 re-put after tombstone reads new value " as *u8, g_eq(out, n, "Alice West;pub=NEWKEY99" as *u8, 23), pass) 127 128 g_pw("BROWSER-PROFILE-GATE pass=" as *u8); g_pn(pass[0]); g_pw("/7" as *u8) 129 if pass[0]==7 { g_pw(" verdict=GREEN -- profile store + cache split proven (clear cache, keep profile)\n" as *u8); return 0 } 130 g_pw(" verdict=RED\n" as *u8) 131 return 1 132}