code wiki / _hdl_build / nx_tpl_parts.nx
nx_tpl_parts.nx source
↩ module page · 240 lines · 11998 B
1// nx_tpl_parts.nx -- R-PARTS of the SITE FACTORY (the LEGO half of "ingest parts AND complete templates"):
2// extract SECTION-LEVEL patterns from template HTML into the pattern corpus as reusable BRICKS. For each
3// content section a template uses (hero/feat/proof/price/gal/vid/faq/form/cta) we keep only the abstract
4// STRUCTURE: the section kind + bucketed feature metrics (links/imgs/headings/forms/buttons) + its position.
5// Each distinct (kind, metric-buckets) collapses to ONE content-addressed `part:<hash>` record in the SAME
6// seg_store corpus that holds the page-level `pat:` records -- one corpus, two granularities, so composition
7// can lego from bricks as well as whole-page patterns. BUDGET-GUARDED by construction (max_parts + byte
8// ceiling, fail-fast trap; [[feedback-substrate-generators-must-have-budget-guard]]); idempotent (in-run +
9// cross-run dedup). We store structure only -- never a template's assets. license_tier: ORIGINAL
10// usage: nx_tpl_parts <template-dir> <corpus-prefix> [max_parts]
11import "nx_tpl_ingest.nx"
12const TP_MAGIC_131072: i64 = 131072
13const TP_MAGIC_1024: i64 = 1024
14const TP_MAGIC_2000: i64 = 2000
15
16const TP_RECCAP: i64 = 1024
17const TP_MAXK: i64 = 12
18
19func tp_bucket(v: i64) -> i64 {
20 if v == 0 { return 0 }
21 if v <= 2 { return 1 }
22 if v <= 5 { return 2 }
23 return 3
24}
25
26// scan content sections (after </nav>, like ti_seq): fill (tokptr, off) pairs sorted by offset. returns count.
27func tp_scan(h: *u8, n: i64, toks: *i64, offs: *i64) -> i64 {
28 var cstart: i64 = 0
29 let navend: i64 = ti_find_ci(h, 0, n, "</nav>" as *u8)
30 if navend >= 0 { cstart = navend + 6 } else {
31 let hdend: i64 = ti_find_ci(h, 0, n, "</header>" as *u8)
32 if hdend >= 0 { cstart = hdend + 9 }
33 }
34 let mt: *i64 = sys_mmap(TP_MAXK * 8) as *i64
35 let mm: *i64 = sys_mmap(TP_MAXK * 8) as *i64
36 mt[0] = ("hero" as *u8) as i64; mm[0] = ("hero" as *u8) as i64
37 mt[1] = ("feat" as *u8) as i64; mm[1] = ("feature" as *u8) as i64
38 mt[2] = ("proof" as *u8) as i64; mm[2] = ("testimonial" as *u8) as i64
39 mt[3] = ("price" as *u8) as i64; mm[3] = ("pricing" as *u8) as i64
40 mt[4] = ("gal" as *u8) as i64; mm[4] = ("gallery" as *u8) as i64
41 mt[5] = ("vid" as *u8) as i64; mm[5] = ("<video" as *u8) as i64
42 mt[6] = ("faq" as *u8) as i64; mm[6] = ("faq" as *u8) as i64
43 mt[7] = ("form" as *u8) as i64; mm[7] = ("<form" as *u8) as i64
44 var cnt: i64 = 0
45 var i: i64 = 0
46 while i < 8 {
47 let off_i: i64 = ti_find_ci(h, cstart, n, mm[i] as *u8)
48 if off_i >= 0 { toks[cnt] = mt[i]; offs[cnt] = off_i; cnt = cnt + 1 }
49 i = i + 1
50 }
51 let ctao: i64 = ti_cta_off(h, cstart, n)
52 if ctao <= n { toks[cnt] = ("cta" as *u8) as i64; offs[cnt] = ctao; cnt = cnt + 1 }
53 // insertion sort by offset
54 i = 1
55 while i < cnt {
56 let ct: i64 = toks[i]
57 let co: i64 = offs[i]
58 var j: i64 = i - 1
59 var go: i64 = 1
60 while go == 1 {
61 if j < 0 { go = 0 } else {
62 if offs[j] > co { toks[j+1] = toks[j]; offs[j+1] = offs[j]; j = j - 1 } else { go = 0 }
63 }
64 }
65 toks[j+1] = ct
66 offs[j+1] = co
67 i = i + 1
68 }
69 return cnt
70}
71
72// structural metrics of h[from..to): m[0]=links m[1]=imgs m[2]=headings m[3]=forms m[4]=buttons
73func tp_metrics(h: *u8, from: i64, to: i64, m: *i64) -> i64 {
74 let seg: *u8 = (h as i64 + from) as *u8
75 let len: i64 = to - from
76 m[0] = ti_count_ci(seg, len, "<a " as *u8)
77 m[1] = ti_count_ci(seg, len, "<img" as *u8)
78 m[2] = ti_count_ci(seg, len, "<h2" as *u8) + ti_count_ci(seg, len, "<h3" as *u8)
79 m[3] = ti_count_ci(seg, len, "<form" as *u8)
80 m[4] = ti_count_ci(seg, len, "<button" as *u8) + ti_count_ci(seg, len, "btn" as *u8)
81 return 0
82}
83
84// dedup key "part:" + hash(kind \x1f bucket-digits)
85func tp_mkkey(kind: *u8, m: *i64, keyout: *u8) -> i64 {
86 let canon: *u8 = sys_mmap(64)
87 var o: i64 = ti_cat(canon, 0, kind)
88 canon[o] = 31 as u8; o = o + 1
89 var i: i64 = 0
90 while i < 5 { canon[o] = (48 + tp_bucket(m[i])) as u8; o = o + 1; i = i + 1 }
91 canon[o] = 0 as u8
92 let hsh: i64 = ti_hash(canon, o)
93 var ko: i64 = ti_cat(keyout, 0, "part:" as *u8)
94 ko = ti_catn(keyout, ko, hsh)
95 keyout[ko] = 0 as u8
96 return ko
97}
98
99// record: line-oriented k|v (abstract structure only)
100func tp_record(kind: *u8, m: *i64, pos: i64, src: *u8, out: *u8) -> i64 {
101 var o: i64 = ti_cat(out, 0, "kind|" as *u8); o = ti_cat(out, o, kind)
102 o = ti_cat(out, o, "\nlinks|" as *u8); o = ti_catn(out, o, m[0])
103 o = ti_cat(out, o, "\nimgs|" as *u8); o = ti_catn(out, o, m[1])
104 o = ti_cat(out, o, "\nheads|" as *u8); o = ti_catn(out, o, m[2])
105 o = ti_cat(out, o, "\nforms|" as *u8); o = ti_catn(out, o, m[3])
106 o = ti_cat(out, o, "\nbtns|" as *u8); o = ti_catn(out, o, m[4])
107 o = ti_cat(out, o, "\npos|" as *u8); o = ti_catn(out, o, pos)
108 o = ti_cat(out, o, "\nsrc|" as *u8); o = ti_cat(out, o, src)
109 o = ti_cat(out, o, "\n" as *u8)
110 out[o] = 0 as u8
111 return o
112}
113
114// THE PARTS INGEST. counts: [0]stored [1]dups [2]skipped-files [3]segs [4]files [5]trapped [6]bytes [7]parts-seen
115func tp_run(tpldir: *u8, prefix: *u8, max_parts: i64, counts: *i64) -> i64 {
116 var ci: i64 = 0
117 while ci < 8 { counts[ci] = 0; ci = ci + 1 }
118 let segs: *i64 = sys_mmap(256 * 8) as *i64
119 let nseg: i64 = ss_manifest_file(prefix, "manifest.txt" as *u8, segs)
120 var segid: i64 = 1
121 var si: i64 = 0
122 // ROOT FIX seq1730 (id 1785450987): segs[] holds POINTERS to seg-<id> name strings
123 // (nx_seg_store.nx:1234 stores segs[cnt] = name as i64), NOT ids -- so segs[si] + 1 produced
124 // MMAP_ADDRESS+1 (~1.4e14), the pointer-shaped poison that PINS a plane forever: every later
125 // epoch id sorts BELOW it in supersede order and its rows are silently shadowed while rc=0.
126 // Parse the DIGITS, as nx_web_shard_compact.nx:55-58 already does on this SAME array.
127 while si < nseg {
128 let sg_nm: *u8 = segs[si] as *u8
129 var sg_v: i64 = 0
130 var sg_ci: i64 = 0
131 while sg_nm[sg_ci] != (0 as u8) { let sg_c: i64 = sg_nm[sg_ci] as i64; if sg_c >= 48 { if sg_c <= 57 { sg_v = sg_v * 10 + (sg_c - 48) } } sg_ci = sg_ci + 1 }
132 if sg_v >= segid { segid = sg_v + 1 }
133 si = si + 1
134 }
135 let hh: *i64 = ss_open(prefix)
136 let pbox: *i64 = sys_mmap(16) as *i64
137 let lbox: *i64 = sys_mmap(16) as *i64
138 let seenbuf: *u8 = sys_mmap(TI_SEENCAP * TI_KEYW)
139 var nseen: i64 = 0
140 let dbuf: *u8 = sys_mmap(TP_MAGIC_131072)
141 let path: *u8 = sys_mmap(TP_MAGIC_1024)
142 let key: *u8 = sys_mmap(64)
143 let rec: *u8 = sys_mmap(TP_RECCAP)
144 let toks: *i64 = sys_mmap(TP_MAXK * 8) as *i64
145 let offs: *i64 = sys_mmap(TP_MAXK * 8) as *i64
146 let mets: *i64 = sys_mmap(8 * 8) as *i64
147 let szp: *i64 = sys_mmap(16) as *i64
148 let fd: i64 = sys_openat_rd(tpldir)
149 if fd < 0 { ti_puts("tpl-parts: cannot open dir " as *u8); ti_puts(tpldir); ti_puts("\n" as *u8); return 0 - 1 }
150 var w: *i64 = ss_begin()
151 var go: i64 = 1
152 while go == 1 {
153 let nr: i64 = sys_getdents64(fd, dbuf, TP_MAGIC_131072)
154 if nr <= 0 { go = 0 } else {
155 var off: i64 = 0
156 while off < nr {
157 let recd: *u8 = (dbuf as i64 + off) as *u8
158 let ty: i64 = dirent_type(recd)
159 let nm: *u8 = dirent_name(recd)
160 off = off + dirent_reclen(recd)
161 if ty != 4 {
162 var ishtml: i64 = 0
163 if ti_suffix(nm, ".html" as *u8) == 1 { ishtml = 1 }
164 if ti_suffix(nm, ".htm" as *u8) == 1 { ishtml = 1 }
165 if ishtml == 1 {
166 counts[4] = counts[4] + 1
167 var po: i64 = ti_cat(path, 0, tpldir)
168 po = ti_cat(path, po, "/" as *u8)
169 po = ti_cat(path, po, nm)
170 path[po] = 0 as u8
171 let raw: *u8 = ss_readall(path, szp)
172 var rn: i64 = szp[0]
173 if rn > TI_RAWCAP { rn = 0 }
174 if rn < TI_MINDOC { counts[2] = counts[2] + 1 } else {
175 if ti_find_ci(raw, 0, rn, "<" as *u8) < 0 { counts[2] = counts[2] + 1 } else {
176 let np: i64 = tp_scan(raw, rn, toks, offs)
177 var pi: i64 = 0
178 while pi < np {
179 counts[7] = counts[7] + 1
180 if counts[7] > max_parts { counts[5] = 1; pi = np; go = 0; off = nr } else {
181 var to2: i64 = rn
182 if pi + 1 < np { to2 = offs[pi + 1] }
183 tp_metrics(raw, offs[pi], to2, mets)
184 tp_mkkey(toks[pi] as *u8, mets, key)
185 var dup: i64 = 0
186 if ti_seen(seenbuf, nseen, key) == 1 { dup = 1 }
187 if dup == 0 { if (hh as i64) != 0 { if ss_hget(hh, key, pbox, lbox) == 1 { dup = 1 } } }
188 if dup == 1 { counts[1] = counts[1] + 1 } else {
189 let rl: i64 = tp_record(toks[pi] as *u8, mets, pi, nm, rec)
190 if nseen < TI_SEENCAP {
191 let dst: *u8 = (seenbuf as i64 + nseen * TI_KEYW) as *u8
192 var kk: i64 = 0
193 while key[kk] != (0 as u8) { dst[kk] = key[kk]; kk = kk + 1 }
194 dst[kk] = 0 as u8
195 nseen = nseen + 1
196 }
197 let addr: i64 = ss_add(w, 1, key, rec, rl)
198 if addr < 0 {
199 if ss_commit(prefix, w, segid) == 0 { counts[3] = counts[3] + 1 }
200 segid = segid + 1
201 w = ss_begin()
202 let addr2: i64 = ss_add(w, 1, key, rec, rl)
203 if addr2 < 0 { counts[2] = counts[2] + 1 } else { counts[0] = counts[0] + 1; counts[6] = counts[6] + rl }
204 } else { counts[0] = counts[0] + 1; counts[6] = counts[6] + rl }
205 }
206 pi = pi + 1
207 }
208 }
209 }
210 }
211 }
212 }
213 }
214 }
215 }
216 sys_close(fd)
217 if w[1] > 0 { if ss_commit(prefix, w, segid) == 0 { counts[3] = counts[3] + 1 } }
218 return counts[0]
219}
220
221func main(argc: i64, argv: *i64) -> i64 {
222 if argc < 3 { ti_puts("usage: nx_tpl_parts <template-dir> <corpus-prefix> [max_parts]\n" as *u8); return 2 }
223 let dir: *u8 = argv[1] as *u8
224 let prefix: *u8 = argv[2] as *u8
225 var maxp: i64 = TP_MAGIC_2000
226 if argc >= 4 { let mm: i64 = ti_atoi(argv[3] as *u8); if mm > 0 { maxp = mm } }
227 let counts: *i64 = sys_mmap(64) as *i64
228 let rc: i64 = tp_run(dir, prefix, maxp, counts)
229 ti_puts("TPL-PARTS dir=" as *u8); ti_puts(dir)
230 ti_puts(" files=" as *u8); ti_num(counts[4])
231 ti_puts(" parts_seen=" as *u8); ti_num(counts[7])
232 ti_puts(" stored=" as *u8); ti_num(counts[0])
233 ti_puts(" dups=" as *u8); ti_num(counts[1])
234 ti_puts(" segs=" as *u8); ti_num(counts[3])
235 ti_puts(" bytes=" as *u8); ti_num(counts[6])
236 ti_puts(" trapped=" as *u8); ti_num(counts[5])
237 ti_puts("\n" as *u8)
238 if rc < 0 { return 1 }
239 return 0
240}