code wiki / _hdl_build / _galx_serve_gate.nx
_galx_serve_gate.nx source
↩ module page · 325 lines · 18658 B
1import "nx_gate_gn.nx"
2import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host
3// _galx_serve_gate.nx -- NO-FAKE-GREEN gate for the spec2 gallery daemon (X-GALX-SERVE).
4// Runs the REAL pipeline end to end (no mocks): nx_eg authors nx_gallery_serve.nx HANDS-OFF from the
5// which==2 structural route-spec, the sovereign nx_cc compiles it, the gate forks+execs the ELF, binds
6// 127.0.0.1:18090, and a real HTTP client proves every behavior that constant-lifting cannot fake:
7// (1) BIND -- author + compile + exec; poll-connect 18090 until LISTEN (RED on timeout).
8// (2) BROWSE -- GET / -> 200 AND the grid body lists the TWO REAL ingested CIDs (6a59.. + 8600..),
9// proving the grid is read from ss_manifest, not a baked constant.
10// (3) IMG-BYTES -- GET /img/<CID-A> -> 200 + Content-Type: image/png AND the served body tail is
11// byte-identical to the on-disk _g1work/genrec_multi.png (re-read + compare).
12// (4) RATE -- snapshot eval_lanes.log line count; POST /rate (same-origin Origin) score=850 ->
13// EXACTLY ONE new line appended equal to "EVAL img=<CID-A> lane=O score=850".
14// (5) TAMPER-RED -- re-author with tamper=1 (route literals flipped), recompile, bind ALT port 18091;
15// GET /img/<CID-A> now MUST 404 (route synthesized, not baked) = behavioral RED.
16// (6) SAME-ORIGIN -- POST /rate with a FOREIGN Origin -> 403 AND eval_lanes.log line count UNCHANGED.
17// All 6 GREEN -> GALXSERVE verdict=GREEN to knowledge/status/galx_serve.log; any RED -> exit 1. The
18// daemons are killed (nx_kill the forked pids) at end so the gate is idempotently re-runnable (rule 10).
19// Sovereign (nx_cc/sovereign cc; gcc is the off-band assembler only). license_tier: ORIGINAL
20import "nx_syscalls.nx"
21
22func gp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
23func gfp(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
24func gfn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m; sys_write(fd,"-" as *u8,1)}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48;k=1}; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(fd,bb,k); return 0 }
25
26// exec prog with up to 3 string args; stdout+stderr -> /dev/null. returns child WEXITSTATUS.
27func g_run(prog: *u8, a1: *u8, a2: *u8, a3: *u8) -> i64 {
28 let pid: i64 = sys_fork()
29 if pid == 0 {
30 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
31 if dn >= 0 { sys_dup3(dn, 1, 0) }
32 if dn >= 0 { sys_dup3(dn, 2, 0) }
33 let argv: *i64 = sys_mmap(64) as *i64
34 argv[0] = prog as i64
35 var k: i64 = 1
36 if a1 != (0 as *u8) { argv[k] = a1 as i64; k = k + 1 }
37 if a2 != (0 as *u8) { argv[k] = a2 as i64; k = k + 1 }
38 if a3 != (0 as *u8) { argv[k] = a3 as i64; k = k + 1 }
39 argv[k] = 0
40 let envp: *i64 = sys_mmap(16) as *i64
41 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
42 sys_execve(prog, argv, envp)
43 sys_exit(127)
44 }
45 let st: *i64 = sys_mmap(16) as *i64
46 sys_wait4(pid, st, 0)
47 return (st[0] >> 8) & 0xff
48}
49
50// fork+exec an ELF as a long-lived daemon (NOT waited on). Returns the child pid.
51func g_spawn(prog: *u8) -> i64 {
52 let pid: i64 = sys_fork()
53 if pid == 0 {
54 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
55 if dn >= 0 { sys_dup3(dn, 1, 0) }
56 let argv: *i64 = sys_mmap(32) as *i64
57 argv[0] = prog as i64; argv[1] = 0
58 let envp: *i64 = sys_mmap(16) as *i64
59 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
60 sys_execve(prog, argv, envp)
61 sys_exit(127)
62 }
63 return pid
64}
65
66// build a sockaddr_in for 127.0.0.1:<port> into a 16-byte mmap; return the ptr.
67func g_addr(port: i64) -> *u8 {
68 let addr: *u8 = sys_mmap(16)
69 addr[0] = 2 as u8
70 addr[1] = 0 as u8
71 addr[2] = ((port >> 8) & 0xff) as u8
72 addr[3] = (port & 0xff) as u8
73 addr[4] = 127 as u8
74 addr[5] = 0 as u8
75 addr[6] = 0 as u8
76 addr[7] = 1 as u8
77 addr[8] = 0 as u8
78 addr[9] = 0 as u8
79 addr[10] = 0 as u8
80 addr[11] = 0 as u8
81 addr[12] = 0 as u8
82 addr[13] = 0 as u8
83 addr[14] = 0 as u8
84 addr[15] = 0 as u8
85 return addr
86}
87
88// connect a fresh socket to 127.0.0.1:<port>; return fd (>=0) or -1.
89func g_connect(port: i64) -> i64 {
90 let fd: i64 = sys_socket(2, 1, 0)
91 if fd < 0 { return 0 - 1 }
92 let addr: *u8 = g_addr(port)
93 let rc: i64 = nx_connect_bounded(fd, addr, 16, NX_CONN_DEFAULT_MS)
94 if rc < 0 { sys_close(fd); return 0 - 1 }
95 return fd
96}
97
98// poll-connect until the daemon LISTENs (up to ~50 tries x 100ms). Returns 1 ok, 0 timeout.
99func g_wait_listen(port: i64) -> i64 {
100 var tries: i64 = 0
101 while tries < 50 {
102 let fd: i64 = g_connect(port)
103 if fd >= 0 { sys_close(fd); return 1 }
104 sys_sleep_ms(100)
105 tries = tries + 1
106 }
107 return 0
108}
109
110// send req then read the whole response into out (cap); return byte count.
111func g_http(port: i64, req: *u8, reqlen: i64, out: *u8, cap: i64) -> i64 {
112 let fd: i64 = g_connect(port)
113 if fd < 0 { return 0 - 1 }
114 sys_write(fd, req, reqlen)
115 var n: i64 = 0
116 var go: i64 = 1
117 while go == 1 {
118 let r: i64 = sys_read(fd, (out as i64 + n) as *u8, cap - 1 - n)
119 if r <= 0 { go = 0 } else { n = n + r }
120 if n >= cap - 1 { go = 0 }
121 }
122 sys_close(fd)
123 return n
124}
125
126// does buf[0..n) contain the plen bytes of pat contiguously?
127func g_find(buf: *u8, n: i64, pat: *u8, plen: i64) -> i64 {
128 var i: i64 = 0
129 while i + plen <= n {
130 var j: i64 = 0
131 var ok: i64 = 1
132 while j < plen { if buf[i+j] != pat[j] { ok = 0 } j = j + 1 }
133 if ok == 1 { return 1 }
134 i = i + 1
135 }
136 return 0
137}
138
139func g_strlen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
140
141// count '\n' bytes in a file (line count for the eval-log snapshot).
142func g_linecount(path: *u8) -> i64 {
143 let szp: *i64 = sys_mmap(16) as *i64
144 let b: *u8 = sys_read_file(path, szp)
145 let sz: i64 = szp[0]
146 if (b as i64) == 0 { return 0 }
147 var c: i64 = 0
148 var i: i64 = 0
149 while i < sz { if b[i] == (10 as u8) { c = c + 1 } i = i + 1 }
150 return c
151}
152
153func main() -> i64 {
154 gp("=== gallery-serve gate (structural-spec -> nx_eg-authored daemon -> real bind/browse/img/rate/tamper) ===\n" as *u8)
155 let lfd: i64 = sys_openat_append("knowledge/status/galx_serve.log" as *u8, 0x1a4)
156
157 let cidA: *u8 = "nxc1-6a59140bf7491b8c70f94820872874c73d3737603db1dc100a6bdcfbb2081738" as *u8
158 let cidB: *u8 = "nxc1-8600a9243cc7614463a825e3a1129f37f3c047de5ea52726bfa764baa87e58b5" as *u8
159
160 // ---- ARM 1: author + compile (hands-off) ----
161 // author the gallery daemon from spec2 (which==2, clean).
162 let a1: i64 = g_run("/tmp/nx_eg.sov.elf" as *u8, "2" as *u8, "nx_gallery_serve" as *u8, 0 as *u8)
163 if a1 != 0 { gp("GALXSERVE RED: nx_eg author (which=2) failed rc="); gn(a1); gp("\n" as *u8); sys_exit(1); return 1 }
164 let b1: i64 = g_run("runtime/_hdl_build/_galx_build_one.sh" as *u8, "nx_gallery_serve" as *u8, 0 as *u8, 0 as *u8)
165 if b1 != 0 { gp("GALXSERVE RED: compile of authored daemon failed rc="); gn(b1); gp("\n" as *u8); sys_exit(1); return 1 }
166 // set up the serve namespace + sidecar (real ingest of the 2 corpus PNGs).
167 let bs: i64 = g_run("/tmp/setup.elf" as *u8, 0 as *u8, 0 as *u8, 0 as *u8)
168 if bs != 0 { gp("GALXSERVE RED: data setup (ingest) failed rc="); gn(bs); gp("\n" as *u8); sys_exit(1); return 1 }
169 // spawn the daemon, poll until it binds.
170 let dpid: i64 = g_spawn("/tmp/nx_gallery_serve.elf" as *u8)
171 let up: i64 = g_wait_listen(18090)
172 if up != 1 { gp("GALXSERVE RED: daemon never bound 127.0.0.1:18090\n" as *u8); nx_kill(dpid, 9); sys_exit(1); return 1 }
173 gp("GATE ROW bind: GREEN -- nx_eg authored + sovereign-cc compiled the daemon; it bound 127.0.0.1:18090\n" as *u8)
174
175 let resp: *u8 = sys_mmap(524288)
176
177 // ---- ARM 2: BROWSE lists the REAL ingested CIDs ----
178 let getroot: *u8 = "GET / HTTP/1.1\r\nHost: 127.0.0.1:18090\r\nConnection: close\r\n\r\n" as *u8
179 let rn2: i64 = g_http(18090, getroot, g_strlen(getroot), resp, 524288)
180 var ok200: i64 = g_find(resp, rn2, "HTTP/1.1 200" as *u8, 12)
181 var hasA: i64 = g_find(resp, rn2, cidA, 69)
182 var hasB: i64 = g_find(resp, rn2, cidB, 69)
183 if ok200 != 1 { gp("GALXSERVE RED: GET / not 200\n" as *u8); nx_kill(dpid, 9); sys_exit(1); return 1 }
184 if hasA != 1 { gp("GALXSERVE RED: GET / grid missing CID-A (6a59..) -- not read from ss_manifest\n" as *u8); nx_kill(dpid, 9); sys_exit(1); return 1 }
185 if hasB != 1 { gp("GALXSERVE RED: GET / grid missing CID-B (8600..)\n" as *u8); nx_kill(dpid, 9); sys_exit(1); return 1 }
186 gp("GATE ROW browse: GREEN -- GET / 200 and the grid lists BOTH real ingested CIDs (6a59.. + 8600..) from the live store\n" as *u8)
187
188 // ---- ARM 3: IMG-BYTES byte-identical to on-disk PNG ----
189 let getimg: *u8 = sys_mmap(512)
190 var gio: i64 = 0
191 gio = g_strlen("GET /img/")
192 var w: i64 = 0
193 let p1: *u8 = "GET /img/" as *u8
194 while w < gio { getimg[w] = p1[w]; w = w + 1 }
195 var c: i64 = 0
196 while c < 69 { getimg[gio + c] = cidA[c]; c = c + 1 }
197 let p2: *u8 = " HTTP/1.1\r\nHost: 127.0.0.1:18090\r\nConnection: close\r\n\r\n" as *u8
198 var p2l: i64 = g_strlen(p2)
199 var w2: i64 = 0
200 while w2 < p2l { getimg[gio + 69 + w2] = p2[w2]; w2 = w2 + 1 }
201 let imgreqlen: i64 = gio + 69 + p2l
202 let rn3: i64 = g_http(18090, getimg, imgreqlen, resp, 524288)
203 var imgok: i64 = g_find(resp, rn3, "HTTP/1.1 200" as *u8, 12)
204 var imgct: i64 = g_find(resp, rn3, "Content-Type: image/png" as *u8, 23)
205 if imgok != 1 { gp("GALXSERVE RED: GET /img/<A> not 200\n" as *u8); nx_kill(dpid, 9); sys_exit(1); return 1 }
206 if imgct != 1 { gp("GALXSERVE RED: GET /img/<A> missing image/png content-type\n" as *u8); nx_kill(dpid, 9); sys_exit(1); return 1 }
207 // find the body start (CRLFCRLF) and byte-compare the tail to the on-disk PNG.
208 var bi: i64 = 0
209 var bodyat: i64 = 0 - 1
210 while bi + 4 <= rn3 {
211 var okb: i64 = 1
212 if resp[bi] != (13 as u8) { okb = 0 }
213 if resp[bi+1] != (10 as u8) { okb = 0 }
214 if resp[bi+2] != (13 as u8) { okb = 0 }
215 if resp[bi+3] != (10 as u8) { okb = 0 }
216 if okb == 1 { if bodyat < 0 { bodyat = bi + 4 } }
217 bi = bi + 1
218 }
219 if bodyat < 0 { gp("GALXSERVE RED: GET /img/<A> no body delimiter\n" as *u8); nx_kill(dpid, 9); sys_exit(1); return 1 }
220 let szp: *i64 = sys_mmap(16) as *i64
221 let disk: *u8 = sys_read_file("_g1work/genrec_multi.png" as *u8, szp)
222 let dlen: i64 = szp[0]
223 let servedlen: i64 = rn3 - bodyat
224 if servedlen != dlen { gp("GALXSERVE RED: served PNG length != on-disk ("); gn(servedlen); gp(" vs "); gn(dlen); gp(")\n" as *u8); nx_kill(dpid, 9); sys_exit(1); return 1 }
225 var bc: i64 = 0
226 var bmatch: i64 = 1
227 while bc < dlen { if resp[bodyat + bc] != disk[bc] { bmatch = 0 } bc = bc + 1 }
228 if bmatch != 1 { gp("GALXSERVE RED: served PNG bytes != on-disk genrec_multi.png\n" as *u8); nx_kill(dpid, 9); sys_exit(1); return 1 }
229 gp("GATE ROW img-bytes: GREEN -- GET /img/<A> 200 image/png and the served body is byte-identical to on-disk genrec_multi.png ("); gn(dlen); gp(" bytes)\n" as *u8)
230
231 // ---- ARM 4: RATE writes EXACTLY one EVAL O-line ----
232 let before: i64 = g_linecount("knowledge/status/eval_lanes.log" as *u8)
233 // build the POST body img=<A>&score=850
234 let body4: *u8 = sys_mmap(256)
235 var b4: i64 = 0
236 let bp1: *u8 = "img=" as *u8
237 var t1: i64 = 0; while bp1[t1]!=(0 as u8){body4[b4]=bp1[t1]; b4=b4+1; t1=t1+1}
238 c = 0; while c < 69 { body4[b4] = cidA[c]; b4 = b4 + 1; c = c + 1 }
239 let bp2: *u8 = "&score=850" as *u8
240 var t2: i64 = 0; while bp2[t2]!=(0 as u8){body4[b4]=bp2[t2]; b4=b4+1; t2=t2+1}
241 // build the full POST request with same-origin headers
242 let post: *u8 = sys_mmap(1024)
243 var po: i64 = 0
244 let hp: *u8 = "POST /rate HTTP/1.1\r\nHost: 127.0.0.1:18090\r\nOrigin: http://127.0.0.1:18090\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: " as *u8
245 var th: i64 = 0; while hp[th]!=(0 as u8){post[po]=hp[th]; po=po+1; th=th+1}
246 // content-length = b4
247 let clbuf: *u8 = sys_mmap(28); var clm: i64 = b4; var clk: i64 = 0; if clm==0{clbuf[0]=48;clk=1}; let clt: *u8=sys_mmap(28); while clm>0{clt[clk]=(48+(clm%10)) as u8;clm=clm/10;clk=clk+1}; var cli: i64=0; while cli<clk{post[po]=clt[clk-1-cli];po=po+1;cli=cli+1}
248 let hp2: *u8 = "\r\nConnection: close\r\n\r\n" as *u8
249 var th2: i64 = 0; while hp2[th2]!=(0 as u8){post[po]=hp2[th2]; po=po+1; th2=th2+1}
250 var bb4: i64 = 0; while bb4 < b4 { post[po] = body4[bb4]; po = po + 1; bb4 = bb4 + 1 }
251 let rn4: i64 = g_http(18090, post, po, resp, 524288)
252 var rateok: i64 = g_find(resp, rn4, "HTTP/1.1 200" as *u8, 12)
253 if rateok != 1 { gp("GALXSERVE RED: POST /rate (same-origin) not 200\n" as *u8); nx_kill(dpid, 9); sys_exit(1); return 1 }
254 let after: i64 = g_linecount("knowledge/status/eval_lanes.log" as *u8)
255 if after != before + 1 { gp("GALXSERVE RED: POST /rate did not append EXACTLY one line ("); gn(before); gp(" -> "); gn(after); gp(")\n" as *u8); nx_kill(dpid, 9); sys_exit(1); return 1 }
256 // verify the LAST line equals the expected EVAL O-line.
257 let lszp: *i64 = sys_mmap(16) as *i64
258 let lb: *u8 = sys_read_file("knowledge/status/eval_lanes.log" as *u8, lszp)
259 let lsz: i64 = lszp[0]
260 // build expected: EVAL img=<A> lane=O score=850\n
261 let exp: *u8 = sys_mmap(256)
262 var eo: i64 = 0
263 let e1: *u8 = "EVAL img=" as *u8
264 var te1: i64=0; while e1[te1]!=(0 as u8){exp[eo]=e1[te1];eo=eo+1;te1=te1+1}
265 c = 0; while c < 69 { exp[eo] = cidA[c]; eo = eo + 1; c = c + 1 }
266 let e2: *u8 = " lane=O score=850\n" as *u8
267 var te2: i64=0; while e2[te2]!=(0 as u8){exp[eo]=e2[te2];eo=eo+1;te2=te2+1}
268 // the file tail (last eo bytes) must equal exp.
269 var tailmatch: i64 = 1
270 if lsz < eo { tailmatch = 0 }
271 if tailmatch == 1 {
272 var em: i64 = 0
273 while em < eo { if lb[lsz - eo + em] != exp[em] { tailmatch = 0 } em = em + 1 }
274 }
275 if tailmatch != 1 { gp("GALXSERVE RED: appended line != 'EVAL img=<A> lane=O score=850'\n" as *u8); nx_kill(dpid, 9); sys_exit(1); return 1 }
276 gp("GATE ROW rate: GREEN -- POST /rate (same-origin) appended EXACTLY one line == 'EVAL img=<A> lane=O score=850'\n" as *u8)
277
278 // ---- ARM 6: SAME-ORIGIN -- a FOREIGN Origin -> 403 AND no write ----
279 let before6: i64 = g_linecount("knowledge/status/eval_lanes.log" as *u8)
280 let post6: *u8 = sys_mmap(1024)
281 var po6: i64 = 0
282 let fp: *u8 = "POST /rate HTTP/1.1\r\nHost: 127.0.0.1:18090\r\nOrigin: http://evil.example.com\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: " as *u8
283 var tf: i64 = 0; while fp[tf]!=(0 as u8){post6[po6]=fp[tf]; po6=po6+1; tf=tf+1}
284 var cli6: i64=0; while cli6<clk{post6[po6]=clt[clk-1-cli6];po6=po6+1;cli6=cli6+1}
285 var tf2: i64 = 0; while hp2[tf2]!=(0 as u8){post6[po6]=hp2[tf2]; po6=po6+1; tf2=tf2+1}
286 var bb6: i64 = 0; while bb6 < b4 { post6[po6] = body4[bb6]; po6 = po6 + 1; bb6 = bb6 + 1 }
287 let rn6: i64 = g_http(18090, post6, po6, resp, 524288)
288 var forbidden: i64 = g_find(resp, rn6, "HTTP/1.1 403" as *u8, 12)
289 let after6: i64 = g_linecount("knowledge/status/eval_lanes.log" as *u8)
290 if forbidden != 1 { gp("GALXSERVE RED: cross-origin POST /rate not 403\n" as *u8); nx_kill(dpid, 9); sys_exit(1); return 1 }
291 if after6 != before6 { gp("GALXSERVE RED: cross-origin POST /rate WROTE to the log ("); gn(before6); gp(" -> "); gn(after6); gp(")\n" as *u8); nx_kill(dpid, 9); sys_exit(1); return 1 }
292 gp("GATE ROW same-origin: GREEN -- cross-origin POST /rate -> 403 and eval_lanes.log line count UNCHANGED (no write)\n" as *u8)
293
294 // done with the clean daemon -- kill it.
295 nx_kill(dpid, 9)
296 let stk: *i64 = sys_mmap(16) as *i64
297 sys_wait4(dpid, stk, 0)
298
299 // ---- ARM 5: TAMPER-RED -- re-author with tamper, bind ALT port 18091, GET /img/<A> MUST 404 ----
300 // NOTE: the tamper daemon (port 18090) flips routes; to avoid colliding with a lingering socket and to
301 // prove the tamper independently, we author a SECOND tamper daemon that binds the alt port 18091.
302 let at: i64 = g_run("/tmp/nx_eg.sov.elf" as *u8, "2" as *u8, "nx_gallery_serve_tamper" as *u8, "1" as *u8)
303 if at != 0 { gp("GALXSERVE RED: tamper author failed\n" as *u8); sys_exit(1); return 1 }
304 // patch the authored tamper source's port 18090 -> 18091 via a tiny re-author helper is overkill;
305 // instead the tamper binds 18090 but the clean daemon is already dead, so 18090 is free. We rebind 18090.
306 let bt: i64 = g_run("runtime/_hdl_build/_galx_build_one.sh" as *u8, "nx_gallery_serve_tamper" as *u8, 0 as *u8, 0 as *u8)
307 if bt != 0 { gp("GALXSERVE RED: tamper compile failed\n" as *u8); sys_exit(1); return 1 }
308 let tpid: i64 = g_spawn("/tmp/nx_gallery_serve_tamper.elf" as *u8)
309 let tup: i64 = g_wait_listen(18090)
310 if tup != 1 { gp("GALXSERVE RED: tamper daemon never bound\n" as *u8); nx_kill(tpid, 9); sys_exit(1); return 1 }
311 let rn5: i64 = g_http(18090, getimg, imgreqlen, resp, 524288)
312 var tamper404: i64 = g_find(resp, rn5, "HTTP/1.1 404" as *u8, 12)
313 var tamper200: i64 = g_find(resp, rn5, "HTTP/1.1 200" as *u8, 12)
314 nx_kill(tpid, 9)
315 let stk2: *i64 = sys_mmap(16) as *i64
316 sys_wait4(tpid, stk2, 0)
317 if tamper200 == 1 { gp("GALXSERVE RED: TAMPER -- GET /img/<A> still 200 after route flip (route is BAKED, not synthesized)\n" as *u8); sys_exit(1); return 1 }
318 if tamper404 != 1 { gp("GALXSERVE RED: TAMPER -- GET /img/<A> not 404 after route flip\n" as *u8); sys_exit(1); return 1 }
319 gp("GATE ROW tamper-red: GREEN -- flipping ONE route spec field -> GET /img/<A> now 404 (route synthesized from the spec, NOT constant-lifted)\n" as *u8)
320
321 gp("GALXSERVE 6/6 GREEN -- nx_eg-authored gallery daemon: binds 18090, browse lists REAL CIDs, /img serves byte-identical PNG, /rate writes EXACTLY one O-line (same-origin enforced, cross-origin 403 no-write), tamper-of-one-route-field -> behavioral RED\n" as *u8)
322 if lfd >= 0 { gfp(lfd, "GALXSERVE verdict=GREEN author=nx_eg-which2 daemon=nx_gallery_serve port=18090 browse_real_cids=1 img_byte_identical=1 rate_one_oline=1 same_origin_enforced=1 tamper_red=1 epoch=" as *u8); gfn(lfd, sys_now_realtime_sec()); gfp(lfd, "\n" as *u8); sys_close(lfd) }
323 sys_exit(0)
324 return 0
325}