code wiki / _hdl_build / nx_ale_plan.nx
nx_ale_plan.nx source
↩ module page · 155 lines · 6523 B
1// nx_ale_plan.nx -- sovereign ALE agent-core PLAN-phase organ (rung ALE-R2a).
2// THE decompose step the whole ALE-R2 agent-core routes through: the smallest load-bearing
3// slice (deterministic, grounded, artifact-terminal decomposition). PURE function of one file:
4// argv[1] = TASK spec path (ALE-format "contract|field|value" lines; ale_format.spec grammar)
5// argv[2] = PLAN OUT path (the ordered plan is written here as "step|<n>|<verb>|<arg>" lines)
6// CONTRACT (data-driven; no magic numbers -- the step shape comes from ale_plan.spec):
7// REQUIRED task fields = instruction, input_stage, artifact_path. If ANY is absent the
8// planner REFUSES: exit 1, emits NOTHING (grounding check bites = rule-4 made mechanical).
9// Otherwise it emits exactly this ordered, grounded, artifact-terminal plan:
10// step|1|stage_input|<task.input_stage value>
11// step|2|run_organ|<task.instruction value>
12// step|3|write_artifact|<task.artifact_path value>
13// Every <arg> is COPIED VERBATIM from a task field VALUE actually present in the spec
14// (GROUNDED: the planner never synthesizes a value the spec did not declare). Step numbers
15// start at 1 and increase by 1 with no gaps (ORDERED). The FINAL step is write_artifact
16// whose <arg> is the declared artifact_path (ARTIFACT-TERMINAL). No clock, no rand -> two
17// runs on the same spec emit a BYTE-IDENTICAL plan (DETERMINISTIC).
18// Landmines respected: nested ifs (no &&/||), flat exprs, <=6 args/func, no empty-string
19// literal, strings via Write, openat_wr has no O_TRUNC (gate uses a fresh scratch path).
20// Helpers reuse the ALE-R0a line-grammar (av_*) and the ALE-R1a decimal writer (ap_wn).
21// license_tier: ORIGINAL
22import "nx_syscalls.nx"
23import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
24const K_MAGIC_262144: i64 = 262144
25const K_MAGIC_8192: i64 = 8192
26
27// read whole file at path into buf (cap), return byte count (0 on open-fail)
28func ap_read(path: *u8, buf: *u8, cap: i64) -> i64 {
29 let fd: i64 = sys_openat_rd(path)
30 if fd < 0 { return 0 }
31 var n: i64 = 0
32 var go: i64 = 1
33 while go == 1 {
34 let r: i64 = sys_read(fd, (buf as i64 + n) as *u8, cap - 1 - n)
35 if r <= 0 { go = 0 } else { n = n + r }
36 if n >= cap - 1 { go = 0 }
37 }
38 sys_close(fd)
39 return n
40}
41
42// length of a C string
43func ap_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
44
45// does buf[pos..] match pat (len pl)? 1/0
46func ap_match(buf: *u8, n: i64, pos: i64, pat: *u8, pl: i64) -> i64 {
47 if pos + pl > n { return 0 }
48 var k: i64 = 0
49 while k < pl {
50 if buf[pos + k] != pat[k] { return 0 }
51 k = k + 1
52 }
53 return 1
54}
55
56// is pos a line start? (pos==0 or previous byte is newline)
57func ap_is_bol(buf: *u8, pos: i64) -> i64 {
58 if pos == 0 { return 1 }
59 if buf[pos - 1] == (10 as u8) { return 1 }
60 return 0
61}
62
63// find a line beginning with prefix; return its start index, or -1
64func ap_find_line(buf: *u8, n: i64, prefix: *u8) -> i64 {
65 let pl: i64 = ap_len(prefix)
66 var i: i64 = 0
67 while i < n {
68 if ap_is_bol(buf, i) == 1 {
69 if ap_match(buf, n, i, prefix, pl) == 1 { return i }
70 }
71 i = i + 1
72 }
73 return 0 - 1
74}
75
76// Extract the VALUE of the field whose line starts with prefix: copy bytes from after the
77// prefix up to (not including) the end-of-line newline into out, NUL-terminate, return the
78// value length. Returns -1 if the field line is absent (the GROUNDING check: a value the
79// spec did not declare can never be copied into a step arg). cap bounds the copy.
80func ap_field_val(buf: *u8, n: i64, prefix: *u8, out: *u8, cap: i64) -> i64 {
81 let start: i64 = ap_find_line(buf, n, prefix)
82 if start < 0 { return 0 - 1 }
83 let pl: i64 = ap_len(prefix)
84 var p: i64 = start + pl
85 var k: i64 = 0
86 var go: i64 = 1
87 while go == 1 {
88 if p >= n { go = 0 } else {
89 if buf[p] == (10 as u8) { go = 0 } else {
90 if k < cap - 1 { out[k] = buf[p]; k = k + 1 }
91 p = p + 1
92 }
93 }
94 }
95 out[k] = 0 as u8
96 return k
97}
98
99// write decimal v (>=0) to fd (no newline; the caller adds field separators)
100// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
101// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
102// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
103// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
104func ap_wn(fd: i64, v: i64) -> i64 { nxi_fd(fd, v); return 0 }
105
106// emit one plan step: "step|<n>|<verb>|<arg>\n" to fd. n is the step number, verb a fixed
107// vocabulary token, arg the grounded value copied from a task field.
108func ap_step(fd: i64, n: i64, verb: *u8, arg: *u8) -> i64 {
109 sys_write(fd, "step|" as *u8, 5)
110 ap_wn(fd, n)
111 sys_write(fd, "|" as *u8, 1)
112 let vl: i64 = ap_len(verb)
113 sys_write(fd, verb, vl)
114 sys_write(fd, "|" as *u8, 1)
115 let al: i64 = ap_len(arg)
116 sys_write(fd, arg, al)
117 sys_write(fd, "\n" as *u8, 1)
118 return 0
119}
120
121func main(argc: i64, argv: *i64) -> i64 {
122 if argc < 3 { sys_exit(2); return 2 }
123 let taskp: *u8 = argv[1] as *u8
124 let outp: *u8 = argv[2] as *u8
125
126 let buf: *u8 = sys_mmap(K_MAGIC_262144)
127 let n: i64 = ap_read(taskp, buf, K_MAGIC_262144)
128 if n <= 0 { sys_exit(3); return 3 }
129
130 // Extract the THREE required task field VALUES. -1 => field absent => REFUSE.
131 let v_input: *u8 = sys_mmap(K_MAGIC_8192)
132 let v_instr: *u8 = sys_mmap(K_MAGIC_8192)
133 let v_art: *u8 = sys_mmap(K_MAGIC_8192)
134 let li: i64 = ap_field_val(buf, n, "task|input_stage|" as *u8, v_input, K_MAGIC_8192)
135 let ln: i64 = ap_field_val(buf, n, "task|instruction|" as *u8, v_instr, K_MAGIC_8192)
136 let la: i64 = ap_field_val(buf, n, "task|artifact_path|" as *u8, v_art, K_MAGIC_8192)
137
138 // GROUNDING / TAMPER-REJECT: a required field missing -> exit 1, emit NOTHING.
139 var bad: i64 = 0
140 if li < 0 { bad = 1 }
141 if ln < 0 { bad = 1 }
142 if la < 0 { bad = 1 }
143 if bad == 1 { sys_exit(1); return 1 }
144
145 // Open the plan OUT path and emit the ordered, grounded, artifact-terminal plan.
146 let ofd: i64 = sys_openat_wr(outp, 0x1a4)
147 if ofd < 0 { sys_exit(4); return 4 }
148 ap_step(ofd, 1, "stage_input" as *u8, v_input)
149 ap_step(ofd, 2, "run_organ" as *u8, v_instr)
150 ap_step(ofd, 3, "write_artifact" as *u8, v_art)
151 sys_close(ofd)
152
153 sys_exit(0)
154 return 0
155}