code wiki / _hdl_build / nx_pub_loop_gate.nx

nx_pub_loop_gate.nx source

↩ module page · 106 lines · 6270 B

1// nx_pub_loop_gate.nx -- R2 proof for THE NISHI PUBLISHER core loop. A queue of 5 requests (3 unique + 2 exact 2// duplicates) is processed by pub_run, which must: (1) DEDUP -- publish each unique (sha,dest) exactly once; 3// (2) be IDEMPOTENT on re-run -- a second pass over the same queue publishes nothing; (3) SERIALIZE -- two 4// concurrent sys_fork publisher instances (with a forced race window) still produce exactly 3 ledger entries, 5// never double-publishing; (4) NEG-CONTROL -- the SAME two publishers with the lock OFF DO double-publish 6// (ledger > 3), proving fl_acquire is load-bearing. Sovereign + per-wsid isolated. license_tier: ORIGINAL expect_exit: 0 7import "nx_syscalls.nx" 8import "nx_publisher.nx" 9import "nx_runpath.nx" 10 11func g_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 12func g_n(v: i64) -> i64 { var m: i64=v; if m<0{g_w("-" as *u8);m=0-m} let t:*u8=sys_mmap(24); 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} var i:i64=0; let o:*u8=sys_mmap(24); while i<k{o[i]=t[k-1-i];i=i+1} sys_write(1,o,k); return 0 } 13func g_row(id: *u8, ok: i64, pass: *i64) -> i64 { g_w(" " as *u8); g_w(id); g_w(": " as *u8); if ok==1 { g_w("OK\n" as *u8); pass[0]=pass[0]+1 } else { g_w("FAIL\n" as *u8) } return 0 } 14 15func lg_reset(path: *u8) -> i64 { let fd: i64 = sys_openat_wr(path, 0x1a4); if fd >= 0 { sys_close(fd) } return 0 } 16func lg_make(path: *u8, content: *u8) -> i64 { 17 let fd: i64 = sys_openat_wr(path, 0x1a4) 18 if fd < 0 { return 0 } 19 var n: i64 = 0; while content[n]!=(0 as u8){n=n+1} 20 sys_write(fd, content, n); sys_close(fd); return 1 21} 22func lg_count(path: *u8) -> i64 { 23 let lenp: *i64 = sys_mmap(8) as *i64 24 let data: *u8 = sys_read_file(path, lenp) 25 if (data as i64) == 0 { return 0 } 26 let n: i64 = lenp[0]; var i: i64 = 0; var c: i64 = 0 27 while i < n { if data[i]==(10 as u8){ c=c+1 } i=i+1 } 28 return c 29} 30// write ONE pre-hashed request line (lean: no per-line sys_read_file -> keeps the parent's footprint small so 31// the later fork() does not ENOMEM under sibling memory pressure). 32func lg_rec(qpath: *u8, sha: *u8, dest: *u8) -> i64 { 33 let rec: *u8 = sys_mmap(2048) 34 pub_build_rec(rec, "nf" as *u8, "ws" as *u8, sha, "src" as *u8, dest, "internal" as *u8) 35 fa_appendz(qpath, rec, 2048) 36 return 0 37} 38// seed: 3 unique (sa/a, sb/b, sc/c) + 2 exact duplicates = 5 queue lines, 3 unique (sha,dest). Each src hashed ONCE. 39func lg_seed(qpath: *u8, sa: *u8, sb: *u8, sc: *u8) -> i64 { 40 let ha: *u8 = sys_mmap(72); pub_sha_file(sa, ha) 41 let hb: *u8 = sys_mmap(72); pub_sha_file(sb, hb) 42 let hc: *u8 = sys_mmap(72); pub_sha_file(sc, hc) 43 lg_rec(qpath, ha, "d/a.html" as *u8) 44 lg_rec(qpath, hb, "d/b.html" as *u8) 45 lg_rec(qpath, hc, "d/c.html" as *u8) 46 lg_rec(qpath, ha, "d/a.html" as *u8) 47 lg_rec(qpath, hb, "d/b.html" as *u8) 48 return 0 49} 50func lg_child(qpath: *u8, ledpath: *u8, lockres: *u8, locked: i64) -> i64 { pub_run(qpath, ledpath, lockres, locked, 500); sys_exit(0); return 0 } 51func lg_concurrent(qpath: *u8, ledpath: *u8, lockres: *u8, locked: i64) -> i64 { 52 var i: i64 = 0 53 while i < 2 { let pid: i64 = sys_fork(); if pid == 0 { lg_child(qpath, ledpath, lockres, locked) } i = i + 1 } 54 let status: *i64 = sys_mmap(8) as *i64; i = 0 55 while i < 2 { sys_wait4(0 - 1, status, 0); i = i + 1 } 56 return 0 57} 58 59func main() -> i64 { 60 let pass: *i64 = sys_mmap(8) as *i64; pass[0]=0 61 g_w("=== NX-PUBLISHER LOOP GATE (dequeue -> serialize -> idempotent sha-skip -> ledger) ===\n" as *u8) 62 let wsid: *u8 = sys_mmap(64); rp_wsid(wsid); rp_ensure(wsid) 63 let qpath: *u8 = sys_mmap(512); rp_path(wsid, "pub_loop_q" as *u8, qpath) 64 let ledpath: *u8 = sys_mmap(512); rp_path(wsid, "pub_loop_led" as *u8, ledpath) 65 let sa: *u8 = sys_mmap(512); rp_path(wsid, "pub_loop_sa" as *u8, sa) 66 let sb: *u8 = sys_mmap(512); rp_path(wsid, "pub_loop_sb" as *u8, sb) 67 let sc: *u8 = sys_mmap(512); rp_path(wsid, "pub_loop_sc" as *u8, sc) 68 let lockres: *u8 = sys_mmap(128); var lo: i64=0; var li: i64=0 69 let lpfx: *u8 = "pub_loop_"; while lpfx[li]!=(0 as u8){ lockres[lo]=lpfx[li]; lo=lo+1; li=li+1 } 70 li=0; while wsid[li]!=(0 as u8){ lockres[lo]=wsid[li]; lo=lo+1; li=li+1 } lockres[lo]=0 as u8 71 72 lg_make(sa, "artifact-A\n" as *u8); lg_make(sb, "artifact-B\n" as *u8); lg_make(sc, "artifact-C\n" as *u8) 73 lg_reset(qpath); lg_seed(qpath, sa, sb, sc) 74 let qlines: i64 = lg_count(qpath) 75 76 // Concurrent phases FIRST, while the parent footprint is still small (so fork() does not ENOMEM). 77 // Phase A: two LOCKED concurrent publishers (forced race window) -> still exactly 3. 78 lg_reset(ledpath) 79 lg_concurrent(qpath, ledpath, lockres, 1) 80 let ledc: i64 = lg_count(ledpath) 81 82 // Phase B: NEG-CONTROL -- two UNLOCKED concurrent publishers -> double-publish (> 3). 83 lg_reset(ledpath) 84 lg_concurrent(qpath, ledpath, lockres, 0) 85 let ledu: i64 = lg_count(ledpath) 86 87 // Phase C (LAST, leaky in-parent): single-run dedup + idempotent re-run. 88 lg_reset(ledpath) 89 let p1: i64 = pub_run(qpath, ledpath, lockres, 1, 0) 90 let led1: i64 = lg_count(ledpath) 91 let p2: i64 = pub_run(qpath, ledpath, lockres, 1, 0) 92 let led2: i64 = lg_count(ledpath) 93 94 g_w(" queue lines="); g_n(qlines); g_w(" (3 unique + 2 dup)\n") 95 g_w(" single-run: published="); g_n(p1); g_w(" ledger="); g_n(led1); g_w(" re-run: published="); g_n(p2); g_w(" ledger="); g_n(led2); g_w("\n") 96 g_w(" concurrent LOCKED ledger="); g_n(ledc); g_w(" concurrent UNLOCKED ledger="); g_n(ledu); g_w("\n") 97 98 g_row("DEDUP: 5 requests (2 dup) -> exactly 3 published, ledger==3" as *u8, ((p1==3) as i64) & ((led1==3) as i64), pass) 99 g_row("IDEMPOTENT re-run: second pass publishes 0, ledger stays 3" as *u8, ((p2==0) as i64) & ((led2==3) as i64), pass) 100 g_row("SERIALIZE: 2 concurrent locked publishers -> ledger==3 (no double-publish)" as *u8, (ledc==3) as i64, pass) 101 g_row("NEG-CONTROL: 2 UNLOCKED publishers double-publish (ledger>3) = lock load-bearing" as *u8, (ledu>3) as i64, pass) 102 103 g_w("PUB-LOOP rows=4 pass="); g_n(pass[0]) 104 if pass[0]==4 { g_w(" verdict=GREEN\n"); sys_exit(0); return 0 } 105 g_w(" verdict=RED\n"); sys_exit(1); return 1 106}