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}