nx_gate_lib.nx source
↩ module page · 197 lines · 9077 B
1// nx_gate_lib.nx -- THE SHARED BASE FOR GATE ORGANS (gl_*), authored 2026-07-25 to eat debt seq938.
2//
3// WHY THIS EXISTS: nx_feed_gate, nx_p384_ecdh_gate and nx_tls12_prf_gate were each written with a PRIVATE
4// copy of the same six helpers (slen/puts/putn/bcat/bcatn/contains) under three different prefixes --
5// fdg_ / pkg_ / tpg_. That is the exact drift the flip family already paid to fix with nx_flip_lib.nx's
6// fx_* base: a fix to one copy fixes ONE gate, and the family silently diverges. Same mistake, same cure.
7//
8// It also fixes the contract every gate member must honour, so a new gate inherits it instead of
9// re-deriving it:
10// (1) print FAILURES ONLY -- a roster of PASS lines buries the failure the gate exists to surface,
11// and the plan-runner snippet cap (200B) will truncate it away entirely.
12// (2) emit a `verdict=GREEN|RED pass=N/M` anchor LAST so the D001 judge and the beat can read it.
13// (3) counts[0]=total counts[1]=pass, so a case can never be "counted" without being adjudicated.
14// (4) a case asserts BOTH an exit code AND a required output substring -- an exit code alone lets a
15// silently-wrong organ pass, and a substring alone lets a crashed one pass.
16//
17// license_tier: ORIGINAL No hw writes (Rule 26).
18import "nx_syscalls.nx"
19import "nx_tool_run.nx"
20
21const GL_OUTCAP: i64 = 1048576 // per-case fork capture (1 MiB: some probed pages exceed 64KB)
22const GL_BUF: i64 = 262144
23const GL_AVCAP: i64 = 192
24const GL_SCRATCH: i64 = 32
25const GL_EXIT_RED: i64 = 1
26
27func gl_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
28func gl_puts(s: *u8) -> i64 { sys_write(1, s, gl_slen(s)); return 0 }
29func gl_putn(v: i64) -> i64 {
30 let b: *u8 = sys_mmap(24)
31 var m: i64 = v
32 if m == 0 { b[0] = 48 as u8; sys_write(1, b, 1); return 0 }
33 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
34 var nd: i64 = 0
35 var t: i64 = m
36 while t > 0 { nd = nd + 1; t = t / 10 }
37 var i: i64 = nd - 1
38 while i >= 0 { b[i] = (48 + (m % 10)) as u8; m = m / 10; i = i - 1 }
39 sys_write(1, b, nd)
40 return 0
41}
42// append a NUL-terminated string into a buffer at offset o; returns the new offset
43func gl_bcat(b: *u8, o: i64, s: *u8) -> i64 {
44 var i: i64 = 0
45 var oo: i64 = o
46 while s[i] != (0 as u8) { b[oo] = s[i]; oo = oo + 1; i = i + 1 }
47 return oo
48}
49// append a signed decimal into a buffer at offset o; returns the new offset
50func gl_bcatn(b: *u8, o: i64, v: i64) -> i64 {
51 var oo: i64 = o
52 var m: i64 = v
53 if m < 0 { b[oo] = 45 as u8; oo = oo + 1; m = 0 - m }
54 if m == 0 { b[oo] = 48 as u8; return oo + 1 }
55 let tb: *u8 = sys_mmap(24)
56 var nd: i64 = 0
57 while m > 0 { tb[nd] = (48 + (m % 10)) as u8; m = m / 10; nd = nd + 1 }
58 var i: i64 = nd - 1
59 while i >= 0 { b[oo] = tb[i]; oo = oo + 1; i = i - 1 }
60 return oo
61}
62// does haystack[0..n) contain the NUL-terminated needle?
63func gl_contains(h: *u8, n: i64, needle: *u8) -> i64 {
64 var m: i64 = 0
65 while needle[m] != (0 as u8) { m = m + 1 }
66 if m == 0 { return 1 }
67 if m > n { return 0 }
68 var i: i64 = 0
69 var found: i64 = 0
70 while i <= n - m {
71 if found == 0 {
72 var j: i64 = 0
73 var ok: i64 = 1
74 while j < m {
75 if ok == 1 { if h[i+j] != needle[j] { ok = 0 } }
76 j = j + 1
77 }
78 if ok == 1 { found = 1 }
79 }
80 i = i + 1
81 }
82 return found
83}
84// adjudicate an already-computed boolean. counts[0]=total counts[1]=pass. FAILURES ONLY are printed.
85// ★FRAME-ELEMENT FLOOR, extracted 2026-08-14. The same distinct-colour loop was found hand-written
86// in nx_wasm_craft_gate (three copies), in nx_gassim_gate, and MISSING from eleven gates that had
87// settled for "more than 100 non-background pixels" instead. Extracting it is the point of this lib.
88//
89// THE DEFECT IT ANSWERS: a raster row whose LABEL names several elements -- "Sun + planets",
90// "pivot + rod + bob + trail", "ground + two trajectories", "20 speed-coloured particles" -- while
91// its PREDICATE merely counts non-background pixels. ANY ONE of those elements satisfies such a
92// count, so the rest can vanish with the row still green. Measured that day: nx_pendulum_gate's
93// raster row passed on frames where the bob was rendering at x = -1, entirely outside the picture.
94//
95// Distinct colour count is the one property that scales with the ELEMENT COUNT while needing no
96// per-engine geometry: separate elements are drawn in separate colours, so a frame carrying N of
97// them carries at least N non-background colours.
98// ⚠IT IS A FLOOR, NOT AN IDENTIFICATION. It cannot say WHICH element is missing, only that fewer
99// than N are present, and two elements sharing a colour read as one. Where a gate can compute an
100// element's screen position it should assert that directly instead -- nx_solarsim_gate and
101// nx_gassim_gate do exactly that. This is for the frames whose geometry the gate cannot reconstruct.
102// ⚠THE RETURN SATURATES AT cap and is therefore also a floor in that direction; every caller asserts
103// >= N with N far below cap, and a floor is sound for that comparison. Do NOT use it to claim an
104// exact palette size.
105func gl_distinct_colours(fb: *i64, npx: i64, bg: i64, cap: i64, seen: *i64) -> i64 {
106 var n: i64 = 0
107 var i: i64 = 0
108 while i < npx {
109 let c: i64 = fb[i]
110 if c != bg {
111 var j: i64 = 0
112 var dup: i64 = 0
113 while j < n { if seen[j] == c { dup = 1; j = n } else { j = j + 1 } }
114 if dup == 0 { if n < cap { seen[n] = c; n = n + 1 } else { i = npx } }
115 }
116 i = i + 1
117 }
118 return n
119}
120
121func gl_check(nm: *u8, ok: i64, counts: *i64) -> i64 {
122 counts[0] = counts[0] + 1
123 if ok == 1 { counts[1] = counts[1] + 1; return 0 }
124 gl_puts("FAIL " as *u8); gl_puts(nm); gl_puts("\n" as *u8)
125 return 0
126}
127// fork a live organ and assert BOTH its exit code AND a required output substring.
128// Buffered variant: FAIL rows accumulate into pb at offset po; returns the new offset.
129func gl_case(nm: *u8, path: *u8, av: *i64, want_exit: i64, want_sub: *u8,
130 counts: *i64, pb: *u8, po: i64) -> i64 {
131 let out: *u8 = sys_mmap(GL_OUTCAP)
132 let ol: *i64 = sys_mmap(GL_SCRATCH) as *i64
133 let rc: i64 = tr_run_capture(path, av, out, GL_OUTCAP, ol)
134 var ok: i64 = 1
135 if rc != want_exit { ok = 0 }
136 if gl_contains(out, ol[0], want_sub) == 0 { ok = 0 }
137 counts[0] = counts[0] + 1
138 if ok == 1 { counts[1] = counts[1] + 1; return po }
139 var o: i64 = po
140 o = gl_bcat(pb, o, "FAIL " as *u8)
141 o = gl_bcat(pb, o, nm)
142 o = gl_bcat(pb, o, " exit=" as *u8); o = gl_bcatn(pb, o, rc)
143 o = gl_bcat(pb, o, " want_exit=" as *u8); o = gl_bcatn(pb, o, want_exit)
144 o = gl_bcat(pb, o, " want=" as *u8); o = gl_bcat(pb, o, want_sub)
145 o = gl_bcat(pb, o, "\n" as *u8)
146 return o
147}
148// build a 1-URL argv vector for the common "fork <elf> <url>" case
149func gl_av1(path: *u8, a1: *u8) -> *i64 {
150 let av: *i64 = sys_mmap(GL_AVCAP) as *i64
151 av[0] = path as i64
152 av[1] = a1 as i64
153 av[2] = 0
154 return av
155}
156// APPEND one durable verdict line to a log path. WHY THIS EXISTS (measured 2026-07-25): the tickless clock
157// daemon's clk_dispatch_run forks a job, wait4()s it, and counts it as dispatched whenever it RAN -- it does
158// NOT distinguish exit 0 from exit 1, and the child's stdout goes NOWHERE. So an hourly gate that turns RED
159// turns red in a VACUUM: nothing records it and nothing alerts. Rather than change the shared dispatcher
160// (blast radius: every clock job in the ecosystem), each gate now writes its OWN durable evidence -- the
161// same knowledge/status/*.log idiom the auction/census organs already use.
162func gl_log(path: *u8, banner: *u8, counts: *i64) -> i64 {
163 let fd: i64 = sys_openat_append(path, 0x1a4)
164 if fd < 0 { return 0 - 1 }
165 let b: *u8 = sys_mmap(512)
166 var o: i64 = 0
167 o = gl_bcatn(b, o, sys_now_realtime_sec())
168 o = gl_bcat(b, o, " " as *u8)
169 o = gl_bcat(b, o, banner)
170 o = gl_bcat(b, o, " verdict=" as *u8)
171 if counts[1] == counts[0] { o = gl_bcat(b, o, "GREEN" as *u8) } else { o = gl_bcat(b, o, "RED" as *u8) }
172 o = gl_bcat(b, o, " pass=" as *u8)
173 o = gl_bcatn(b, o, counts[1])
174 o = gl_bcat(b, o, "/" as *u8)
175 o = gl_bcatn(b, o, counts[0])
176 b[o] = 10 as u8
177 o = o + 1
178 sys_write(fd, b, o)
179 sys_close(fd)
180 return 0
181}
182
183// emit the D001 verdict anchor LAST, then flush buffered FAIL rows. Returns the process exit code.
184func gl_verdict(banner: *u8, counts: *i64, ref: *u8, pb: *u8, po: i64) -> i64 {
185 gl_puts(banner)
186 gl_puts("\nverdict=" as *u8)
187 if counts[1] == counts[0] { gl_puts("GREEN" as *u8) } else { gl_puts("RED" as *u8) }
188 gl_puts(" pass=" as *u8); gl_putn(counts[1])
189 gl_puts("/" as *u8); gl_putn(counts[0])
190 if ref[0] != (0 as u8) { gl_puts(" " as *u8); gl_puts(ref) }
191 gl_puts("\n" as *u8)
192 if po > 0 { sys_write(1, pb, po) }
193 if counts[1] == counts[0] { return 0 }
194 return GL_EXIT_RED
195}
196
197func main() -> i64 { return 0 }