nx_swcompare_hub.nx source
↩ module page · 274 lines · 22856 B
1// nx_swcompare_hub.nx -- GENERATOR for the /compare hub. Reads knowledge/compare/registry (data, one line per
2// comparison: title|kind|href|radar-href-or-dash|stat) and emits the SoftwareCompare landing HTML. This RETIRES
3// the hand-authored hub -> the surface is self-assembling: a workstream that ships a comparison just appends a
4// registry line + reruns this. Kills the multi-session hub-clobber problem (the registry is the SSOT; the hub is
5// always regenerated from it). Modes: no-arg = console + liar-kill (gate); "html" = emit /compare/index.html.
6// NOTE: no '#'/'!' in string literals (nx_cc trap) -> rgb() + emit '!' byte. license_tier: ORIGINAL expect_exit:0
7import "nx_syscalls.nx"
8const K_MAGIC_65536: i64 = 65536
9const K_MAGIC_4096: i64 = 4096
10const K_MAGIC_1024: i64 = 1024
11const K_MAGIC_1536: i64 = 1536
12const K_MAGIC_2048: i64 = 2048
13const K_MAGIC_20480: i64 = 20480
14const K_MAGIC_20479: i64 = 20479
15
16func w(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 }
17func wc(fd: i64, code: i64) -> i64 { let t: *u8 = sys_mmap(2); t[0] = code as u8; sys_write(fd, t, 1); return 0 }
18func wn(fd: i64, v: i64) -> i64 {
19 var m: i64 = v; if m < 0 { w(fd, "-" as *u8); m = 0 - m }
20 let t: *u8 = sys_mmap(24); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 }
21 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
22 let o: *u8 = sys_mmap(24); var i: i64 = 0; while i < k { o[i] = t[k-1-i]; i = i + 1 } sys_write(fd, o, k); return 0
23}
24func streq(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } if b[i] != (0 as u8) { return 0 } return 1 }
25func c_read(path: *u8, buf: *u8, cap: i64) -> i64 {
26 let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 - 1 }
27 var tot: i64 = 0
28 while tot < cap { let r: i64 = sys_read(fd, (buf as i64 + tot) as *u8, cap - tot); if r <= 0 { break } tot = tot + r }
29 sys_close(fd); return tot
30}
31// split line [ls,le) of buf by '|' into fbuf (5 slots x 512), return field count
32func split5(buf: *u8, ls: i64, le: i64, fbuf: *u8) -> i64 {
33 var fi: i64 = 0; var fp: i64 = 0; var q: i64 = ls
34 while q < le {
35 let ch: u8 = buf[q]
36 if ch == (124 as u8) { fbuf[fi*512 + fp] = 0 as u8; if fi < 4 { fi = fi + 1 } fp = 0 } else { if fp < 511 { fbuf[fi*512 + fp] = ch; fp = fp + 1 } }
37 q = q + 1
38 }
39 fbuf[fi*512 + fp] = 0 as u8
40 return fi + 1
41}
42
43func scopy(dst: *u8, doff: i64, src: *u8) -> i64 { var i: i64 = 0; while src[i] != (0 as u8) { dst[doff+i] = src[i]; i = i + 1 } return doff + i }
44func c_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 }
45func wj(fd: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { let c: i64 = s[i] as i64; if c == 34 { wc(fd, 92); wc(fd, 34) } else { if c == 92 { wc(fd, 92); wc(fd, 92) } else { if c < 32 { wc(fd, 32) } else { wc(fd, c) } } } i = i + 1 } return 0 }
46func wq(fd: i64) -> i64 { wc(fd, 34); return 0 }
47func kv_s(fd: i64, key: *u8, val: *u8) -> i64 { wq(fd); w(fd, key); wq(fd); wc(fd, 58); wq(fd); wj(fd, val); wq(fd); return 0 }
48func kv_n(fd: i64, key: *u8, v: i64) -> i64 { wq(fd); w(fd, key); wq(fd); wc(fd, 58); wn(fd, v); return 0 }
49func dom_of(href: *u8, out: *u8) -> i64 { let pfx: *u8 = "/compare/" as *u8; var p: i64 = 0; while pfx[p] != (0 as u8) { if href[p] != pfx[p] { out[0] = 0 as u8; return 0 } p = p + 1 } var o: i64 = 0; while href[p] != (0 as u8) { if href[p] == (47 as u8) { break } out[o] = href[p]; o = o + 1; p = p + 1 } out[o] = 0 as u8; return o }
50// w2: write a literal converting every apostrophe (39) to a double quote (34) -- lets JSON fragments live in
51// nishilang string literals (which cannot contain the double-quote character) as single-quoted text.
52func w2(fd: i64, s: *u8) -> i64 {
53 var i: i64 = 0
54 while s[i] != (0 as u8) { if (s[i] as i64) == 39 { wc(fd, 34) } else { wc(fd, s[i] as i64) } i = i + 1 }
55 return 0
56}
57// wref: emit {"$ref":"#/components/schemas/<nm>"} -- the '#' byte via wc(35) (nx_cc literal trap).
58func wref(fd: i64, nm: *u8) -> i64 {
59 w2(fd, "{'$ref':'" as *u8); wc(fd, 35); w2(fd, "/components/schemas/" as *u8); w(fd, nm); w2(fd, "'}" as *u8)
60 return 0
61}
62// does machine-readable matrix data exist for this domain? Checks BOTH layouts: the laptop authoring copy
63// (knowledge/compare/<dom>-api.json, CWD=nxc2) and the live docroot (../sites/nishifamily/compare/<dom>/api.json,
64// CWD=nishihost/buildroot during on-NAS regen). Either counts.
65func data_exists(dbuf: *u8, pbuf: *u8) -> i64 {
66 var o: i64 = scopy(pbuf, 0, "knowledge/compare/" as *u8); o = scopy(pbuf, o, dbuf); o = scopy(pbuf, o, "-api.json" as *u8); pbuf[o] = 0 as u8
67 if c_exists(pbuf) == 1 { return 1 }
68 o = scopy(pbuf, 0, "../sites/nishifamily/compare/" as *u8); o = scopy(pbuf, o, dbuf); o = scopy(pbuf, o, "/api.json" as *u8); pbuf[o] = 0 as u8
69 return c_exists(pbuf)
70}
71
72func main(argc: i64, argv: *i64) -> i64 {
73 var html: i64 = 0
74 if argc >= 2 { if streq(argv[1] as *u8, "html" as *u8) == 1 { html = 1 } }
75 var jsonmode: i64 = 0
76 if argc >= 2 { if streq(argv[1] as *u8, "json" as *u8) == 1 { jsonmode = 1 } }
77 var oamode: i64 = 0
78 if argc >= 2 { if streq(argv[1] as *u8, "openapi" as *u8) == 1 { oamode = 1 } }
79 let cap: i64 = K_MAGIC_65536
80 let sbuf: *u8 = sys_mmap(cap)
81 let sn: i64 = c_read("knowledge/compare/registry" as *u8, sbuf, cap)
82 let fbuf: *u8 = sys_mmap(K_MAGIC_4096)
83
84 if oamode == 1 {
85 // OpenAPI 3.1 generated IN CODE from the same registry the endpoints serve -- SSOT, cannot drift.
86 let dbuf: *u8 = sys_mmap(256)
87 let pbuf: *u8 = sys_mmap(512)
88 w2(1, "{'openapi':'3.1.0','info':{'title':'Nishi Compare API','version':'1.1.0'," as *u8)
89 w2(1, "'summary':'Mechanically measured, liar-killed software comparisons - Nishi vs the field.'," as *u8)
90 w2(1, "'description':'Machine-readable comparison data. Every Nishi cell is verified against real organ source on disk (no self-grading); competitor cells are documented capability presence; " as *u8)
91 w2(1, "each matrix is liar-killed (a faked win fails the build) and republished by nx_compare_regen only when its gate exits GREEN. Served bits-up by the sovereign Nishi stack over TLS 1.3.'," as *u8)
92 w2(1, "'x-generated-by':'nx_swcompare_hub openapi (in-code SSOT)','x-generated-unix':" as *u8)
93 wn(1, sys_now_realtime_sec())
94 w2(1, "},'servers':[{'url':'https://nishifamily.com'}],'x-available-domains':[" as *u8)
95 var i0: i64 = 0; var first0: i64 = 1
96 while i0 < sn {
97 var j0: i64 = i0
98 while j0 < sn { if sbuf[j0] == (10 as u8) { break } j0 = j0 + 1 }
99 if sbuf[i0] != (35 as u8) { if j0 > i0 {
100 let nf0: i64 = split5(sbuf, i0, j0, fbuf)
101 if nf0 >= 5 {
102 dom_of((fbuf as i64 + K_MAGIC_1024) as *u8, dbuf)
103 if dbuf[0] != (0 as u8) { if data_exists(dbuf, pbuf) == 1 {
104 if first0 == 0 { wc(1, 44) }
105 first0 = 0
106 wq(1); wj(1, dbuf); wq(1)
107 } }
108 }
109 } }
110 i0 = j0 + 1
111 }
112 w2(1, "],'paths':{'/compare/api.json':{'get':{'operationId':'getCompareIndex','summary':'List every comparison (index)','responses':{'200':{'description':'The comparison index','content':{'application/json':{'schema':" as *u8)
113 wref(1, "CompareIndex" as *u8)
114 w2(1, "}}}}}},'/compare/{domain}/api.json':{'get':{'operationId':'getCompareMatrix','summary':'Head-to-head matrix data for one domain','parameters':[{'name':'domain','in':'path','required':true,'schema':{'type':'string'}," as *u8)
115 w2(1, "'description':'Comparison domain; see x-available-domains'}],'responses':{'200':{'description':'Matrix data','content':{'application/json':{'schema':" as *u8)
116 wref(1, "CompareMatrix" as *u8)
117 w2(1, "}}},'404':{'description':'No machine-readable data for this domain'}}}},'/compare/openapi.json':{'get':{'operationId':'getOpenApi','summary':'This OpenAPI document','responses':{'200':{'description':'OpenAPI 3.1 document'}}}}}," as *u8)
118 w2(1, "'components':{'schemas':{'CompareIndex':{'type':'object','required':['v','api','resource','comparisons'],'properties':{'v':{'type':'integer','const':1},'api':{'type':'string'},'generated_unix':{'type':'integer'},'resource':{'type':'string'}," as *u8)
119 w2(1, "'comparisons':{'type':'array','items':" as *u8)
120 wref(1, "Comparison" as *u8)
121 w2(1, "},'_links':{'type':'object','additionalProperties':{'type':'string'}}}},'Comparison':{'type':'object','required':['domain','title','kind','page'],'properties':{'domain':{'type':'string'},'title':{'type':'string'}," as *u8)
122 w2(1, "'kind':{'type':'string','enum':['live','radar','soon']},'page':{'type':'string'},'radar':{'type':'string'},'data':{'type':'string','description':'Machine-readable matrix endpoint; present only when available'},'summary':{'type':'string'}}}," as *u8)
123 w2(1, "'CompareMatrix':{'type':'object','required':['v','api','domain','kind','competitors','axes','tally'],'properties':{'v':{'type':'integer','const':1},'api':{'type':'string'},'generated_unix':{'type':'integer','description':'Wall-clock epoch seconds when this matrix was measured'}," as *u8)
124 w2(1, "'domain':{'type':'string'},'kind':{'type':'string','const':'matrix'},'title':{'type':'string'},'subtitle':{'type':'string'},'competitors':{'type':'array','items':{'type':'string'}},'axes':{'type':'array','items':" as *u8)
125 wref(1, "Axis" as *u8)
126 w2(1, "},'tally':" as *u8)
127 wref(1, "Tally" as *u8)
128 w2(1, ",'codes':{'type':'string'},'measurement':{'type':'string'}}},'Axis':{'type':'object','required':['label','nishi','cells'],'properties':{'label':{'type':'string'},'nishi':{'type':'integer','description':'0=No 1=Yes 2=Best 3=Part'},'exceed':{'type':'integer'}," as *u8)
129 w2(1, "'cells':{'type':'array','items':{'type':'integer'},'description':'One code per competitor, same order as competitors'},'note':{'type':'string'}}},'Tally':{'type':'object','properties':{'coverage':{'type':'integer','description':'permille (present+exceeds)/total'}," as *u8)
130 w2(1, "'exceeds':{'type':'integer'},'present':{'type':'integer'},'absent':{'type':'integer'},'total':{'type':'integer'}}}}}}" as *u8)
131 wc(1, 10)
132 sys_exit(0); return 0
133 }
134
135 if jsonmode == 1 {
136 let dbuf: *u8 = sys_mmap(256)
137 let pbuf: *u8 = sys_mmap(512)
138 wc(1, 123)
139 kv_n(1, "v" as *u8, 1); wc(1, 44)
140 kv_s(1, "api" as *u8, "nishi-compare" as *u8); wc(1, 44)
141 kv_n(1, "generated_unix" as *u8, sys_now_realtime_sec()); wc(1, 44)
142 kv_s(1, "resource" as *u8, "index" as *u8); wc(1, 44)
143 wq(1); w(1, "comparisons" as *u8); wq(1); wc(1, 58); wc(1, 91)
144 var i: i64 = 0; var first: i64 = 1
145 while i < sn {
146 var j: i64 = i
147 while j < sn { if sbuf[j] == (10 as u8) { break } j = j + 1 }
148 if sbuf[i] != (35 as u8) { if j > i {
149 let nf: i64 = split5(sbuf, i, j, fbuf)
150 if nf >= 5 {
151 let title: *u8 = (fbuf as i64) as *u8
152 let kind: *u8 = (fbuf as i64 + 512) as *u8
153 let href: *u8 = (fbuf as i64 + K_MAGIC_1024) as *u8
154 let radar: *u8 = (fbuf as i64 + K_MAGIC_1536) as *u8
155 let stat: *u8 = (fbuf as i64 + K_MAGIC_2048) as *u8
156 dom_of(href, dbuf)
157 if first == 0 { wc(1, 44) }
158 first = 0
159 wc(1, 123)
160 kv_s(1, "domain" as *u8, dbuf); wc(1, 44)
161 kv_s(1, "title" as *u8, title); wc(1, 44)
162 kv_s(1, "kind" as *u8, kind); wc(1, 44)
163 kv_s(1, "page" as *u8, href); wc(1, 44)
164 if streq(radar, "-" as *u8) == 0 { kv_s(1, "radar" as *u8, radar); wc(1, 44) }
165 if data_exists(dbuf, pbuf) == 1 { wq(1); w(1, "data" as *u8); wq(1); wc(1, 58); wq(1); w(1, "/compare/" as *u8); wj(1, dbuf); w(1, "/api.json" as *u8); wq(1); wc(1, 44) }
166 kv_s(1, "summary" as *u8, stat)
167 wc(1, 125)
168 }
169 } }
170 i = j + 1
171 }
172 wc(1, 93); wc(1, 44)
173 wq(1); w(1, "_links" as *u8); wq(1); wc(1, 58); wc(1, 123)
174 kv_s(1, "self" as *u8, "/compare/api.json" as *u8); wc(1, 44)
175 kv_s(1, "openapi" as *u8, "/compare/openapi.json" as *u8); wc(1, 44)
176 kv_s(1, "html" as *u8, "/compare" as *u8)
177 wc(1, 125); wc(1, 125); wc(1, 10)
178 sys_exit(0); return 0
179 }
180
181 if html == 1 {
182 // shared site chrome (nav + footer) generated by nx_site_chrome from knowledge/site/surfaces.reg.
183 // Read as self-contained fragments; graceful fallback to a minimal nav if absent.
184 let hdrbuf: *u8 = sys_mmap(K_MAGIC_20480)
185 var hdn: i64 = c_read("knowledge/site/chrome_header.html" as *u8, hdrbuf, K_MAGIC_20479)
186 if hdn < 0 { hdn = 0 }
187 hdrbuf[hdn] = 0 as u8
188 let ftbuf: *u8 = sys_mmap(K_MAGIC_20480)
189 var ftn: i64 = c_read("knowledge/site/chrome_footer.html" as *u8, ftbuf, K_MAGIC_20479)
190 if ftn < 0 { ftn = 0 }
191 ftbuf[ftn] = 0 as u8
192 w(1, "<" as *u8); wc(1, 33); w(1, "DOCTYPE html>\n<html lang=\"en\"><head><meta charset='utf-8'><meta name='viewport' content='width=device-width, initial-scale=1'>\n" as *u8)
193 w(1, "<title>Nishi Compare -- sovereign, measured software comparison</title>\n<style>\n" as *u8)
194 w(1, ":root{--nx-color-bg:rgb(255,255,255);--nx-color-fg:rgb(22,22,34);--nx-color-accent:rgb(42,77,143);--bg:var(--nx-color-bg);--fg:var(--nx-color-fg);--ac:var(--nx-color-accent);--line:rgb(227,227,234);--soft:rgb(246,247,251);--mut:rgb(102,102,102);--r:rgb(130,80,223)}\n" as *u8)
195 w(1, "*{box-sizing:border-box}body{background:var(--bg);font-family:-apple-system,Segoe UI,Roboto,sans-serif;max-width:820px;margin:0 auto;padding:0 clamp(16px,5vw,22px) 6vh;color:var(--fg);line-height:1.6;font-size:clamp(15px,0.6vw + 13px,17px)}\n" as *u8)
196 w(1, "h1{font-size:clamp(1.7rem,5vw,2.1rem);margin:0 0 6px;background:linear-gradient(90deg,var(--ac),var(--r));-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent}.sub{color:var(--mut);font-size:clamp(.98rem,2vw,1.08rem);margin:0 0 4px}.crumb{font-size:.85rem;margin-bottom:16px}a{color:var(--ac);text-decoration:none}a:hover{text-decoration:underline}\n" as *u8)
197 w(1, ".skip-link{position:absolute;left:-999px;top:0;background:var(--ac);color:rgb(255,255,255);padding:12px 16px;z-index:9;border-radius:0 0 8px 0}.skip-link:focus{left:0}\n" as *u8)
198 w(1, ".hd{background:linear-gradient(90deg,var(--ac),rgb(9,58,136));border-radius:0 0 12px 12px;margin:0 0 20px}.hd nav{display:flex;gap:8px;flex-wrap:wrap;padding:8px 14px}.hd a{color:rgb(255,255,255);text-decoration:none;padding:10px 12px;border-radius:8px;font-weight:600;min-height:44px;display:inline-flex;align-items:center}.hd a:hover{background:rgba(255,255,255,0.16)}\n" as *u8)
199 w(1, ".lead{background:var(--soft);border:1px solid var(--line);border-radius:12px;padding:16px 20px;margin:22px 0;font-size:.95rem}\n" as *u8)
200 w(1, ".card{display:block;border:1px solid var(--line);border-radius:14px;padding:16px 20px;margin:14px 0 6px;color:inherit;box-shadow:0 1px 3px rgba(16,20,28,0.08)}.card:hover{border-color:var(--ac);box-shadow:0 4px 14px rgba(42,77,143,0.15)}.card h2{margin:0 0 4px;font-size:1.2rem;color:var(--ac)}.card .stat{color:var(--mut);font-size:.88rem}\n" as *u8)
201 w(1, ".pill{display:inline-block;font-size:.72rem;padding:2px 9px;border-radius:20px;background:var(--ac);color:rgb(255,255,255);vertical-align:middle;margin-left:8px;font-weight:600}.pill.r{background:var(--r)}.pill.soon{background:rgb(153,153,153)}\n" as *u8)
202 w(1, ".frl{margin:0 0 16px 6px;font-size:.9rem}.foot{margin-top:34px;color:rgb(136,136,136);font-size:.8rem;border-top:1px solid var(--line);padding-top:14px}\n" as *u8)
203 w(1, ".srch{margin:20px 0 4px}.srch input{width:100%;padding:13px 16px;font-size:1rem;border:1px solid var(--line);border-radius:12px;background:var(--soft);color:var(--fg);min-height:48px}.srch input:focus{outline:3px solid var(--ac);outline-offset:1px;border-color:var(--ac)}.srh{color:var(--mut);font-size:.82rem;margin:6px 4px 2px;min-height:1.1em}\n" as *u8)
204 w(1, ":focus-visible{outline:3px solid var(--ac);outline-offset:2px}main>*{animation:rise .5s ease both}main>*:nth-child(2){animation-delay:.05s}main>*:nth-child(3){animation-delay:.1s}main>*:nth-child(4){animation-delay:.15s}@keyframes rise{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}.card{animation:rise linear both;animation-timeline:view();animation-range:entry 0% cover 20%}@media(prefers-reduced-motion:reduce){main>*,.card{animation:none}}\n" as *u8)
205 w(1, "@media(prefers-color-scheme:dark){:root{--nx-color-bg:rgb(15,15,20);--nx-color-fg:rgb(230,230,238);--line:rgb(38,38,47);--soft:rgb(23,23,31);--mut:rgb(154,154,166)}}\n" as *u8)
206 w(1, "</style></head><body>\n" as *u8)
207 w(1, "<a class='skip-link' href='" as *u8); wc(1, 35); w(1, "main'>Skip to content</a>\n" as *u8)
208 if hdn > 0 { w(1, hdrbuf) } else { w(1, "<header class='hd'><nav><a href='/'>Nishi Family</a><a href='/compare'>Compare</a></nav></header>" as *u8) }
209 w(1, "<main id='main'>\n" as *u8)
210 w(1, "<p class='crumb'><a href='/'>Nishi Family</a> › Compare</p>\n<h1>Nishi Compare</h1>\n" as *u8)
211 w(1, "<p class='sub'>Nishi vs the field — <b>mechanically measured</b>, not analyst opinion.</p>\n" as *u8)
212 w(1, "<div class='lead'>Every comparison is generated by a sovereign Nishi organ: each <b>Nishi</b> cell is verified against real source on disk (no self-grading), competitor cells are cited, and each matrix is <b>liar-killed</b> — a faked win fails the build. The <b>Frontier Radars</b> are fed by the nishi researcher over the live 2025/26 frontier: they surface where to test, deepen, or research next. No quadrants, no pay-to-play, no trackers. Measured bits-up.</div>\n" as *u8)
213 w2(1, "<div class='srch'><label for='cmpq' class='vh' style='position:absolute;left:-999px'>Search comparisons</label><input type='search' id='cmpq' placeholder='Search comparisons -- try instrument, llm, containers, team...' autocomplete='off' spellcheck='false'><p class='srh' id='srh' role='status' aria-live='polite'></p></div>\n" as *u8)
214 w2(1, "<div class='cardwrap' id='cards'>\n" as *u8)
215
216 var i: i64 = 0; var cards: i64 = 0
217 while i < sn {
218 var j: i64 = i
219 while j < sn { if sbuf[j] == (10 as u8) { break } j = j + 1 }
220 if sbuf[i] != (35 as u8) {
221 if j > i {
222 let nf: i64 = split5(sbuf, i, j, fbuf)
223 if nf >= 5 {
224 let title: *u8 = (fbuf as i64) as *u8
225 let kind: *u8 = (fbuf as i64 + 512) as *u8
226 let href: *u8 = (fbuf as i64 + K_MAGIC_1024) as *u8
227 let radar: *u8 = (fbuf as i64 + K_MAGIC_1536) as *u8
228 let stat: *u8 = (fbuf as i64 + K_MAGIC_2048) as *u8
229 w(1, "<div class='cu' data-t='" as *u8); w(1, title); w(1, " " as *u8); w(1, kind); w(1, " " as *u8); w(1, stat); w(1, "'>" as *u8)
230 w(1, "<a class='card' href='" as *u8); w(1, href); w(1, "'><h2>" as *u8); w(1, title)
231 w(1, " <span class='pill" as *u8)
232 if streq(kind, "radar" as *u8) == 1 { w(1, " r" as *u8) }
233 if streq(kind, "soon" as *u8) == 1 { w(1, " soon" as *u8) }
234 w(1, "'>" as *u8); w(1, kind); w(1, "</span></h2><div class='stat'>" as *u8); w(1, stat); w(1, "</div></a>\n" as *u8)
235 if streq(radar, "-" as *u8) == 0 { w(1, "<p class='frl'><a href='" as *u8); w(1, radar); w(1, "'>→ Frontier Radar (2025/26 gaps & opportunities)</a></p>\n" as *u8) }
236 w(1, "</div>\n" as *u8)
237 cards = cards + 1
238 }
239 }
240 }
241 i = j + 1
242 }
243 w(1, "</div>\n" as *u8)
244 w(1, "<p class='foot'>Generated by nx_swcompare_hub from knowledge/compare/registry (" as *u8); wn(1, cards); w(1, " comparisons). Self-assembling — a workstream that ships a comparison appends a registry line and reruns. Search is progressive enhancement: every comparison renders without JavaScript. Sovereign Nishi stack — TLS 1.3, no third-party web server, no trackers.</p>\n" as *u8)
245 w(1, "</main>\n" as *u8)
246 if ftn > 0 { w(1, ftbuf) }
247 w2(1, "<script>(function(){var q=document.getElementById('cmpq');var sr=document.getElementById('srh');var wrap=document.getElementById('cards');if(q===null){return;}if(wrap===null){return;}var cards=[].slice.call(wrap.querySelectorAll('.cu'));q.addEventListener('input',function(){var v=q.value.trim().toLowerCase();var n=0;var k=0;while(k<cards.length){var c=cards[k];var hay=c.getAttribute('data-t').toLowerCase();var m=(v.length===0)||(hay.indexOf(v)>=0);c.style.display=m?'':'none';if(m){n=n+1;}k=k+1;}sr.textContent=(v.length>0)?(n+' match'+(n===1?'':'es')):'';});})();</script>\n" as *u8)
248 w(1, "</body></html>\n" as *u8)
249 sys_exit(0); return 0
250 }
251
252 // console / gate
253 w(1, "=== NX-SWCOMPARE-HUB -- generate /compare hub from registry ===\n" as *u8)
254 var i2: i64 = 0; var n: i64 = 0
255 while i2 < sn {
256 var j2: i64 = i2
257 while j2 < sn { if sbuf[j2] == (10 as u8) { break } j2 = j2 + 1 }
258 if sbuf[i2] != (35 as u8) {
259 if j2 > i2 {
260 let nf: i64 = split5(sbuf, i2, j2, fbuf)
261 if nf >= 5 { w(1, " card: " as *u8); w(1, (fbuf as i64) as *u8); w(1, " -> " as *u8); w(1, (fbuf as i64 + K_MAGIC_1024) as *u8); w(1, "\n" as *u8); n = n + 1 }
262 }
263 }
264 i2 = j2 + 1
265 }
266 w(1, " registry entries="); wn(1, n); w(1, "\n" as *u8)
267 let liar_reg: i64 = (sn > 0) as i64
268 let liar_n: i64 = (n >= 1) as i64
269 w(1, " LIAR-KILL: registry-loaded="); wn(1, liar_reg); w(1, " has-entries="); wn(1, liar_n); w(1, "\n" as *u8)
270 let ok: i64 = liar_reg & liar_n
271 w(1, "NX-SWCOMPARE-HUB entries="); wn(1, n); w(1, " verdict=")
272 if ok == 1 { w(1, "OK -- run with 'html' to emit the hub page\n" as *u8); sys_exit(0); return 0 }
273 w(1, "RED (registry missing or empty)\n" as *u8); sys_exit(1); return 1
274}