code wiki / (root) / nx_importcensus.nx

nx_importcensus.nx source

↩ module page · 171 lines · 9533 B

1// nx_importcensus.nx -- IMPORTER REACH PER SOURCE FILE, as a flat, stamped artifact (2026-08-23, compare CE2). 2// 3// WHY: about half of a /compare board's rows name a LIBRARY -- no top-level main(), no binary by design -- 4// and for a library the adoption question is IMPORTER COUNT (nx_catalog's own verdict text), which nothing 5// published per name. The import graph already exists: knowledge/store/ecograph_full, walked from 6// buildroot/runtime by the nx_eco_graph_build pin and judged daily by nx_arch_board. It lives in a seg-store 7// that costs a load to ask, and a board classifies ~40 rows per emit across ~70 domains per regen beat. 8// ONE load here, one flat TSV for every consumer, is the syscalls-per-unit-of-output discipline (rule F). 9// 10// ROWS name<TAB>importers<TAB>importers_nonval<TAB>imports<TAB>first_nonval_importer 11// importers direct fan-in Ca from the graph: every source that imports this one 12// importers_nonval the same minus VALIDATION importers -- sources named *_gate.nx *_test.nx *_bench.nx 13// *_demo.nx *_probe.nx *_smoke.nx *_kat.nx *_negtest.nx (the suffix taxonomy 14// nx_eco_graph_honesty's histe() applies). A lib imported ONLY by its own gate is the 15// BUILT+UNWIRED class (LN8 eqsat, measured 2026-08-23), and THAT is the number a board 16// needs: a gate importing a lib proves the lib is tested, never that it is used. 17// imports fan-out Ce (what this source imports), printed so a reader can tell a leaf from a hub 18// first_nonval_importer one witness name (presence needs one witness), "-" when there is none 19// LAST LINE (the canonical verdict row, anchored BY POSITION -- consumers read the last line, never grep): 20// # asof=<epoch> store=<prefix> nodes=N edges=M rows=N has_nonval=A val_only=B orphan=C 21// nonval_excludes=_gate,_test,_bench,_demo,_probe,_smoke,_kat,_negtest 22// A + B + C == rows is the partition, printed by the organ and checked by its gate. 23// FRESHNESS IS THE CONSUMER'S TO JUDGE from asof=; this organ never overwrites a good artifact with a bad 24// one: an unreadable store writes NOTHING (exit 3), so a stale file stays visibly stale by its own stamp. 25// 26// usage: nx_importcensus [store-prefix] [out-path] 27// defaults knowledge/store/ecograph_full knowledge/status/importers.tsv 28// exit 0 written (tmp + fsync + rename: a reader never sees a half file) | 3 UNOBSERVABLE store | 4 write failed 29// license_tier: ORIGINAL Read-only over the estate except its one artifact. No hw writes (Rule 26). 30import "nx_syscalls.nx" 31import "nx_eco_graph.nx" 32 33const IC_DEC_MAX: i64 = 20 // digits of an i64 plus sign: the width of one rendered number 34const IC_ROW_FIXED: i64 = 4 + 3 * IC_DEC_MAX + 2 // tabs + three numbers + the "-" witness + newline 35const IC_TAIL_FIXED: i64 = 512 // the stamped last line: keys + six numbers + the suffix list 36const IC_NSUFFIX: i64 = 8 37 38func ic_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 39func ic_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 40func ic_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; var p: i64 = o; while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } return p } 41func ic_catn(d: *u8, o: i64, v: i64) -> i64 { 42 var p: i64 = o 43 var m: i64 = v 44 if m < 0 { d[p] = 45 as u8; p = p + 1; m = 0 - m } 45 let t: *u8 = sys_mmap(IC_DEC_MAX + 4) 46 var k: i64 = 0 47 if m == 0 { t[0] = 48 as u8; k = 1 } 48 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 49 var j: i64 = 0 50 while j < k { d[p] = t[k - 1 - j]; p = p + 1; j = j + 1 } 51 sys_munmap(t, IC_DEC_MAX + 4) 52 return p 53} 54func ic_putn(v: i64) -> i64 { let b: *u8 = sys_mmap(IC_DEC_MAX + 4); let n: i64 = ic_catn(b, 0, v); sys_write(1, b, n); sys_munmap(b, IC_DEC_MAX + 4); return 0 } 55 56// the validation-suffix taxonomy, as DATA the gate can read back from the artifact's last line 57func ic_suffix(i: i64) -> *u8 { 58 if i == 0 { return "_gate.nx" as *u8 } 59 if i == 1 { return "_test.nx" as *u8 } 60 if i == 2 { return "_bench.nx" as *u8 } 61 if i == 3 { return "_demo.nx" as *u8 } 62 if i == 4 { return "_probe.nx" as *u8 } 63 if i == 5 { return "_smoke.nx" as *u8 } 64 if i == 6 { return "_kat.nx" as *u8 } 65 return "_negtest.nx" as *u8 66} 67// 1 when the basename ends with a validation suffix (a gate, test, bench, demo, probe, smoke, kat, negtest) 68func ic_is_val(name: *u8) -> i64 { 69 let nl: i64 = ic_slen(name) 70 var i: i64 = 0 71 while i < IC_NSUFFIX { 72 let sfx: *u8 = ic_suffix(i) 73 let sl: i64 = ic_slen(sfx) 74 if nl > sl { 75 var k: i64 = 0 76 var same: i64 = 1 77 while k < sl { if name[nl - sl + k] != sfx[k] { same = 0; k = sl } else { k = k + 1 } } 78 if same == 1 { return 1 } 79 } 80 i = i + 1 81 } 82 return 0 83} 84func ic_name(g: *EcoGraph, idx: i64) -> *u8 { return ((g.arena as i64) + g.node_off[idx]) as *u8 } 85 86func main(argc: i64, argv: *i64) -> i64 { 87 var prefix: *u8 = "knowledge/store/ecograph_full" as *u8 88 var outp: *u8 = "knowledge/status/importers.tsv" as *u8 89 if argc > 1 { prefix = argv[1] as *u8 } 90 if argc > 2 { outp = argv[2] as *u8 } 91 let g: *EcoGraph = eg_load(prefix) 92 if (g as i64) == 0 { 93 ic_puts("NX-IMPORTCENSUS UNOBSERVABLE: store unreadable at " as *u8); ic_puts(prefix) 94 ic_puts(" -- nothing written, the existing artifact (if any) keeps its own asof= stamp\n" as *u8) 95 sys_exit(3); return 3 96 } 97 let n: i64 = g.node_count 98 // BUFFER DERIVED FROM THE DATA IT HOLDS: every row is a name plus a witness name (both from the arena, 99 // so 2 x arena_used bounds them together) plus the fixed row skeleton; then the stamped tail. 100 let cap: i64 = 2 * g.arena_used + n * IC_ROW_FIXED + IC_TAIL_FIXED + ic_slen(prefix) 101 let out: *u8 = sys_mmap(cap) 102 var o: i64 = 0 103 var has_nonval: i64 = 0 104 var val_only: i64 = 0 105 var orphan: i64 = 0 106 var i: i64 = 0 107 while i < n { 108 let ca: i64 = eg_ca(g, i) 109 var nonval: i64 = 0 110 var first: i64 = 0 - 1 111 var j: i64 = g.in_head[i] 112 let je: i64 = g.in_head[i + 1] 113 while j < je { 114 let src: i64 = g.in_list[j] 115 if ic_is_val(ic_name(g, src)) == 0 { nonval = nonval + 1; if first < 0 { first = src } } 116 j = j + 1 117 } 118 if ca == 0 { orphan = orphan + 1 } else { if nonval > 0 { has_nonval = has_nonval + 1 } else { val_only = val_only + 1 } } 119 o = ic_cat(out, o, ic_name(g, i)); out[o] = 9 as u8; o = o + 1 120 o = ic_catn(out, o, ca); out[o] = 9 as u8; o = o + 1 121 o = ic_catn(out, o, nonval); out[o] = 9 as u8; o = o + 1 122 o = ic_catn(out, o, eg_ce(g, i)); out[o] = 9 as u8; o = o + 1 123 if first >= 0 { o = ic_cat(out, o, ic_name(g, first)) } else { out[o] = 45 as u8; o = o + 1 } 124 out[o] = 10 as u8; o = o + 1 125 i = i + 1 126 } 127 let asof: i64 = sys_now_realtime_sec() 128 o = ic_cat(out, o, "# asof=" as *u8); o = ic_catn(out, o, asof) 129 o = ic_cat(out, o, " store=" as *u8); o = ic_cat(out, o, prefix) 130 o = ic_cat(out, o, " nodes=" as *u8); o = ic_catn(out, o, n) 131 o = ic_cat(out, o, " edges=" as *u8); o = ic_catn(out, o, g.edge_count) 132 o = ic_cat(out, o, " rows=" as *u8); o = ic_catn(out, o, n) 133 o = ic_cat(out, o, " has_nonval=" as *u8); o = ic_catn(out, o, has_nonval) 134 o = ic_cat(out, o, " val_only=" as *u8); o = ic_catn(out, o, val_only) 135 o = ic_cat(out, o, " orphan=" as *u8); o = ic_catn(out, o, orphan) 136 o = ic_cat(out, o, " nonval_excludes=" as *u8) 137 var si: i64 = 0 138 while si < IC_NSUFFIX { 139 if si > 0 { out[o] = 44 as u8; o = o + 1 } 140 let sfx: *u8 = ic_suffix(si) 141 let sl: i64 = ic_slen(sfx) - 3 // drop the ".nx" so the list reads as suffixes, not files 142 var c: i64 = 0 143 while c < sl { out[o] = sfx[c]; o = o + 1; c = c + 1 } 144 si = si + 1 145 } 146 out[o] = 10 as u8; o = o + 1 147 // TRUNCATE-WRITE, ATOMIC: tmp beside the target, fsync, rename -- a consumer never reads a half file 148 let tmp: *u8 = sys_mmap(ic_slen(outp) + 8) 149 var to: i64 = ic_cat(tmp, 0, outp); to = ic_cat(tmp, to, ".tmp" as *u8); tmp[to] = 0 as u8 150 let fd: i64 = sys_openat_wr(tmp, MODE_0644) 151 if fd < 0 { ic_puts("NX-IMPORTCENSUS WRITE-FAILED: cannot open " as *u8); ic_puts(tmp); ic_puts("\n" as *u8); sys_exit(4); return 4 } 152 var wrote: i64 = 0 153 while wrote < o { 154 let w: i64 = sys_write(fd, ((out as i64) + wrote) as *u8, o - wrote) 155 if w <= 0 { sys_close(fd); ic_puts("NX-IMPORTCENSUS WRITE-FAILED: short write\n" as *u8); sys_exit(4); return 4 } 156 wrote = wrote + w 157 } 158 sys_fsync(fd) 159 sys_close(fd) 160 if sys_renameat(tmp, outp) != 0 { ic_puts("NX-IMPORTCENSUS WRITE-FAILED: rename\n" as *u8); sys_exit(4); return 4 } 161 // the receipt repeats the partition so a reader of stdout and a reader of the file see one number 162 ic_puts("NX-IMPORTCENSUS rows=" as *u8); ic_putn(n) 163 ic_puts(" has_nonval=" as *u8); ic_putn(has_nonval) 164 ic_puts(" val_only=" as *u8); ic_putn(val_only) 165 ic_puts(" orphan=" as *u8); ic_putn(orphan) 166 ic_puts(" sum=" as *u8); ic_putn(has_nonval + val_only + orphan) 167 ic_puts(" edges=" as *u8); ic_putn(g.edge_count) 168 ic_puts(" asof=" as *u8); ic_putn(asof) 169 ic_puts(" wrote=" as *u8); ic_putn(o); ic_puts(" of=" as *u8); ic_puts(outp); ic_puts("\n" as *u8) 170 return 0 171}