code wiki / (root) / nx_field_seedgen.nx

nx_field_seedgen.nx source

↩ module page · 148 lines · 7942 B

1// nx_field_seedgen.nx -- DERIVE A DOMAIN'S SEEDS FROM ITS OWN BOARD (/compare/fieldwatch fleet campaign, 2026-09-05). 2// The first fieldbeat skipped 110 of 111 domains for having no .seeds file. Every one of them already declares its 3// population -- the @cols rivals of <dom>.matrix -- and pins their pages in <dom>.refs. This program writes <dom>.seeds 4// rows of kind named from those two files (decisions in nx_field_seedgen_lib), so the next beat discovers a field for 5// every board without a seat authoring URLs, and it never guesses: an unsourced column is a counted comment, a file a 6// seat curated by hand (no marker line) is refused untouched, and a domain with nothing sourced gets NO file so the 7// beat keeps skipping it cleanly. Discovery seeds (wiki-raw, gh-topic, md-list) remain per-domain curation. 8// Usage: nx_field_seedgen <dom> | --all [--dir <compare-dir>] [--list <regen-list>] 9// Receipt per domain: SEEDGEN dom= class= cols= sourced= unsourced= out=; summary SEEDGEN-OK ... sum= (partition printed) 10// Exits: 0 | 1 a domain was UNWRITABLE | 2 usage | 3 refused (single domain: hand-authored, no matrix, no cols or nothing sourced; 11// --all: the list was unreadable or named no domain) 12// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 13import "nx_syscalls.nx" 14import "nx_field_seedgen_lib.nx" 15 16const SGP_ROOT: *u8 = "/volume1/homes/elderwesto/nishihost/" 17const SGP_DIR_DEFAULT: *u8 = "buildroot/knowledge/compare/" 18const SGP_LIST_DEFAULT: *u8 = "buildroot/knowledge/compare/regen.list" 19const SGP_PATH_CAP: i64 = 1024 20const SGP_EXIT_RED: i64 = 1 21const SGP_EXIT_USAGE: i64 = 2 22const SGP_EXIT_REFUSE: i64 = 3 23const SGP_OUTFD: i64 = 1 24const SGP_ERRFD: i64 = 2 25const SGP_T_COLS: i64 = 0 // totals vector slots 26const SGP_T_SOURCED: i64 = 1 27const SGP_T_UNSOURCED: i64 = 2 28const SGP_T_N: i64 = 3 29 30func sgp_out(s: *u8) -> i64 { fb_puts(SGP_OUTFD, s); return 0 } 31func sgp_err(s: *u8) -> i64 { fb_puts(SGP_ERRFD, s); return 0 } 32func sgp_read(path: *u8, lenout: *i64) -> *u8 { 33 let lp: *i64 = sys_mmap(16) as *i64 34 let b: *u8 = sys_read_file(path, lp) 35 if (b as i64) == 0 { lenout[0] = 0; return 0 as *u8 } 36 lenout[0] = lp[0] 37 return b 38} 39func sgp_path(dst: *u8, dir: *u8, dom: *u8, ext: *u8) -> i64 { 40 var o: i64 = fb_cat(dst, 0, dir, SGP_PATH_CAP) 41 o = fb_cat(dst, o, dom, SGP_PATH_CAP) 42 return fb_cat(dst, o, ext, SGP_PATH_CAP) 43} 44 45// ONE domain: read matrix + refs + any existing seeds, decide, write. Returns the class; tot accumulates cols/sourced/unsourced. 46func sg_one(dir: *u8, dom: *u8, ts: i64, tot: *i64) -> i64 { 47 let mp: *u8 = sys_mmap(SGP_PATH_CAP) 48 let rp: *u8 = sys_mmap(SGP_PATH_CAP) 49 let sp: *u8 = sys_mmap(SGP_PATH_CAP) 50 sgp_path(mp, dir, dom, ".matrix" as *u8) 51 sgp_path(rp, dir, dom, ".refs" as *u8) 52 sgp_path(sp, dir, dom, ".seeds" as *u8) 53 let sl: *i64 = sys_mmap(16) as *i64 54 let sb: *u8 = sgp_read(sp, sl) 55 if (sb as i64) != 0 { if sg_is_derived(sb, sl[0]) == 0 { return SG_CLASS_HAND } } 56 let ml: *i64 = sys_mmap(16) as *i64 57 let mb: *u8 = sgp_read(mp, ml) 58 if (mb as i64) == 0 { return SG_CLASS_NO_MATRIX } 59 let spans: *i64 = sys_mmap(8 * 2 * SG_MAX_COLS) as *i64 60 let ncols: i64 = sg_cols(mb, ml[0], spans) 61 if ncols < 1 { return SG_CLASS_NO_COLS } 62 tot[SGP_T_COLS] = tot[SGP_T_COLS] + ncols 63 let rl: *i64 = sys_mmap(16) as *i64 64 var rb: *u8 = sgp_read(rp, rl) 65 if (rb as i64) == 0 { rb = sys_mmap(1); rl[0] = 0 } 66 // dry pass into a scratch fd is not needed: emit counts as it writes, so write to the file and remove it if nothing sourced 67 let fd: i64 = sys_openat_wr(sp, MODE_0644) 68 if fd < 0 { return SG_CLASS_UNWRITABLE } 69 let counts: *i64 = sys_mmap(16) as *i64 70 sg_emit(fd, dom, ts, mb, spans, ncols, rb, rl[0], counts) 71 sys_close(fd) 72 tot[SGP_T_SOURCED] = tot[SGP_T_SOURCED] + counts[0] 73 tot[SGP_T_UNSOURCED] = tot[SGP_T_UNSOURCED] + counts[1] 74 if counts[0] < 1 { sys_unlinkat(sp); return SG_CLASS_NO_SOURCED } 75 return SG_CLASS_GENERATED 76} 77 78func main(argc: i64, argv: *i64) -> i64 { 79 if argc < 2 { sgp_err("usage: nx_field_seedgen <dom> | --all [--dir <compare-dir>] [--list <regen-list>]\n" as *u8); return SGP_EXIT_USAGE } 80 sys_chdir(SGP_ROOT) 81 sgp_out("[nx_field_seedgen] CWD anchored to " as *u8); sgp_out(SGP_ROOT); sgp_out("\n" as *u8) 82 var dir: *u8 = SGP_DIR_DEFAULT 83 var list: *u8 = SGP_LIST_DEFAULT 84 var all: i64 = 0 85 var dom: *u8 = 0 as *u8 86 var a: i64 = 1 87 while a < argc { 88 let s: *u8 = argv[a] as *u8 89 if fb_streq(s, "--all" as *u8) == 1 { all = 1 } else { 90 if fb_streq(s, "--dir" as *u8) == 1 { if a + 1 < argc { dir = argv[a + 1] as *u8; a = a + 1 } } else { 91 if fb_streq(s, "--list" as *u8) == 1 { if a + 1 < argc { list = argv[a + 1] as *u8; a = a + 1 } } else { dom = s } 92 } 93 } 94 a = a + 1 95 } 96 if all == 0 { if (dom as i64) == 0 { sgp_err("usage: nx_field_seedgen <dom> | --all [--dir <compare-dir>] [--list <regen-list>]\n" as *u8); return SGP_EXIT_USAGE } } 97 let tsb: *i64 = sys_mmap(16) as *i64 98 sys_clock_gettime_real(tsb) 99 let ts: i64 = tsb[0] 100 let tot: *i64 = sys_mmap(8 * SGP_T_N) as *i64 101 let cls: *i64 = sys_mmap(8 * SG_CLASS_N) as *i64 102 var n: i64 = 0 103 var names: *u8 = 0 as *u8 104 if all == 1 { 105 let lp: *i64 = sys_mmap(16) as *i64 106 let lb: *u8 = sgp_read(list, lp) 107 if (lb as i64) == 0 { sgp_err("SEEDGEN-REFUSE list unreadable: " as *u8); sgp_err(list); sgp_err("\n" as *u8); return SGP_EXIT_REFUSE } 108 names = sys_mmap(FB_NAME_CAP * FB_MAX_DOMAINS) 109 let capped: *i64 = sys_mmap(16) as *i64 110 n = fb_list_domains(lb, lp[0], names, capped) 111 if n < 1 { sgp_err("SEEDGEN-REFUSE the list names no domain\n" as *u8); return SGP_EXIT_REFUSE } 112 if capped[0] == 1 { sgp_out("SEEDGEN-CAPPED the list holds more than FB_MAX_DOMAINS rows; domains= is a FLOOR\n" as *u8) } 113 } else { n = 1 } 114 var i: i64 = 0 115 var last: i64 = 0 116 while i < n { 117 var d: *u8 = dom 118 if all == 1 { d = fb_domain_at(names, i) } 119 let before: i64 = tot[SGP_T_SOURCED] 120 let ubefore: i64 = tot[SGP_T_UNSOURCED] 121 let cbefore: i64 = tot[SGP_T_COLS] 122 let c: i64 = sg_one(dir, d, ts, tot) 123 cls[c] = cls[c] + 1 124 last = c 125 sgp_out("SEEDGEN dom=" as *u8); sgp_out(d) 126 sgp_out(" class=" as *u8); sgp_out(sg_class_name(c)) 127 sgp_out(" cols=" as *u8); fb_putn(SGP_OUTFD, tot[SGP_T_COLS] - cbefore) 128 sgp_out(" sourced=" as *u8); fb_putn(SGP_OUTFD, tot[SGP_T_SOURCED] - before) 129 sgp_out(" unsourced=" as *u8); fb_putn(SGP_OUTFD, tot[SGP_T_UNSOURCED] - ubefore) 130 sgp_out(" out=" as *u8); sgp_out(dir); sgp_out(d); sgp_out(".seeds\n" as *u8) 131 i = i + 1 132 } 133 sgp_out("SEEDGEN-OK domains=" as *u8); fb_putn(SGP_OUTFD, n) 134 sgp_out(" generated=" as *u8); fb_putn(SGP_OUTFD, cls[SG_CLASS_GENERATED]) 135 sgp_out(" hand=" as *u8); fb_putn(SGP_OUTFD, cls[SG_CLASS_HAND]) 136 sgp_out(" no_matrix=" as *u8); fb_putn(SGP_OUTFD, cls[SG_CLASS_NO_MATRIX]) 137 sgp_out(" no_cols=" as *u8); fb_putn(SGP_OUTFD, cls[SG_CLASS_NO_COLS]) 138 sgp_out(" no_sourced=" as *u8); fb_putn(SGP_OUTFD, cls[SG_CLASS_NO_SOURCED]) 139 sgp_out(" unwritable=" as *u8); fb_putn(SGP_OUTFD, cls[SG_CLASS_UNWRITABLE]) 140 sgp_out(" sum=" as *u8); fb_putn(SGP_OUTFD, cls[SG_CLASS_GENERATED] + cls[SG_CLASS_HAND] + cls[SG_CLASS_NO_MATRIX] + cls[SG_CLASS_NO_COLS] + cls[SG_CLASS_NO_SOURCED] + cls[SG_CLASS_UNWRITABLE]) 141 sgp_out(" cols_total=" as *u8); fb_putn(SGP_OUTFD, tot[SGP_T_COLS]) 142 sgp_out(" sourced=" as *u8); fb_putn(SGP_OUTFD, tot[SGP_T_SOURCED]) 143 sgp_out(" unsourced=" as *u8); fb_putn(SGP_OUTFD, tot[SGP_T_UNSOURCED]) 144 sgp_out("\n" as *u8) 145 if cls[SG_CLASS_UNWRITABLE] > 0 { return SGP_EXIT_RED } 146 if all == 0 { if last != SG_CLASS_GENERATED { return SGP_EXIT_REFUSE } } 147 return 0 148}