code wiki / _hdl_build / nx_featuremine.nx
nx_featuremine.nx source
↩ module page · 395 lines · 18205 B
1// nx_featuremine.nx -- FEATURES-CLASS MINER over the frontier- plane (miner-sota F1016, 2026-07-23).
2// The census (nx_minecov MC05) measured features COVERED-but-UNMINED: nx_frontier_board derives CPM
3// (ES/EF/float/critical-path/READY/BLOCKED) over the DAG, but nobody mines the BACKLOG ITSELF. The
4// signal CPM does not give is DEPENDENCY IN-DEGREE: which feature BLOCKS THE MOST OTHERS. A row with
5// float 0 is on the critical path; a row with in-degree 9 is a BOTTLENECK -- different questions, and
6// the second is what tells a PM where to put people. Also: per-owner load with a real done-rate,
7// status distribution, unowned rows, and BLOCKED (a dep that is not yet D) kept distinct from READY.
8// ★HONEST LIMIT DECLARED IN THE OUTPUT: frontier ids are F-numbers, NOT epochs, so AGE IS NOT
9// DERIVABLE from this plane -- the organ reports aging_available:0 rather than inventing a number.
10// Composes nx_sovjson_lib (sj_*). Read-only. No hw writes (Rule 26).
11// mine <source> [loader|-] [minsup] -> JSON: status/owner/dep-bottleneck/blocked + declared limits
12// selftest <scratch-prefix> -> gate T1..T8
13// row cols: id TAB title TAB w TAB _ TAB owner TAB status(T|D|X) TAB deps TAB lane TAB milestone
14// license_tier: ORIGINAL
15import "nx_sovjson_lib.nx"
16import "nx_syscalls.nx"
17import "nx_gate_verdict.nx"
18import "nx_tool_run.nx"
19const FM_MAGIC_4088: i64 = 4088
20
21const FM_CAP: i64 = 1048576
22const FM_OUT: i64 = 65536
23const FM_PATH: i64 = 512
24const FM_ROWS: i64 = 1024
25const FM_OWNERS: i64 = 256
26const FM_TOPN: i64 = 15
27const FM_ALLOW: i64 = 131072
28const FM_PERMIL: i64 = 1000
29const FM_NAME_MAX: i64 = 120
30const FM_MODE_644: i64 = 420
31
32func fm_read(path: *u8, buf: *u8, cap: i64) -> i64 {
33 let fd: i64 = sys_openat_rd(path)
34 if fd < 0 { return -1 }
35 var n: i64 = 0
36 var go: i64 = 1
37 while go == 1 { let r: i64 = sys_read(fd, ((buf as i64)+n) as *u8, cap-n); if r <= 0 { go = 0 } else { n = n + r } if n >= cap { go = 0 } }
38 sys_close(fd)
39 return n
40}
41func fm_find(q: *u8, n: i64, lit: *u8) -> i64 {
42 let ll: i64 = sj_vlen(lit)
43 if ll == 0 { return 0 }
44 var i: i64 = 0
45 while i + ll <= n {
46 var k: i64 = 0
47 var ok: i64 = 1
48 while k < ll { if q[i+k] != lit[k] { ok = 0; k = ll } else { k = k + 1 } }
49 if ok == 1 { return 1 }
50 i = i + 1
51 }
52 return 0
53}
54// DELEGATES to the shared base (rule-15 extraction 2026-07-23)
55func fm_allow_path(name: *u8, outp: *u8) -> i64 { return sj_allow_path(name, outp) }
56func fm_key(d: *u8, o: i64, name: *u8) -> i64 {
57 d[o] = 34 as u8
58 var p: i64 = o + 1
59 p = sj_cat(d, p, name)
60 d[p] = 34 as u8
61 p = p + 1
62 d[p] = 58 as u8
63 p = p + 1
64 return p
65}
66func fm_absent(q: *u8, s: i64, e: i64) -> i64 {
67 if e <= s { return 1 }
68 if e - s == 1 { if q[s] == (45 as u8) { return 1 } }
69 return 0
70}
71func fm_span_eq(q: *u8, a: i64, ae: i64, b: i64, be: i64) -> i64 {
72 if ae - a != be - b { return 0 }
73 var i: i64 = 0
74 while a + i < ae { if q[a+i] != q[b+i] { return 0 } i = i + 1 }
75 return 1
76}
77func fm_load(src: *u8, loader: *u8, buf: *u8, lcx: *i64) -> i64 {
78 lcx[0] = 0
79 if sj_lit_eq(loader, 0, sj_vlen(loader), "-" as *u8) == 1 {
80 let n: i64 = fm_read(src, buf, FM_CAP - 8)
81 if n <= 0 { return -1 }
82 return n
83 }
84 let lp: *u8 = sys_mmap(FM_PATH)
85 if fm_allow_path(loader, lp) == 0 { return -2 }
86 lcx[0] = 1
87 let av: *i64 = sys_mmap(64) as *i64
88 av[0] = lp as i64
89 av[1] = src as i64
90 av[2] = "load" as *u8 as i64
91 av[3] = 0
92 let cl: *i64 = sys_mmap(16) as *i64
93 let ex: i64 = tr_run_capture(lp, av, buf, FM_CAP - 8, cl)
94 if ex != 0 { return -3 }
95 if cl[0] <= 0 { return -1 }
96 return cl[0]
97}
98func fm_mine_json(src: *u8, loader: *u8, minsup: i64, d: *u8) -> i64 {
99 let q: *u8 = sys_mmap(FM_CAP)
100 let lcx: *i64 = sys_mmap(16) as *i64
101 let n: i64 = fm_load(src, loader, q, lcx)
102 if n < 0 { return n }
103 // pass 1: index every row's id / status / owner / deps
104 let ids: *i64 = sys_mmap(8 * FM_ROWS) as *i64
105 let ide: *i64 = sys_mmap(8 * FM_ROWS) as *i64
106 let stat: *i64 = sys_mmap(8 * FM_ROWS) as *i64
107 let deps: *i64 = sys_mmap(8 * FM_ROWS) as *i64
108 let depe: *i64 = sys_mmap(8 * FM_ROWS) as *i64
109 let indeg: *i64 = sys_mmap(8 * FM_ROWS) as *i64
110 let ows: *i64 = sys_mmap(8 * FM_OWNERS) as *i64
111 let owe: *i64 = sys_mmap(8 * FM_OWNERS) as *i64
112 let owc: *i64 = sys_mmap(8 * FM_OWNERS) as *i64
113 let owd: *i64 = sys_mmap(8 * FM_OWNERS) as *i64
114 let done: *i64 = sys_mmap(8 * FM_ROWS) as *i64
115 let sp: *i64 = sys_mmap(16) as *i64
116 var nr: i64 = 0
117 var nown: i64 = 0
118 var rcapped: i64 = 0
119 var malformed: i64 = 0
120 var todo: i64 = 0
121 var ndone: i64 = 0
122 var ext: i64 = 0
123 var other: i64 = 0
124 var unowned: i64 = 0
125 var i: i64 = 0
126 while i < n {
127 let le: i64 = sj_le(q, i, n)
128 var ok: i64 = 0
129 var cmt: i64 = 0
130 if le > i { if q[i] == (35 as u8) { cmt = 1 } }
131 if le > i { if cmt == 0 { if sj_col(q, i, le, 6, sp) == 1 { ok = 1 } } }
132 if ok == 0 { if le > i { if cmt == 0 { malformed = malformed + 1 } } } else {
133 if nr >= FM_ROWS { rcapped = 1 } else {
134 deps[nr] = sp[0]
135 depe[nr] = sp[1]
136 sj_col(q, i, le, 0, sp)
137 ids[nr] = sp[0]
138 ide[nr] = sp[1]
139 sj_col(q, i, le, 5, sp)
140 var st: i64 = 3
141 if sj_lit_eq(q, sp[0], sp[1], "T" as *u8) == 1 { st = 0; todo = todo + 1 }
142 if sj_lit_eq(q, sp[0], sp[1], "D" as *u8) == 1 { st = 1; ndone = ndone + 1 }
143 if sj_lit_eq(q, sp[0], sp[1], "X" as *u8) == 1 { st = 2; ext = ext + 1 }
144 if st == 3 { other = other + 1 }
145 stat[nr] = st
146 sj_col(q, i, le, 4, sp)
147 if fm_absent(q, sp[0], sp[1]) == 1 { unowned = unowned + 1 } else {
148 var oi: i64 = 0 - 1
149 var k: i64 = 0
150 while k < nown {
151 if fm_span_eq(q, sp[0], sp[1], ows[k], owe[k]) == 1 { oi = k; k = nown }
152 k = k + 1
153 }
154 if oi < 0 { if nown < FM_OWNERS { ows[nown] = sp[0]; owe[nown] = sp[1]; oi = nown; nown = nown + 1 } }
155 if oi >= 0 { owc[oi] = owc[oi] + 1; if st == 1 { owd[oi] = owd[oi] + 1 } }
156 }
157 nr = nr + 1
158 }
159 }
160 i = le + 1
161 }
162 // pass 2: dependency in-degree + blocked (a dep that is not yet D)
163 var blocked: i64 = 0
164 var ready: i64 = 0
165 var dangling: i64 = 0
166 var r: i64 = 0
167 while r < nr {
168 if fm_absent(q, deps[r], depe[r]) == 1 { if stat[r] == 0 { ready = ready + 1 } } else {
169 var di: i64 = 0 - 1
170 var k: i64 = 0
171 while k < nr {
172 if fm_span_eq(q, deps[r], depe[r], ids[k], ide[k]) == 1 { di = k; k = nr }
173 k = k + 1
174 }
175 if di < 0 { dangling = dangling + 1 } else {
176 indeg[di] = indeg[di] + 1
177 if stat[r] == 0 { if stat[di] != 1 { blocked = blocked + 1 } else { ready = ready + 1 } }
178 }
179 }
180 r = r + 1
181 }
182 var p: i64 = 0
183 d[p] = 123 as u8; p = p + 1
184 p = fm_key(d, p, "v" as *u8); p = sj_catn(d, p, 1); d[p] = 44 as u8; p = p + 1
185 p = fm_key(d, p, "tool" as *u8)
186 d[p] = 34 as u8; p = p + 1
187 p = sj_cat(d, p, "nx_featuremine" as *u8)
188 d[p] = 34 as u8; p = p + 1
189 d[p] = 44 as u8; p = p + 1
190 p = fm_key(d, p, "averb" as *u8)
191 d[p] = 34 as u8; p = p + 1
192 p = sj_cat(d, p, "mine" as *u8)
193 d[p] = 34 as u8; p = p + 1
194 d[p] = 44 as u8; p = p + 1
195 p = fm_key(d, p, "source" as *u8)
196 d[p] = 34 as u8; p = p + 1
197 p = sj_cat_esc(d, p, src, 0, sj_vlen(src), FM_NAME_MAX)
198 d[p] = 34 as u8; p = p + 1
199 d[p] = 44 as u8; p = p + 1
200 p = fm_key(d, p, "loader_resolved" as *u8); p = sj_catn(d, p, lcx[0]); d[p] = 44 as u8; p = p + 1
201 p = fm_key(d, p, "rows" as *u8); p = sj_catn(d, p, nr); d[p] = 44 as u8; p = p + 1
202 p = fm_key(d, p, "malformed" as *u8); p = sj_catn(d, p, malformed); d[p] = 44 as u8; p = p + 1
203 p = fm_key(d, p, "rows_capped" as *u8); p = sj_catn(d, p, rcapped); d[p] = 44 as u8; p = p + 1
204 p = fm_key(d, p, "todo" as *u8); p = sj_catn(d, p, todo); d[p] = 44 as u8; p = p + 1
205 p = fm_key(d, p, "done" as *u8); p = sj_catn(d, p, ndone); d[p] = 44 as u8; p = p + 1
206 p = fm_key(d, p, "external" as *u8); p = sj_catn(d, p, ext); d[p] = 44 as u8; p = p + 1
207 p = fm_key(d, p, "other_status" as *u8); p = sj_catn(d, p, other); d[p] = 44 as u8; p = p + 1
208 var dp: i64 = 0 - 1
209 if nr > 0 { dp = ndone * FM_PERMIL / nr }
210 p = fm_key(d, p, "done_permil" as *u8); p = sj_catn(d, p, dp); d[p] = 44 as u8; p = p + 1
211 p = fm_key(d, p, "unowned" as *u8); p = sj_catn(d, p, unowned); d[p] = 44 as u8; p = p + 1
212 p = fm_key(d, p, "blocked_todo" as *u8); p = sj_catn(d, p, blocked); d[p] = 44 as u8; p = p + 1
213 p = fm_key(d, p, "ready_todo" as *u8); p = sj_catn(d, p, ready); d[p] = 44 as u8; p = p + 1
214 p = fm_key(d, p, "dangling_deps" as *u8); p = sj_catn(d, p, dangling); d[p] = 44 as u8; p = p + 1
215 // ★declared limit: frontier ids are F-numbers, not epochs -- age is NOT derivable here
216 p = fm_key(d, p, "aging_available" as *u8); p = sj_catn(d, p, 0); d[p] = 44 as u8; p = p + 1
217 // dep bottlenecks: highest in-degree first (who blocks the most)
218 p = fm_key(d, p, "dep_bottleneck" as *u8)
219 d[p] = 91 as u8; p = p + 1
220 var shown: i64 = 0
221 var efirst: i64 = 1
222 var pass: i64 = 0
223 while pass < nr {
224 if shown < FM_TOPN {
225 var mi: i64 = 0 - 1
226 var mx: i64 = 0
227 var k: i64 = 0
228 while k < nr {
229 if done[k] == 0 { if indeg[k] > mx { mx = indeg[k]; mi = k } }
230 k = k + 1
231 }
232 if mi >= 0 {
233 done[mi] = 1
234 if mx >= minsup {
235 if efirst == 0 { d[p] = 44 as u8; p = p + 1 }
236 efirst = 0
237 d[p] = 123 as u8; p = p + 1
238 p = fm_key(d, p, "id" as *u8)
239 d[p] = 34 as u8; p = p + 1
240 p = sj_cat_esc(d, p, q, ids[mi], ide[mi], FM_NAME_MAX)
241 d[p] = 34 as u8; p = p + 1
242 d[p] = 44 as u8; p = p + 1
243 p = fm_key(d, p, "blocks" as *u8); p = sj_catn(d, p, mx); d[p] = 44 as u8; p = p + 1
244 p = fm_key(d, p, "status" as *u8)
245 d[p] = 34 as u8; p = p + 1
246 if stat[mi] == 0 { p = sj_cat(d, p, "T" as *u8) } else {
247 if stat[mi] == 1 { p = sj_cat(d, p, "D" as *u8) } else {
248 if stat[mi] == 2 { p = sj_cat(d, p, "X" as *u8) } else { p = sj_cat(d, p, "?" as *u8) }
249 }
250 }
251 d[p] = 34 as u8; p = p + 1
252 d[p] = 125 as u8; p = p + 1
253 shown = shown + 1
254 }
255 }
256 }
257 pass = pass + 1
258 }
259 d[p] = 93 as u8; p = p + 1
260 d[p] = 44 as u8; p = p + 1
261 p = fm_key(d, p, "bottlenecks_shown" as *u8); p = sj_catn(d, p, shown); d[p] = 44 as u8; p = p + 1
262 // per-owner load with a REAL done-rate
263 p = fm_key(d, p, "by_owner" as *u8)
264 d[p] = 91 as u8; p = p + 1
265 let odone: *i64 = sys_mmap(8 * FM_OWNERS) as *i64
266 var oshown: i64 = 0
267 var ofirst: i64 = 1
268 var op: i64 = 0
269 while op < nown {
270 var mi2: i64 = 0 - 1
271 var mx2: i64 = 0 - 1
272 var k2: i64 = 0
273 while k2 < nown {
274 if odone[k2] == 0 { if owc[k2] > mx2 { mx2 = owc[k2]; mi2 = k2 } }
275 k2 = k2 + 1
276 }
277 if mi2 >= 0 {
278 odone[mi2] = 1
279 if oshown < FM_TOPN {
280 if ofirst == 0 { d[p] = 44 as u8; p = p + 1 }
281 ofirst = 0
282 d[p] = 123 as u8; p = p + 1
283 p = fm_key(d, p, "owner" as *u8)
284 d[p] = 34 as u8; p = p + 1
285 p = sj_cat_esc(d, p, q, ows[mi2], owe[mi2], FM_NAME_MAX)
286 d[p] = 34 as u8; p = p + 1
287 d[p] = 44 as u8; p = p + 1
288 p = fm_key(d, p, "rows" as *u8); p = sj_catn(d, p, owc[mi2]); d[p] = 44 as u8; p = p + 1
289 p = fm_key(d, p, "done" as *u8); p = sj_catn(d, p, owd[mi2]); d[p] = 44 as u8; p = p + 1
290 var odp: i64 = 0
291 if owc[mi2] > 0 { odp = owd[mi2] * FM_PERMIL / owc[mi2] }
292 p = fm_key(d, p, "done_permil" as *u8); p = sj_catn(d, p, odp)
293 d[p] = 125 as u8; p = p + 1
294 oshown = oshown + 1
295 }
296 }
297 op = op + 1
298 }
299 d[p] = 93 as u8; p = p + 1
300 d[p] = 44 as u8; p = p + 1
301 p = fm_key(d, p, "owners" as *u8); p = sj_catn(d, p, nown)
302 d[p] = 125 as u8; p = p + 1
303 d[p] = 10 as u8; p = p + 1
304 return p
305}
306func fm_selftest(prefix: *u8) -> i64 {
307 let ctr: *i64 = gv_ctr()
308 gv_head("nx_featuremine selftest -- dep in-degree bottleneck teeth (blocks-the-most is not float)" as *u8)
309 let fx: *u8 = sys_mmap(FM_PATH)
310 var o: i64 = sj_cat(fx, 0, prefix)
311 o = sj_catn(fx, o, sys_now_realtime_sec())
312 o = sj_cat(fx, o, ".fm" as *u8)
313 fx[o] = 0 as u8
314 let miss: *u8 = sys_mmap(FM_PATH)
315 o = sj_cat(miss, 0, fx)
316 o = sj_cat(miss, o, ".absent" as *u8)
317 miss[o] = 0 as u8
318 // K1 done, blocks 3 (K2,K3,K4 depend on it). K5 depends on K2 (still T) => blocked.
319 // K6 depends on GHOST => dangling. K7 no deps, T => ready. K8 unowned.
320 let fd: i64 = sys_openat_wr(fx, FM_MODE_644)
321 let lb: *u8 = sys_mmap(FM_MAGIC_4088)
322 var lo: i64 = sj_cat(lb, 0, "# fixture\n" as *u8)
323 lo = sj_cat(lb, lo, "K1\tbase\t8\t0\tpm\tD\t-\tlane\tms\n" as *u8)
324 lo = sj_cat(lb, lo, "K2\tone\t7\t0\tpm\tT\tK1\tlane\tms\n" as *u8)
325 lo = sj_cat(lb, lo, "K3\ttwo\t7\t0\thr\tT\tK1\tlane\tms\n" as *u8)
326 lo = sj_cat(lb, lo, "K4\tthree\t6\t0\tpm\tD\tK1\tlane\tms\n" as *u8)
327 lo = sj_cat(lb, lo, "K5\tfour\t6\t0\thr\tT\tK2\tlane\tms\n" as *u8)
328 lo = sj_cat(lb, lo, "K6\tfive\t5\t0\tpm\tT\tGHOST\tlane\tms\n" as *u8)
329 lo = sj_cat(lb, lo, "K7\tsix\t5\t0\tpm\tT\t-\tlane\tms\n" as *u8)
330 lo = sj_cat(lb, lo, "K8\tseven\t4\t0\t-\tX\t-\tlane\tms\n" as *u8)
331 lo = sj_cat(lb, lo, "junk\n" as *u8)
332 sys_write(fd, lb, lo)
333 sys_close(fd)
334 let d: *u8 = sys_mmap(FM_OUT)
335 let r1: i64 = fm_mine_json(miss, "-" as *u8, 1, d)
336 var ok1: i64 = 0
337 if r1 < 0 { ok1 = 1 }
338 gv_check("T1 missing source refused fail closed" as *u8, ok1, ctr)
339 let dl: i64 = fm_mine_json(fx, "-" as *u8, 1, d)
340 var ok2: i64 = 0
341 if dl > 0 { if fm_find(d, dl, "\"rows\":8,\"malformed\":1" as *u8) == 1 { ok2 = 1 } }
342 gv_check("T2 exact rows 8, junk row counted malformed (comment skipped)" as *u8, ok2, ctr)
343 var ok3: i64 = 0
344 if fm_find(d, dl, "\"todo\":5,\"done\":2,\"external\":1,\"other_status\":0" as *u8) == 1 { if fm_find(d, dl, "\"done_permil\":250" as *u8) == 1 { ok3 = 1 } }
345 gv_check("T3 status split exact 5T/2D/1X and done_permil 250" as *u8, ok3, ctr)
346 var ok4: i64 = 0
347 if fm_find(d, dl, "\"id\":\"K1\",\"blocks\":3,\"status\":\"D\"" as *u8) == 1 { ok4 = 1 }
348 gv_check("T4 dep IN-DEGREE exact: K1 blocks 3 (the bottleneck CPM float cannot name)" as *u8, ok4, ctr)
349 var ok5: i64 = 0
350 if fm_find(d, dl, "\"id\":\"K2\",\"blocks\":1,\"status\":\"T\"" as *u8) == 1 { ok5 = 1 }
351 gv_check("T5 a still-open bottleneck is ranked with its OWN status (K2 blocks 1, T)" as *u8, ok5, ctr)
352 var ok6: i64 = 0
353 // K5 alone has a non-done dep (K2 is T) => blocked 1. K2/K3 depend on the DONE K1, K7 has no deps
354 // => ready 3. K6's dangling dep counts DANGLING only, deliberately not blocked (declared choice).
355 if fm_find(d, dl, "\"blocked_todo\":1,\"ready_todo\":3" as *u8) == 1 { ok6 = 1 }
356 gv_check("T6 BLOCKED (dep not yet D) kept distinct from READY: exactly 1 and 3" as *u8, ok6, ctr)
357 var ok7: i64 = 0
358 if fm_find(d, dl, "\"dangling_deps\":1" as *u8) == 1 { if fm_find(d, dl, "\"id\":\"GHOST\"" as *u8) == 0 { ok7 = 1 } }
359 gv_check("T7 a dep pointing at a nonexistent id is DANGLING, never invented as a row" as *u8, ok7, ctr)
360 var ok8: i64 = 0
361 if fm_find(d, dl, "\"unowned\":1" as *u8) == 1 { if fm_find(d, dl, "\"owner\":\"pm\",\"rows\":5,\"done\":2,\"done_permil\":400" as *u8) == 1 { if fm_find(d, dl, "\"aging_available\":0" as *u8) == 1 { ok8 = 1 } } }
362 gv_check("T8 per-owner done-rate exact (pm 2/5=400) + unowned counted + aging LIMIT declared" as *u8, ok8, ctr)
363 let rc: i64 = gv_verdict("FEATUREMINE-GATE" as *u8, ctr, "feature mining: dep in-degree bottlenecks, blocked-vs-ready, per-owner done-rate, dangling deps, declared aging limit" as *u8)
364 return rc
365}
366
367func main(argc: i64, argv: *i64) -> i64 {
368 if argc < 3 { sj_puts("usage: nx_featuremine {mine <source> [loader|-] [minsup] | selftest <scratch-prefix>}\n" as *u8); sys_exit(2); return 2 }
369 let verb: *u8 = argv[1] as *u8
370 let vl: i64 = sj_vlen(verb)
371 if sj_lit_eq(verb, 0, vl, "selftest" as *u8) == 1 {
372 let rc: i64 = fm_selftest(argv[2] as *u8)
373 sys_exit(rc)
374 return rc
375 }
376 if sj_lit_eq(verb, 0, vl, "mine" as *u8) == 1 {
377 let loader: *u8 = sys_mmap(128)
378 var lo: i64 = 0
379 if argc >= 4 { lo = sj_cat(loader, 0, argv[3] as *u8) } else { lo = sj_cat(loader, 0, "nx_store_put" as *u8) }
380 loader[lo] = 0 as u8
381 var minsup: i64 = 1
382 if argc >= 5 { let mz: i64 = sj_atoi_z(argv[4] as *u8); if mz > 0 { minsup = mz } }
383 let d: *u8 = sys_mmap(FM_OUT)
384 let dl: i64 = fm_mine_json(argv[2] as *u8, loader, minsup, d)
385 if dl == (0 - 2) { sj_puts("REFUSED loader not in the allowlist\n" as *u8); sys_exit(3); return 3 }
386 if dl == (0 - 3) { sj_puts("REFUSED loader exited nonzero\n" as *u8); sys_exit(3); return 3 }
387 if dl < 0 { sj_puts("REFUSED source missing or empty\n" as *u8); sys_exit(3); return 3 }
388 sys_write(1, d, dl)
389 sys_exit(0)
390 return 0
391 }
392 sj_puts("unknown verb\n" as *u8)
393 sys_exit(2)
394 return 2
395}