code wiki / _hdl_build / nx_eco_graph_build.nx

nx_eco_graph_build.nx source

↩ module page · 237 lines · 12074 B

1// nx_eco_graph_build.nx -- R0 brick-3: the LIVE whole-tree walk that POPULATES the ecosystem graph from real 2// organs, then answers the operator's query. Composes nx_dr_tree's getdents recursion + nx_import_scan (accurate 3// edges) + nx_eco_graph (queries). Usage: nx_eco_graph_build <root-dir> [query-basename] 4// no query -> summary (nodes, edges, files, top hub, orphan count) 5// query X.nx -> its ROOTS-TO-GOD (transitive imports/ancestors), CHILDREN (transitive importers), Ca/Ce. 6// license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_eco_graph.nx" 9import "nx_import_scan.nx" 10import "nx_heavyio_lib.nx" // THE CLASS BOUND (hub-spoke, 2026-09-03): this WALK is a declared heavy-I/O producer 11const EGB_MAGIC_3900: i64 = 3900 12const EGB_MAGIC_131072: i64 = 131072 13const EGB_MAGIC_1024: i64 = 1024 14const EGB_MAGIC_4096: i64 = 4096 15 16const EGB_MAXNODE: i64 = 24000 17const EGB_MAXEDGE: i64 = 300000 18const EGB_ARENA: i64 = 4194304 19const EGB_HASH: i64 = 65536 20const EGB_FILECAP: i64 = 262144 21 22func bw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 23func bn(v: i64) -> i64 { let b: *u8=sys_mmap(24); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m} let t: *u8=sys_mmap(24); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var j: i64=0; while j<k{b[j]=t[k-1-j];j=j+1} sys_write(1,b,k); return 0 } 24func bslen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 25 26func egb_is_nx(nm: *u8, n: i64) -> i64 { 27 if n < 4 { return 0 } 28 if nm[n-3] != (46 as u8) { return 0 } 29 if nm[n-2] != (110 as u8) { return 0 } 30 if nm[n-1] != (120 as u8) { return 0 } 31 return 1 32} 33// append "/name" to path at base_n; return new length (NOT NUL-terminated here). 34func egb_join(path: *u8, base_n: i64, nm: *u8) -> i64 { 35 path[base_n] = 47 as u8 36 var o: i64 = base_n + 1 37 var i: i64 = 0 38 while nm[i] != (0 as u8) { path[o] = nm[i]; o = o + 1; i = i + 1 } 39 return o 40} 41func egb_read(path: *u8, buf: *u8, cap: i64) -> i64 { 42 let fd: i64 = sys_openat_rd(path) 43 if fd < 0 { return 0 } 44 var total: i64 = 0 45 var go: i64 = 1 46 while go == 1 { 47 let nr: i64 = sys_read(fd, ((buf as i64)+total) as *u8, cap - total) 48 if nr <= 0 { go = 0 } else { total = total + nr; if total >= cap { go = 0 } } 49 } 50 sys_close(fd) 51 return total 52} 53func egb_isdotdot(nm: *u8) -> i64 { 54 if nm[0] == (46 as u8) { if nm[1] == (0 as u8) { return 1 } if nm[1] == (46 as u8) { if nm[2] == (0 as u8) { return 1 } } } 55 return 0 56} 57// recursive walk: st[0]=files scanned, st[1]=edges added 58func egb_walk(g: *EcoGraph, path: *u8, path_n: i64, filebuf: *u8, aoff: *i64, alen: *i64, st: *i64) -> i64 { 59 if path_n > EGB_MAGIC_3900 { return 0 } 60 path[path_n] = 0 as u8 61 let fd: i64 = sys_openat_rd(path) 62 if fd < 0 { return 0 } 63 let dbuf: *u8 = sys_mmap(EGB_MAGIC_131072) 64 var go: i64 = 1 65 while go == 1 { 66 let nr: i64 = sys_getdents64(fd, dbuf, EGB_MAGIC_131072) 67 if nr <= 0 { go = 0 } else { 68 var off: i64 = 0 69 while off < nr { 70 let rec: *u8 = ((dbuf as i64) + off) as *u8 71 let ty: i64 = dirent_type(rec) 72 let nm: *u8 = dirent_name(rec) 73 if egb_isdotdot(nm) == 0 { 74 let cs: i64 = egb_join(path, path_n, nm) 75 if ty == 4 { 76 egb_walk(g, path, cs, filebuf, aoff, alen, st) 77 } else { 78 let nmn: i64 = bslen(nm) 79 if egb_is_nx(nm, nmn) == 1 { 80 let fnode: i64 = eg_intern(g, nm, nmn) 81 if fnode >= 0 { 82 path[cs] = 0 as u8 83 let flen: i64 = egb_read(path, filebuf, EGB_FILECAP) 84 if flen > 0 { 85 let ic: i64 = nis_scan(filebuf, flen, aoff, alen, EGB_MAGIC_1024) 86 var k: i64 = 0 87 while k < ic { 88 // basename of the import path (strip dir prefix) 89 let io: i64 = aoff[k] 90 let il: i64 = alen[k] 91 var bs: i64 = io 92 var j: i64 = io 93 while j < io + il { if filebuf[j] == (47 as u8) { bs = j + 1 } j = j + 1 } 94 let bl: i64 = (io + il) - bs 95 let inode: i64 = eg_intern(g, ((filebuf as i64)+bs) as *u8, bl) 96 if inode >= 0 { eg_add_edge(g, fnode, inode); st[1] = st[1] + 1 } 97 k = k + 1 98 } 99 st[0] = st[0] + 1 100 } 101 } 102 } 103 } 104 } 105 off = off + dirent_reclen(rec) 106 } 107 } 108 } 109 sys_close(fd) 110 sys_munmap(dbuf, EGB_MAGIC_131072) 111 return 0 112} 113 114func egb_printname(g: *EcoGraph, idx: i64) -> i64 { 115 let off: i64 = g.node_off[idx] 116 var i: i64 = 0 117 while g.arena[off+i] != (0 as u8) { i = i + 1 } 118 sys_write(1, ((g.arena as i64)+off) as *u8, i) 119 return 0 120} 121 122func bq() -> i64 { let c: *u8 = sys_mmap(1); c[0] = 34 as u8; sys_write(1, c, 1); return 0 } 123func egb_jname(g: *EcoGraph, idx: i64) -> i64 { bq(); egb_printname(g, idx); bq(); return 0 } 124// R1-b: emit the query result as JSON (the API/MCP response contract) from a LOADED store. 125func egb_json_query(g: *EcoGraph, q: *u8) -> i64 { 126 let qi: i64 = eg_find(g, q, bslen(q)) 127 bw("{" as *u8); bq(); bw("node" as *u8); bq(); bw(":" as *u8); bq(); bw(q); bq() 128 if qi < 0 { bw("," as *u8); bq(); bw("found" as *u8); bq(); bw(":false}\n" as *u8); return 0 } 129 bw("," as *u8); bq(); bw("found" as *u8); bq(); bw(":true," as *u8); bq(); bw("ca" as *u8); bq(); bw(":" as *u8); bn(eg_ca(g, qi)) 130 bw("," as *u8); bq(); bw("ce" as *u8); bq(); bw(":" as *u8); bn(eg_ce(g, qi)) 131 bw("," as *u8); bq(); bw("orphan" as *u8); bq(); bw(":" as *u8) 132 if eg_ca(g, qi) == 0 { bw("true" as *u8) } else { bw("false" as *u8) } 133 let vis: *u8 = sys_mmap(EGB_MAXNODE) 134 let out: *i64 = sys_mmap(EGB_MAXNODE*8) as *i64 135 let on: *i64 = sys_mmap(8) as *i64 136 var z: i64 = 0 137 while z < g.node_count { vis[z] = 0 as u8; z = z + 1 } 138 on[0] = 0; vis[qi] = 1 as u8 139 eg_ancestors(g, qi, vis, out, on, EGB_MAXNODE) 140 bw("," as *u8); bq(); bw("roots_to_god" as *u8); bq(); bw(":[" as *u8) 141 var k: i64 = 0 142 while k < on[0] { if k > 0 { bw("," as *u8) } egb_jname(g, out[k]); k = k + 1 } 143 bw("]" as *u8) 144 z = 0 145 while z < g.node_count { vis[z] = 0 as u8; z = z + 1 } 146 on[0] = 0; vis[qi] = 1 as u8 147 eg_descendants(g, qi, vis, out, on, EGB_MAXNODE) 148 bw("," as *u8); bq(); bw("children_count" as *u8); bq(); bw(":" as *u8); bn(on[0]) 149 bw("," as *u8); bq(); bw("children" as *u8); bq(); bw(":[" as *u8) 150 k = 0 151 while k < on[0] { if k < 200 { if k > 0 { bw("," as *u8) } egb_jname(g, out[k]) } k = k + 1 } 152 bw("]}\n" as *u8) 153 return 0 154} 155 156const EGB_EXIT_DEFER: i64 = 4 // the estate's deferred/refused code (nx_memvel, nx_plan_run): the clock requeues on it 157 158func main(argc: i64, argv: *i64) -> i64 { 159 if argc < 2 { bw("usage: nx_eco_graph_build <root> [query] [save-prefix] | --load <store-prefix> <query>\n" as *u8); return 2 } 160 let a1: *u8 = argv[1] as *u8 161 // ---- QUERY-ONLY from the SOVEREIGN seg_store (no walk; pure JSON = the API/MCP entry) ---- 162 if a1[0] == (45 as u8) { 163 if argc < 4 { bw("usage: nx_eco_graph_build --load <store-prefix> <query>\n" as *u8); return 2 } 164 let gl: *EcoGraph = eg_load(argv[2] as *u8) 165 if (gl as i64) == 0 { bw("{" as *u8); bq(); bw("error" as *u8); bq(); bw(":" as *u8); bq(); bw("store_not_found" as *u8); bq(); bw("}\n" as *u8); return 3 } 166 egb_json_query(gl, argv[3] as *u8) 167 return 0 168 } 169 // ---- THE CLASS BOUND (hub-spoke, 2026-09-03), before the walk: this organ is a declared heavy-I/O 170 // producer in knowledge/heavyio.conf. hio_admit counts the class RUNNING across every launch surface 171 // against the derived width, with the storm witness as its second conjunct. The --load query path above 172 // is pure JSON and never admits. DEFER -> named refusal, exit EGB_EXIT_DEFER (the clock requeues); 173 // UNOBSERVABLE -> announced, proceed. The conf is at the estate root; the ../ twin covers a build-root CWD. 174 let hio: *i64 = sys_mmap(32) as *i64 175 var hv: i64 = hio_admit(hio) 176 if hv == HIO_UNOBSERVABLE { hv = hio_admit_conf("../knowledge/heavyio.conf" as *u8, hio) } 177 hio_announce(1, hv, hio) 178 if hv == HIO_DEFER { bw("REFUSED-HEAVYIO: the heavy-I/O class bound is reached; this walk would only deepen the storm -- requeue and re-fire when the HEAVYIO line reads ADMIT\n" as *u8); return EGB_EXIT_DEFER } 179 let root: *u8 = argv[1] as *u8 180 let g: *EcoGraph = eg_new(EGB_MAXNODE, EGB_MAXEDGE, EGB_ARENA, EGB_HASH) 181 let path: *u8 = sys_mmap(EGB_MAGIC_4096) 182 var rn: i64 = 0 183 while root[rn] != (0 as u8) { path[rn] = root[rn]; rn = rn + 1 } 184 let filebuf: *u8 = sys_mmap(EGB_FILECAP) 185 let aoff: *i64 = sys_mmap(EGB_MAGIC_1024*8) as *i64 186 let alen: *i64 = sys_mmap(EGB_MAGIC_1024*8) as *i64 187 let st: *i64 = sys_mmap(16) as *i64 188 st[0] = 0; st[1] = 0 189 bw("=== nx_eco_graph_build: living ecosystem graph over " as *u8); bw(root); bw(" ===\n" as *u8) 190 egb_walk(g, path, rn, filebuf, aoff, alen, st) 191 eg_finalize(g) // R0b: CSR adjacency + degree arrays -> O(1) coupling, O(reachable) traversals at 16k scale 192 bw(" nodes=" as *u8); bn(g.node_count); bw(" edges=" as *u8); bn(g.edge_count); bw(" files_scanned=" as *u8); bn(st[0]); bw("\n" as *u8) 193 if argc >= 4 { eg_save(g, argv[3] as *u8); bw(" SAVED to sovereign seg_store: " as *u8); bw(argv[3] as *u8); bw("\n" as *u8) } 194 195 // orphan count (Ca==0) + top hub (max Ca) 196 var orphans: i64 = 0 197 var hub: i64 = 0 198 var hubca: i64 = 0 199 var i: i64 = 0 200 while i < g.node_count { 201 let ca: i64 = eg_ca(g, i) 202 if ca == 0 { orphans = orphans + 1 } 203 if ca > hubca { hubca = ca; hub = i } 204 i = i + 1 205 } 206 bw(" top hub (most imported): " as *u8); egb_printname(g, hub); bw(" (Ca=" as *u8); bn(hubca); bw(") Ca==0 nodes=" as *u8); bn(orphans); bw(" (entry-points + orphans)\n" as *u8) 207 208 if argc >= 3 { 209 let q: *u8 = argv[2] as *u8 210 let qi: i64 = eg_intern(g, q, bslen(q)) 211 bw("\n QUERY " as *u8); bw(q); bw(" Ca(importers)=" as *u8); bn(eg_ca(g, qi)); bw(" Ce(imports)=" as *u8); bn(eg_ce(g, qi)); bw("\n" as *u8) 212 let vis: *u8 = sys_mmap(EGB_MAXNODE) 213 let out: *i64 = sys_mmap(EGB_MAXNODE*8) as *i64 214 let on: *i64 = sys_mmap(8) as *i64 215 // roots-to-god 216 var z: i64 = 0 217 while z < g.node_count { vis[z] = 0 as u8; z = z + 1 } 218 on[0] = 0; vis[qi] = 1 as u8 219 eg_ancestors(g, qi, vis, out, on, EGB_MAXNODE) 220 bw(" ROOTS-TO-GOD (" as *u8); bn(on[0]); bw(" transitive ancestors):\n " as *u8) 221 var k: i64 = 0 222 while k < on[0] { egb_printname(g, out[k]); bw(" " as *u8); k = k + 1 } 223 bw("\n" as *u8) 224 // children-to-newest 225 z = 0 226 while z < g.node_count { vis[z] = 0 as u8; z = z + 1 } 227 on[0] = 0; vis[qi] = 1 as u8 228 eg_descendants(g, qi, vis, out, on, EGB_MAXNODE) 229 bw(" CHILDREN-TO-NEWEST (" as *u8); bn(on[0]); bw(" transitive importers):\n " as *u8) 230 k = 0 231 while k < on[0] { if k < 40 { egb_printname(g, out[k]); bw(" " as *u8) } k = k + 1 } 232 if on[0] > 40 { bw("... (+" as *u8); bn(on[0]-40); bw(" more)" as *u8) } 233 bw("\n" as *u8) 234 } 235 bw("=== eco-graph built (living: re-run to refresh; brick-3 live) ===\n" as *u8) 236 return 0 237}