code wiki / _hdl_build / nx_capgraph_edges_lib.nx
nx_capgraph_edges_lib.nx source
↩ module page · 591 lines · 19611 B
1// nx_capgraph_edges_lib.nx -- pure core for nx_capgraph_edges: ownership, resolution, closure walk.
2//
3// SPLIT OUT 2026-07-31 so the measuring organ can be GATED. By this ecosystem's own ladder (L5) a
4// capability with no non-vacuous gate is at most level 2 (WORKS), never 3 (GATED) -- and it would have
5// been dishonest for the organ that MEASURES capability levels to claim a level it had not earned. The
6// helpers below were unreachable from a gate while they sat beside a main(), so they moved here.
7// license_tier: ORIGINAL No hw writes (Rule 26).
8import "nx_capgraph_lib.nx"
9import "nx_tool_run.nx"
10
11const CE_CAP: i64 = 262144
12const CE_HEAD: i64 = 32768
13const CE_MAXDOM: i64 = 128
14const CE_MAXOWN: i64 = 2048
15const CE_MAXSRC: i64 = 2048
16const CE_MAXE: i64 = 1024
17const CE_NAMEW: i64 = 64
18const CE_PATHW: i64 = 160
19const CE_MAXQ: i64 = 512
20// NOT a code constant (rule 11). The transitive depth is read from CE_CFG at run time and its value is
21// JUSTIFIED BY A MEASURED CURVE (`--depthscan` prints edges-found per depth, so the cut is chosen where
22// the curve plateaus, not by taste). CE_DEPTH_FALLBACK applies only when the config row is absent, and
23// the emitted envelope says which of the two was used -- an unconfigured run must never look configured.
24const CE_DEPTH_FALLBACK: i64 = 3
25const CE_DEPTH_SCANMAX: i64 = 8
26const CE_CFG: *u8 = "knowledge/status/capgraph.conf" as *u8
27const CE_DEPTH_KEY_LEN: i64 = 17
28const CE_SHARED: i64 = 0 - 2
29const CE_SOTA: *u8 = "/volume1/homes/elderwesto/nishihost/nx_sota_status.elf" as *u8
30const CE_OUTDEF: *u8 = "knowledge/status/capgraph_edges.conf" as *u8
31
32static ce_dom: *u8
33static ce_ndom: i64
34static ce_ownname: *u8
35static ce_ownd: *i64
36static ce_nown: i64
37static ce_srcd: *i64
38static ce_srcp: *u8
39static ce_nsrc: i64
40static ce_ef: *i64
41static ce_et: *i64
42static ce_ne: i64
43static ce_if: *i64
44static ce_it: *i64
45static ce_nie: i64
46static ce_buf: *u8
47static ce_scr: *u8
48static ce_scr2: *u8
49static ce_path: *u8
50static ce_fd: i64
51static ce_missing: i64
52static ce_ambig: i64
53static ce_scanned: i64
54static ce_nonnx: i64
55static ce_altres: i64
56static ce_res_bld: i64
57static ce_res_srv: i64
58static ce_res_base: i64
59static ce_trans: i64
60static ce_q: *u8
61static ce_qd: *i64
62static ce_qh: i64
63static ce_qt: i64
64static ce_seen: *u8
65static ce_nseen: i64
66static ce_imp: *u8
67static ce_transedges: i64
68static ce_maxdepth: i64
69static ce_depthsrc: i64
70static ce_depthscan: i64
71static ce_enc: *u8
72static ce_encown: *i64
73static ce_enccnt: *i64
74static ce_encdom: *i64
75static ce_nenc: i64
76
77func ce_init() {
78 ce_ndom = 0
79 ce_nown = 0
80 ce_nsrc = 0
81 ce_ne = 0
82 ce_missing = 0
83 ce_ambig = 0
84 ce_scanned = 0
85 ce_nonnx = 0
86 ce_altres = 0
87 ce_res_bld = 0
88 ce_res_srv = 0
89 ce_res_base = 0
90 // TRANSITIVE IS THE DEFAULT. A domain can depend on another THROUGH shared infrastructure, and that
91 // build dependency is exactly as real as a direct import -- measured: it finds 7 more domain edges
92 // (13 -> 20) via 69 infra-mediated attributions, still sparse (20 of 756 possible) and deterministic.
93 // Defaulting to it is also the CONSERVATIVE choice: L4 edges only ever LOWER an effective level, so
94 // a found edge can never flatter, while a MISSING edge lets a dependent read healthier than the
95 // layer it stands on. `--direct` restores the strict one-hop subset.
96 ce_trans = 1
97 ce_transedges = 0
98 ce_qh = 0
99 ce_qt = 0
100 ce_nseen = 0
101 ce_q = sys_mmap(CE_MAXQ * CE_NAMEW + 64) as *u8
102 ce_qd = sys_mmap(CE_MAXQ * 8 + 64) as *i64
103 ce_seen = sys_mmap(CE_MAXQ * CE_NAMEW + 64) as *u8
104 ce_imp = sys_mmap(CE_NAMEW + 64) as *u8
105 ce_enc = sys_mmap(CE_MAXOWN * CE_NAMEW + 64) as *u8
106 ce_encown = sys_mmap(CE_MAXOWN * 8 + 64) as *i64
107 ce_enccnt = sys_mmap(CE_MAXOWN * 8 + 64) as *i64
108 ce_encdom = sys_mmap(CE_MAXOWN * 8 + 64) as *i64
109 ce_nenc = 0
110 ce_fd = 0 - 1
111 ce_dom = sys_mmap(CE_MAXDOM * CE_NAMEW + 64) as *u8
112 ce_ownname = sys_mmap(CE_MAXOWN * CE_NAMEW + 64) as *u8
113 ce_ownd = sys_mmap(CE_MAXOWN * 8 + 64) as *i64
114 ce_srcd = sys_mmap(CE_MAXSRC * 8 + 64) as *i64
115 ce_srcp = sys_mmap(CE_MAXSRC * CE_PATHW + 64) as *u8
116 ce_ef = sys_mmap(CE_MAXE * 8 + 64) as *i64
117 ce_et = sys_mmap(CE_MAXE * 8 + 64) as *i64
118 ce_if = sys_mmap(CE_MAXE * 8 + 64) as *i64
119 ce_it = sys_mmap(CE_MAXE * 8 + 64) as *i64
120 ce_nie = 0
121 ce_buf = sys_mmap(CE_CAP + 64) as *u8
122 ce_scr = sys_mmap(CE_PATHW + 64) as *u8
123 ce_scr2 = sys_mmap(CE_PATHW + 64) as *u8
124 ce_path = sys_mmap(CE_PATHW + 64) as *u8
125}
126
127func ce_cpy(dst: *u8, src: *u8, cap: i64) -> i64 {
128 var w: i64 = 0
129 var done: i64 = 0
130 while done == 0 {
131 let c: i64 = src[w] as i64
132 if c == 0 { done = 1 }
133 else {
134 if w >= cap - 1 { done = 1 }
135 else {
136 dst[w] = src[w]
137 w = w + 1
138 }
139 }
140 }
141 dst[w] = 0 as u8
142 return w
143}
144
145func ce_dom_add(nm: *u8) -> i64 {
146 if ce_ndom >= CE_MAXDOM { return 0 - 1 }
147 let id: i64 = ce_ndom
148 ce_cpy(((ce_dom as i64) + id * CE_NAMEW) as *u8, nm, CE_NAMEW)
149 ce_ndom = ce_ndom + 1
150 return id
151}
152
153func ce_dom_name(i: i64) -> *u8 {
154 return ((ce_dom as i64) + i * CE_NAMEW) as *u8
155}
156
157func ce_own_find(base: *u8) -> i64 {
158 var i: i64 = 0
159 var hit: i64 = 0 - 1
160 while i < ce_nown {
161 if cg_streq(((ce_ownname as i64) + i * CE_NAMEW) as *u8, base) == 1 {
162 hit = ce_ownd[i]
163 i = ce_nown
164 } else { i = i + 1 }
165 }
166 return hit
167}
168
169func ce_own_idx(base: *u8) -> i64 {
170 var i: i64 = 0
171 var hit: i64 = 0 - 1
172 while i < ce_nown {
173 if cg_streq(((ce_ownname as i64) + i * CE_NAMEW) as *u8, base) == 1 {
174 hit = i
175 i = ce_nown
176 } else { i = i + 1 }
177 }
178 return hit
179}
180
181// A module claimed by MORE THAN ONE domain is SHARED INFRASTRUCTURE, not owned -- importing it
182// establishes no DIRECTIONAL dependency. First-wins ownership was measured to make the majority of
183// edges ORDER-DEPENDENT (144 of 252 modules ambiguous; llm>modelwright and modelwright>llm both
184// derivable from the same corpus depending only on iteration order). Marking shared modules CE_SHARED
185// and excluding them makes the result DETERMINISTIC, and honours the banked law that a wrong answer is
186// worse than an absent one. Fewer sound edges beat more order-dependent ones.
187func ce_own_add(base: *u8, d: i64) {
188 if ce_nown >= CE_MAXOWN { return }
189 let at: i64 = ce_own_idx(base)
190 if at >= 0 {
191 if ce_ownd[at] != d {
192 if ce_ownd[at] != CE_SHARED {
193 ce_ownd[at] = CE_SHARED
194 ce_ambig = ce_ambig + 1
195 }
196 }
197 return
198 }
199 ce_cpy(((ce_ownname as i64) + ce_nown * CE_NAMEW) as *u8, base, CE_NAMEW)
200 ce_ownd[ce_nown] = d
201 ce_nown = ce_nown + 1
202}
203
204func ce_src_add(d: i64, path: *u8) {
205 if ce_nsrc >= CE_MAXSRC { return }
206 ce_srcd[ce_nsrc] = d
207 ce_cpy(((ce_srcp as i64) + ce_nsrc * CE_PATHW) as *u8, path, CE_PATHW)
208 ce_nsrc = ce_nsrc + 1
209}
210
211func ce_edge_add(a: i64, b: i64) {
212 if a < 0 { return }
213 if b < 0 { return }
214 if a == b { return }
215 if ce_ne >= CE_MAXE { return }
216 var i: i64 = 0
217 var dup: i64 = 0
218 while i < ce_ne {
219 if ce_ef[i] == a {
220 if ce_et[i] == b { dup = 1 }
221 }
222 i = i + 1
223 }
224 if dup == 1 { return }
225 ce_ef[ce_ne] = a
226 ce_et[ce_ne] = b
227 ce_ne = ce_ne + 1
228}
229
230// A SHARED module is not noise to be discarded -- it is INFRASTRUCTURE, and the domains importing it
231// all stand on it. Recording (module -> importing domain) keeps that dependency instead of throwing it
232// away, and makes the chokepoint visible: a module N domains import is exactly the lib worth migrating
233// first. Direction is unambiguous here because the module is the prerequisite in every case.
234func ce_infra_add(modidx: i64, d: i64) {
235 if modidx < 0 { return }
236 if d < 0 { return }
237 if ce_nie >= CE_MAXE { return }
238 var i: i64 = 0
239 var dup: i64 = 0
240 while i < ce_nie {
241 if ce_if[i] == modidx {
242 if ce_it[i] == d { dup = 1 }
243 }
244 i = i + 1
245 }
246 if dup == 1 { return }
247 ce_if[ce_nie] = modidx
248 ce_it[ce_nie] = d
249 ce_nie = ce_nie + 1
250}
251
252func ce_basename(src: *u8) {
253 var last: i64 = 0 - 1
254 var i: i64 = 0
255 while src[i] != (0 as u8) {
256 if src[i] == (47 as u8) { last = i }
257 i = i + 1
258 }
259 ce_cpy(ce_scr2, ((src as i64) + last + 1) as *u8, CE_PATHW)
260}
261
262func ce_join(pfx: *u8, sfx: *u8) {
263 var w: i64 = 0
264 var i: i64 = 0
265 while pfx[i] != (0 as u8) {
266 if w < CE_PATHW - 1 {
267 ce_path[w] = pfx[i]
268 w = w + 1
269 }
270 i = i + 1
271 }
272 var j: i64 = 0
273 while sfx[j] != (0 as u8) {
274 if w < CE_PATHW - 1 {
275 ce_path[w] = sfx[j]
276 w = w + 1
277 }
278 j = j + 1
279 }
280 ce_path[w] = 0 as u8
281}
282
283// A matrix row may cite a NON-SOURCE artifact (.js/.tsv/.md/.html/.spec). Those carry no NishiLang
284// imports and can never yield an edge -- counting them as "missing" conflated a FILE THAT IS ABSENT
285// with a FILE THAT IS NOT A SOURCE, which made the envelope dishonest in the direction that flatters.
286func ce_is_nx(p: *u8) -> i64 {
287 var n: i64 = 0
288 while p[n] != (0 as u8) { n = n + 1 }
289 if n < 3 { return 0 }
290 if p[n - 3] != (46 as u8) { return 0 }
291 if p[n - 2] != (110 as u8) { return 0 }
292 if p[n - 1] != (120 as u8) { return 0 }
293 return 1
294}
295
296// Extract pipe-delimited field `idx` from ce_buf[ls..le) into ce_scr.
297func ce_field(ls: i64, le: i64, idx: i64) -> i64 {
298 var f: i64 = 0
299 var w: i64 = 0
300 var i: i64 = ls
301 var done: i64 = 0
302 while done == 0 {
303 if i >= le { done = 1 }
304 else {
305 let c: i64 = ce_buf[i] as i64
306 if c == 124 {
307 f = f + 1
308 if f > idx { done = 1 }
309 else { i = i + 1 }
310 } else {
311 if f == idx {
312 if w < CE_PATHW - 1 {
313 ce_scr[w] = ce_buf[i]
314 w = w + 1
315 }
316 }
317 i = i + 1
318 }
319 }
320 }
321 ce_scr[w] = 0 as u8
322 return w
323}
324
325func ce_read_into_buf(path: *u8, cap: i64) -> i64 {
326 let fd: i64 = sys_openat_rd(path)
327 if fd < 0 { return 0 - 1 }
328 var total: i64 = 0
329 var done: i64 = 0
330 while done == 0 {
331 let want: i64 = cap - total
332 if want <= 0 { done = 1 }
333 else {
334 let got: i64 = sys_read(fd, ((ce_buf as i64) + total) as *u8, want)
335 if got <= 0 { done = 1 }
336 else { total = total + got }
337 }
338 }
339 sys_close(fd)
340 ce_buf[total] = 0 as u8
341 return total
342}
343
344func ce_w(s: *u8) {
345 var n: i64 = 0
346 while s[n] != (0 as u8) { n = n + 1 }
347 sys_write(ce_fd, s, n)
348}
349
350func ce_wi(x: i64) {
351 let b: *u8 = sys_mmap(64) as *u8
352 var v: i64 = x
353 var neg: i64 = 0
354 if v < 0 {
355 neg = 1
356 v = 0 - v
357 }
358 var i: i64 = 40
359 if v == 0 {
360 i = i - 1
361 b[i] = 48 as u8
362 }
363 while v > 0 {
364 let d: i64 = v - (v / 10) * 10
365 i = i - 1
366 b[i] = (d + 48) as u8
367 v = v / 10
368 }
369 if neg == 1 {
370 i = i - 1
371 b[i] = 45 as u8
372 }
373 sys_write(ce_fd, ((b as i64) + i) as *u8, 40 - i)
374}
375
376// OWNERSHIP COVERAGE, measured rather than asserted. Every module the closure actually touches is
377// recorded once, flagged by whether ANY domain owns it. An UNOWNED module is exactly where dependency
378// information dies: the closure walks through it but can attribute nothing on the far side. Reporting
379// owned/seen turns "coverage is bounded by the matrices" from a hand-wave into a number that updates
380// itself as the matrices grow.
381// ⚠RAW IMPORT COUNT RANKS THE WRONG THING -- measured, and nearly shipped. Sorting unowned modules by
382// hits puts nx_syscalls.nx (2129), nx_tier.nx (591), nx_sha256/nx_tls13/... on top: UNIVERSAL SUBSTRATE,
383// which must NEVER be domain-owned. Claiming one would fabricate edges from its "owner" to every domain.
384// The discriminator needs no new threshold, because the design already has a natural one: track how many
385// DISTINCT DOMAINS import each module. Imported by exactly ONE domain => unambiguously that domain's to
386// claim. Imported by many => substrate, and the right answer is to leave it unowned.
387func ce_enc_add(base: *u8, sd: i64) {
388 var i: i64 = 0
389 while i < ce_nenc {
390 if cg_streq(((ce_enc as i64) + i * CE_NAMEW) as *u8, base) == 1 {
391 ce_enccnt[i] = ce_enccnt[i] + 1
392 if ce_encdom[i] >= 0 {
393 if ce_encdom[i] != sd { ce_encdom[i] = CE_SHARED }
394 }
395 return
396 }
397 i = i + 1
398 }
399 if ce_nenc >= CE_MAXOWN { return }
400 ce_cpy(((ce_enc as i64) + ce_nenc * CE_NAMEW) as *u8, base, CE_NAMEW)
401 var owned: i64 = 0
402 if ce_own_idx(base) >= 0 { owned = 1 }
403 ce_encown[ce_nenc] = owned
404 ce_enccnt[ce_nenc] = 1
405 ce_encdom[ce_nenc] = sd
406 ce_nenc = ce_nenc + 1
407}
408
409func ce_enc_owned() -> i64 {
410 var c: i64 = 0
411 var i: i64 = 0
412 while i < ce_nenc {
413 if ce_encown[i] == 1 { c = c + 1 }
414 i = i + 1
415 }
416 return c
417}
418
419func ce_seen_has(base: *u8) -> i64 {
420 var i: i64 = 0
421 var hit: i64 = 0
422 while i < ce_nseen {
423 if cg_streq(((ce_seen as i64) + i * CE_NAMEW) as *u8, base) == 1 {
424 hit = 1
425 i = ce_nseen
426 } else { i = i + 1 }
427 }
428 return hit
429}
430
431func ce_qpush(base: *u8, depth: i64) {
432 if depth > ce_maxdepth { return }
433 if ce_qt >= CE_MAXQ { return }
434 if ce_nseen >= CE_MAXQ { return }
435 if ce_seen_has(base) == 1 { return }
436 ce_cpy(((ce_seen as i64) + ce_nseen * CE_NAMEW) as *u8, base, CE_NAMEW)
437 ce_nseen = ce_nseen + 1
438 ce_cpy(((ce_q as i64) + ce_qt * CE_NAMEW) as *u8, base, CE_NAMEW)
439 ce_qd[ce_qt] = depth
440 ce_qt = ce_qt + 1
441}
442
443// Resolve a bare module basename to a file and read it into ce_buf. Imports name a module, not a path,
444// so the two source dirs are the only places it can live.
445func ce_resolve_base(base: *u8) -> i64 {
446 ce_join("buildroot/runtime/" as *u8, base)
447 var n: i64 = ce_read_into_buf(ce_path, CE_HEAD)
448 if n < 0 {
449 ce_join("buildroot/runtime/_hdl_build/" as *u8, base)
450 n = ce_read_into_buf(ce_path, CE_HEAD)
451 }
452 return n
453}
454
455// Scan the CURRENT ce_buf for `import "<mod>"` lines and attribute each one to source-domain sd.
456// An OWNED module yields an edge immediately and is NOT followed -- the dependency is already
457// attributed. A SHARED or UNOWNED module is followed (when --transitive) because a domain can depend
458// on another THROUGH infrastructure, and that dependency is just as real as a direct one.
459// Names are copied into the queue before any further read, so the single shared buffer is safe.
460func ce_scan_buf_imports(sd: i64, depth: i64, n: i64) {
461 var fls: i64 = 0
462 var f: i64 = 0
463 while f <= n {
464 var fe: i64 = 0
465 if f == n { fe = 1 }
466 else { if ce_buf[f] == (10 as u8) { fe = 1 } }
467 if fe == 1 {
468 var isimp: i64 = 0
469 if fls + 8 < f {
470 if ce_buf[fls] == (105 as u8) {
471 if ce_buf[fls + 1] == (109 as u8) {
472 if ce_buf[fls + 2] == (112 as u8) {
473 if ce_buf[fls + 3] == (111 as u8) {
474 if ce_buf[fls + 4] == (114 as u8) {
475 if ce_buf[fls + 5] == (116 as u8) { isimp = 1 }
476 }
477 }
478 }
479 }
480 }
481 }
482 if isimp == 1 {
483 var q1: i64 = 0 - 1
484 var z: i64 = fls
485 while z < f {
486 if ce_buf[z] == (34 as u8) {
487 if q1 < 0 { q1 = z }
488 }
489 z = z + 1
490 }
491 if q1 > 0 {
492 var w2: i64 = 0
493 var y: i64 = q1 + 1
494 var dd: i64 = 0
495 while dd == 0 {
496 if y >= f { dd = 1 }
497 else {
498 if ce_buf[y] == (34 as u8) { dd = 1 }
499 else {
500 if w2 < CE_NAMEW - 1 {
501 ce_imp[w2] = ce_buf[y]
502 w2 = w2 + 1
503 }
504 y = y + 1
505 }
506 }
507 }
508 ce_imp[w2] = 0 as u8
509 if w2 > 0 {
510 ce_enc_add(ce_imp, sd)
511 let midx: i64 = ce_own_idx(ce_imp)
512 if midx >= 0 {
513 let owner: i64 = ce_ownd[midx]
514 if owner >= 0 {
515 if owner != sd {
516 if depth > 1 { ce_transedges = ce_transedges + 1 }
517 }
518 ce_edge_add(owner, sd)
519 }
520 if owner == CE_SHARED {
521 ce_infra_add(midx, sd)
522 if ce_trans == 1 { ce_qpush(ce_imp, depth + 1) }
523 }
524 } else {
525 if ce_trans == 1 { ce_qpush(ce_imp, depth + 1) }
526 }
527 }
528 }
529 }
530 fls = f + 1
531 }
532 f = f + 1
533 }
534}
535
536// Depth comes from a CONFIG ROW, never a code constant (rule 11). An absent config yields the declared
537// fallback AND records that fact in ce_depthsrc, so the emitted envelope can never claim "configured"
538// when nothing configured it -- a silently-defaulted knob is indistinguishable from a chosen one.
539func ce_load_depth() {
540 ce_maxdepth = CE_DEPTH_FALLBACK
541 ce_depthsrc = 0
542 let cl: *i64 = sys_mmap(16) as *i64
543 let cb: *u8 = sys_read_file(CE_CFG, cl)
544 let n: i64 = cl[0]
545 if n <= 0 { return }
546 let key: *u8 = "transitive_depth=" as *u8
547 var i: i64 = 0
548 var done: i64 = 0
549 while done == 0 {
550 if i + CE_DEPTH_KEY_LEN >= n { done = 1 }
551 else {
552 var k: i64 = 0
553 var ok: i64 = 1
554 while k < CE_DEPTH_KEY_LEN {
555 if cb[i + k] != key[k] { ok = 0 }
556 k = k + 1
557 }
558 if ok == 1 {
559 var v: i64 = 0
560 var any: i64 = 0
561 var j: i64 = i + CE_DEPTH_KEY_LEN
562 var d2: i64 = 0
563 while d2 == 0 {
564 if j >= n { d2 = 1 }
565 else {
566 let c: i64 = cb[j] as i64
567 if c < 48 { d2 = 1 }
568 else {
569 if c > 57 { d2 = 1 }
570 else {
571 v = v * 10 + (c - 48)
572 any = 1
573 j = j + 1
574 }
575 }
576 }
577 }
578 if any == 1 {
579 if v >= 1 {
580 if v <= CE_DEPTH_SCANMAX {
581 ce_maxdepth = v
582 ce_depthsrc = 1
583 }
584 }
585 }
586 done = 1
587 } else { i = i + 1 }
588 }
589 }
590}
591