code wiki / _hdl_build / _wiki_wikilink_gate.nx
_wiki_wikilink_gate.nx source
↩ module page · 176 lines · 8445 B
1// _wiki_wikilink_gate.nx -- THE LIVE-[[WIKILINK]] GATE.
2//
3// Re-proves, from a REAL run (never a fabricated GREEN), that served
4// [[wikilink]] cross-references actually WORK -- they render as LIVE clickable
5// <a> anchors (resolved) or clean broken-spans (missing), NOT as html-escaped
6// dead text (<a ...) and NOT always-broken. Judged on GROUND-TRUTH SUBSTRINGS
7// in the actually-served HTML, driven through the SAME handler the daemon forks
8// (nx_wiki_doc_handle) -- never a bare rc==const.
9//
10// THE TWO BUGS THIS KILLS (both pre-existing):
11// 1. ESCAPED -- the preprocessor expanded [[X]] -> <a ...> BEFORE markdown,
12// so markdown_inline html-escaped the '<','>' to <,> and
13// the link served as DEAD TEXT. FIX: resolve [[X]] in a
14// POST-markdown pass, emitting the <a> RAW (never re-escaped).
15// 2. BROKEN -- the handler init'd the resolver with doc_names_count=0 (a
16// 16-arg IR cap trimmed the names arg), so EVERY [[X]] resolved
17// to a broken-span even when X existed. FIX: derive the
18// known-page set FROM THE STORE the handler holds.
19//
20// SEED a doc store with two pages:
21// realpage -- a real page (URL /wiki/realpage), so [[realpage]] resolves.
22// linker -- body "...[[realpage]]... [[zzqmissing]]..." (URL /wiki/linker);
23// the page under test. zzqmissing is NOT a page -> broken-span.
24//
25// live_ok the served HTML contains a LIVE <a href="/wiki/realpage"
26// (NOT <a, NOT a broken-span for realpage).
27// not_escaped the served HTML does NOT contain "<a href=" ANYWHERE
28// (no dead html-escaped anchor leaked through).
29// broken_ok [[zzqmissing]] rendered to <span class="wikilink-broken".
30//
31// Verdict line (stdout + knowledge/status/wiki_wikilink_gate.log):
32// WIKILINKLIVE live_ok=<0|1> not_escaped=<0|1> broken_ok=<0|1> verdict=GREEN|RED
33//
34// Pure NishiLang, NO SQL, NO .sh/.py/.js, no new .tsv/.conf. nx_sites_daemon
35// UNTOUCHED. Imports the served handler under test; each shared base module
36// resolves via a single canonical path to avoid the nxasm rc6 double-import.
37// license_tier: ORIGINAL
38import "nx_syscalls.nx"
39import "wiki/nx_wiki_index_builder.nx"
40import "wiki/nx_wiki_doc_handler.nx"
41import "wiki/nx_artifact_store.nx"
42
43const WLG_LOG: *u8 = "knowledge/status/wiki_wikilink_gate.log"
44const WLG_RESP_CAP: i64 = 2097152 // 2 MiB served-response buffer
45
46// ===== io helpers (mirror _wiki_integrate_gate.nx) ===========================
47func wlg_w(fd: i64, s: *u8) -> i64 {
48 var n: i64 = 0
49 while s[n] != (0 as u8) { n = n + 1 }
50 sys_write(fd, s, n)
51 return 0
52}
53func wlg_n(fd: i64, v: i64) -> i64 {
54 let bb: *u8 = sys_mmap(28)
55 var m: i64 = v
56 if m < 0 { m = 0 - m; sys_write(fd, "-" as *u8, 1) }
57 let t: *u8 = sys_mmap(28)
58 var k: i64 = 0
59 if m == 0 { t[0] = 48 as u8; k = 1 }
60 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
61 var i: i64 = 0
62 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
63 sys_write(fd, bb, k)
64 return 0
65}
66func wlg_w2(lfd: i64, s: *u8) -> i64 { wlg_w(1, s); if lfd >= 0 { wlg_w(lfd, s) } return 0 }
67func wlg_n2(lfd: i64, v: i64) -> i64 { wlg_n(1, v); if lfd >= 0 { wlg_n(lfd, v) } return 0 }
68func wlg_p(s: *u8) -> i64 { wlg_w(1, s); return 0 }
69func wlg_pn(v: i64) -> i64 { wlg_n(1, v); return 0 }
70func wlg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
71
72// ===== GROUND-TRUTH substring search =========================================
73func wlg_find(hay: *u8, hn: i64, needle: *u8) -> i64 {
74 let nn: i64 = wlg_slen(needle)
75 if nn == 0 { return 0 - 1 }
76 if nn > hn { return 0 - 1 }
77 var i: i64 = 0
78 let last: i64 = hn - nn
79 while i <= last {
80 var j: i64 = 0
81 var eq: i64 = 1
82 while j < nn {
83 if eq == 1 { if hay[i + j] != needle[j] { eq = 0 } }
84 j = j + 1
85 }
86 if eq == 1 { return i }
87 i = i + 1
88 }
89 return 0 - 1
90}
91func wlg_has(hay: *u8, hn: i64, needle: *u8) -> i64 {
92 if wlg_find(hay, hn, needle) >= 0 { return 1 }
93 return 0
94}
95
96func main() -> i64 {
97 wlg_p("WIKILINKLIVE-GATE: start (served [[wikilink]] -> live anchor / clean broken-span)\n" as *u8)
98
99 // ===== SEED a doc store: realpage (real) + linker (links to both) =========
100 let store: *NxWikiDocStore = sys_mmap(2048) as *NxWikiDocStore
101 let rc_init: i64 = nx_wiki_doc_store_init(store, 16, 4096, 4096, 65536)
102 wlg_p(" store_init rc=" as *u8); wlg_pn(rc_init); wlg_p("\n" as *u8)
103
104 // realpage: a real, resolvable page.
105 let rp_body: *u8 = "# Real Page\n\nThis is the real target page.\n" as *u8
106 let rp_rid: i64 = nx_wiki_doc_store_add(store,
107 "Real Page" as *u8, 9, "/wiki/realpage" as *u8, 14, rp_body, wlg_slen(rp_body))
108 // linker: its body links to the real page AND to a missing page.
109 let lk_body: *u8 = "# Linker\n\nGo to [[realpage]] for the goods, but [[zzqmissing]] does not exist.\n" as *u8
110 let lk_rid: i64 = nx_wiki_doc_store_add(store,
111 "Linker" as *u8, 6, "/wiki/linker" as *u8, 12, lk_body, wlg_slen(lk_body))
112 wlg_p(" seeded rowids: realpage=" as *u8); wlg_pn(rp_rid)
113 wlg_p(" linker=" as *u8); wlg_pn(lk_rid)
114 wlg_p(" doc_count=" as *u8); wlg_pn(nx_wiki_doc_store_count(store)); wlg_p("\n" as *u8)
115
116 // ===== RENDER linker via the REAL served handler =========================
117 let url: *u8 = "/wiki/linker" as *u8
118 let url_n: i64 = 12
119 let resp: *u8 = sys_mmap(WLG_RESP_CAP)
120 let resp_n: *i64 = (sys_mmap(8)) as *i64
121 resp_n[0] = 0
122 // artifact_store = 0: the handler treats a null artifact store as a graceful
123 // no-op (no pipeline banner) per Cardinal 14 -- the page still renders.
124 let h_rc: i64 = nx_wiki_doc_handle(store, 0 as *NxArtifactStore, url, url_n,
125 resp, WLG_RESP_CAP, resp_n)
126 let hn: i64 = resp_n[0]
127 wlg_p(" linker handle rc=" as *u8); wlg_pn(h_rc); wlg_p(" resp_len=" as *u8); wlg_pn(hn); wlg_p("\n" as *u8)
128
129 // ---- live_ok: a LIVE <a href="/wiki/realpage" present (resolved anchor) ----
130 var live_ok: i64 = 0
131 let live_at: i64 = wlg_find(resp, hn, "<a href=\"/wiki/realpage\"" as *u8)
132 if live_at >= 0 { live_ok = 1 }
133 wlg_p(" live: <a href=/wiki/realpage @" as *u8); wlg_pn(live_at)
134 wlg_p(" -> live_ok=" as *u8); wlg_pn(live_ok); wlg_p("\n" as *u8)
135
136 // ---- not_escaped: NO "<a href=" anywhere (no dead escaped anchor) ----
137 var not_escaped: i64 = 1
138 let esc_at: i64 = wlg_find(resp, hn, "<a href=" as *u8)
139 if esc_at >= 0 { not_escaped = 0 }
140 wlg_p(" escaped-anchor: <a href= @" as *u8); wlg_pn(esc_at)
141 wlg_p(" (-1=absent=GOOD) -> not_escaped=" as *u8); wlg_pn(not_escaped); wlg_p("\n" as *u8)
142
143 // ---- broken_ok: [[zzqmissing]] -> <span class="wikilink-broken" ----
144 var broken_ok: i64 = 0
145 let broken_at: i64 = wlg_find(resp, hn, "<span class=\"wikilink-broken\"" as *u8)
146 // and the broken target text is intact inside it (no garble): "[[zzqmissing]]"
147 let zzq_at: i64 = wlg_find(resp, hn, "wikilink-broken\">[[zzqmissing]]</span>" as *u8)
148 if broken_at >= 0 { if zzq_at >= 0 { broken_ok = 1 } }
149 wlg_p(" broken: span@" as *u8); wlg_pn(broken_at)
150 wlg_p(" [[zzqmissing]]-span@" as *u8); wlg_pn(zzq_at)
151 wlg_p(" -> broken_ok=" as *u8); wlg_pn(broken_ok); wlg_p("\n" as *u8)
152
153 // EVIDENCE: echo the served article body region (around the links).
154 wlg_p(" ---- served linker HTML (first 1600 bytes) ----\n" as *u8)
155 var dh: i64 = hn
156 if dh > 1600 { dh = 1600 }
157 sys_write(1, resp, dh)
158 wlg_p("\n ---- /served ----\n" as *u8)
159
160 // ===== VERDICT ===========================================================
161 var green: i64 = 1
162 if live_ok != 1 { green = 0 }
163 if not_escaped != 1 { green = 0 }
164 if broken_ok != 1 { green = 0 }
165
166 let lfd: i64 = sys_openat_append(WLG_LOG, 420)
167 wlg_w2(lfd, "WIKILINKLIVE live_ok=" as *u8); wlg_n2(lfd, live_ok)
168 wlg_w2(lfd, " not_escaped=" as *u8); wlg_n2(lfd, not_escaped)
169 wlg_w2(lfd, " broken_ok=" as *u8); wlg_n2(lfd, broken_ok)
170 if green == 1 { wlg_w2(lfd, " verdict=GREEN\n" as *u8) } else { wlg_w2(lfd, " verdict=RED\n" as *u8) }
171 if lfd >= 0 { sys_close(lfd) }
172
173 if green == 1 { sys_exit(0); return 0 }
174 sys_exit(1)
175 return 1
176}