code wiki / _hdl_build / nx_work_predict_lib.nx
nx_work_predict_lib.nx source
↩ module page · 240 lines · 9238 B
1// nx_work_predict_lib.nx -- the FUTURE axis: GENEALOGY-grounded prediction of what work grows next.
2// Reads capability_ladder.tsv (itself COMPUTED from real deps+DONE status -- "NOT asserted", so it is
3// already a non-hallucinated source) and finds the ADJACENT-POSSIBLE frontier: a capability whose
4// status is not DONE but ALL of its prerequisites ARE DONE -- i.e. the parent just got built, so this
5// node is the next thing that can grow "out from god". Prediction as DATA, never prose from a model:
6// every prediction is a row whose deps are mechanically verified DONE, with the WHY = which
7// prerequisite unlocked it. (per author-by-organ-not-claude + no-wave-measured-exceed.)
8//
9// columns of capability_ladder.tsv: layer<TAB>id<TAB>status<TAB>grounding<TAB>deps (deps "-" or a,b,c)
10// REUSE (DRY): jx_find / jx_len from nx_json_lib. Sovereign. license_tier: ORIGINAL
11import "nx_syscalls.nx"
12import "nx_json_lib.nx"
13const WP_MAGIC_1024: i64 = 1024
14
15const WP_DONE: i64 = 0 // status already DONE -> not a prediction
16const WP_ADJACENT: i64 = 1 // not DONE, has real dep(s), ALL deps DONE -> probable-next (the gold)
17const WP_ROOT: i64 = 2 // not DONE, deps "-" -> foundational-available (no parent to grow from)
18const WP_BLOCKED: i64 = 3 // not DONE, some dep NOT DONE -> still blocked, not yet predictable
19
20const WP_MAXADJ: i64 = 1024
21const WP_IDCAP: i64 = 96
22const WP_DONECAP: i64 = 262144
23
24func wp_streq(a: *u8, b: *u8) -> i64 {
25 var i: i64 = 0
26 while i < 256 {
27 if a[i] != b[i] { return 0 }
28 if a[i] == (0 as u8) { return 1 }
29 i = i + 1
30 }
31 return 1
32}
33func wp_cat(dst: *u8, off: i64, s: *u8) -> i64 { var o: i64 = off; var i: i64 = 0; while s[i] != (0 as u8) { dst[o] = s[i]; o = o + 1; i = i + 1 } return o }
34func wp_catn(dst: *u8, off: i64, v: i64) -> i64 {
35 var o: i64 = off; var m: i64 = v
36 if m == 0 { dst[o] = 48 as u8; return o + 1 }
37 if m < 0 { dst[o] = 45 as u8; o = o + 1; m = 0 - m }
38 let t: *u8 = sys_mmap(32); var k: i64 = 0
39 while m > 0 { t[k] = ((48 + (m % 10)) as u8); m = m / 10; k = k + 1 }
40 while k > 0 { dst[o] = t[k - 1]; o = o + 1; k = k - 1 }
41 return o
42}
43
44// is `id` present in doneset (a "\tID1\tID2\t...\t" tab-bounded buffer)? boundary tabs prevent the
45// X-B0-1 / X-B0-10 partial-match class.
46func wp_is_done(doneset: *u8, donelen: i64, id: *u8) -> i64 {
47 let needle: *u8 = sys_mmap(jx_len(id) + 4)
48 var o: i64 = 0
49 needle[o] = 9 as u8; o = o + 1
50 var i: i64 = 0
51 while id[i] != (0 as u8) { needle[o] = id[i]; o = o + 1; i = i + 1 }
52 needle[o] = 9 as u8; o = o + 1
53 needle[o] = 0 as u8
54 if jx_find(doneset, donelen, 0, needle) >= 0 { return 1 }
55 return 0
56}
57
58// classify a row from its status + deps (pure -- the gateable core).
59func wp_classify(status: *u8, deps: *u8, doneset: *u8, donelen: i64) -> i64 {
60 if wp_streq(status, "DONE" as *u8) == 1 { return WP_DONE }
61 if deps[0] == (45 as u8) { if deps[1] == (0 as u8) { return WP_ROOT } } // deps == "-"
62 let sub: *u8 = sys_mmap(256)
63 let n: i64 = jx_len(deps)
64 var i: i64 = 0
65 var so: i64 = 0
66 var alldone: i64 = 1
67 var anydep: i64 = 0
68 while i <= n {
69 let c: i64 = deps[i] as i64 // deps[n] == 0 (terminator)
70 var brk: i64 = 0
71 if c == 44 { brk = 1 } // ','
72 if c == 0 { brk = 1 }
73 if brk == 1 {
74 if so > 0 {
75 sub[so] = 0 as u8
76 anydep = 1
77 if wp_is_done(doneset, donelen, sub) == 0 { alldone = 0 }
78 }
79 so = 0
80 } else {
81 if so < 255 { sub[so] = c as u8; so = so + 1 }
82 }
83 i = i + 1
84 }
85 if anydep == 0 { return WP_ROOT }
86 if alldone == 1 { return WP_ADJACENT }
87 return WP_BLOCKED
88}
89
90// copy field k (0-based, TAB-separated) of the line buf[ls..le) into out (NUL-term). returns length,
91// or -1 if the line has fewer than k+1 fields.
92func wp_field(buf: *u8, ls: i64, le: i64, k: i64, out: *u8, outcap: i64) -> i64 {
93 var fi: i64 = 0
94 var i: i64 = ls
95 var o: i64 = 0
96 while i < le {
97 let c: i64 = buf[i] as i64
98 if c == 9 {
99 if fi == k { out[o] = 0 as u8; return o }
100 fi = fi + 1
101 o = 0
102 } else {
103 if fi == k { if o < outcap - 1 { out[o] = c as u8; o = o + 1 } }
104 }
105 i = i + 1
106 }
107 out[o] = 0 as u8
108 if fi == k { return o }
109 return 0 - 1
110}
111func wp_atoi(s: *u8) -> i64 {
112 var v: i64 = 0; var i: i64 = 0
113 while s[i] != (0 as u8) { let c: i64 = s[i] as i64; if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } i = i + 1 }
114 return v
115}
116
117// copy `deps` up to the first ',' (the first prerequisite -- used as the WHY) into out.
118func wp_first_dep(deps: *u8, out: *u8) -> i64 {
119 var k: i64 = 0
120 var stop: i64 = 0
121 while stop == 0 {
122 let c: i64 = deps[k] as i64
123 if c == 0 { stop = 1 } else { if c == 44 { stop = 1 } else { out[k] = c as u8; k = k + 1 } }
124 }
125 out[k] = 0 as u8
126 return k
127}
128
129// PASS 1: build the DONE-set buffer ("\tID\tID\t...\t") from every status==DONE row.
130func wp_build_doneset(buf: *u8, len: i64, ds: *u8, dscap: i64) -> i64 {
131 var dlen: i64 = 0
132 ds[dlen] = 9 as u8; dlen = dlen + 1 // leading tab boundary
133 let id: *u8 = sys_mmap(WP_IDCAP)
134 let st: *u8 = sys_mmap(64)
135 var ls: i64 = 0
136 while ls < len {
137 var le: i64 = ls
138 var d: i64 = 0
139 while d == 0 { if le >= len { d = 1 } else { if buf[le] == (10 as u8) { d = 1 } else { le = le + 1 } } }
140 if ls < le { if buf[ls] != (35 as u8) { // skip '#' comment lines
141 wp_field(buf, ls, le, 2, st, 64)
142 if wp_streq(st, "DONE" as *u8) == 1 {
143 wp_field(buf, ls, le, 1, id, WP_IDCAP)
144 var j: i64 = 0
145 while id[j] != (0 as u8) { if dlen < dscap - 2 { ds[dlen] = id[j]; dlen = dlen + 1 } j = j + 1 }
146 if dlen < dscap - 1 { ds[dlen] = 9 as u8; dlen = dlen + 1 }
147 }
148 } }
149 ls = le + 1
150 }
151 ds[dlen] = 0 as u8
152 return dlen
153}
154
155// PASS 2 + emit: collect ADJACENT rows, sort by layer ascending (the growth front nearest the root),
156// emit "id\t(layer L)\t<- dep DONE" lines into out. stats[0..4]=rows,done,adjacent,root,blocked.
157// returns the adjacent (probable-next) count.
158func wp_predict(buf: *u8, len: i64, out: *u8, outcap: i64, stats: *i64) -> i64 {
159 let ds: *u8 = sys_mmap(WP_DONECAP)
160 let dslen: i64 = wp_build_doneset(buf, len, ds, WP_DONECAP)
161
162 let layers: *i64 = sys_mmap(8 * WP_MAXADJ) as *i64
163 let idps: *i64 = sys_mmap(8 * WP_MAXADJ) as *i64
164 let depps: *i64 = sys_mmap(8 * WP_MAXADJ) as *i64
165 var nadj: i64 = 0
166 var nrows: i64 = 0
167 var ndone: i64 = 0
168 var nroot: i64 = 0
169 var nblock: i64 = 0
170
171 let st: *u8 = sys_mmap(64)
172 let dp: *u8 = sys_mmap(WP_MAGIC_1024)
173 var ls: i64 = 0
174 while ls < len {
175 var le: i64 = ls
176 var d: i64 = 0
177 while d == 0 { if le >= len { d = 1 } else { if buf[le] == (10 as u8) { d = 1 } else { le = le + 1 } } }
178 if ls < le { if buf[ls] != (35 as u8) {
179 nrows = nrows + 1
180 wp_field(buf, ls, le, 2, st, 64)
181 wp_field(buf, ls, le, 4, dp, WP_MAGIC_1024)
182 let cls: i64 = wp_classify(st, dp, ds, dslen)
183 if cls == WP_DONE { ndone = ndone + 1 }
184 if cls == WP_ROOT { nroot = nroot + 1 }
185 if cls == WP_BLOCKED { nblock = nblock + 1 }
186 if cls == WP_ADJACENT {
187 if nadj < WP_MAXADJ {
188 let lf: *u8 = sys_mmap(16)
189 wp_field(buf, ls, le, 0, lf, 16)
190 let idb: *u8 = sys_mmap(WP_IDCAP)
191 wp_field(buf, ls, le, 1, idb, WP_IDCAP)
192 let depb: *u8 = sys_mmap(WP_IDCAP)
193 wp_first_dep(dp, depb)
194 layers[nadj] = wp_atoi(lf)
195 idps[nadj] = idb as i64
196 depps[nadj] = depb as i64
197 nadj = nadj + 1
198 }
199 }
200 } }
201 ls = le + 1
202 }
203
204 // insertion sort by layer ascending (carry id + dep pointers).
205 var a: i64 = 1
206 while a < nadj {
207 let lv: i64 = layers[a]
208 let iv: i64 = idps[a]
209 let dv: i64 = depps[a]
210 var b: i64 = a - 1
211 var go: i64 = 1
212 while go == 1 {
213 if b < 0 { go = 0 } else {
214 if layers[b] > lv { layers[b + 1] = layers[b]; idps[b + 1] = idps[b]; depps[b + 1] = depps[b]; b = b - 1 } else { go = 0 }
215 }
216 }
217 layers[b + 1] = lv; idps[b + 1] = iv; depps[b + 1] = dv
218 a = a + 1
219 }
220
221 var o: i64 = 0
222 var i: i64 = 0
223 while i < nadj {
224 o = wp_cat(out, o, idps[i] as *u8)
225 o = wp_cat(out, o, "\t(layer " as *u8)
226 o = wp_catn(out, o, layers[i])
227 o = wp_cat(out, o, ")\t<- " as *u8)
228 o = wp_cat(out, o, depps[i] as *u8)
229 o = wp_cat(out, o, " DONE\n" as *u8)
230 i = i + 1
231 }
232 out[o] = 0 as u8
233
234 stats[0] = nrows
235 stats[1] = ndone
236 stats[2] = nadj
237 stats[3] = nroot
238 stats[4] = nblock
239 return nadj
240}