code wiki / _hdl_build / nx_adverse_net_gate.nx
nx_adverse_net_gate.nx source
↩ module page · 180 lines · 9514 B
1// nx_adverse_net_gate.nx -- THE MEASURED ADVERSE-NETWORK SCORECARD (NET-R6, no-wave).
2// Simulates "a girl on a bad mobile link (high latency + jitter + ~8% loss + reorder) playing with a
3// boy in Texas" and runs the FULL sovereign netcode stack over the trace vs a NAIVE baseline:
4// bandwidth : nx_netquant delta bit-coding vs raw 28-byte frames
5// smoothness : nx_interp + dead-reckoning vs snap-to-latest (zero-order hold)
6// reliability: nx_fec_xor zero-RTT recovery vs best-effort (no recovery)
7// latency : nx_jitterbuf adaptive playout delay -- reported as the HONEST cost (not a "win")
8// WIN is asserted ONLY where measured; the playout-delay latency is reported, not hidden.
9// Built nx_cc_sovereign -> nxasm_x86 (no gcc, no .sh). license_tier: ORIGINAL
10import "nx_syscalls.nx"
11import "nx_gate_emit_lib.nx"
12import "nx_netquant.nx"
13import "nx_interp.nx"
14import "nx_jitterbuf.nx"
15import "nx_fec_xor.nx"
16import "nx_gate_verdict.nx"
17
18func g_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v }
19// ground-truth path: walk out, turn at t=1500, walk back (a direction change -> honest interp/extrap error)
20func pos(t: i64) -> i64 { if t <= 1500 { return t / 3 } return 500 - (t - 1500) / 3 }
21// deterministic adverse link: jitter in [-80,80], ~8% loss (never the first packet)
22func jit(i: i64) -> i64 { return ((i * 37) % 161) - 80 }
23func lost(i: i64) -> i64 { if i == 0 { return 0 } if (i * 13) % 12 == 0 { return 1 } return 0 }
24func setx(f: *i64, x: i64) -> i64 { var j: i64=0; while j<10 { f[j]=0; j=j+1 } f[0]=x; return 0 }
25func fcopy(d: *i64, s: *i64) -> i64 { var j: i64=0; while j<10 { d[j]=s[j]; j=j+1 } return 0 }
26
27func main() -> i64 {
28 g_puts("nx_adverse_net SCORECARD (NET-R6): bad-mobile x Texas, full stack vs naive (no-wave)\n" as *u8)
29 var pass: i64 = 0; var total: i64 = 0
30
31 let NS: i64 = 45 // snapshots
32 let TICK: i64 = 67 // ~15 Hz send
33 let DISP: i64 = 33 // ~30 Hz display
34 let SESS: i64 = 3000
35 let LAT: i64 = 150 // base one-way latency (cross-country + mobile)
36 let KINT: i64 = 10 // keyframe interval (resync)
37 let MAXEX: i64 = 300
38
39 let buf: *u8 = sys_mmap(64)
40 let fcur: *i64 = sys_mmap(10*8) as *i64
41 let fprev: *i64 = sys_mmap(10*8) as *i64
42 let ff: *i64 = sys_mmap(10*8) as *i64
43 let out: *i64 = sys_mmap(10*8) as *i64
44 let rst: *i64 = sys_mmap(64*8) as *i64 // received: server time
45 let rarr:*i64 = sys_mmap(64*8) as *i64 // arrival time
46 let rval:*i64 = sys_mmap(64*8) as *i64 // x value
47 var nr: i64 = 0
48 var nishi_bytes: i64 = 0
49 var naive_bytes: i64 = 0
50
51 // ---- send loop: measure bandwidth + build the received (lossy) stream ----
52 var i: i64 = 0
53 while i < NS {
54 let st: i64 = i * TICK
55 let x: i64 = pos(st)
56 setx(fcur, x)
57 if (i % KINT) == 0 { nishi_bytes = nishi_bytes + nx_bits_bytes(nq_pack_full(buf, fcur)) }
58 else { nishi_bytes = nishi_bytes + nx_bits_bytes(nq_pack_delta(buf, fprev, fcur)) }
59 naive_bytes = naive_bytes + 28
60 fcopy(fprev, fcur)
61 if lost(i) == 0 {
62 rst[nr] = st; rarr[nr] = st + LAT + jit(i); rval[nr] = x; nr = nr + 1
63 }
64 i = i + 1
65 }
66 // sort received by arrival (insertion sort, 3 parallel arrays) -- models reorder at the receiver
67 var a: i64 = 1
68 while a < nr {
69 let ka: i64 = rarr[a]; let ks: i64 = rst[a]; let kv: i64 = rval[a]
70 var b: i64 = a - 1
71 var go: i64 = 1
72 while go == 1 {
73 if b < 0 { go = 0 } else {
74 if rarr[b] > ka { rarr[b+1]=rarr[b]; rst[b+1]=rst[b]; rval[b+1]=rval[b]; b = b - 1 } else { go = 0 }
75 }
76 }
77 rarr[b+1]=ka; rst[b+1]=ks; rval[b+1]=kv
78 a = a + 1
79 }
80
81 // ---- jitterbuf -> adaptive playout delay (the honest latency cost) ----
82 let jb: *i64 = sys_mmap(8*8) as *i64
83 jb_init(jb, TICK, 100, 600)
84 var k: i64 = 0
85 while k < nr { jb_on_recv(jb, rarr[k]); k = k + 1 }
86 let PD: i64 = jb_playout(jb)
87
88 // ---- render loop: smoothness (frame-to-frame jump) + Nishi fidelity-to-target ----
89 let HK: i64 = 48
90 let hist: *i64 = sys_mmap((1 + HK*IP_STRIDE) * 8) as *i64
91 ip_init(hist)
92 var pidx: i64 = 0
93 var prev_rx: i64 = 0 - 999999
94 var prev_nv: i64 = 0 - 999999
95 var jump_nishi: i64 = 0
96 var jump_naive: i64 = 0
97 var fid_max: i64 = 0
98 var fid_sum: i64 = 0
99 var fid_cnt: i64 = 0
100 var dt: i64 = 0
101 while dt <= SESS {
102 var go2: i64 = 1
103 while go2 == 1 {
104 if pidx < nr { if rarr[pidx] <= dt { setx(ff, rval[pidx]); ip_push(hist, HK, rst[pidx], ff); pidx = pidx + 1 } else { go2 = 0 } } else { go2 = 0 }
105 }
106 let rtm: i64 = dt - PD
107 if rtm >= 0 {
108 let stt: i64 = ip_sample_ex(hist, rtm, MAXEX, out)
109 if stt > 0 {
110 let rx: i64 = out[0]
111 if prev_rx > 0 - 999999 { let j: i64 = g_abs(rx - prev_rx); if j > jump_nishi { jump_nishi = j } }
112 prev_rx = rx
113 let fe: i64 = g_abs(rx - pos(rtm)); if fe > fid_max { fid_max = fe }
114 fid_sum = fid_sum + fe; fid_cnt = fid_cnt + 1
115 }
116 }
117 if pidx > 0 {
118 let nv: i64 = rval[pidx - 1] // naive shows the newest-ARRIVED state (reorder -> jumps)
119 if prev_nv > 0 - 999999 { let j: i64 = g_abs(nv - prev_nv); if j > jump_naive { jump_naive = j } }
120 prev_nv = nv
121 }
122 dt = dt + DISP
123 }
124
125 // ---- FEC reliability: post-recovery effective loss vs raw loss (zero-RTT, no retransmit) ----
126 let L: i64 = 4; let D: i64 = 3; let S: i64 = 12; let BK: i64 = L*D
127 let src: *u8 = sys_mmap(BK*S); let rows: *u8 = sys_mmap(D*S); let cols: *u8 = sys_mmap(L*S)
128 let present: *i64 = sys_mmap(BK*8) as *i64
129 let rpz: *i64 = sys_mmap(D*8) as *i64
130 let cpz: *i64 = sys_mmap(L*8) as *i64
131 var raw_lost: i64 = 0
132 var eff_lost: i64 = 0
133 var blk: i64 = 0
134 while blk * BK < NS {
135 var z: i64 = 0
136 while z < BK { let p: *u8 = fec_pkt(src, z, S); var bb: i64=0; while bb<S { p[bb]=((z*5+bb)&0xff) as u8; bb=bb+1 } z=z+1 }
137 fec_encode_rows(src, L, D, S, rows); fec_encode_cols(src, L, D, S, cols)
138 var z2: i64 = 0; while z2 < BK { present[z2]=1; z2=z2+1 }
139 var z3: i64 = 0; while z3 < D { rpz[z3]=1; z3=z3+1 }
140 var z4: i64 = 0; while z4 < L { cpz[z4]=1; z4=z4+1 }
141 z = 0
142 while z < BK {
143 let gi: i64 = blk*BK + z
144 if gi < NS { if lost(gi) == 1 { present[z]=0; fec_zero(fec_pkt(src,z,S), S); raw_lost = raw_lost + 1 } }
145 z = z + 1
146 }
147 let rem: i64 = fec_decode_2d(src, L, D, S, present, rows, rpz, cols, cpz)
148 eff_lost = eff_lost + rem
149 blk = blk + 1
150 }
151
152 // ================= SCORECARD =================
153 g_puts(" -------------------------------------------------------------\n" as *u8)
154 g_puts(" BANDWIDTH nishi=" as *u8); g_pn(nishi_bytes); g_puts(" B naive=" as *u8); g_pn(naive_bytes); g_puts(" B (over " as *u8); g_pn(NS); g_puts(" snapshots)\n" as *u8)
155 g_puts(" SMOOTHNESS max frame jump: nishi=" as *u8); g_pn(jump_nishi); g_puts(" naive=" as *u8); g_pn(jump_naive); g_puts(" (lower=smoother)\n" as *u8)
156 g_puts(" RELIABILITY raw_lost=" as *u8); g_pn(raw_lost); g_puts(" -> post-FEC eff_lost=" as *u8); g_pn(eff_lost); g_puts(" (zero retransmit)\n" as *u8)
157 var fid_avg: i64 = 0
158 if fid_cnt > 0 { fid_avg = fid_sum / fid_cnt }
159 g_puts(" FIDELITY nishi reconstruction err vs target: avg=" as *u8); g_pn(fid_avg); g_puts(" max=" as *u8); g_pn(fid_max); g_puts(" voxels (max spike is the hard direction-reversal frame)\n" as *u8)
160 g_puts(" LATENCY nishi adaptive playout delay = " as *u8); g_pn(PD); g_puts(" ms (HONEST cost: trades lag for smoothness)\n" as *u8)
161 g_puts(" -------------------------------------------------------------\n" as *u8)
162
163 pass = pass + g_check("BANDWIDTH: nishi delta-coding << naive raw frames" as *u8, nishi_bytes < naive_bytes); total=total+1
164 pass = pass + g_check("SMOOTHNESS: nishi max frame-jump < naive (seamless)" as *u8, jump_nishi < jump_naive); total=total+1
165 pass = pass + g_check("RELIABILITY: post-FEC effective loss < raw loss (zero-RTT recovery)" as *u8, eff_lost < raw_lost); total=total+1
166 // honest bound: avg near-zero on steady motion; max < 2 snapshot-intervals of motion (~44) AND < 8% of the 500-voxel path
167 pass = pass + g_check("FIDELITY: avg err small (<=15) AND max bounded (<2 snapshot-intervals, <=44)" as *u8, (fid_avg <= 15) & (fid_max <= 44)); total=total+1
168 pass = pass + g_check("LATENCY reported honestly (playout delay > 0, a real cost)" as *u8, PD > 0); total=total+1
169
170 g_puts("---- adverse-net scorecard: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8)
171 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
172 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
173 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
174 let ctr__dry: *i64 = gv_ctr()
175 ctr__dry[0] = pass
176 ctr__dry[1] = total
177 let rc__dry: i64 = gv_verdict("ADVERSE-NET-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
178 sys_exit(rc__dry)
179 return rc__dry
180}