code wiki / (root) / nx_entity_discover.nx

nx_entity_discover.nx source

↩ module page · 250 lines · 11619 B

1// nx_entity_discover.nx -- SREACH R3b: CRAWLER-DRIVEN ENTITY DISCOVERY. 2// 3// module: nishi-core.search.entity_discover 4// depends: nx_guarded_run.nx, nx_html_links.nx, nx_bm25.nx, 5// /tmp/_ed_fetch_html.sov.elf (seed HTML), /tmp/_dlr_fetch_one.sov.elf (text) 6// capability: GATE + EVIDENCE 7// 8// OPERATOR LINE CLOSED HERE: seeds are no longer hand-curated. The crawler 9// starts from entity hub pages OUR index already reaches (wikidata + wikipedia), 10// extracts their outbound links with the nx_html_links kernel, keeps the 11// CROSS-HOST ones whose URL names the entity, then guarded-fetches each 12// DISCOVERED page over the sovereign stack, indexes it, and retrieves the 13// entity query from THAT index. Every result row is durable evidence; walls 14// stay named-not-faked. GATE (Rule #11 bars): 15// discovered >= 3 -- the link harvest found genuinely new cross-host pages 16// retrieved >= 1 -- at least one DISCOVERED page fetched+indexed+retrievable 17// (conservative: anonymous fetches of social hosts often hit login walls -- 18// a wall is a finding, not a discovery failure) 19 20import "nx_str.nx" 21import "nx_syscalls.nx" 22import "nx_search_inverted.nx" // nx_bm25_tf + nx_inv_hash_bytes_lower. The header above lists nx_bm25.nx 23 // as the dependency for these -- it never carried them. 24import "nx_guarded_run.nx" 25import "nx_html_links.nx" 26import "nx_bm25.nx" 27import "nx_html_to_text.nx" 28import "nx_content_measure.nx" 29const NX_MAGIC_131072: i64 = 131072 30const NX_MAGIC_524288: i64 = 524288 31const NX_MAGIC_2048: i64 = 2048 32 33const NX_ED_SEEDS: i64 = 2 34const NX_ED_MAXDISC: i64 = 8 35const NX_ED_DEADLINE: i64 = 18000 36const NX_ED_MIN_DISCOVERED: i64 = 3 37const NX_ED_MIN_RETRIEVED: i64 = 1 38 39func ed_p(s: *u8) -> i64 { sys_write(1, s, nx_str_len(s)); return 0 } 40func ed_n(v: i64) -> i64 { 41 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 } 42 var m: i64 = v; if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 43 let t: *u8 = sys_mmap(28); var k: i64 = 0 44 while m > 0 { t[k] = 0x30 + (m - (m/10)*10); m = m/10; k = k + 1 } 45 while k > 0 { k = k - 1; sys_write(1, (((t as i64)+k) as *u8), 1) } 46 return 0 47} 48func ed_f(fd: i64, s: *u8) -> i64 { sys_write(fd, s, nx_str_len(s)); return 0 } 49func ed_fn(fd: i64, v: i64) -> i64 { 50 let b: *u8 = sys_mmap(28); let t: *u8 = sys_mmap(28) 51 var m: i64 = v; if m < 0 { m = 0 - m } 52 var k: i64 = 0 53 if m == 0 { t[0] = 48; k = 1 } 54 while m > 0 { t[k] = 48 + (m % 10); m = m / 10; k = k + 1 } 55 var i: i64 = 0 56 while i < k { b[i] = t[k-1-i]; i = i + 1 } 57 sys_write(fd, b, k) 58 return 0 59} 60func ed_lc(c: i64) -> i64 { if c >= 0x41 { if c <= 0x5A { return c + 0x20 } } return c } 61func ed_ci_contains(hay: *u8, needle: *u8) -> i64 { 62 let hn: i64 = nx_str_len(hay) 63 let nn: i64 = nx_str_len(needle) 64 if nn > hn { return 0 } 65 var i: i64 = 0 66 while i <= hn - nn { 67 var j: i64 = 0 68 var ok: i64 = 1 69 while j < nn { 70 if ed_lc(hay[i+j] as i64) != ed_lc(needle[j] as i64) { ok = 0; j = nn } else { j = j + 1 } 71 } 72 if ok == 1 { return 1 } 73 i = i + 1 74 } 75 return 0 76} 77func ed_streq(a: *u8, b: *u8) -> i64 { 78 var i: i64 = 0 79 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 80 if b[i] != (0 as u8) { return 0 } 81 return 1 82} 83 84func ed_seed_url(e: i64) -> *u8 { 85 if e == 0 { return "https://www.wikidata.org/wiki/Q283504" } 86 if e == 1 { return "https://en.wikipedia.org/wiki/Diora_Baird" } 87 return "?" 88} 89func ed_seed_out(e: i64) -> *u8 { 90 if e == 0 { return "/tmp/ed_seed_0.html\x00" } 91 return "/tmp/ed_seed_1.html\x00" 92} 93func ed_disc_out(d: i64) -> *u8 { 94 if d == 0 { return "/tmp/ed_disc_0.html\x00" } 95 if d == 1 { return "/tmp/ed_disc_1.html\x00" } 96 if d == 2 { return "/tmp/ed_disc_2.html\x00" } 97 if d == 3 { return "/tmp/ed_disc_3.html\x00" } 98 if d == 4 { return "/tmp/ed_disc_4.html\x00" } 99 if d == 5 { return "/tmp/ed_disc_5.html\x00" } 100 if d == 6 { return "/tmp/ed_disc_6.html\x00" } 101 return "/tmp/ed_disc_7.html\x00" 102} 103 104func ed_read_all(path: *u8, buf: *u8, cap: i64) -> i64 { 105 let fd: i64 = sys_openat_rd(path) 106 if fd < 0 { return 0 } 107 var total: i64 = 0 108 var go: i64 = 1 109 while go == 1 { 110 let n: i64 = sys_read(fd, (((buf as i64) + total) as *u8), cap - total) 111 if n <= 0 { go = 0 } 112 if n > 0 { total = total + n; if total >= cap { go = 0 } } 113 } 114 sys_close(fd) 115 return total 116} 117 118// own-corpus host (the seeds' hosts) -> NOT a discovery 119func ed_is_seed_host(url: *u8) -> i64 { 120 if ed_ci_contains(url, "wikipedia.org") == 1 { return 1 } 121 if ed_ci_contains(url, "wikidata.org") == 1 { return 1 } 122 if ed_ci_contains(url, "wikimedia.org") == 1 { return 1 } 123 return 0 124} 125 126func main() -> i64 { 127 ed_p("=== ENTITY DISCOVERY (R3b): crawler finds the pages, no hand-curated seeds ===\n") 128 let html_child: *u8 = "/tmp/_ed_fetch_html.sov.elf\x00" 129 let pr1: i64 = sys_openat_rd(html_child) 130 if pr1 < 0 { ed_p(" prereq missing: _ed_fetch_html\n"); sys_exit(3); return 3 } 131 sys_close(pr1) 132 let envp: *i64 = sys_mmap(16) as *i64 133 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0 134 let devnull: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4) 135 let lfd: i64 = sys_openat_append("knowledge/status/search_discovery.log" as *u8, 0x1a4) 136 if lfd < 0 { ed_p(" log open failed\n"); sys_exit(1); return 1 } 137 ed_f(lfd, "ED-RUN epoch=" as *u8); ed_fn(lfd, sys_now_realtime_sec()); ed_f(lfd, "\n" as *u8) 138 139 // ---- harvest links from the seed hub pages ---- 140 let store: *u8 = sys_mmap(NX_MAGIC_131072) 141 let offs: *i64 = sys_mmap(512 * 8) as *i64 142 let durl: **u8 = sys_mmap(NX_ED_MAXDISC * 8) as **u8 143 var ndisc: i64 = 0 144 var nlinks_total: i64 = 0 145 var e: i64 = 0 146 while e < NX_ED_SEEDS { 147 let av: *i64 = sys_mmap(8 * 4) as *i64 148 av[0] = html_child as i64; av[1] = ed_seed_url(e) as i64; av[2] = ed_seed_out(e) as i64; av[3] = 0 149 let rc: i64 = nx_guarded_run(html_child, av, envp, NX_ED_DEADLINE, devnull, devnull) 150 ed_p(" seed "); ed_p(ed_seed_url(e)); ed_p(" -> ") 151 if rc != 0 { ed_p("fetch rc="); ed_n(rc); ed_p(" (named)\n") } else { 152 let html: *u8 = sys_mmap(NX_MAGIC_524288) 153 let hn: i64 = ed_read_all(ed_seed_out(e), html, NX_MAGIC_524288) 154 let nl: i64 = nx_html_links(html, hn, store, NX_MAGIC_131072, offs, 512) 155 nlinks_total = nlinks_total + nl 156 ed_p("OK "); ed_n(hn); ed_p(" html bytes, "); ed_n(nl); ed_p(" https links\n") 157 // filter: entity-named URL, cross-host, deduped, capped 158 var li: i64 = 0 159 while li < nl { 160 let u: *u8 = (((store as i64) + offs[li]) as *u8) 161 var keep: i64 = 0 162 if ed_ci_contains(u, "diora") == 1 { keep = 1 } 163 if keep == 1 { if ed_is_seed_host(u) == 1 { keep = 0 } } 164 if keep == 1 { 165 var dd: i64 = 0 166 while dd < ndisc { if ed_streq(u, durl[dd]) == 1 { keep = 0; dd = ndisc } else { dd = dd + 1 } } 167 } 168 if keep == 1 { 169 if ndisc < NX_ED_MAXDISC { 170 // persist a copy (store is reused across seeds) 171 let cp: *u8 = sys_mmap(NX_MAGIC_2048) 172 var c: i64 = 0 173 while u[c] != (0 as u8) { cp[c] = u[c]; c = c + 1 } 174 cp[c] = 0 as u8 175 durl[ndisc] = cp 176 ndisc = ndisc + 1 177 } 178 } 179 li = li + 1 180 } 181 } 182 e = e + 1 183 } 184 ed_p(" discovered (cross-host, entity-named, deduped): "); ed_n(ndisc); ed_p(" of "); ed_n(nlinks_total); ed_p(" harvested links\n") 185 ed_f(lfd, "ED-HARVEST links=" as *u8); ed_fn(lfd, nlinks_total) 186 ed_f(lfd, " discovered=" as *u8); ed_fn(lfd, ndisc); ed_f(lfd, "\n" as *u8) 187 188 // ---- fetch + index + retrieve each DISCOVERED page ---- 189 let h_diora: i64 = nx_inv_hash_bytes_lower("diora", 5) 190 let h_baird: i64 = nx_inv_hash_bytes_lower("baird", 5) 191 // R3c-a: discovered docs are fetched as HTML so content value is MEASURED 192 // from the served bytes (nx_content_measure: text-length + media tags), 193 // never inferred; text for retrieval is extracted in-process. Retrieved 194 // docs feed the durable corpus (knowledge/index/discovered_corpus.txt) the 195 // live SERP grows from -- corpus growth by crawl, not by seed-table edit. 196 let cfd: i64 = sys_openat_append("knowledge/index/discovered_corpus.txt" as *u8, 0x1a4) 197 var nret: i64 = 0 198 var d: i64 = 0 199 while d < ndisc { 200 let av2: *i64 = sys_mmap(8 * 4) as *i64 201 av2[0] = html_child as i64; av2[1] = durl[d] as i64; av2[2] = ed_disc_out(d) as i64; av2[3] = 0 202 let rc2: i64 = nx_guarded_run(html_child, av2, envp, NX_ED_DEADLINE, devnull, devnull) 203 ed_p(" #"); ed_n(d + 1); ed_p(" "); ed_p(durl[d]); ed_p(" -> ") 204 ed_f(lfd, "ED-DOC url=" as *u8); ed_f(lfd, durl[d]); ed_f(lfd, " rc=" as *u8); ed_fn(lfd, rc2) 205 if rc2 != 0 { 206 if rc2 == 124 { ed_p("TIMEOUT-REAPED\n"); ed_f(lfd, " status=TIMEOUT\n" as *u8) } 207 if rc2 != 124 { ed_p("walled/fail rc="); ed_n(rc2); ed_p(" (named)\n"); ed_f(lfd, " status=WALLED\n" as *u8) } 208 } else { 209 let html: *u8 = sys_mmap(NX_MAGIC_524288) 210 let hn: i64 = ed_read_all(ed_disc_out(d), html, NX_MAGIC_524288) 211 let text: *u8 = sys_mmap(NX_MAGIC_524288) 212 let tl: i64 = nx_html_to_text(html, hn, text, NX_MAGIC_524288) 213 let tf: i64 = nx_bm25_tf(text, tl, h_diora) + nx_bm25_tf(text, tl, h_baird) 214 let cm: i64 = nx_content_measure(html, hn, tl) 215 let cm_permil: i64 = (cm * 1000) >> 16 216 ed_p("OK "); ed_n(tl); ed_p(" chars, entity-tf "); ed_n(tf) 217 ed_p(", content-permil "); ed_n(cm_permil) 218 ed_f(lfd, " status=FETCHED chars=" as *u8); ed_fn(lfd, tl) 219 ed_f(lfd, " entity_tf=" as *u8); ed_fn(lfd, tf) 220 ed_f(lfd, " content_permil=" as *u8); ed_fn(lfd, cm_permil) 221 if tf > 0 { 222 nret = nret + 1 223 ed_p(" <- RETRIEVED\n"); ed_f(lfd, " retrieved=1\n" as *u8) 224 if cfd >= 0 { 225 ed_f(cfd, "DC-URL url=" as *u8); ed_f(cfd, durl[d]) 226 ed_f(cfd, " tf=" as *u8); ed_fn(cfd, tf) 227 ed_f(cfd, " content_permil=" as *u8); ed_fn(cfd, cm_permil) 228 ed_f(cfd, " epoch=" as *u8); ed_fn(cfd, sys_now_realtime_sec()) 229 ed_f(cfd, "\n" as *u8) 230 } 231 } else { ed_p("\n"); ed_f(lfd, " retrieved=0\n" as *u8) } 232 } 233 d = d + 1 234 } 235 if cfd >= 0 { sys_close(cfd) } 236 237 var green: i64 = 0 238 if ndisc >= NX_ED_MIN_DISCOVERED { if nret >= NX_ED_MIN_RETRIEVED { green = 1 } } 239 ed_p(" discovery: "); ed_n(ndisc); ed_p(" found / "); ed_n(nret); ed_p(" retrieved from OUR index\n") 240 ed_f(lfd, "ED-GATE discovered=" as *u8); ed_fn(lfd, ndisc) 241 ed_f(lfd, " retrieved=" as *u8); ed_fn(lfd, nret) 242 ed_f(lfd, " bars=" as *u8); ed_fn(lfd, NX_ED_MIN_DISCOVERED) 243 ed_f(lfd, "/" as *u8); ed_fn(lfd, NX_ED_MIN_RETRIEVED) 244 if green == 1 { ed_f(lfd, " verdict=GREEN\n" as *u8) } else { ed_f(lfd, " verdict=RED\n" as *u8) } 245 sys_close(lfd) 246 if green == 1 { ed_p(" ENTITY-DISCOVERY GATE: GREEN (the crawler found them, we did not)\n"); sys_exit(0); return 0 } 247 ed_p(" ENTITY-DISCOVERY GATE: RED\n") 248 sys_exit(1) 249 return 1 250}