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}