code wiki / _hdl_build / nx_ale_exec.nx

nx_ale_exec.nx source

↩ module page · 483 lines · 21480 B

1// nx_ale_exec.nx -- sovereign ALE agent-core EXECUTE/dispatch organ (rung ALE-R2b). 2// THE execute step the whole ALE-R2 agent-core routes through: it CONSUMES the ALE-R2a ordered 3// plan and the task spec and DISPATCHES each step IN ORDER over a sandbox working dir to produce a 4// REAL artifact file -- never re-planning, never opening the reference path. PURE function of: 5// argv[1] = PLAN path (ALE-R2a plan: "step|<n>|<verb>|<arg>" lines, ordered from 1) 6// argv[2] = TASK path (ALE-format task spec: "contract|field|value" lines) 7// argv[3] = SANDBOX dir (the working dir; staged files + the artifact land here) 8// CONTRACT (data-driven; the step shape comes from ale_exec.spec / ale_plan.spec): 9// REQUIRED task fields = materials_dir, input_stage, artifact_path. If ANY is absent the 10// executor REFUSES: exit non-zero, produces NO artifact. 11// The plan is walked TOP-TO-BOTHOM and consumed STRICTLY in order via a 3-state machine: 12// step 1 must be stage_input -> copies materials_dir/input_stage VERBATIM into sandbox/input_stage 13// step 2 must be run_organ -> applies the instruction's named DETERMINISTIC transform over the 14// staged bytes (extract_kv_to_units: each "kv|k|v" -> "unit|k|v") 15// step 3 must be write_artifact -> writes the transform output VERBATIM to sandbox/artifact_path 16// Any out-of-order verb, an unknown transform token, or a plan MISSING write_artifact => REFUSE 17// (exit non-zero, NO artifact). The executor reads ONLY argv[1..3] + materials_dir/input_stage; 18// it NEVER opens the reference path -> the artifact is independent of reference presence (no 19// leakage, enforced end-to-end). No clock, no rand -> two runs on the same (plan,task,fresh 20// sandbox) yield a BYTE-IDENTICAL artifact (DETERMINISTIC). 21// Landmines respected: nested ifs (no &&/||), flat exprs, <=6 args/func, no empty-string literal, 22// strings via Write, openat_wr fresh path. Helpers mirror the ALE-R2a/R1a line-grammar (ae_*). 23// license_tier: ORIGINAL 24import "nx_syscalls.nx" 25const K_MAGIC_262144: i64 = 262144 26const K_MAGIC_8192: i64 = 8192 27const K_MAGIC_16384: i64 = 16384 28 29// read whole file at path into buf (cap), return byte count (0 on open-fail) 30func ae_read(path: *u8, buf: *u8, cap: i64) -> i64 { 31 let fd: i64 = sys_openat_rd(path) 32 if fd < 0 { return 0 } 33 var n: i64 = 0 34 var go: i64 = 1 35 while go == 1 { 36 let r: i64 = sys_read(fd, (buf as i64 + n) as *u8, cap - 1 - n) 37 if r <= 0 { go = 0 } else { n = n + r } 38 if n >= cap - 1 { go = 0 } 39 } 40 sys_close(fd) 41 return n 42} 43 44// length of a C string 45func ae_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 46 47// does buf[pos..] match pat (len pl)? 1/0 48func ae_match(buf: *u8, n: i64, pos: i64, pat: *u8, pl: i64) -> i64 { 49 if pos + pl > n { return 0 } 50 var k: i64 = 0 51 while k < pl { 52 if buf[pos + k] != pat[k] { return 0 } 53 k = k + 1 54 } 55 return 1 56} 57 58// is pos a line start? (pos==0 or previous byte is newline) 59func ae_is_bol(buf: *u8, pos: i64) -> i64 { 60 if pos == 0 { return 1 } 61 if buf[pos - 1] == (10 as u8) { return 1 } 62 return 0 63} 64 65// find a line beginning with prefix; return its start index, or -1 66func ae_find_line(buf: *u8, n: i64, prefix: *u8) -> i64 { 67 let pl: i64 = ae_len(prefix) 68 var i: i64 = 0 69 while i < n { 70 if ae_is_bol(buf, i) == 1 { 71 if ae_match(buf, n, i, prefix, pl) == 1 { return i } 72 } 73 i = i + 1 74 } 75 return 0 - 1 76} 77 78// Extract the VALUE of the field whose line starts with prefix: copy bytes from after the prefix 79// up to (not including) the end-of-line newline into out, NUL-terminate, return value length. 80// Returns -1 if the field line is absent (the GROUNDING check). cap bounds the copy. 81func ae_field_val(buf: *u8, n: i64, prefix: *u8, out: *u8, cap: i64) -> i64 { 82 let start: i64 = ae_find_line(buf, n, prefix) 83 if start < 0 { return 0 - 1 } 84 let pl: i64 = ae_len(prefix) 85 var p: i64 = start + pl 86 var k: i64 = 0 87 var go: i64 = 1 88 while go == 1 { 89 if p >= n { go = 0 } else { 90 if buf[p] == (10 as u8) { go = 0 } else { 91 if k < cap - 1 { out[k] = buf[p]; k = k + 1 } 92 p = p + 1 93 } 94 } 95 } 96 out[k] = 0 as u8 97 return k 98} 99 100// join a + "/" + b into out (NUL-terminated). a,b are NUL-terminated. returns length. 101func ae_join(a: *u8, b: *u8, out: *u8) -> i64 { 102 var k: i64 = 0 103 var i: i64 = 0 104 while a[i] != (0 as u8) { out[k] = a[i]; k = k + 1; i = i + 1 } 105 out[k] = 47 as u8; k = k + 1 // '/' 106 var j: i64 = 0 107 while b[j] != (0 as u8) { out[k] = b[j]; k = k + 1; j = j + 1 } 108 out[k] = 0 as u8 109 return k 110} 111 112// write n bytes from buf to a fresh file at path (mode 0644). 1 on success, 0 on open-fail. 113func ae_write_file(path: *u8, buf: *u8, n: i64) -> i64 { 114 let fd: i64 = sys_openat_wr(path, 0x1a4) 115 if fd < 0 { return 0 } 116 if n > 0 { sys_write(fd, buf, n) } 117 sys_close(fd) 118 return 1 119} 120 121// the run_organ TRANSFORM extract_kv_to_units: for each staged line "kv|<rest>", emit 122// "unit|<rest>\n" into out (in input order). Non-"kv|" lines (comments/blanks) are skipped. 123// Returns the produced byte count. PURE function of the staged bytes (no clock/rand). 124func ae_transform_kv(inb: *u8, n: i64, out: *u8) -> i64 { 125 var o: i64 = 0 126 var i: i64 = 0 127 while i < n { 128 if ae_is_bol(inb, i) == 1 { 129 if ae_match(inb, n, i, "kv|" as *u8, 3) == 1 { 130 // emit "unit|" then the bytes after "kv|" up to and including the newline 131 out[o] = 117 as u8; o = o + 1 // u 132 out[o] = 110 as u8; o = o + 1 // n 133 out[o] = 105 as u8; o = o + 1 // i 134 out[o] = 116 as u8; o = o + 1 // t 135 out[o] = 124 as u8; o = o + 1 // | 136 var p: i64 = i + 3 137 var go: i64 = 1 138 while go == 1 { 139 if p >= n { out[o] = 10 as u8; o = o + 1; go = 0 } else { 140 if inb[p] == (10 as u8) { out[o] = 10 as u8; o = o + 1; p = p + 1; go = 0 } else { 141 out[o] = inb[p]; o = o + 1; p = p + 1 142 } 143 } 144 } 145 } 146 } 147 i = i + 1 148 } 149 return o 150} 151 152// the run_organ TRANSFORM copy_verbatim (ALE-R3a): the IDENTITY transform -- emit the staged 153// bytes UNCHANGED as the deliverable (artifact == staged input, byte-for-byte). PURE function of 154// the staged bytes: no clock, no rand, no synthesis. Returns the produced byte count (== n). 155func ae_transform_copy(inb: *u8, n: i64, out: *u8) -> i64 { 156 var i: i64 = 0 157 while i < n { out[i] = inb[i]; i = i + 1 } 158 return n 159} 160 161// the run_organ TRANSFORM count_lines (ALE-R4 seed-task DATA/CLI domain skill): count the staged 162// input's newline-terminated lines and emit a SINGLE grading unit "unit|line_count|<N>\n". PURE 163// function of the staged bytes (no clock/rand): N = number of '\n' bytes. A DISTINCT skill 164// (aggregation/counting) beyond kv-extraction/identity-copy -- grows the agent's vocabulary so the 165// harness can measure a counting task end-to-end. Returns the produced byte count. 166func ae_transform_count(inb: *u8, n: i64, out: *u8) -> i64 { 167 var lines: i64 = 0 168 var i: i64 = 0 169 while i < n { if inb[i] == (10 as u8) { lines = lines + 1 } i = i + 1 } 170 var o: i64 = 0 171 let pre: *u8 = "unit|line_count|" as *u8 172 var j: i64 = 0 173 while pre[j] != (0 as u8) { out[o] = pre[j]; o = o + 1; j = j + 1 } 174 var m: i64 = lines 175 let t: *u8 = sys_mmap(28) 176 var k: i64 = 0 177 if m == 0 { t[0] = 48 as u8; k = 1 } 178 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 179 var p: i64 = 0 180 while p < k { out[o] = t[k - 1 - p]; o = o + 1; p = p + 1 } 181 out[o] = 10 as u8; o = o + 1 182 return o 183} 184 185// find a line in buf (len n) beginning with pat (len pl) at a BOL; return its index, or -1. 186func ae_plan_find(buf: *u8, n: i64, pat: *u8, pl: i64) -> i64 { 187 var i: i64 = 0 188 while i < n { 189 if ae_is_bol(buf, i) == 1 { 190 if ae_match(buf, n, i, pat, pl) == 1 { return i } 191 } 192 i = i + 1 193 } 194 return 0 - 1 195} 196 197// read the verb of the plan step whose number is num into vbuf (cap); also copy its <arg> into 198// abuf (cap). A plan line is "step|<num>|<verb>|<arg>". Returns 1 if the step line was found, else 0. 199func ae_plan_step(buf: *u8, n: i64, num: i64, vbuf: *u8, abuf: *u8, cap: i64) -> i64 { 200 // build prefix "step|<num>|" 201 let pb: *u8 = sys_mmap(64) 202 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 203 var m: i64 = num 204 let t: *u8 = sys_mmap(28) 205 var k: i64 = 0 206 if m == 0 { t[0] = 48; k = 1 } 207 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 208 var w: i64 = 5 209 var j: i64 = 0 210 while j < k { pb[w] = t[k - 1 - j]; w = w + 1; j = j + 1 } 211 pb[w] = 124 as u8; w = w + 1; pb[w] = 0 as u8 212 let pl: i64 = w 213 let start: i64 = ae_plan_find(buf, n, pb, pl) 214 if start < 0 { return 0 } 215 // from start, skip the prefix (pl bytes) -> verb starts; copy verb to next '|' 216 var q: i64 = start + pl 217 var vk: i64 = 0 218 var g1: i64 = 1 219 while g1 == 1 { 220 if q >= n { g1 = 0 } else { 221 if buf[q] == (124 as u8) { g1 = 0 } else { 222 if vk < cap - 1 { vbuf[vk] = buf[q]; vk = vk + 1 } 223 q = q + 1 224 } 225 } 226 } 227 vbuf[vk] = 0 as u8 228 // after the verb's '|' -> arg starts; copy arg to newline/EOF 229 if q < n { q = q + 1 } 230 var ak: i64 = 0 231 var g2: i64 = 1 232 while g2 == 1 { 233 if q >= n { g2 = 0 } else { 234 if buf[q] == (10 as u8) { g2 = 0 } else { 235 if ak < cap - 1 { abuf[ak] = buf[q]; ak = ak + 1 } 236 q = q + 1 237 } 238 } 239 } 240 abuf[ak] = 0 as u8 241 return 1 242} 243 244// equal NUL-terminated strings? 1/0 245func ae_streq(a: *u8, b: *u8) -> i64 { 246 var i: i64 = 0 247 while a[i] != (0 as u8) { 248 if a[i] != b[i] { return 0 } 249 i = i + 1 250 } 251 if b[i] != (0 as u8) { return 0 } 252 return 1 253} 254 255// does s start with prefix p (both NUL-terminated)? 1/0 (transform-token dispatch) 256func ae_starts(s: *u8, p: *u8) -> i64 { 257 var i: i64 = 0 258 while p[i] != (0 as u8) { 259 if s[i] != p[i] { return 0 } 260 i = i + 1 261 } 262 return 1 263} 264 265// the run_organ TRANSFORM sum_values (ALE-R5 RSI-loop: the capability BUILT to close the 266// data/sum-values-001 GAP the flywheel detected): sum the staged input's integer lines and emit a 267// SINGLE grading unit "unit|sum|<TOTAL>\n". PURE function of the staged bytes (no clock/rand): each 268// maximal digit-run terminated by newline/EOF is one integer; TOTAL = their sum. A distinct 269// arithmetic-aggregation skill. Returns the produced byte count. 270func ae_transform_sum(inb: *u8, n: i64, out: *u8) -> i64 { 271 var total: i64 = 0 272 var cur: i64 = 0 273 var indig: i64 = 0 274 var i: i64 = 0 275 while i < n { 276 let c: i64 = inb[i] as i64 277 if c >= 48 { if c <= 57 { cur = cur * 10 + (c - 48); indig = 1 } } 278 if c == 10 { if indig == 1 { total = total + cur } cur = 0; indig = 0 } 279 i = i + 1 280 } 281 if indig == 1 { total = total + cur } 282 var o: i64 = 0 283 let pre: *u8 = "unit|sum|" as *u8 284 var j: i64 = 0 285 while pre[j] != (0 as u8) { out[o] = pre[j]; o = o + 1; j = j + 1 } 286 var m: i64 = total 287 let t: *u8 = sys_mmap(28) 288 var k: i64 = 0 289 if m == 0 { t[0] = 48 as u8; k = 1 } 290 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 291 var p: i64 = 0 292 while p < k { out[o] = t[k - 1 - p]; o = o + 1; p = p + 1 } 293 out[o] = 10 as u8; o = o + 1 294 return o 295} 296 297// parse helpers for the PARAMETERIZED reducer. 298func ae_rd_skipword(s: *u8, i: i64) -> i64 { var p: i64 = i; var g: i64 = 1; while g == 1 { if s[p] == (0 as u8) { g = 0 } else { if s[p] == (32 as u8) { g = 0 } else { p = p + 1 } } } return p } 299func ae_rd_skipsp(s: *u8, i: i64) -> i64 { var p: i64 = i; while s[p] == (32 as u8) { p = p + 1 } return p } 300func ae_rd_atoi(s: *u8, i: i64) -> i64 { var p: i64 = i; var neg: i64 = 0; if s[p] == (45 as u8) { neg = 1; p = p + 1 } var v: i64 = 0; var g: i64 = 1; while g == 1 { if s[p] >= (48 as u8) { if s[p] <= (57 as u8) { v = v * 10 + ((s[p] as i64) - 48); p = p + 1 } else { g = 0 } } else { g = 0 } } if neg == 1 { return 0 - v } return v } 301 302// the run_organ TRANSFORM reduce_op (PARAMETERIZED -- the evolutionary member's GENE TARGET): the 303// instruction "reduce_op <op> <init>" carries the genes (op in {add,mul,max,min}, init an integer). 304// acc=init; for each staged integer line v: add->acc+v mul->acc*v max->max min->min. Emits 305// "unit|reduced|<acc>". A GENERAL reducer: sum is (add,0), PRODUCT is (mul,1) -- genes nx_evolve 306// DISCOVERS (tier-1 search can't supply parameters; tier-2 evolution searches them). license_tier: ORIGINAL 307func ae_transform_reduce(inb: *u8, n: i64, out: *u8, args: *u8) -> i64 { 308 var p: i64 = ae_rd_skipword(args, 0) 309 p = ae_rd_skipsp(args, p) 310 let op_at: i64 = p 311 p = ae_rd_skipword(args, p) 312 var op: i64 = 0 313 if args[op_at] == (109 as u8) { 314 if args[op_at+1] == (117 as u8) { op = 1 } 315 if args[op_at+1] == (97 as u8) { op = 2 } 316 if args[op_at+1] == (105 as u8) { op = 3 } 317 } 318 p = ae_rd_skipsp(args, p) 319 let init: i64 = ae_rd_atoi(args, p) 320 var acc: i64 = init 321 var i: i64 = 0 322 var cur: i64 = 0 323 var indig: i64 = 0 324 while i < n { 325 let c: i64 = inb[i] as i64 326 if c >= 48 { if c <= 57 { cur = cur * 10 + (c - 48); indig = 1 } } 327 if c == 10 { if indig == 1 { if op == 0 { acc = acc + cur } if op == 1 { acc = acc * cur } if op == 2 { if cur > acc { acc = cur } } if op == 3 { if cur < acc { acc = cur } } } cur = 0; indig = 0 } 328 i = i + 1 329 } 330 if indig == 1 { if op == 0 { acc = acc + cur } if op == 1 { acc = acc * cur } if op == 2 { if cur > acc { acc = cur } } if op == 3 { if cur < acc { acc = cur } } } 331 var o: i64 = 0 332 let pre: *u8 = "unit|reduced|" as *u8 333 var j: i64 = 0 334 while pre[j] != (0 as u8) { out[o] = pre[j]; o = o + 1; j = j + 1 } 335 var m: i64 = acc 336 if m < 0 { out[o] = 45 as u8; o = o + 1; m = 0 - m } 337 let t: *u8 = sys_mmap(28) 338 var k: i64 = 0 339 if m == 0 { t[0] = 48 as u8; k = 1 } 340 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 341 var q: i64 = 0 342 while q < k { out[o] = t[k - 1 - q]; o = o + 1; q = q + 1 } 343 out[o] = 10 as u8; o = o + 1 344 return o 345} 346 347// ---- ALE-R3a: the run_organ TRANSFORM VOCABULARY as a DATA TABLE ---- 348// The dispatch is data-driven: a parallel-array table of (token, transform-id) rows. Adding a 349// transform means adding ONE token-row here + one ae_transform_* fn -- the dispatch loop never 350// grows a per-transform if-chain. transform-id values are abstract handles (1,2,...); the run_organ 351// branch invokes the selected fn by id. Mirrors ale_exec.spec's `transform|<token>|...` rows. 352// ae_vocab_build fills caller arrays toks[] (token *u8) + ids[] (transform-id i64) and returns the 353// row count. cap bounds the row count. 354func ae_vocab_build(toks: *i64, ids: *i64, cap: i64) -> i64 { 355 var c: i64 = 0 356 if c < cap { toks[c] = "extract_kv_to_units" as *u8 as i64; ids[c] = 1; c = c + 1 } 357 if c < cap { toks[c] = "copy_verbatim" as *u8 as i64; ids[c] = 2; c = c + 1 } 358 if c < cap { toks[c] = "count_lines" as *u8 as i64; ids[c] = 3; c = c + 1 } 359 if c < cap { toks[c] = "sum_values" as *u8 as i64; ids[c] = 4; c = c + 1 } 360 if c < cap { toks[c] = "reduce_op" as *u8 as i64; ids[c] = 5; c = c + 1 } 361 return c 362} 363 364// data-driven dispatch: return the transform-id whose token is a PREFIX of instruction s, or 0 if 365// no vocabulary token matches (unknown token -> the caller REFUSES). Walks the table in order. 366func ae_vocab_lookup(s: *u8, toks: *i64, ids: *i64, cnt: i64) -> i64 { 367 var i: i64 = 0 368 while i < cnt { 369 let tk: *u8 = toks[i] as *u8 370 if ae_starts(s, tk) == 1 { return ids[i] } 371 i = i + 1 372 } 373 return 0 374} 375 376func main(argc: i64, argv: *i64) -> i64 { 377 if argc < 4 { sys_exit(2); return 2 } 378 let planp: *u8 = argv[1] as *u8 379 let taskp: *u8 = argv[2] as *u8 380 let sandbox: *u8 = argv[3] as *u8 381 382 let pbuf: *u8 = sys_mmap(K_MAGIC_262144) 383 let tbuf: *u8 = sys_mmap(K_MAGIC_262144) 384 let pn: i64 = ae_read(planp, pbuf, K_MAGIC_262144) 385 let tn: i64 = ae_read(taskp, tbuf, K_MAGIC_262144) 386 if pn <= 0 { sys_exit(3); return 3 } 387 if tn <= 0 { sys_exit(3); return 3 } 388 389 // REQUIRED task fields; -1 => absent => REFUSE. 390 let v_mat: *u8 = sys_mmap(K_MAGIC_8192) 391 let v_in: *u8 = sys_mmap(K_MAGIC_8192) 392 let v_art: *u8 = sys_mmap(K_MAGIC_8192) 393 let lm: i64 = ae_field_val(tbuf, tn, "task|materials_dir|" as *u8, v_mat, K_MAGIC_8192) 394 let lin: i64 = ae_field_val(tbuf, tn, "task|input_stage|" as *u8, v_in, K_MAGIC_8192) 395 let lar: i64 = ae_field_val(tbuf, tn, "task|artifact_path|" as *u8, v_art, K_MAGIC_8192) 396 var bad: i64 = 0 397 if lm < 0 { bad = 1 } 398 if lin < 0 { bad = 1 } 399 if lar < 0 { bad = 1 } 400 if bad == 1 { sys_exit(1); return 1 } 401 402 // The plan MUST contain a write_artifact step or we refuse (no terminal deliverable). 403 let has_wa: i64 = ae_plan_find(pbuf, pn, "step|3|write_artifact|" as *u8, 22) 404 if has_wa < 0 { sys_exit(4); return 4 } 405 406 // 3-state machine over plan steps 1,2,3 -- consumed STRICTLY in order. 407 let vb: *u8 = sys_mmap(K_MAGIC_8192) 408 let ab: *u8 = sys_mmap(K_MAGIC_8192) 409 let content: *u8 = sys_mmap(K_MAGIC_262144) 410 var contn: i64 = 0 411 var staged: i64 = 0 412 var transformed: i64 = 0 413 var written: i64 = 0 414 var step: i64 = 1 415 var run: i64 = 1 416 417 // ALE-R3a: build the run_organ transform-vocabulary table ONCE (token -> transform-id). The 418 // run_organ branch dispatches DATA-DRIVEN off this table; no per-transform if-chain. 419 let vtoks: *i64 = sys_mmap(256) as *i64 420 let vids: *i64 = sys_mmap(256) as *i64 421 let vcnt: i64 = ae_vocab_build(vtoks, vids, 16) 422 while run == 1 { 423 let found: i64 = ae_plan_step(pbuf, pn, step, vb, ab, K_MAGIC_8192) 424 if found == 0 { run = 0 } else { 425 // dispatch the verb of THIS step. order law: stage_input before run_organ before write_artifact. 426 if ae_streq(vb, "stage_input" as *u8) == 1 { 427 if step != 1 { sys_exit(5); return 5 } 428 // copy materials_dir/input_stage -> sandbox/input_stage (verbatim bytes) 429 let srcp: *u8 = sys_mmap(K_MAGIC_16384) 430 ae_join(v_mat, v_in, srcp) 431 let dstp: *u8 = sys_mmap(K_MAGIC_16384) 432 ae_join(sandbox, v_in, dstp) 433 let mbuf: *u8 = sys_mmap(K_MAGIC_262144) 434 let mn: i64 = ae_read(srcp, mbuf, K_MAGIC_262144) 435 if mn <= 0 { sys_exit(6); return 6 } 436 let okw: i64 = ae_write_file(dstp, mbuf, mn) 437 if okw == 0 { sys_exit(7); return 7 } 438 staged = 1 439 } else { 440 if ae_streq(vb, "run_organ" as *u8) == 1 { 441 if staged != 1 { sys_exit(8); return 8 } 442 if step != 2 { sys_exit(8); return 8 } 443 // DATA-DRIVEN dispatch: look the instruction's leading token up in the vocabulary 444 // table (ab = plan step-2 arg) -> abstract transform-id. id 0 = unknown -> REFUSE. 445 let tid: i64 = ae_vocab_lookup(ab, vtoks, vids, vcnt) 446 if tid == 0 { sys_exit(10); return 10 } 447 // read the STAGED file (not the source) once; the selected transform consumes it. 448 let stagedp: *u8 = sys_mmap(K_MAGIC_16384) 449 ae_join(sandbox, v_in, stagedp) 450 let sbuf: *u8 = sys_mmap(K_MAGIC_262144) 451 let sn: i64 = ae_read(stagedp, sbuf, K_MAGIC_262144) 452 if sn <= 0 { sys_exit(9); return 9 } 453 // invoke the transform by its abstract id (composition dispatch, not a token if-chain). 454 if tid == 1 { contn = ae_transform_kv(sbuf, sn, content) } 455 if tid == 2 { contn = ae_transform_copy(sbuf, sn, content) } 456 if tid == 3 { contn = ae_transform_count(sbuf, sn, content) } 457 if tid == 4 { contn = ae_transform_sum(sbuf, sn, content) } 458 if tid == 5 { contn = ae_transform_reduce(sbuf, sn, content, ab) } 459 transformed = 1 460 } else { 461 if ae_streq(vb, "write_artifact" as *u8) == 1 { 462 if transformed != 1 { sys_exit(11); return 11 } 463 if step != 3 { sys_exit(11); return 11 } 464 let artp: *u8 = sys_mmap(K_MAGIC_16384) 465 ae_join(sandbox, v_art, artp) 466 if contn <= 0 { sys_exit(12); return 12 } 467 let okw2: i64 = ae_write_file(artp, content, contn) 468 if okw2 == 0 { sys_exit(13); return 13 } 469 written = 1 470 } else { 471 // unknown verb -> REFUSE 472 sys_exit(14); return 14 473 } 474 } 475 } 476 step = step + 1 477 } 478 } 479 480 if written != 1 { sys_exit(15); return 15 } 481 sys_exit(0) 482 return 0 483}