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}