nx_field_seedgen_lib.nx source
↩ module page · 281 lines · 15139 B
1// nx_field_seedgen_lib.nx -- THE DECISION CORE OF THE SEED GENERATOR (/compare/fieldwatch fleet campaign, 2026-09-05).
2// A domain's DECLARED population already exists on its board: the @cols rivals of <dom>.matrix, whose pages are already
3// mirrored and pinned as <dom>.refs rows. This lib turns those two data files into <dom>.seeds rows of kind `named`, one
4// per column that a refs row names, so every domain inherits a field on the next fieldbeat without a seat authoring URLs
5// by hand -- and it NEVER invents a URL: a column no refs row names is emitted as an UNSOURCED comment, counted, announced.
6// Discovery seeds (wiki-raw, gh-topic, md-list) stay hand-curated per domain; a derived file carries a marker line so the
7// generator only ever rewrites its own output and refuses a hand-authored file. Pure functions over buffers; the program
8// owns the reads and the write. Byte helpers come from the beat lib (one slen, one puts, one putn in this family).
9// license_tier: ORIGINAL No hw writes (Rule 26).
10import "nx_syscalls.nx"
11import "nx_field_beat_lib.nx"
12
13const SG_MAX_COLS: i64 = 16 // nx_compare_rank parses @cols with maxf=8; 16 is twice that so a wide board is never cut here
14const SG_TOK_CAP: i64 = 48
15const SG_MAX_TOKS: i64 = 12
16const SG_TOK_MIN: i64 = 3 // shorter runs (4, 5, io) match everything and name nothing
17const SG_SCORE_URL: i64 = 2
18const SG_SCORE_CITE: i64 = 1
19const SG_SCORE_MIN: i64 = 2 // one url hit, or two prose hits: a single word in a citation is not a member
20const SG_SLUG_CAP: i64 = 16
21const SG_REF_F: i64 = 9
22const SG_F_KEY: i64 = 1
23const SG_F_CITE: i64 = 2
24const SG_F_URL: i64 = 3
25const SG_F_MIRROR: i64 = 4 // the seat's own declaration of what was fetched: a mirror banked as .img/.png/.pdf is an asset, whatever the url looks like
26const SG_CH_PIPE: i64 = 124
27const SG_CH_A: i64 = 97
28const SG_CH_Z: i64 = 122
29const SG_CH_AU: i64 = 65
30const SG_CH_ZU: i64 = 90
31const SG_CH_0: i64 = 48
32const SG_CH_9: i64 = 57
33const SG_CASE_GAP: i64 = 32
34const SG_COLS_PFX: *u8 = "@cols "
35const SG_MARKER: *u8 = " SEEDGEN-MARKER regenerable: rewritten by nx_field_seedgen while this line stands"
36const SG_CLASS_GENERATED: i64 = 1
37const SG_CLASS_HAND: i64 = 2 // an existing seeds file without the marker: a seat curated it, never touched
38const SG_CLASS_NO_MATRIX: i64 = 3
39const SG_CLASS_NO_COLS: i64 = 4
40const SG_CLASS_NO_SOURCED: i64 = 5 // every column unsourced: nothing written, so the beat keeps skipping the domain cleanly
41const SG_CLASS_UNWRITABLE: i64 = 6
42const SG_CLASS_N: i64 = 7
43
44func sg_lower(c: i64) -> i64 { if c >= SG_CH_AU { if c <= SG_CH_ZU { return c + SG_CASE_GAP } } return c }
45func sg_is_alnum(c: i64) -> i64 {
46 if c >= SG_CH_A { if c <= SG_CH_Z { return 1 } }
47 if c >= SG_CH_AU { if c <= SG_CH_ZU { return 1 } }
48 if c >= SG_CH_0 { if c <= SG_CH_9 { return 1 } }
49 return 0
50}
51func sg_putspan(fd: i64, b: *u8, s: i64, e: i64) -> i64 { if e > s { sys_write(fd, ((b as i64) + s) as *u8, e - s) } return 0 }
52func sg_tok_at(toks: *u8, i: i64) -> *u8 { return ((toks as i64) + i * SG_TOK_CAP) as *u8 }
53// words that name a KIND of rival, never a rival: they would match every citation in the register
54func sg_is_stop(t: *u8) -> i64 {
55 if fb_streq(t, "the" as *u8) == 1 { return 1 }
56 if fb_streq(t, "and" as *u8) == 1 { return 1 }
57 if fb_streq(t, "plus" as *u8) == 1 { return 1 }
58 if fb_streq(t, "class" as *u8) == 1 { return 1 }
59 if fb_streq(t, "stack" as *u8) == 1 { return 1 }
60 if fb_streq(t, "web" as *u8) == 1 { return 1 }
61 if fb_streq(t, "app" as *u8) == 1 { return 1 }
62 if fb_streq(t, "tool" as *u8) == 1 { return 1 }
63 if fb_streq(t, "kit" as *u8) == 1 { return 1 }
64 if fb_streq(t, "lab" as *u8) == 1 { return 1 }
65 if fb_streq(t, "desk" as *u8) == 1 { return 1 }
66 if fb_streq(t, "platform" as *u8) == 1 { return 1 }
67 if fb_streq(t, "brand" as *u8) == 1 { return 1 }
68 if fb_streq(t, "program" as *u8) == 1 { return 1 }
69 if fb_streq(t, "data" as *u8) == 1 { return 1 }
70 if fb_streq(t, "svc" as *u8) == 1 { return 1 }
71 if fb_streq(t, "open" as *u8) == 1 { return 1 }
72 if fb_streq(t, "free" as *u8) == 1 { return 1 }
73 if fb_streq(t, "native" as *u8) == 1 { return 1 }
74 if fb_streq(t, "manual" as *u8) == 1 { return 1 }
75 if fb_streq(t, "service" as *u8) == 1 { return 1 }
76 if fb_streq(t, "engine" as *u8) == 1 { return 1 }
77 if fb_streq(t, "results" as *u8) == 1 { return 1 }
78 if fb_streq(t, "provider" as *u8) == 1 { return 1 }
79 if fb_streq(t, "shop" as *u8) == 1 { return 1 }
80 if fb_streq(t, "print" as *u8) == 1 { return 1 }
81 if fb_streq(t, "transfer" as *u8) == 1 { return 1 }
82 if fb_streq(t, "research" as *u8) == 1 { return 1 }
83 if fb_streq(t, "line" as *u8) == 1 { return 1 }
84 if fb_streq(t, "apis" as *u8) == 1 { return 1 }
85 if fb_streq(t, "standard" as *u8) == 1 { return 1 }
86 if fb_streq(t, "index" as *u8) == 1 { return 1 }
87 if fb_streq(t, "grid" as *u8) == 1 { return 1 }
88 if fb_streq(t, "wave" as *u8) == 1 { return 1 }
89 if fb_streq(t, "search" as *u8) == 1 { return 1 }
90 return 0
91}
92// PURE: the first @cols line of a matrix -> column spans (start,end pairs, spaces trimmed). -1 when the matrix has none.
93func sg_cols(b: *u8, n: i64, spans: *i64) -> i64 {
94 var i: i64 = 0
95 while i < n {
96 var e: i64 = i
97 while e < n { if (b[e] as i64) == FB_CH_NL { break } e = e + 1 }
98 if fb_prefix_at(b, i, e, SG_COLS_PFX) == 1 {
99 var cnt: i64 = 0
100 var f0: i64 = i + fb_slen(SG_COLS_PFX)
101 var q: i64 = f0
102 while q <= e {
103 var atend: i64 = 0
104 if q == e { atend = 1 } else { if (b[q] as i64) == SG_CH_PIPE { atend = 1 } }
105 if atend == 1 {
106 var s: i64 = f0
107 var t: i64 = q
108 while s < t { if (b[s] as i64) == FB_CH_SP { s = s + 1 } else { break } }
109 while t > s { if (b[t - 1] as i64) == FB_CH_SP { t = t - 1 } else { if (b[t - 1] as i64) == FB_CH_CR { t = t - 1 } else { break } } }
110 if t > s { if cnt < SG_MAX_COLS { spans[cnt * 2] = s; spans[cnt * 2 + 1] = t; cnt = cnt + 1 } }
111 f0 = q + 1
112 }
113 q = q + 1
114 }
115 return cnt
116 }
117 i = e + 1
118 }
119 return 0 - 1
120}
121// PURE: a column name -> its lowercase alnum tokens (len >= SG_TOK_MIN, stop words dropped). toks arena = SG_TOK_CAP * SG_MAX_TOKS.
122func sg_tokens(b: *u8, s: i64, e: i64, toks: *u8) -> i64 {
123 var ntok: i64 = 0
124 var i: i64 = s
125 var rs: i64 = 0 - 1
126 while i <= e {
127 var al: i64 = 0
128 if i < e { al = sg_is_alnum(b[i] as i64) }
129 if al == 1 { if rs < 0 { rs = i } } else {
130 if rs >= 0 {
131 let ln: i64 = i - rs
132 if ln >= SG_TOK_MIN { if ntok < SG_MAX_TOKS {
133 let t: *u8 = sg_tok_at(toks, ntok)
134 var k: i64 = 0
135 while k < ln { if k < SG_TOK_CAP - 1 { t[k] = sg_lower(b[rs + k] as i64) as u8 } k = k + 1 }
136 if ln > SG_TOK_CAP - 1 { t[SG_TOK_CAP - 1] = 0 as u8 } else { t[ln] = 0 as u8 }
137 if sg_is_stop(t) == 0 { ntok = ntok + 1 }
138 } }
139 rs = 0 - 1
140 }
141 }
142 i = i + 1
143 }
144 return ntok
145}
146// PURE: case-insensitive substring of a lowercase token inside [hs,he)
147func sg_contains_ci(hay: *u8, hs: i64, he: i64, tok: *u8) -> i64 {
148 let tl: i64 = fb_slen(tok)
149 if tl == 0 { return 0 }
150 var i: i64 = hs
151 while i + tl <= he {
152 var j: i64 = 0
153 var same: i64 = 1
154 while j < tl { if sg_lower(hay[i + j] as i64) != (tok[j] as i64) { same = 0; j = tl } else { j = j + 1 } }
155 if same == 1 { return 1 }
156 i = i + 1
157 }
158 return 0
159}
160// PURE: how strongly one refs row names a column: SG_SCORE_URL per token found in the url, else SG_SCORE_CITE if in the citation
161func sg_score(b: *u8, us: i64, ue: i64, cs: i64, ce: i64, toks: *u8, ntok: i64) -> i64 {
162 var sc: i64 = 0
163 var k: i64 = 0
164 while k < ntok {
165 let t: *u8 = sg_tok_at(toks, k)
166 if sg_contains_ci(b, us, ue, t) == 1 { sc = sc + SG_SCORE_URL } else { if sg_contains_ci(b, cs, ce, t) == 1 { sc = sc + SG_SCORE_CITE } }
167 k = k + 1
168 }
169 return sc
170}
171// PURE: a member's page must be a PAGE. A refs row whose url is an image, a font, an archive or a paper file names a
172// mirrored asset, never a home page (measured on graphics.refs: Unreal Engine 5 matched a social-share png first).
173func sg_url_is_page(b: *u8, s: i64, e: i64) -> i64 {
174 if sg_url_ends(b, s, e, ".png" as *u8) == 1 { return 0 }
175 if sg_url_ends(b, s, e, ".jpg" as *u8) == 1 { return 0 }
176 if sg_url_ends(b, s, e, ".jpeg" as *u8) == 1 { return 0 }
177 if sg_url_ends(b, s, e, ".gif" as *u8) == 1 { return 0 }
178 if sg_url_ends(b, s, e, ".webp" as *u8) == 1 { return 0 }
179 if sg_url_ends(b, s, e, ".svg" as *u8) == 1 { return 0 }
180 if sg_url_ends(b, s, e, ".ico" as *u8) == 1 { return 0 }
181 if sg_url_ends(b, s, e, ".pdf" as *u8) == 1 { return 0 }
182 if sg_url_ends(b, s, e, ".zip" as *u8) == 1 { return 0 }
183 if sg_url_ends(b, s, e, ".mp4" as *u8) == 1 { return 0 }
184 if sg_url_ends(b, s, e, ".woff" as *u8) == 1 { return 0 }
185 if sg_url_ends(b, s, e, ".woff2" as *u8) == 1 { return 0 }
186 if sg_url_ends(b, s, e, ".img" as *u8) == 1 { return 0 }
187 if sg_url_ends(b, s, e, ".bin" as *u8) == 1 { return 0 }
188 if sg_url_ends(b, s, e, ".raw" as *u8) == 1 { return 0 }
189 return 1
190}
191// PURE: the mirror field is the seat's own declaration of what was fetched, so an asset behind an extension-less CDN url
192// (measured: cms-assets.unrealengine.com/.../auto_image/... banked as cmp_graphics_metahuman_ref1.img) is caught here.
193// A row too short to carry a mirror abstains toward the pre-change behaviour (allowed), never toward inventing a verdict.
194func sg_mirror_is_page(refs: *u8, fs: *i64, nf: i64) -> i64 {
195 if nf <= SG_F_MIRROR { return 1 }
196 return sg_url_is_page(refs, fs[SG_F_MIRROR * 2], fs[SG_F_MIRROR * 2 + 1])
197}
198// PURE: case-insensitive suffix test on a url span (a trailing query string is not stripped: a refs url carries none)
199func sg_url_ends(b: *u8, s: i64, e: i64, ext: *u8) -> i64 {
200 let xl: i64 = fb_slen(ext)
201 if e - s < xl { return 0 }
202 var k: i64 = 0
203 while k < xl { if sg_lower(b[e - xl + k] as i64) != (ext[k] as i64) { return 0 } k = k + 1 }
204 return 1
205}
206// PURE: the best refs row for a column. out[0..1] = url span, out[2..3] = key span. Returns the best score, -1 when no row.
207// Rows are ref|key|cite|url|... ; comment lines and rows without a url field never compete.
208func sg_pick(refs: *u8, n: i64, toks: *u8, ntok: i64, out: *i64) -> i64 {
209 var best: i64 = 0 - 1
210 let fs: *i64 = sys_mmap(8 * 2 * SG_REF_F) as *i64
211 var i: i64 = 0
212 while i < n {
213 var e: i64 = i
214 while e < n { if (refs[e] as i64) == FB_CH_NL { break } e = e + 1 }
215 if e > i { if (refs[i] as i64) != FB_CH_HASH {
216 var nf: i64 = 0
217 var f0: i64 = i
218 var q: i64 = i
219 while q <= e {
220 var atend: i64 = 0
221 if q == e { atend = 1 } else { if (refs[q] as i64) == SG_CH_PIPE { atend = 1 } }
222 if atend == 1 { if nf < SG_REF_F { fs[nf * 2] = f0; fs[nf * 2 + 1] = q; nf = nf + 1 } f0 = q + 1 }
223 q = q + 1
224 }
225 if nf > SG_F_URL { if fb_prefix_at(refs, fs[0], fs[1], "ref" as *u8) == 1 { if fs[1] - fs[0] == 3 { if sg_url_is_page(refs, fs[SG_F_URL * 2], fs[SG_F_URL * 2 + 1]) == 1 { if sg_mirror_is_page(refs, fs, nf) == 1 {
226 let sc: i64 = sg_score(refs, fs[SG_F_URL * 2], fs[SG_F_URL * 2 + 1], fs[SG_F_CITE * 2], fs[SG_F_CITE * 2 + 1], toks, ntok)
227 if sc > best { best = sc; out[0] = fs[SG_F_URL * 2]; out[1] = fs[SG_F_URL * 2 + 1]; out[2] = fs[SG_F_KEY * 2]; out[3] = fs[SG_F_KEY * 2 + 1] }
228 } } } } }
229 } }
230 i = e + 1
231 }
232 return best
233}
234// PURE: does a seeds file carry the generator's marker (so it is ours to rewrite)?
235func sg_is_derived(b: *u8, n: i64) -> i64 {
236 let ml: i64 = fb_slen(SG_MARKER)
237 var i: i64 = 0
238 while i + ml <= n { if fb_prefix_at(b, i, n, SG_MARKER) == 1 { return 1 } i = i + 1 }
239 return 0
240}
241func sg_class_name(c: i64) -> *u8 {
242 if c == SG_CLASS_GENERATED { return "GENERATED" as *u8 }
243 if c == SG_CLASS_HAND { return "HAND-AUTHORED" as *u8 }
244 if c == SG_CLASS_NO_MATRIX { return "NO-MATRIX" as *u8 }
245 if c == SG_CLASS_NO_COLS { return "NO-COLS" as *u8 }
246 if c == SG_CLASS_NO_SOURCED { return "NO-SOURCED" as *u8 }
247 return "UNWRITABLE" as *u8
248}
249func sg_hash(fd: i64) -> i64 { let h: *u8 = sys_mmap(1); h[0] = FB_CH_HASH as u8; sys_write(fd, h, 1); return 0 }
250// PURE over an fd: the derived seeds file. counts[0]=sourced counts[1]=unsourced. Never writes a url it did not read from refs.
251func sg_emit(fd: i64, dom: *u8, ts: i64, mx: *u8, spans: *i64, ncols: i64, refs: *u8, rn: i64, counts: *i64) -> i64 {
252 counts[0] = 0; counts[1] = 0
253 sg_hash(fd); fb_puts(fd, " " as *u8); fb_puts(fd, dom); fb_puts(fd, ".seeds -- DERIVED by nx_field_seedgen at ts=" as *u8); fb_putn(fd, ts)
254 fb_puts(fd, " from " as *u8); fb_puts(fd, dom); fb_puts(fd, ".matrix @cols (the declared population) and " as *u8); fb_puts(fd, dom); fb_puts(fd, ".refs (their pinned pages); kind named only. To hand-curate: delete the marker line below and add rows (seed|key|url|kind|why|Display Name; kinds wiki-raw gh-topic md-list named).\n" as *u8)
255 sg_hash(fd); fb_puts(fd, SG_MARKER); fb_puts(fd, "\n" as *u8)
256 let toks: *u8 = sys_mmap(SG_TOK_CAP * SG_MAX_TOKS)
257 let out: *i64 = sys_mmap(8 * 4) as *i64
258 var c: i64 = 0
259 while c < ncols {
260 let cs: i64 = spans[c * 2]
261 let ce: i64 = spans[c * 2 + 1]
262 let ntok: i64 = sg_tokens(mx, cs, ce, toks)
263 var sc: i64 = 0 - 1
264 if ntok > 0 { sc = sg_pick(refs, rn, toks, ntok, out) }
265 if sc >= SG_SCORE_MIN {
266 fb_puts(fd, "seed|col" as *u8); fb_putn(fd, c); fb_puts(fd, "-" as *u8)
267 let t0: *u8 = sg_tok_at(toks, 0)
268 var k: i64 = 0
269 while t0[k] != (0 as u8) { if k < SG_SLUG_CAP { sys_write(fd, ((t0 as i64) + k) as *u8, 1) } k = k + 1 }
270 fb_puts(fd, "|" as *u8); sg_putspan(fd, refs, out[0], out[1])
271 fb_puts(fd, "|named|derived from @cols column " as *u8); fb_putn(fd, c); fb_puts(fd, " and refs row " as *u8); sg_putspan(fd, refs, out[2], out[3]); fb_puts(fd, " (score " as *u8); fb_putn(fd, sc); fb_puts(fd, ")|" as *u8)
272 sg_putspan(fd, mx, cs, ce); fb_puts(fd, "\n" as *u8)
273 counts[0] = counts[0] + 1
274 } else {
275 sg_hash(fd); fb_puts(fd, " UNSOURCED col" as *u8); fb_putn(fd, c); fb_puts(fd, " \x22" as *u8); sg_putspan(fd, mx, cs, ce); fb_puts(fd, "\x22: no refs row names it (best score " as *u8); fb_putn(fd, sc); fb_puts(fd, ") -- add a seed row by hand, never a guessed url\n" as *u8)
276 counts[1] = counts[1] + 1
277 }
278 c = c + 1
279 }
280 return counts[0]
281}