code wiki / _hdl_build / _ale_plan_gate.nx
_ale_plan_gate.nx source
↩ module page · 369 lines · 15201 B
1// _ale_plan_gate.nx -- the ALE-R2a gate: sovereign agent-core PLAN-phase organ.
2// Diff-lane / no-mocks: runs the REAL sovereign planner nx_ale_plan.elf (built by
3// nx_cc_sovereign->nxasm_x86_main, NO gcc) over REAL ALE-format task fixtures and asserts:
4// (1) INGEST -- over task_good the organ emits a PLAN file of ordered
5// "step|<n>|<verb>|<arg>" lines (>=3 step lines, all step|-prefixed)
6// (2) ORDERED -- the emitted step numbers are exactly 1,2,3 contiguous (no gaps)
7// (3) GROUNDED -- every step's <arg> equals a task field VALUE present in the spec
8// (each plan arg appears in the task spec as a "task|<field>|<arg>"
9// value-tail line -> no step references a field the spec didn't declare)
10// (4) ARTIFACT-TERMINAL -- the FINAL step is write_artifact and its <arg> is the task's
11// declared artifact_path value (the plan aims at the scored deliverable)
12// (5) DETERMINISTIC -- two consecutive runs on the SAME spec emit BYTE-IDENTICAL plans
13// (6) TAMPER REJECTED -- over task_missing_artifact (no artifact_path) the organ REFUSES:
14// child exits NON-ZERO and writes NO plan (the grounding check bites,
15// negative control mirroring the nondet-stub tamper in _ale_grade_gate)
16// Evidence -> knowledge/status/ale_plan.log (ALEPLANGATE row; the queue row's ||MARK= reads it).
17// Sovereign orchestration (fork/dup3/execve/wait4). The planner's purity (no clock/rand) IS the
18// oracle: a pure grounded decomposer needs no external oracle, exactly as ALE-R1a established.
19// license_tier: ORIGINAL
20import "nx_syscalls.nx"
21
22func g_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
23func g_fp(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 g_fn(fd: i64, v: i64) -> i64 { let bb: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m }; 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// run nx_ale_plan.elf <task> <planout>; return child exit code (decoded from wait status)
27func g_run_plan(task: *u8, planout: *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); sys_dup3(dn, 2, 0) }
32 let argv: *i64 = sys_mmap(32) as *i64
33 argv[0] = "_offc/nx_ale_plan.elf" as *u8 as i64
34 argv[1] = task as i64
35 argv[2] = planout as i64
36 argv[3] = 0
37 let envp: *i64 = sys_mmap(16) as *i64
38 envp[0] = 0
39 sys_execve("_offc/nx_ale_plan.elf" as *u8, argv, envp)
40 sys_exit(127)
41 }
42 let st: *i64 = sys_mmap(16) as *i64
43 sys_wait4(pid, st, 0)
44 return (st[0] >> 8) & 0xff
45}
46
47// read whole file into buf (cap), return byte count (0 on open-fail / empty)
48func g_read(path: *u8, buf: *u8, cap: i64) -> i64 {
49 let fd: i64 = sys_openat_rd(path)
50 if fd < 0 { return 0 }
51 var n: i64 = 0
52 var go: i64 = 1
53 while go == 1 {
54 let r: i64 = sys_read(fd, (buf as i64 + n) as *u8, cap - 1 - n)
55 if r <= 0 { go = 0 } else { n = n + r }
56 if n >= cap - 1 { go = 0 }
57 }
58 sys_close(fd)
59 return n
60}
61
62func g_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
63
64// does buf[pos..] match pat (len pl)? 1/0
65func g_match(buf: *u8, n: i64, pos: i64, pat: *u8, pl: i64) -> i64 {
66 if pos + pl > n { return 0 }
67 var k: i64 = 0
68 while k < pl { if buf[pos + k] != pat[k] { return 0 } k = k + 1 }
69 return 1
70}
71
72// is pos a line start? (pos==0 or previous byte is newline)
73func g_is_bol(buf: *u8, pos: i64) -> i64 {
74 if pos == 0 { return 1 }
75 if buf[pos - 1] == (10 as u8) { return 1 }
76 return 0
77}
78
79// count lines in buf that begin with prefix
80func g_count_prefix(buf: *u8, n: i64, prefix: *u8) -> i64 {
81 let pl: i64 = g_len(prefix)
82 var c: i64 = 0
83 var i: i64 = 0
84 while i < n {
85 if g_is_bol(buf, i) == 1 {
86 if g_match(buf, n, i, prefix, pl) == 1 { c = c + 1 }
87 }
88 i = i + 1
89 }
90 return c
91}
92
93// two files byte-identical? 1/0
94func g_files_eq(pa: *u8, pb: *u8) -> i64 {
95 let ba: *u8 = sys_mmap(262144)
96 let bb: *u8 = sys_mmap(262144)
97 let na: i64 = g_read(pa, ba, 262144)
98 let nb: i64 = g_read(pb, bb, 262144)
99 if na != nb { return 0 }
100 if na == 0 { return 0 }
101 var i: i64 = 0
102 while i < na { if ba[i] != bb[i] { return 0 } i = i + 1 }
103 return 1
104}
105
106// ORDERED: the i-th step line (i from 1) in the plan begins with the literal "step|<i>|".
107// Builds the expected prefix "step|<num>|" for num and confirms a line with that exact
108// prefix exists; the planner emits exactly maxn steps 1..maxn so contiguity == all present.
109func g_step_num_present(buf: *u8, n: i64, num: i64) -> i64 {
110 let pb: *u8 = sys_mmap(64)
111 pb[0] = 115 as u8 // s
112 pb[1] = 116 as u8 // t
113 pb[2] = 101 as u8 // e
114 pb[3] = 112 as u8 // p
115 pb[4] = 124 as u8 // |
116 // append decimal num
117 var m: i64 = num
118 let t: *u8 = sys_mmap(28)
119 var k: i64 = 0
120 if m == 0 { t[0] = 48; k = 1 }
121 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
122 var w: i64 = 5
123 var j: i64 = 0
124 while j < k { pb[w] = t[k - 1 - j]; w = w + 1; j = j + 1 }
125 pb[w] = 124 as u8 // |
126 w = w + 1
127 pb[w] = 0 as u8
128 let pl: i64 = w
129 var i: i64 = 0
130 while i < n {
131 if g_is_bol(buf, i) == 1 {
132 if g_match(buf, n, i, pb, pl) == 1 { return 1 }
133 }
134 i = i + 1
135 }
136 return 0
137}
138
139// GROUNDED helper: extract the <arg> (text after the 3rd '|' to end-of-line) of the plan
140// step line whose 2nd field is num, into out (cap). Returns arg length, or -1 if absent.
141// A plan line is "step|<num>|<verb>|<arg>"; we walk to the 3rd pipe then copy to newline.
142func g_step_arg(buf: *u8, n: i64, num: i64, out: *u8, cap: i64) -> i64 {
143 // locate the line start of "step|<num>|"
144 let pb: *u8 = sys_mmap(64)
145 pb[0] = 115 as u8; pb[1] = 116 as u8; pb[2] = 101 as u8; pb[3] = 112 as u8; pb[4] = 124 as u8
146 var m: i64 = num
147 let t: *u8 = sys_mmap(28)
148 var k: i64 = 0
149 if m == 0 { t[0] = 48; k = 1 }
150 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
151 var w: i64 = 5
152 var j: i64 = 0
153 while j < k { pb[w] = t[k - 1 - j]; w = w + 1; j = j + 1 }
154 pb[w] = 124 as u8; w = w + 1; pb[w] = 0 as u8
155 let pl: i64 = w
156 var start: i64 = 0 - 1
157 var i: i64 = 0
158 while i < n {
159 if g_is_bol(buf, i) == 1 {
160 if g_match(buf, n, i, pb, pl) == 1 { start = i; i = n }
161 }
162 i = i + 1
163 }
164 if start < 0 { return 0 - 1 }
165 // from start, skip 3 pipes ('|') then copy to newline
166 var p: i64 = start
167 var pipes: i64 = 0
168 var go: i64 = 1
169 while go == 1 {
170 if p >= n { go = 0 } else {
171 if buf[p] == (124 as u8) { pipes = pipes + 1; p = p + 1; if pipes == 3 { go = 0 } } else { p = p + 1 }
172 }
173 }
174 if pipes < 3 { return 0 - 1 }
175 var c: i64 = 0
176 var g2: i64 = 1
177 while g2 == 1 {
178 if p >= n { g2 = 0 } else {
179 if buf[p] == (10 as u8) { g2 = 0 } else {
180 if c < cap - 1 { out[c] = buf[p]; c = c + 1 }
181 p = p + 1
182 }
183 }
184 }
185 out[c] = 0 as u8
186 return c
187}
188
189// GROUNDED check: does the task spec contain a line "task|<anything>|<arg>" whose value-tail
190// equals arg exactly (value ends at end-of-line)? 1/0. Proves the plan arg traces to a
191// declared task field value (no hallucinated context). We scan task| lines and compare the
192// substring after the 2nd '|' to arg.
193func g_arg_in_task(tbuf: *u8, tn: i64, arg: *u8) -> i64 {
194 let al: i64 = g_len(arg)
195 var i: i64 = 0
196 while i < tn {
197 if g_is_bol(tbuf, i) == 1 {
198 if g_match(tbuf, tn, i, "task|" as *u8, 5) == 1 {
199 // skip to after the 2nd '|' (the value start)
200 var p: i64 = i
201 var pipes: i64 = 0
202 var go: i64 = 1
203 while go == 1 {
204 if p >= tn { go = 0 } else {
205 if tbuf[p] == (124 as u8) { pipes = pipes + 1; p = p + 1; if pipes == 2 { go = 0 } } else { p = p + 1 }
206 }
207 }
208 if pipes == 2 {
209 if g_match(tbuf, tn, p, arg, al) == 1 {
210 let after: i64 = p + al
211 if after >= tn { return 1 }
212 if tbuf[after] == (10 as u8) { return 1 }
213 }
214 }
215 }
216 }
217 i = i + 1
218 }
219 return 0
220}
221
222func main() -> i64 {
223 let task_good: *u8 = "knowledge/specs/ale_plan_examples/task_good.txt" as *u8
224 let task_bad: *u8 = "knowledge/specs/ale_plan_examples/task_missing_artifact.txt" as *u8
225 let p1: *u8 = "/tmp/_aleplan_p1" as *u8
226 let p2: *u8 = "/tmp/_aleplan_p2" as *u8
227 let pbad: *u8 = "/tmp/_aleplan_bad_neverwritten" as *u8
228 g_p("=== ALE-plan gate (ALE-R2a: sovereign agent-core PLAN phase) ===\n" as *u8)
229
230 // run the planner over the good task into p1, and a 2nd time into p2 (determinism)
231 let rc1: i64 = g_run_plan(task_good, p1)
232 let rc2: i64 = g_run_plan(task_good, p2)
233
234 // load the emitted plan and the task spec
235 let plan: *u8 = sys_mmap(262144)
236 let pn: i64 = g_read(p1, plan, 262144)
237 let tbuf: *u8 = sys_mmap(262144)
238 let tn: i64 = g_read(task_good, tbuf, 262144)
239
240 // (1) INGEST: child exited 0 and emitted >=3 "step|"-prefixed lines
241 let nsteps: i64 = g_count_prefix(plan, pn, "step|" as *u8)
242 var c1: i64 = 0
243 if rc1 == 0 { if pn > 0 { if nsteps >= 3 { c1 = 1 } } }
244
245 // (2) ORDERED: step numbers 1,2,3 present AND no step|4| (exactly the 3-step sequence,
246 // contiguous from 1 with no gaps -- a real ordered sequence, not a bag)
247 var c2: i64 = 0
248 if g_step_num_present(plan, pn, 1) == 1 {
249 if g_step_num_present(plan, pn, 2) == 1 {
250 if g_step_num_present(plan, pn, 3) == 1 {
251 if g_step_num_present(plan, pn, 4) == 0 { if nsteps == 3 { c2 = 1 } }
252 }
253 }
254 }
255
256 // (3) GROUNDED: each step's <arg> equals a task field VALUE present in the spec
257 let arg1: *u8 = sys_mmap(8192)
258 let arg2: *u8 = sys_mmap(8192)
259 let arg3: *u8 = sys_mmap(8192)
260 let la1: i64 = g_step_arg(plan, pn, 1, arg1, 8192)
261 let la2: i64 = g_step_arg(plan, pn, 2, arg2, 8192)
262 let la3: i64 = g_step_arg(plan, pn, 3, arg3, 8192)
263 var c3: i64 = 0
264 if la1 > 0 { if la2 > 0 { if la3 > 0 {
265 if g_arg_in_task(tbuf, tn, arg1) == 1 {
266 if g_arg_in_task(tbuf, tn, arg2) == 1 {
267 if g_arg_in_task(tbuf, tn, arg3) == 1 { c3 = 1 }
268 }
269 }
270 } } }
271
272 // (4) ARTIFACT-TERMINAL: the FINAL step (step 3, the highest) is write_artifact and its
273 // <arg> equals the task's declared artifact_path value. Confirm via: step|3|write_artifact|
274 // line present AND step-3 arg appears as the task|artifact_path| value-tail.
275 var has_wa: i64 = 0
276 var i: i64 = 0
277 while i < pn {
278 if g_is_bol(plan, i) == 1 {
279 if g_match(plan, pn, i, "step|3|write_artifact|" as *u8, 22) == 1 { has_wa = 1 }
280 }
281 i = i + 1
282 }
283 // the artifact_path value must equal step-3 arg AND be the task's declared artifact_path
284 // confirm task|artifact_path|<arg3> line exists (arg3 is the declared deliverable)
285 let pfx: *u8 = sys_mmap(64)
286 pfx[0] = 116 as u8; pfx[1] = 97 as u8; pfx[2] = 115 as u8; pfx[3] = 107 as u8; pfx[4] = 124 as u8 // task|
287 // append "artifact_path|"
288 let apw: *u8 = "artifact_path|" as *u8
289 var aw: i64 = 5
290 var z: i64 = 0
291 while apw[z] != (0 as u8) { pfx[aw] = apw[z]; aw = aw + 1; z = z + 1 }
292 pfx[aw] = 0 as u8
293 // find that prefix line and compare its value-tail to arg3
294 var matchart: i64 = 0
295 var q: i64 = 0
296 while q < tn {
297 if g_is_bol(tbuf, q) == 1 {
298 if g_match(tbuf, tn, q, pfx, aw) == 1 {
299 if g_match(tbuf, tn, q + aw, arg3, la3) == 1 {
300 let after: i64 = q + aw + la3
301 if after >= tn { matchart = 1 } else { if tbuf[after] == (10 as u8) { matchart = 1 } }
302 }
303 }
304 }
305 q = q + 1
306 }
307 var c4: i64 = 0
308 if has_wa == 1 { if matchart == 1 { c4 = 1 } }
309
310 // (5) DETERMINISTIC: p1 and p2 byte-identical
311 var c5: i64 = 0
312 if rc1 == 0 { if rc2 == 0 { if g_files_eq(p1, p2) == 1 { c5 = 1 } } }
313
314 // (6) TAMPER REJECTED: missing-artifact spec -> child non-zero AND no plan written.
315 // pbad is a scratch path the gate NEVER writes the good plan to, so an empty/absent
316 // file here means the organ refused to emit. (organ exits 1 BEFORE opening the file.)
317 let rcbad: i64 = g_run_plan(task_bad, pbad)
318 let badbuf: *u8 = sys_mmap(4096)
319 let badn: i64 = g_read(pbad, badbuf, 4096)
320 var tamper_rejected: i64 = 0
321 if rcbad != 0 { if badn == 0 { tamper_rejected = 1 } }
322
323 g_p(" rc_good=" as *u8); g_fn(1, rc1)
324 g_p(" nsteps=" as *u8); g_fn(1, nsteps)
325 g_p(" det(eq=" as *u8); g_fn(1, g_files_eq(p1, p2)); g_p(")" as *u8)
326 g_p(" rc_bad=" as *u8); g_fn(1, rcbad)
327 g_p(" bad_plan_bytes=" as *u8); g_fn(1, badn); g_p("\n" as *u8)
328 g_p(" c1_ingest=" as *u8); g_fn(1, c1)
329 g_p(" c2_ordered=" as *u8); g_fn(1, c2)
330 g_p(" c3_grounded=" as *u8); g_fn(1, c3)
331 g_p(" c4_artifact_terminal=" as *u8); g_fn(1, c4)
332 g_p(" c5_deterministic=" as *u8); g_fn(1, c5)
333 g_p(" tamper_rejected=" as *u8); g_fn(1, tamper_rejected)
334 g_p("\n" as *u8)
335
336 var allok: i64 = 1
337 if c1 == 0 { allok = 0 }
338 if c2 == 0 { allok = 0 }
339 if c3 == 0 { allok = 0 }
340 if c4 == 0 { allok = 0 }
341 if c5 == 0 { allok = 0 }
342 if tamper_rejected == 0 { allok = 0 }
343
344 let lfd: i64 = sys_openat_append("knowledge/status/ale_plan.log" as *u8, 0x1a4)
345 if allok == 1 {
346 g_p("ALEPLANGATE verdict=GREEN (ingest ordered grounded artifact-terminal deterministic; missing-field tamper REJECTED)\n" as *u8)
347 if lfd >= 0 {
348 g_fp(lfd, "ALEPLANGATE verdict=GREEN ingest=1 ordered=1 grounded=1 artifact_terminal=1 deterministic=1 tamper_rejected=1 rung=ALE-R2a epoch=" as *u8)
349 g_fn(lfd, sys_now_realtime_sec())
350 g_fp(lfd, "\n" as *u8)
351 sys_close(lfd)
352 }
353 sys_exit(0)
354 return 0
355 }
356 g_p("ALEPLANGATE verdict=RED (a check did not fire)\n" as *u8)
357 if lfd >= 0 {
358 g_fp(lfd, "ALEPLANGATE verdict=RED c1=" as *u8); g_fn(lfd, c1)
359 g_fp(lfd, " c2=" as *u8); g_fn(lfd, c2)
360 g_fp(lfd, " c3=" as *u8); g_fn(lfd, c3)
361 g_fp(lfd, " c4=" as *u8); g_fn(lfd, c4)
362 g_fp(lfd, " c5=" as *u8); g_fn(lfd, c5)
363 g_fp(lfd, " tamper_rejected=" as *u8); g_fn(lfd, tamper_rejected)
364 g_fp(lfd, "\n" as *u8)
365 sys_close(lfd)
366 }
367 sys_exit(1)
368 return 1
369}