code wiki / (root) / nx_swcompare_hub.nx

nx_swcompare_hub.nx source

↩ module page · 1259 lines · 94777 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 7// 8// v3 (2026-08-24, operator: "the hub is just a big long scroll list without search or filtering or anything else 9// I'd expect from a hub page"): HUB-GRADE USABILITY, ALL DATA-DRIVEN, ALL PROGRESSIVE. 10// * every card carries MEASURED FACTS read at emit from the domain's own emitted api.json (coverage permille, 11// exceeds, present, open contracts, measured date, kind, subtitle) -- the registry's prose stays as the 12// curated line; a domain with no registry row gets a full card from its facts, never a placeholder. 13// * cards are GROUPED by knowledge/compare/hub.groups (dom|group, data); a domain with no row lands in 14// "Ungrouped", printed by name in console mode (a count without a worklist is not actionable). 15// * sticky toolbar: search (kept), group chips, kind chips, sort (coverage / exceeds / recently measured / 16// A-Z), live result count, reset, "/" focuses search, Esc clears, filter state in the URL (?q=&g=&k=&s=). 17// * responsive grid, coverage bar per card, jump-nav of groups with counts, footer partition (groups sum to cards). 18// * NO JavaScript required: without it the page is the grouped grid with anchor chips; JS only filters/sorts. 19// * json mode is ADDITIVE: every comparison now also carries kind_measured, group, coverage, exceeds, present, 20// absent, generated_unix, subtitle when known (old fields untouched -- Rule 19 contract stability). 21// * console mode prints the HUB CENSUS: regen.list domains -> carded / page / facts / grouped, ungrouped NAMED. 22// Verdict RED only on the liar-kill and on a renderable domain that produced no card (a bug in this file). 23// 24// v4 (2026-08-31): TWO DEFECTS, BOTH OF THEM "A FIX THAT LIVES IN ONE ORGAN AND NOT ITS SIBLING". 25// * LAYOUT + THEME NOW COME FROM THE ONE EMITTER. This file carried its OWN :root palette (eleven 26// hardcoded rgb() literals, DARK-ONLY -- no html[data-theme] and no prefers-color-scheme block) and 27// its OWN body rule at max-width:1180px. That made the LANDING PAGE the last page in the family 28// still on a private ruler: a 1180px dark index linking to fluid, theme-aware domain pages. It now 29// composes sc_theme_pass + sc_layout_pass from nx_swcompare_lib, exactly as nx_swcompare_matrix and 30// nx_swcompare_sota do. THE CSS IS NOT COPIED -- copying it is the duplicate-ruler defect this whole 31// change exists to remove. 32// * THE SOTA TALLY IS NO LONGER SILENTLY OMITTED (see hub_tally_from_watch). 33// Importing nx_swcompare_lib also DELETES ten helpers this file had hand-copied from it (w, wc, wn, wj, 34// wq, kv_s, kv_n, c_read, streq, scopy -- byte-identical, so the deletion is provable, not judged). 35import "nx_syscalls.nx" 36import "nx_swcompare_lib.nx" 37const K_MAGIC_65536: i64 = 65536 38const K_MAGIC_4096: i64 = 4096 39const K_MAGIC_1024: i64 = 1024 40const K_MAGIC_1536: i64 = 1536 41const K_MAGIC_2048: i64 = 2048 42const K_MAGIC_20480: i64 = 20480 43const K_MAGIC_20479: i64 = 20479 44// v3 card table: HUB_MAXCARDS slots of HUB_SLOT bytes; a slot holds the card's strings at fixed offsets. 45const HUB_MAXCARDS: i64 = 256 46const HUB_SLOT: i64 = 3072 47const HO_TITLE: i64 = 0 // 256 48const HO_KIND: i64 = 256 // 32 registry kind (live/radar/soon/matrix/auto) 49const HO_HREF: i64 = 288 // 256 50const HO_RADAR: i64 = 544 // 256 51const HO_STAT: i64 = 800 // 1024 registry prose 52const HO_DOM: i64 = 1824 // 64 domain atom (or href key for /modelcard-style pages) 53const HO_GROUP: i64 = 1888 // 64 54const HO_SUB: i64 = 1952 // 512 subtitle from api.json (or the file's @sub) 55const HO_MKIND: i64 = 2464 // 32 measured kind from api.json (matrix/sota/frontier-radar) or empty 56const HO_SLUG: i64 = 2496 // 64 group slug 57const HN: i64 = 12 // numeric fields per card (i64 each); the cn mmap derives its size from this 58const HN_COV: i64 = 0 59const HN_EXC: i64 = 1 60const HN_PRES: i64 = 2 61const HN_ABS: i64 = 3 62const HN_TOT: i64 = 4 63const HN_GEN: i64 = 5 64const HN_FACTS: i64 = 6 // 1 = api.json was read 65const HN_GROUPED: i64 = 7 // 1 = a hub.groups row matched 66const HN_UNJ: i64 = 8 // watch rows carrying no judgeable contract -- neither present nor open 67const HN_ADOPT_FULL: i64 = 10 // api.json adopted_full: organs behind this card's rows at FULL adoption 68const HN_ADOPT_PART: i64 = 11 // api.json adopted_partial: built-unpromoted, promoted-unregistered, registered-dark... 69const HN_TSRC: i64 = 9 // which ruler produced this card's tally: HT_SRC_* 70// WHICH RULER PRODUCED THE TALLY, AS A DECLARED THIRD STATE. HN_FACTS stays the plain binary "api.json 71// was read" that its four consumers already test; this is separate, because "read, but no tally was 72// derivable" and "never read" used to be the SAME observation from outside -- both emitted no numbers at 73// all, so a generator that had silently stopped tallying looked exactly like a domain with no data page. 74const HT_SRC_NONE: i64 = 0 // read, and NEITHER ruler could produce a tally -- abstain, never acquit 75const HT_SRC_TALLY: i64 = 1 // matrix-class: the tally block, axis coverage 76const HT_SRC_WATCH: i64 = 2 // sota-class: derived from the MEASURED watch[] statuses 77const HUB_API_CAP: i64 = 262144 78const HUB_MAXGROUPS: i64 = 32 79const HUB_GSLOT: i64 = 128 80const HUB_SECS_PER_DAY: i64 = 86400 81const HUB_DAYS_TO_CIVIL: i64 = 719468 82const HUB_ERA_DAYS: i64 = 146097 83// the civil-date algorithm's cycle lengths in days: a 4-year leap cycle, a 100-year cycle, and one era less a day 84const HUB_DAYS_4Y: i64 = 1460 85const HUB_DAYS_100Y: i64 = 36524 86const HUB_DAYS_ERA_LESS1: i64 = 146096 87const HUB_STAT_CAP: i64 = 1024 88const HUB_PERMILLE: i64 = 1000 89 90// w / wc / wn / streq / c_read WERE HAND-COPIED FROM nx_swcompare_lib AND ARE NOW IMPORTED FROM IT. 91// Each was BYTE-IDENTICAL to the lib's, so removing them is provable rather than judged -- the same 92// five definitions still exist, there is simply one of each now instead of two that nothing compared. 93// split line [ls,le) of buf by '|' into fbuf (5 slots x 512), return field count 94func split5(buf: *u8, ls: i64, le: i64, fbuf: *u8) -> i64 { 95 var fi: i64 = 0; var fp: i64 = 0; var q: i64 = ls 96 while q < le { 97 let ch: u8 = buf[q] 98 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 } } 99 q = q + 1 100 } 101 fbuf[fi*512 + fp] = 0 as u8 102 return fi + 1 103} 104 105// scopy / wj / wq / kv_s / kv_n: same story as the five above -- byte-identical copies of the lib's, 106// now imported. c_exists stays: it is this file's own, the lib has no such helper. 107func c_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 } 108func 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 } 109// w2: write a literal converting every apostrophe (39) to a double quote (34) -- lets JSON fragments live in 110// nishilang string literals (which cannot contain the double-quote character) as single-quoted text. 111func w2(fd: i64, s: *u8) -> i64 { 112 var i: i64 = 0 113 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 } 114 return 0 115} 116// wref: emit {"$ref":"#/components/schemas/<nm>"} -- the '#' byte via wc(35) (nx_cc literal trap). 117func wref(fd: i64, nm: *u8) -> i64 { 118 w2(fd, "{'$ref':'" as *u8); wc(fd, 35); w2(fd, "/components/schemas/" as *u8); w(fd, nm); w2(fd, "'}" as *u8) 119 return 0 120} 121// THE TWO KNOWLEDGE TREES (measured 2026-08-24): nx_compare_regen chdirs to buildroot, so knowledge/compare/ IS the 122// canonical tree; the mgmt daemon's md_cmp_regen runs this same elf with CWD=nishihost, where knowledge/compare/ is 123// the older twin (its regen.list lacked 19 domains -> the union emitted nothing -> a 73-card hub overwrote the 124// 92-card one). Resolve the compare data dir ONCE: buildroot/knowledge/compare/ when visible, else knowledge/compare/. 125func hub_kc(out: *u8) -> i64 { 126 if c_exists("buildroot/knowledge/compare/regen.list" as *u8) == 1 { let a: i64 = scopy(out, 0, "buildroot/knowledge/compare/" as *u8); out[a] = 0 as u8; return a } 127 let b: i64 = scopy(out, 0, "knowledge/compare/" as *u8); out[b] = 0 as u8 128 return b 129} 130func hub_kcpath(out: *u8, tail: *u8) -> i64 { var o: i64 = hub_kc(out); o = scopy(out, o, tail); out[o] = 0 as u8; return o } 131// does machine-readable matrix data exist for this domain? Checks BOTH layouts: the laptop authoring copy 132// (knowledge/compare/<dom>-api.json, CWD=nxc2) and the live docroot (../sites/nishifamily/compare/<dom>/api.json, 133// CWD=nishihost/buildroot during on-NAS regen). Either counts. 134func data_exists(dbuf: *u8, pbuf: *u8) -> i64 { 135 var o: i64 = hub_kc(pbuf); o = scopy(pbuf, o, dbuf); o = scopy(pbuf, o, "-api.json" as *u8); pbuf[o] = 0 as u8 136 if c_exists(pbuf) == 1 { return 1 } 137 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 138 if c_exists(pbuf) == 1 { return 1 } 139 // CWD=nishihost (the mgmt daemon's md_cmp_regen runs the same elf from there): the docroot is a sibling dir. 140 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 141 return c_exists(pbuf) 142} 143 144// ---- EMIT-TIME UNION (2026-08-18): the hub-orphan class made impossible by construction. 145// 18 live domains had pages but no hub card, because the registry SSOT only grows through 146// /api/compare/upsert and seats shipped pages without calling it (the assembler's regen.list 147// union wrote registry_full, which nothing promoted -- BUILT+UNWIRED). The hub now DERIVES the 148// union at emit: every regen.list domain with a real renderable (.matrix/.sota -- the assembler's 149// own rule, so no card can 404) that has no registry card gets a computed overlay card. Zero 150// writes, no auth, self-healing both ways (retire the domain and the card disappears; a curated 151// upsert replaces the overlay on the next emit). The registry stays the SSOT for curated prose. 152func hub_reg_has(sbuf: *u8, sn: i64, dom: *u8) -> i64 { 153 // needle |/compare/<dom>| -- the href field is pipe-delimited, so prefix domains cannot collide 154 let nd: *u8 = sys_mmap(256) 155 var o: i64 = 0 156 nd[o] = 124 as u8; o = o + 1 157 o = scopy(nd, o, "/compare/" as *u8) 158 o = scopy(nd, o, dom) 159 // boundary: the byte after the domain must be '|' (field end) or '/' (a trailing-slash href) -- never a 160 // longer domain name (so 'lang' cannot match 'language'); /compare/pmdash/ therefore matches pmdash. 161 var i: i64 = 0 162 while i + o + 1 <= sn { 163 var k: i64 = 0 164 var hit: i64 = 1 165 while k < o { if sbuf[i+k] != nd[k] { hit = 0; k = o } else { k = k + 1 } } 166 if hit == 1 { 167 let nb: i64 = sbuf[i+o] as i64 168 if nb == 124 { return 1 } 169 if nb == 47 { return 1 } 170 } 171 i = i + 1 172 } 173 return 0 174} 175// read a header directive (@title / @sub) from <dom>.matrix or <dom>.sota into tout; 1 = renderable, 0 = not 176func hub_dom_line(dom: *u8, pfx: *u8, plen: i64, tout: *u8, tbuf: *u8, tcap: i64) -> i64 { 177 let pb: *u8 = sys_mmap(512) 178 var o: i64 = hub_kc(pb) 179 o = scopy(pb, o, dom) 180 let o0: i64 = o 181 o = scopy(pb, o, ".matrix" as *u8); pb[o] = 0 as u8 182 var n: i64 = c_read(pb, tbuf, tcap - 1) 183 if n <= 0 { 184 o = scopy(pb, o0, ".sota" as *u8); pb[o] = 0 as u8 185 n = c_read(pb, tbuf, tcap - 1) 186 } 187 if n <= 0 { return 0 } 188 tbuf[n] = 0 as u8 189 tout[0] = 0 as u8 190 var i: i64 = 0 191 while i < n { 192 var e: i64 = i 193 while e < n { if tbuf[e] == (10 as u8) { break } e = e + 1 } 194 if (e - i) > plen { 195 var m: i64 = 1 196 var k: i64 = 0 197 while k < plen { if tbuf[i+k] != pfx[k] { m = 0; k = plen } else { k = k + 1 } } 198 if m == 1 { 199 var t: i64 = 0 200 var q: i64 = i + plen 201 while q < e { if t < 250 { tout[t] = tbuf[q]; t = t + 1 } q = q + 1 } 202 tout[t] = 0 as u8 203 return 1 204 } 205 } 206 i = e + 1 207 } 208 return 1 209} 210func hub_dom_title(dom: *u8, tout: *u8, tbuf: *u8, tcap: i64) -> i64 { 211 let r: i64 = hub_dom_line(dom, "@title " as *u8, 7, tout, tbuf, tcap) 212 if r == 1 { if tout[0] == (0 as u8) { var d: i64 = scopy(tout, 0, dom); tout[d] = 0 as u8 } } 213 return r 214} 215 216// ---- v3 helpers ---------------------------------------------------------------------------------- 217func hub_slot(cards: *u8, idx: i64, off: i64) -> *u8 { return (cards as i64 + idx * HUB_SLOT + off) as *u8 } 218func hub_num(cn: *i64, idx: i64, f: i64) -> i64 { return cn[idx * HN + f] } 219func hub_setnum(cn: *i64, idx: i64, f: i64, v: i64) -> i64 { cn[idx * HN + f] = v; return 0 } 220func hub_copyn(dst: *u8, src: *u8, cap: i64) -> i64 { var i: i64 = 0; while src[i] != (0 as u8) { if i < cap - 1 { dst[i] = src[i] } i = i + 1 } if i > cap - 1 { i = cap - 1 } dst[i] = 0 as u8; return i } 221// the card KEY: the domain atom for /compare/<dom>..., else the first path segment (modelcard, editor) 222func hub_key_of(href: *u8, out: *u8) -> i64 { 223 let n: i64 = dom_of(href, out) 224 if n > 0 { return n } 225 var p: i64 = 0 226 if href[0] == (47 as u8) { p = 1 } 227 var o: i64 = 0 228 while href[p] != (0 as u8) { if href[p] == (47 as u8) { break } if o < 60 { out[o] = href[p]; o = o + 1 } p = p + 1 } 229 out[o] = 0 as u8 230 return o 231} 232// find needle in buf[0..n), return offset of the byte AFTER the needle or -1 233func hub_find(buf: *u8, n: i64, nd: *u8, nlen: i64) -> i64 { 234 var i: i64 = 0 235 while i + nlen <= n { 236 var k: i64 = 0 237 var hit: i64 = 1 238 while k < nlen { if buf[i+k] != nd[k] { hit = 0; k = nlen } else { k = k + 1 } } 239 if hit == 1 { return i + nlen } 240 i = i + 1 241 } 242 return 0 - 1 243} 244// JSON number field "key":N -> N, or -1 when absent. The needle is built as bytes so the source carries no quote. 245func jnum(buf: *u8, n: i64, key: *u8) -> i64 { 246 let nd: *u8 = sys_mmap(96) 247 var o: i64 = 0 248 nd[o] = 34 as u8; o = o + 1 249 o = scopy(nd, o, key) 250 nd[o] = 34 as u8; o = o + 1 251 nd[o] = 58 as u8; o = o + 1 252 var p: i64 = hub_find(buf, n, nd, o) 253 if p < 0 { return 0 - 1 } 254 while p < n { if buf[p] == (32 as u8) { p = p + 1 } else { break } } 255 var neg: i64 = 0 256 if p < n { if buf[p] == (45 as u8) { neg = 1; p = p + 1 } } 257 var v: i64 = 0 258 var got: i64 = 0 259 while p < n { 260 let c: i64 = buf[p] as i64 261 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); got = 1; p = p + 1 } else { break } } else { break } 262 } 263 if got == 0 { return 0 - 1 } 264 if neg == 1 { return 0 - v } 265 return v 266} 267// JSON string field "key":"..." -> out (unescaping only the two escapes the emitters produce), -1 when absent 268func jstr(buf: *u8, n: i64, key: *u8, out: *u8, cap: i64) -> i64 { 269 let nd: *u8 = sys_mmap(96) 270 var o: i64 = 0 271 nd[o] = 34 as u8; o = o + 1 272 o = scopy(nd, o, key) 273 nd[o] = 34 as u8; o = o + 1 274 nd[o] = 58 as u8; o = o + 1 275 nd[o] = 34 as u8; o = o + 1 276 var p: i64 = hub_find(buf, n, nd, o) 277 if p < 0 { out[0] = 0 as u8; return 0 - 1 } 278 var t: i64 = 0 279 while p < n { 280 let c: i64 = buf[p] as i64 281 if c == 34 { break } 282 if c == 92 { 283 p = p + 1 284 if p < n { let d: i64 = buf[p] as i64; if t < cap - 1 { if d == 110 { out[t] = 32 as u8 } else { out[t] = d as u8 } t = t + 1 } } 285 } else { 286 if t < cap - 1 { out[t] = c as u8; t = t + 1 } 287 } 288 p = p + 1 289 } 290 out[t] = 0 as u8 291 return t 292} 293// ---- THE SOTA TALLY FALLBACK (2026-08-31) ---- 294// hub_facts read EVERY domain's api.json and then looked only for the matrix tally keys, so for all ten 295// sota-class domains every one of the five numbers came back -1, hub_card_html took its else branch, and 296// the card emitted no bar and no counts -- byte-indistinguishable from a domain whose api.json was never 297// read at all. THE DATA WAS NEVER MISSING, ONLY UNTALLIED: a sota api.json carries watch[], one row per 298// symbol contract, each with a status MEASURED on every publish by the same ruler (nx_symdecl_lib 299// sd_declared) that the matrix generator, the ranker and the comparewatch plane use. So this DERIVES the 300// tally from a measurement already in the document; it does not invent one, and it cannot disagree with 301// the domain's own page by construction. 302// Exact-token match: the closing quote must follow the literal, so PRESENT can never match inside a 303// longer word and a truncated tail can never half-match. 304func hub_wis(buf: *u8, n: i64, at: i64, lit: *u8) -> i64 { 305 var k: i64 = 0 306 while lit[k] != (0 as u8) { 307 if at + k >= n { return 0 } 308 if buf[at + k] != lit[k] { return 0 } 309 k = k + 1 310 } 311 if at + k >= n { return 0 } 312 if buf[at + k] != (34 as u8) { return 0 } 313 return 1 314} 315// Count watch[] rows by status into cnt[0..5]. Returns the row count, or -1 when the document carries no 316// watch array at all (which is the honest third state, not a zero). 317// SCOPED TO THE WATCH ARRAY BY CONSTRUCTION: the scan starts at the watch key rather than at byte 0, so a 318// status field anywhere else in the document cannot inflate the count. watch is the LAST key the sota 319// generator emits (measurement, ppp, refs, then watch, then the closing brace), so from that offset to the 320// end IS the watch array -- written down because it is an assumption that a later-added key would break. 321// cnt[5] is UNKNOWN and exists so an unrecognised status word lands in its OWN bucket instead of being 322// folded into a known one: the partition still sums, and a status added to the ruler later cannot silently 323// read as coverage. It is unreachable from today's emitter (wp_status_text is total over the five) and is 324// therefore a guard against a future vocabulary change, not a live case. 325func hub_wcount(buf: *u8, n: i64, cnt: *i64) -> i64 { 326 var z: i64 = 0 327 while z < 6 { cnt[z] = 0; z = z + 1 } 328 let wk: *u8 = sys_mmap(64) 329 var wo: i64 = 0 330 wk[wo] = 34 as u8; wo = wo + 1 331 wo = scopy(wk, wo, "watch" as *u8) 332 wk[wo] = 34 as u8; wo = wo + 1 333 wk[wo] = 58 as u8; wo = wo + 1 334 let wat: i64 = hub_find(buf, n, wk, wo) 335 if wat < 0 { return 0 - 1 } 336 let nd: *u8 = sys_mmap(64) 337 var o: i64 = 0 338 nd[o] = 34 as u8; o = o + 1 339 o = scopy(nd, o, "status" as *u8) 340 nd[o] = 34 as u8; o = o + 1 341 nd[o] = 58 as u8; o = o + 1 342 nd[o] = 34 as u8; o = o + 1 343 var p: i64 = wat 344 var rows: i64 = 0 345 while p < n { 346 let rel: i64 = hub_find((buf as i64 + p) as *u8, n - p, nd, o) 347 if rel < 0 { break } 348 let at: i64 = p + rel 349 // the five literals are distinct exact tokens, so at most one of these can fire; st keeps the 350 // UNKNOWN default when none does, rather than falling into whichever test ran last. 351 var st: i64 = 5 352 if hub_wis(buf, n, at, "LANDED" as *u8) == 1 { st = 0 } 353 if hub_wis(buf, n, at, "PRESENT" as *u8) == 1 { st = 1 } 354 if hub_wis(buf, n, at, "WATCHING" as *u8) == 1 { st = 2 } 355 if hub_wis(buf, n, at, "MISSING" as *u8) == 1 { st = 3 } 356 if hub_wis(buf, n, at, "ABSENT" as *u8) == 1 { st = 4 } 357 cnt[st] = cnt[st] + 1 358 rows = rows + 1 359 p = at + 1 360 } 361 return rows 362} 363func hub_tsrc_name(t: i64) -> *u8 { 364 if t == HT_SRC_TALLY { return "tally" as *u8 } 365 if t == HT_SRC_WATCH { return "watch" as *u8 } 366 return "none" as *u8 367} 368// read the domain's emitted api.json (three layouts, see data_exists) into abuf; fills the numeric facts, 369// the measured kind and the subtitle. 1 = read, 0 = no data page. 370func hub_facts(cards: *u8, cn: *i64, idx: i64, abuf: *u8, pbuf: *u8) -> i64 { 371 let dom: *u8 = hub_slot(cards, idx, HO_DOM) 372 hub_setnum(cn, idx, HN_FACTS, 0) 373 hub_setnum(cn, idx, HN_COV, 0 - 1); hub_setnum(cn, idx, HN_EXC, 0 - 1); hub_setnum(cn, idx, HN_PRES, 0 - 1) 374 hub_setnum(cn, idx, HN_ABS, 0 - 1); hub_setnum(cn, idx, HN_TOT, 0 - 1); hub_setnum(cn, idx, HN_GEN, 0 - 1) 375 hub_setnum(cn, idx, HN_UNJ, 0 - 1); hub_setnum(cn, idx, HN_TSRC, HT_SRC_NONE) 376 // -1 is ABSTAIN, never zero: a card whose api.json carries no adoption tally must not read as a domain 377 // whose organs are all unadopted, which is the direction that would slander a healthy board. 378 hub_setnum(cn, idx, HN_ADOPT_FULL, 0 - 1); hub_setnum(cn, idx, HN_ADOPT_PART, 0 - 1) 379 if dom[0] == (0 as u8) { return 0 } 380 if data_exists(dom, pbuf) == 0 { return 0 } 381 let n: i64 = c_read(pbuf, abuf, HUB_API_CAP - 1) 382 if n <= 0 { return 0 } 383 abuf[n] = 0 as u8 384 hub_setnum(cn, idx, HN_FACTS, 1) 385 jstr(abuf, n, "kind" as *u8, hub_slot(cards, idx, HO_MKIND), 32) 386 hub_setnum(cn, idx, HN_GEN, jnum(abuf, n, "generated_unix" as *u8)) 387 // the matrix tally lives under "tally":{...}; its keys are unique in the document, so a flat search is exact 388 hub_setnum(cn, idx, HN_COV, jnum(abuf, n, "coverage" as *u8)) 389 hub_setnum(cn, idx, HN_EXC, jnum(abuf, n, "exceeds" as *u8)) 390 hub_setnum(cn, idx, HN_PRES, jnum(abuf, n, "present" as *u8)) 391 hub_setnum(cn, idx, HN_ABS, jnum(abuf, n, "absent" as *u8)) 392 hub_setnum(cn, idx, HN_TOT, jnum(abuf, n, "total" as *u8)) 393 // ADOPTION REACHES THE HUB (2026-09-01). Every matrix board has published adopted_full and 394 // adopted_partial in its api.json since the CE2 adoption pass shipped, and this hub read seven keys 395 // and dropped exactly those two -- so the estate's own wiring number existed on 96 cards and no 396 // surface anywhere summed it. jnum is quote-anchored and returns -1 when the key is absent, so a 397 // sota-class or radar-class card that never tallies adoption keeps -1 and is counted as ABSTAINED 398 // by the rollup rather than being scored zero. 399 hub_setnum(cn, idx, HN_ADOPT_FULL, jnum(abuf, n, "adopted_full" as *u8)) 400 hub_setnum(cn, idx, HN_ADOPT_PART, jnum(abuf, n, "adopted_partial" as *u8)) 401 // THE MATRIX TALLY IS THE PREFERRED RULER; THE WATCH FALLBACK ONLY RUNS WHERE IT PRODUCED NOTHING, so 402 // no matrix-class card can change value here and the 85 domains that already tallied are untouched. 403 if hub_num(cn, idx, HN_COV) >= 0 { hub_setnum(cn, idx, HN_TSRC, HT_SRC_TALLY) } else { 404 let wcnt: *i64 = sys_mmap(64) as *i64 405 let wrows: i64 = hub_wcount(abuf, n, wcnt) 406 if wrows > 0 { 407 // THE MAPPING, AND WHY IT IS FAITHFUL RATHER THAN A COERCION. LANDED and PRESENT are both 408 // "the symbol is measured present on disk" -- the lib's own wp_status_class already groups 409 // them into one class -- so they are one bucket. WATCHING (contract still open) and MISSING 410 // (row names something its organ does not carry) are both "named, and not there", which is 411 // exactly what the card renders as open. ABSENT names NO contract at all, so it is neither: 412 // folding it into present would invent evidence and folding it into open would invent a 413 // commitment, and it gets its own count instead. 414 let pres: i64 = wcnt[0] + wcnt[1] 415 let opn: i64 = wcnt[2] + wcnt[3] 416 let judge: i64 = pres + opn 417 hub_setnum(cn, idx, HN_PRES, pres) 418 hub_setnum(cn, idx, HN_ABS, opn) 419 hub_setnum(cn, idx, HN_UNJ, wcnt[4] + wcnt[5]) 420 hub_setnum(cn, idx, HN_TOT, wrows) 421 // per-mille over the JUDGEABLE rows only, so a row carrying no contract can neither inflate 422 // nor deflate the ratio. With no judgeable row the number stays -1 and the card ABSTAINS 423 // rather than publishing a fabricated 0, which would read as a domain that measured badly. 424 if judge > 0 { hub_setnum(cn, idx, HN_COV, pres * HUB_PERMILLE / judge) } 425 hub_setnum(cn, idx, HN_TSRC, HT_SRC_WATCH) 426 } 427 } 428 let sub: *u8 = hub_slot(cards, idx, HO_SUB) 429 if jstr(abuf, n, "subtitle" as *u8, sub, 512) < 1 { sub[0] = 0 as u8 } 430 return 1 431} 432// hub.groups: dom|group rows. 1 = matched (group copied), 0 = Ungrouped 433func hub_group(gbuf: *u8, gn: i64, key: *u8, out: *u8) -> i64 { 434 var i: i64 = 0 435 while i < gn { 436 var e: i64 = i 437 while e < gn { if gbuf[e] == (10 as u8) { break } e = e + 1 } 438 if e > i { if gbuf[i] != (35 as u8) { 439 var k: i64 = 0 440 var m: i64 = 1 441 while key[k] != (0 as u8) { if i + k >= e { m = 0; break } if gbuf[i+k] != key[k] { m = 0; break } k = k + 1 } 442 if m == 1 { if i + k < e { if gbuf[i+k] == (124 as u8) { 443 var o: i64 = 0 444 var q: i64 = i + k + 1 445 while q < e { if o < 62 { out[o] = gbuf[q]; o = o + 1 } q = q + 1 } 446 out[o] = 0 as u8 447 return 1 448 } } } 449 } } 450 i = e + 1 451 } 452 let u: i64 = scopy(out, 0, "Ungrouped" as *u8); out[u] = 0 as u8 453 return 0 454} 455func hub_slugify(src: *u8, out: *u8) -> i64 { 456 var i: i64 = 0; var o: i64 = 0; var dash: i64 = 1 457 while src[i] != (0 as u8) { 458 var c: i64 = src[i] as i64 459 var ok: i64 = 0 460 if c >= 48 { if c <= 57 { ok = 1 } } 461 if c >= 65 { if c <= 90 { c = c + 32; ok = 1 } } 462 if c >= 97 { if c <= 122 { ok = 1 } } 463 if ok == 1 { if o < 60 { out[o] = c as u8; o = o + 1 } dash = 0 } else { if dash == 0 { if o < 60 { out[o] = 45 as u8; o = o + 1 } dash = 1 } } 464 i = i + 1 465 } 466 if o > 0 { if out[o-1] == (45 as u8) { o = o - 1 } } 467 out[o] = 0 as u8 468 return o 469} 470// attribute-safe writer: apostrophe -> &#39; (the '#' via wc(35)), '<' -> &lt; 471func wa(fd: i64, s: *u8) -> i64 { 472 var i: i64 = 0 473 while s[i] != (0 as u8) { 474 let c: i64 = s[i] as i64 475 if c == 39 { w(fd, "&" as *u8); wc(fd, 35); w(fd, "39;" as *u8) } else { if c == 60 { w(fd, "&lt;" as *u8) } else { wc(fd, c) } } 476 i = i + 1 477 } 478 return 0 479} 480func wlower(fd: i64, s: *u8) -> i64 { 481 var i: i64 = 0 482 while s[i] != (0 as u8) { var c: i64 = s[i] as i64; if c >= 65 { if c <= 90 { c = c + 32 } } if c == 39 { wc(fd, 32) } else { wc(fd, c) } i = i + 1 } 483 return 0 484} 485// civil date (YYYY-MM-DD) from epoch seconds -- days-to-civil, no float, no libc 486func wdate(fd: i64, t: i64) -> i64 { 487 if t <= 0 { w(fd, "-" as *u8); return 0 } 488 let z: i64 = t / HUB_SECS_PER_DAY + HUB_DAYS_TO_CIVIL 489 let era: i64 = z / HUB_ERA_DAYS 490 let doe: i64 = z - era * HUB_ERA_DAYS 491 let yoe: i64 = (doe - doe / HUB_DAYS_4Y + doe / HUB_DAYS_100Y - doe / HUB_DAYS_ERA_LESS1) / 365 492 var y: i64 = yoe + era * 400 493 let doy: i64 = doe - (365 * yoe + yoe / 4 - yoe / 100) 494 let mp: i64 = (5 * doy + 2) / 153 495 let d: i64 = doy - (153 * mp + 2) / 5 + 1 496 var m: i64 = mp + 3 497 if mp >= 10 { m = mp - 9 } 498 if m <= 2 { y = y + 1 } 499 wn(fd, y); wc(fd, 45); if m < 10 { wc(fd, 48) } wn(fd, m); wc(fd, 45); if d < 10 { wc(fd, 48) } wn(fd, d) 500 return 0 501} 502// add one card to the table from its five registry-shaped fields; returns the new count 503func hub_add(cards: *u8, cn: *i64, count: i64, title: *u8, kind: *u8, href: *u8, radar: *u8, stat: *u8) -> i64 { 504 if count >= HUB_MAXCARDS { return count } 505 hub_copyn(hub_slot(cards, count, HO_TITLE), title, 256) 506 hub_copyn(hub_slot(cards, count, HO_KIND), kind, 32) 507 hub_copyn(hub_slot(cards, count, HO_HREF), href, 256) 508 hub_copyn(hub_slot(cards, count, HO_RADAR), radar, 256) 509 hub_copyn(hub_slot(cards, count, HO_STAT), stat, HUB_STAT_CAP) 510 hub_key_of(href, hub_slot(cards, count, HO_DOM)) 511 let zs: *u8 = hub_slot(cards, count, HO_SUB); zs[0] = 0 as u8 512 let zm: *u8 = hub_slot(cards, count, HO_MKIND); zm[0] = 0 as u8 513 let zg: *u8 = hub_slot(cards, count, HO_GROUP); zg[0] = 0 as u8 514 let zl: *u8 = hub_slot(cards, count, HO_SLUG); zl[0] = 0 as u8 515 var f: i64 = 0 516 while f < HN { hub_setnum(cn, count, f, 0 - 1); f = f + 1 } 517 return count + 1 518} 519// the display kind: measured kind when facts exist, else the registry kind 520func hub_disp_kind(cards: *u8, cn: *i64, idx: i64, out: *u8) -> i64 { 521 let mk: *u8 = hub_slot(cards, idx, HO_MKIND) 522 if hub_num(cn, idx, HN_FACTS) == 1 { if mk[0] != (0 as u8) { 523 if streq(mk, "matrix" as *u8) == 1 { let a: i64 = scopy(out, 0, "measured" as *u8); out[a] = 0 as u8; return 1 } 524 if streq(mk, "frontier-radar" as *u8) == 1 { let b: i64 = scopy(out, 0, "radar" as *u8); out[b] = 0 as u8; return 1 } 525 let c: i64 = hub_copyn(out, mk, 32); return 1 526 } } 527 let k: *u8 = hub_slot(cards, idx, HO_KIND) 528 if streq(k, "auto" as *u8) == 1 { let d: i64 = scopy(out, 0, "live" as *u8); out[d] = 0 as u8; return 0 } 529 hub_copyn(out, k, 32) 530 return 0 531} 532// emit one card (html) 533func hub_card_html(cards: *u8, cn: *i64, idx: i64) -> i64 { 534 let dk: *u8 = sys_mmap(40) 535 hub_disp_kind(cards, cn, idx, dk) 536 let title: *u8 = hub_slot(cards, idx, HO_TITLE) 537 let href: *u8 = hub_slot(cards, idx, HO_HREF) 538 let radar: *u8 = hub_slot(cards, idx, HO_RADAR) 539 let stat: *u8 = hub_slot(cards, idx, HO_STAT) 540 let sub: *u8 = hub_slot(cards, idx, HO_SUB) 541 let dom: *u8 = hub_slot(cards, idx, HO_DOM) 542 let cov: i64 = hub_num(cn, idx, HN_COV) 543 w(1, "<article class='cu' data-t='" as *u8); w(1, dk); wc(1, 32); wa(1, hub_slot(cards, idx, HO_GROUP)); wc(1, 32); w(1, dom) 544 w(1, "' data-g='" as *u8); w(1, hub_slot(cards, idx, HO_SLUG)) 545 w(1, "' data-k='" as *u8); w(1, dk) 546 w(1, "' data-c='" as *u8); if cov < 0 { wn(1, 0 - 1) } else { wn(1, cov) } 547 w(1, "' data-x='" as *u8); if hub_num(cn, idx, HN_EXC) < 0 { wc(1, 48) } else { wn(1, hub_num(cn, idx, HN_EXC)) } 548 w(1, "' data-u='" as *u8); if hub_num(cn, idx, HN_GEN) < 0 { wc(1, 48) } else { wn(1, hub_num(cn, idx, HN_GEN)) } 549 w(1, "' data-n='" as *u8); wlower(1, title) 550 w(1, "'>\n<a class='card' href='" as *u8); w(1, href); w(1, "'><h3>" as *u8); w(1, title) 551 w(1, " <span class='pill k-" as *u8); w(1, dk); w(1, "'>" as *u8); w(1, dk); w(1, "</span></h3>\n" as *u8) 552 if cov >= 0 { 553 w(1, "<div class='bar' aria-hidden='true'><i style='width:" as *u8); wn(1, cov / 10); w(1, "%'></i></div>\n<div class='nums'>" as *u8) 554 // THE LABEL NAMES THE RULER THAT PRODUCED THE NUMBER. A matrix coverage per-mille (share of 555 // AXES on which Nishi is present) and a sota contract per-mille (share of watch CONTRACTS 556 // measured landed) are two different measurements over two different populations. Publishing 557 // both under the single word coverage would be the subject-mismatch defect -- two witnesses of 558 // DIFFERENT subjects rendered as though they were one, which is how a reader compares numbers 559 // that were never comparable. The bucket words below (present, open) hold for both rulers. 560 if hub_num(cn, idx, HN_TSRC) == HT_SRC_WATCH { w(1, "contracts <b>" as *u8) } else { w(1, "coverage <b>" as *u8) } 561 wn(1, cov); w(1, "</b>/" as *u8); wn(1, HUB_PERMILLE) 562 if hub_num(cn, idx, HN_EXC) >= 0 { w(1, " &middot; " as *u8); wn(1, hub_num(cn, idx, HN_EXC)); w(1, " exceed" as *u8) } 563 if hub_num(cn, idx, HN_PRES) >= 0 { w(1, " &middot; " as *u8); wn(1, hub_num(cn, idx, HN_PRES)); w(1, " present" as *u8) } 564 if hub_num(cn, idx, HN_ABS) >= 0 { w(1, " &middot; " as *u8); wn(1, hub_num(cn, idx, HN_ABS)); w(1, " open" as *u8) } 565 // The unjudgeable rows are printed ONLY when there are some, so every matrix-class card stays 566 // byte-identical; where they exist the card shows present + open + this summing to the rows read. 567 if hub_num(cn, idx, HN_UNJ) > 0 { w(1, " &middot; " as *u8); wn(1, hub_num(cn, idx, HN_UNJ)); w(1, " no contract" as *u8) } 568 if hub_num(cn, idx, HN_GEN) > 0 { w(1, " &middot; measured " as *u8); wdate(1, hub_num(cn, idx, HN_GEN)) } 569 w(1, "</div>\n" as *u8) 570 } else { 571 if hub_num(cn, idx, HN_GEN) > 0 { w(1, "<div class='nums'>" as *u8); w(1, dk); w(1, " &middot; updated " as *u8); wdate(1, hub_num(cn, idx, HN_GEN)); w(1, "</div>\n" as *u8) } 572 } 573 if sub[0] != (0 as u8) { w(1, "<div class='sub2'>" as *u8); wa(1, sub); w(1, "</div>\n" as *u8) } 574 if stat[0] != (0 as u8) { w(1, "<div class='stat'>" as *u8); w(1, stat); w(1, "</div>\n" as *u8) } 575 w(1, "</a>\n" as *u8) 576 if streq(radar, "-" as *u8) == 0 { if radar[0] != (0 as u8) { w(1, "<p class='frl'><a href='" as *u8); w(1, radar); w(1, "'>&rarr; Frontier Radar</a></p>\n" as *u8) } } 577 w(1, "</article>\n" as *u8) 578 return 0 579} 580// emit one card (json object, leading comma handled by the caller) 581func hub_card_json(cards: *u8, cn: *i64, idx: i64, pbuf: *u8) -> i64 { 582 let dk: *u8 = sys_mmap(40) 583 hub_disp_kind(cards, cn, idx, dk) 584 let dom: *u8 = hub_slot(cards, idx, HO_DOM) 585 let radar: *u8 = hub_slot(cards, idx, HO_RADAR) 586 wc(1, 123) 587 kv_s(1, "domain" as *u8, dom); wc(1, 44) 588 kv_s(1, "title" as *u8, hub_slot(cards, idx, HO_TITLE)); wc(1, 44) 589 kv_s(1, "kind" as *u8, hub_slot(cards, idx, HO_KIND)); wc(1, 44) 590 kv_s(1, "kind_measured" as *u8, dk); wc(1, 44) 591 kv_s(1, "group" as *u8, hub_slot(cards, idx, HO_GROUP)); wc(1, 44) 592 kv_s(1, "page" as *u8, hub_slot(cards, idx, HO_HREF)); wc(1, 44) 593 if streq(radar, "-" as *u8) == 0 { if radar[0] != (0 as u8) { kv_s(1, "radar" as *u8, radar); wc(1, 44) } } 594 if hub_num(cn, idx, HN_FACTS) == 1 { wq(1); w(1, "data" as *u8); wq(1); wc(1, 58); wq(1); w(1, "/compare/" as *u8); wj(1, dom); w(1, "/api.json" as *u8); wq(1); wc(1, 44) } 595 if hub_num(cn, idx, HN_COV) >= 0 { kv_n(1, "coverage" as *u8, hub_num(cn, idx, HN_COV)); wc(1, 44) } 596 if hub_num(cn, idx, HN_EXC) >= 0 { kv_n(1, "exceeds" as *u8, hub_num(cn, idx, HN_EXC)); wc(1, 44) } 597 if hub_num(cn, idx, HN_PRES) >= 0 { kv_n(1, "present" as *u8, hub_num(cn, idx, HN_PRES)); wc(1, 44) } 598 if hub_num(cn, idx, HN_ABS) >= 0 { kv_n(1, "absent" as *u8, hub_num(cn, idx, HN_ABS)); wc(1, 44) } 599 // THE THIRD STATE, PUBLISHED RATHER THAN INFERRED. tally_source rides on every card whose api.json 600 // was read, INCLUDING the none case, so a consumer can finally tell "read, but no tally was 601 // derivable" from "there is no data page" -- outside this field those two are the same silence, and 602 // a generator that silently stopped tallying would look exactly like a domain with no data. 603 // The watch-derived cards also carry their population and their unjudgeable count, so the partition 604 // present + absent + watch_unjudgeable = watch_rows is CHECKABLE from outside instead of trusted. 605 if hub_num(cn, idx, HN_FACTS) == 1 { kv_s(1, "tally_source" as *u8, hub_tsrc_name(hub_num(cn, idx, HN_TSRC))); wc(1, 44) } 606 if hub_num(cn, idx, HN_TSRC) == HT_SRC_WATCH { 607 if hub_num(cn, idx, HN_TOT) >= 0 { kv_n(1, "watch_rows" as *u8, hub_num(cn, idx, HN_TOT)); wc(1, 44) } 608 if hub_num(cn, idx, HN_UNJ) >= 0 { kv_n(1, "watch_unjudgeable" as *u8, hub_num(cn, idx, HN_UNJ)); wc(1, 44) } 609 } 610 if hub_num(cn, idx, HN_GEN) > 0 { kv_n(1, "generated_unix" as *u8, hub_num(cn, idx, HN_GEN)); wc(1, 44) } 611 let jsub: *u8 = hub_slot(cards, idx, HO_SUB) 612 if jsub[0] != (0 as u8) { kv_s(1, "subtitle" as *u8, jsub); wc(1, 44) } 613 kv_s(1, "summary" as *u8, hub_slot(cards, idx, HO_STAT)) 614 wc(1, 125) 615 return 0 616} 617// build the card table: registry rows first, then the regen.list union (auto cards), then facts + groups. 618// Returns the card count. The group table (gt) receives the DISTINCT group names in hub.groups file order, 619// Ungrouped last; gcount[0] = number of groups. 620func hub_build(sbuf: *u8, sn: i64, cards: *u8, cn: *i64, gt: *u8, gcount: *i64) -> i64 { 621 let fbuf: *u8 = sys_mmap(K_MAGIC_4096) 622 var count: i64 = 0 623 var i: i64 = 0 624 while i < sn { 625 var j: i64 = i 626 while j < sn { if sbuf[j] == (10 as u8) { break } j = j + 1 } 627 if sbuf[i] != (35 as u8) { if j > i { 628 let nf: i64 = split5(sbuf, i, j, fbuf) 629 if nf >= 5 { 630 count = hub_add(cards, cn, count, (fbuf as i64) as *u8, (fbuf as i64 + 512) as *u8, (fbuf as i64 + K_MAGIC_1024) as *u8, (fbuf as i64 + K_MAGIC_1536) as *u8, (fbuf as i64 + K_MAGIC_2048) as *u8) 631 } 632 } } 633 i = j + 1 634 } 635 // union: every regen.list renderable missing from the registry 636 let rl: *u8 = sys_mmap(K_MAGIC_4096) 637 let rlp: *u8 = sys_mmap(512) 638 hub_kcpath(rlp, "regen.list" as *u8) 639 let rn: i64 = c_read(rlp, rl, K_MAGIC_4096 - 1) 640 let dom: *u8 = sys_mmap(256) 641 let title: *u8 = sys_mmap(256) 642 let tbuf: *u8 = sys_mmap(K_MAGIC_4096) 643 let href: *u8 = sys_mmap(300) 644 let qp: *u8 = sys_mmap(512) 645 let radar: *u8 = sys_mmap(300) 646 var p: i64 = 0 647 while p < rn { 648 var e: i64 = p 649 while e < rn { if rl[e] == (10 as u8) { break } e = e + 1 } 650 if e > p { if rl[p] != (35 as u8) { 651 var d: i64 = 0 652 var q: i64 = p 653 while q < e { if d < 250 { dom[d] = rl[q]; d = d + 1 } q = q + 1 } 654 dom[d] = 0 as u8 655 if hub_reg_has(sbuf, sn, dom) == 0 { 656 if hub_dom_title(dom, title, tbuf, K_MAGIC_4096) == 1 { 657 var h: i64 = scopy(href, 0, "/compare/" as *u8); h = scopy(href, h, dom); href[h] = 0 as u8 658 var o: i64 = hub_kc(qp); o = scopy(qp, o, dom); o = scopy(qp, o, ".q" as *u8); qp[o] = 0 as u8 659 radar[0] = 45 as u8; radar[1] = 0 as u8 660 if c_exists(qp) == 1 { var r: i64 = scopy(radar, 0, href); r = scopy(radar, r, "/frontier" as *u8); radar[r] = 0 as u8 } 661 count = hub_add(cards, cn, count, title, "auto" as *u8, href, radar, "" as *u8) 662 } 663 } 664 } } 665 p = e + 1 666 } 667 // facts + groups 668 let abuf: *u8 = sys_mmap(HUB_API_CAP) 669 let pbuf: *u8 = sys_mmap(512) 670 let gbuf: *u8 = sys_mmap(K_MAGIC_20480) 671 let gp: *u8 = sys_mmap(512) 672 hub_kcpath(gp, "hub.groups" as *u8) 673 var gn: i64 = c_read(gp, gbuf, K_MAGIC_20479) 674 if gn < 0 { gn = 0 } 675 let sub2: *u8 = sys_mmap(300) 676 var c: i64 = 0 677 while c < count { 678 hub_facts(cards, cn, c, abuf, pbuf) 679 // subtitle fallback: the renderable's own @sub line 680 let csub: *u8 = hub_slot(cards, c, HO_SUB) 681 if csub[0] == (0 as u8) { 682 if hub_dom_line(hub_slot(cards, c, HO_DOM), "@sub " as *u8, 5, sub2, tbuf, K_MAGIC_4096) == 1 { hub_copyn(csub, sub2, 512) } 683 } 684 let g: i64 = hub_group(gbuf, gn, hub_slot(cards, c, HO_DOM), hub_slot(cards, c, HO_GROUP)) 685 hub_setnum(cn, c, HN_GROUPED, g) 686 hub_slugify(hub_slot(cards, c, HO_GROUP), hub_slot(cards, c, HO_SLUG)) 687 c = c + 1 688 } 689 // distinct groups in file order (a group named in the file but carrying no card is simply not emitted) 690 var ng: i64 = 0 691 var gi: i64 = 0 692 while gi < gn { 693 var ge: i64 = gi 694 while ge < gn { if gbuf[ge] == (10 as u8) { break } ge = ge + 1 } 695 if ge > gi { if gbuf[gi] != (35 as u8) { 696 var bar: i64 = gi 697 while bar < ge { if gbuf[bar] == (124 as u8) { break } bar = bar + 1 } 698 if bar < ge { 699 let gname: *u8 = (gt as i64 + ng * HUB_GSLOT) as *u8 700 var o2: i64 = 0 701 var q2: i64 = bar + 1 702 while q2 < ge { if o2 < 62 { gname[o2] = gbuf[q2]; o2 = o2 + 1 } q2 = q2 + 1 } 703 gname[o2] = 0 as u8 704 var dup: i64 = 0 705 var k2: i64 = 0 706 while k2 < ng { if streq((gt as i64 + k2 * HUB_GSLOT) as *u8, gname) == 1 { dup = 1; k2 = ng } else { k2 = k2 + 1 } } 707 if dup == 0 { if ng < HUB_MAXGROUPS - 1 { ng = ng + 1 } } 708 } 709 } } 710 gi = ge + 1 711 } 712 let ug: *u8 = (gt as i64 + ng * HUB_GSLOT) as *u8 713 let un: i64 = scopy(ug, 0, "Ungrouped" as *u8); ug[un] = 0 as u8 714 ng = ng + 1 715 gcount[0] = ng 716 return count 717} 718// ---- ESTATE ROLLUP (2026-09-01, ecosystem rung EC9) ---- 719// THE DEFECT THIS CLOSES: hub_facts reads coverage exceeds present absent total generated_unix and (since 720// today) the two adoption counts out of EVERY domain api.json, and hub_card_html/hub_card_json publish them 721// PER CARD. Above the card there was NOTHING -- no sum, no median, no distribution, no oldest-measured. The 722// estate published ninety-six cards of numbers and not one aggregate, so a reader could ask /compare about 723// one domain at a time and never about the estate as a whole. 724// ABSTENTION IS A FIRST-CLASS OUTPUT, NOT A ZERO. A card whose ruler produced no tally is counted in 725// HR_ABSTAINED and EXCLUDED from the percentiles; scoring it 0 would drag the estate median down with 726// domains that were never measured, which is the flattering-direction error inverted -- it would slander a 727// healthy estate. Same rule for adoption: only cards that actually published the keys enter HR_WITH_ADOPT. 728// gname empty = the whole estate; gname set = that lane only, so one function serves both bands and the 729// per-lane numbers cannot drift from the estate ones. 730const HR_DOMAINS: i64 = 0 731const HR_WITH_TALLY: i64 = 1 732const HR_COV_P50: i64 = 2 733const HR_COV_P90: i64 = 3 734const HR_SUM_PRES: i64 = 4 735const HR_SUM_OPEN: i64 = 5 736const HR_SUM_EXC: i64 = 6 737const HR_SUM_UNJ: i64 = 7 738const HR_OLDEST: i64 = 8 739const HR_ABSTAINED: i64 = 9 740const HR_ADOPT_FULL: i64 = 10 741const HR_ADOPT_PART: i64 = 11 742const HR_WITH_ADOPT: i64 = 12 743const HR_N: i64 = 13 744func hub_rollup(cards: *u8, cn: *i64, count: i64, gname: *u8, out: *i64) -> i64 { 745 var z: i64 = 0 746 while z < HR_N { out[z] = 0; z = z + 1 } 747 out[HR_OLDEST] = 0 - 1 748 let covs: *i64 = sys_mmap(HUB_MAXCARDS * 8) as *i64 749 var nc: i64 = 0 750 var i: i64 = 0 751 while i < count { 752 var take: i64 = 1 753 if gname[0] != (0 as u8) { if streq(hub_slot(cards, i, HO_GROUP), gname) == 0 { take = 0 } } 754 if take == 1 { 755 out[HR_DOMAINS] = out[HR_DOMAINS] + 1 756 let cv: i64 = hub_num(cn, i, HN_COV) 757 if cv >= 0 { 758 out[HR_WITH_TALLY] = out[HR_WITH_TALLY] + 1 759 covs[nc] = cv; nc = nc + 1 760 let pr: i64 = hub_num(cn, i, HN_PRES); if pr > 0 { out[HR_SUM_PRES] = out[HR_SUM_PRES] + pr } 761 let ab: i64 = hub_num(cn, i, HN_ABS); if ab > 0 { out[HR_SUM_OPEN] = out[HR_SUM_OPEN] + ab } 762 let ex: i64 = hub_num(cn, i, HN_EXC); if ex > 0 { out[HR_SUM_EXC] = out[HR_SUM_EXC] + ex } 763 let uj: i64 = hub_num(cn, i, HN_UNJ); if uj > 0 { out[HR_SUM_UNJ] = out[HR_SUM_UNJ] + uj } 764 } else { out[HR_ABSTAINED] = out[HR_ABSTAINED] + 1 } 765 let af: i64 = hub_num(cn, i, HN_ADOPT_FULL) 766 if af >= 0 { 767 out[HR_WITH_ADOPT] = out[HR_WITH_ADOPT] + 1 768 out[HR_ADOPT_FULL] = out[HR_ADOPT_FULL] + af 769 let ap: i64 = hub_num(cn, i, HN_ADOPT_PART) 770 if ap > 0 { out[HR_ADOPT_PART] = out[HR_ADOPT_PART] + ap } 771 } 772 let gu: i64 = hub_num(cn, i, HN_GEN) 773 if gu > 0 { if out[HR_OLDEST] < 0 { out[HR_OLDEST] = gu } else { if gu < out[HR_OLDEST] { out[HR_OLDEST] = gu } } } 774 } 775 i = i + 1 776 } 777 // insertion sort ascending. THE LOOP EXIT IS A FLAG, NEVER A SENTINEL WRITTEN INTO THE CURSOR: setting 778 // b to -1 to break would destroy the insertion position the line after the loop depends on, which is a 779 // defect this estate has written four times in one day and is the reason this comment exists. 780 var a: i64 = 1 781 while a < nc { 782 let v: i64 = covs[a] 783 var b: i64 = a - 1 784 var done: i64 = 0 785 while done == 0 { 786 if b < 0 { done = 1 } else { if covs[b] > v { covs[b+1] = covs[b]; b = b - 1 } else { done = 1 } } 787 } 788 covs[b+1] = v 789 a = a + 1 790 } 791 if nc > 0 { 792 out[HR_COV_P50] = covs[nc / 2] 793 var i90: i64 = (nc * 9) / 10 794 if i90 >= nc { i90 = nc - 1 } 795 out[HR_COV_P90] = covs[i90] 796 } else { out[HR_COV_P50] = 0 - 1; out[HR_COV_P90] = 0 - 1 } 797 return out[HR_DOMAINS] 798} 799// order the cards of one group by coverage descending (unknown coverage last), then title; fills ord, returns n 800func hub_order(cards: *u8, cn: *i64, count: i64, gname: *u8, ord: *i64) -> i64 { 801 var n: i64 = 0 802 var i: i64 = 0 803 while i < count { if streq(hub_slot(cards, i, HO_GROUP), gname) == 1 { ord[n] = i; n = n + 1 } i = i + 1 } 804 // selection sort: n <= 256 805 var a: i64 = 0 806 while a < n { 807 var best: i64 = a 808 var b: i64 = a + 1 809 while b < n { 810 let cb: i64 = hub_num(cn, ord[b], HN_COV) 811 let cbest: i64 = hub_num(cn, ord[best], HN_COV) 812 if cb > cbest { best = b } 813 b = b + 1 814 } 815 if best != a { let t: i64 = ord[a]; ord[a] = ord[best]; ord[best] = t } 816 a = a + 1 817 } 818 return n 819} 820 821// The published measurement contract describes the producer; it does not compute a second score. 822func hub_measurement_schema(fd: i64) -> i64 { 823 w2(fd, "'SotaBoardMeasurement':{'type':'object','description':'Published domain-only observation produced by nx_sota_status. The MCP nishi_compare measurement resource serves the same artifact. Presence and evidence confidence do not establish maturity or SOTA benchmark attainment.','required':['v','api','resource','generated_unix','producer','scope','policy','limitations','domains'],'properties':{'v':{'t" as *u8) 824 w2(fd, "ype':'integer','const':1},'api':{'type':'string','const':'nishi-measurement'},'resource':{'type':'string','const':'sota-board'},'generated_unix':{'type':'integer','description':'Observation generation time in Unix seconds; not the execution time of cached evidence.'},'producer':{'type':'string','const':'nx_sota_status'},'scope':{'type':'object','required':['entity_kind','graded_domains','matrix_do" as *u8) 825 w2(fd, "mains','axes_only_domains','omitted_entries','unreadable_directory_passes','local_discovery_complete','estate_total','uncovered_entities','estate_wide'],'properties':{'entity_kind':{'type':'string','const':'domain'},'graded_domains':{'type':'integer','minimum':0,'description':'Number of emitted domains; does not represent an estate inventory denominator.'},'matrix_domains':{'type':'integer','minim" as *u8) 826 w2(fd, "um':0},'axes_only_domains':{'type':'integer','minimum':0},'omitted_entries':{'type':'integer','minimum':0},'unreadable_directory_passes':{'type':'integer','minimum':0},'local_discovery_complete':{'type':'boolean','description':'True only when local discovery reports no omissions or unreadable directory passes; does not establish estate-wide coverage.'},'estate_total':{'type':'null','description':'" as *u8) 827 w2(fd, "Not yet reconciled against Compare and capability inventories.'},'uncovered_entities':{'type':'null','description':'Uncovered entities cannot be enumerated before inventory reconciliation.'},'estate_wide':{'type':'boolean','const':false}}},'policy':{'type':'object','required':['ttl_sec','minimum_method_classes'],'properties':{'ttl_sec':{'type':'integer','minimum':0},'minimum_method_classes':{'type" as *u8) 828 w2(fd, "':'integer','minimum':0}}},'limitations':{'type':'array','items':{'type':'string'},'description':'Material measurement gaps retained in the emitted observation.'},'domains':{'type':'array','items':{'type':'object','required':['domain','classification','presence','source','evidence','rung','sota_benchmark','next_investment'],'properties':{'domain':{'type':'string'},'classification':{'type':'string'" as *u8) 829 w2(fd, ",'enum':['PROVEN','RED','MECH-OK','GATED-UNVERIFIED','CLAIM-ONLY','UNPROVEN'],'description':'Existing evidence classification; not a first-byte rung or SOTA quality score.'},'presence':{'type':'object','required':['permille','present','exceed_claims','gaps','total'],'properties':{'permille':{'type':'integer','minimum':0,'maximum':1000,'description':'Floor of 1000 times (present plus exceed_claims)" as *u8) 830 w2(fd, " divided by total; zero when total is zero. Presence is not maturity.'},'present':{'type':'integer','minimum':0},'exceed_claims':{'type':'integer','minimum':0,'description':'Matrix exceed claims; does not establish independently benchmarked superiority.'},'gaps':{'type':'integer','minimum':0},'total':{'type':'integer','minimum':0,'description':'Exact classified axis denominator: present plus excee" as *u8) 831 w2(fd, "d_claims plus gaps.'}}},'source':{'type':'object','required':['path','bytes_read','state'],'properties':{'path':{'type':['string','null'],'description':'Resolved local matrix or axes path; null when no source resolved.'},'bytes_read':{'type':'integer'},'state':{'type':'string','enum':['read','unreadable_or_empty']}}},'evidence':{'type':'object','required':['has_nonempty_gate_map','stamp_epoch','ag" as *u8) 832 w2(fd, "e_seconds','freshness','referee_reason'],'properties':{'has_nonempty_gate_map':{'type':'boolean'},'stamp_epoch':{'type':['integer','null'],'description':'Cached evidence execution epoch; null when absent.'},'age_seconds':{'type':['integer','null'],'description':'Observation time minus stamp epoch; null when absent, negative for a future stamp.'},'freshness':{'type':'string','enum':['unknown','futu" as *u8) 833 w2(fd, "re_stamp','fresh','stale']},'referee_reason':{'type':['string','null']}}},'rung':{'type':'null','description':'First-byte rung bindings are not yet measured.'},'sota_benchmark':{'type':'null','description':'SOTA benchmark identity and attainment are not yet bound.'},'next_investment':{'type':'null','description':'Requires an authoritative action and effort record; no investment estimate is inferre" as *u8) 834 w2(fd, "d.'}}}}}}," as *u8) 835 return 0 836} 837 838// Publish the existing ledger declaration contract without adding another ROI calculation. 839func hub_investment_schema(fd: i64) -> i64 { 840 w2(fd, "'TokenInvestmentReport':{'type':'object','description':'Exact published nx_tokroi report from the existing eight-column ledger. Values, REALIZED/PROJECTED labels and evidence strings are declarations; not verified savings, execution history or benchmark results. No domain/capability join is asserted.','required':['organ','verb','ok','levers','realized','projected','rows','unknown_status_rows','dec" as *u8) 841 w2(fd, "lared_rows','loaded_rows','beyond_count_rows_detected','history_complete','evidence_scope','units_verified','note'],'properties':{'organ':{'type':'string','const':'nx_tokroi'},'verb':{'type':'string','const':'report'},'ok':{'type':'boolean','const':true},'levers':{'type':'array','items':{'type':'object','required':['id','lever','status','investment','baseline','after','reduction_per_use','uses_per" as *u8) 842 w2(fd, "_day','daily_reduction','payback_uses','evidence','signed_delta','break_even_uses','aggregation_eligible','evidence_verified'],'properties':{'id':{'type':'string','minLength':1},'lever':{'type':'string','minLength':1},'status':{'type':'string','description':'Ledger label. Exact REALIZED and PROJECTED labels are aggregated separately; other labels remain visible and excluded.'},'investment':{'type'" as *u8) 843 w2(fd, ":'integer','minimum':0,'description':'Declared one-off estimate; not observed implementation cost.'},'baseline':{'type':'integer','minimum':0},'after':{'type':'integer','minimum':0},'reduction_per_use':{'type':'integer','minimum':0,'description':'Legacy max(baseline-after,0), preserving the existing nonnegative field.'},'uses_per_day':{'type':'integer','minimum':0,'description':'Declared assumptio" as *u8) 844 w2(fd, "n, not observed use frequency.'},'daily_reduction':{'type':'integer','minimum':0,'description':'Declared reduction_per_use multiplied by assumed uses_per_day; not measured daily savings.'},'payback_uses':{'type':'integer','minimum':-1,'description':'Legacy floor(investment/reduction_per_use), or -1 when reduction is not positive.'},'evidence':{'type':'string','description':'Full ledger evidence st" as *u8) 845 w2(fd, "ring, neither resolved nor independently verified.'},'signed_delta':{'type':'integer','description':'baseline-after; negative values retain declared regressions.'},'break_even_uses':{'type':['integer','null'],'minimum':0,'description':'Ceiling(investment/reduction_per_use) when reduction is positive; otherwise null. Conditional arithmetic assumes comparable units; not a payoff date.'},'aggregation" as *u8) 846 w2(fd, "_eligible':{'type':'boolean','description':'Whether the exact label belongs to the two supported totals; not evidence quality.'},'evidence_verified':{'type':'boolean','const':false}}}},'realized':{'type':'object','description':'Totals for rows labelled REALIZED; the label does not establish observed savings.','required':['daily_reduction','investment','levers'],'properties':{'daily_reduction':{'ty" as *u8) 847 w2(fd, "pe':'integer','minimum':0},'investment':{'type':'integer','minimum':0},'levers':{'type':'integer','minimum':0}}},'projected':{'type':'object','description':'Separate totals for rows labelled PROJECTED.','required':['daily_reduction','investment','levers'],'properties':{'daily_reduction':{'type':'integer','minimum':0},'investment':{'type':'integer','minimum':0},'levers':{'type':'integer','minimum':" as *u8) 848 w2(fd, "0}}},'rows':{'type':'integer','minimum':0},'unknown_status_rows':{'type':'integer','minimum':0},'declared_rows':{'type':'integer','minimum':0},'loaded_rows':{'type':'integer','minimum':0},'beyond_count_rows_detected':{'type':'integer','minimum':0,'description':'Bounded beyond-count detection; does not establish full retained history.'},'history_complete':{'type':'null','description':'The report do" as *u8) 849 w2(fd, "es not verify complete historical coverage.'},'evidence_scope':{'type':'string'},'units_verified':{'type':'boolean','const':false},'note':{'type':'string'}}}," as *u8) 850 return 0 851} 852 853// Describe the existing bindings artifact without upgrading declarations to verified outcomes. 854func hub_bindings_schema(fd: i64) -> i64 { 855 w2(fd, "'DomainBindingsReport':{'type':'object','required':['v','api','resource','status','producer','domain','generated_unix','evidence_scope','plan_source','declared_rung_count','declared_unit_rows','rank_snapshot','declared_rungs','limitations'],'properties':{'v':{'type':'integer','enum':[1]},'api':{'type':'string','enum':['nishi-measurement']},'resource':{'type':'string','enum':['d" as *u8) 856 w2(fd, "omain-bindings']},'status':{'type':'string','enum':['ok']},'producer':{'type':'string','enum':['nx_sota_status']},'domain':{'type':'string'},'generated_unix':{'type':'integer'},'declared_rungs':{'type':'array','items':{'type':'object','required':['id','title','contract_symbol','declared_done_rule','executor_class','estimate_text','dependencies_text','source_record','ordered_obs" as *u8) 857 w2(fd, "ervation','finish_observation','unmapped_observation','behavior_evidence','source_binding','api_binding','mcp_binding'],'properties':{'id':{'type':'string'},'title':{'type':'string'},'source_record':{'type':'object','additionalProperties':true},'contract_symbol':{'type':['string','null']},'declared_done_rule':{'type':['string','null']},'executor_class':{'type':['string','null']" as *u8) 858 w2(fd, "},'estimate_text':{'type':['string','null']},'dependencies_text':{'type':['string','null']},'ordered_observation':{'type':['object','null'],'additionalProperties':true},'finish_observation':{'type':['object','null'],'additionalProperties':true},'unmapped_observation':{'type':['object','null'],'additionalProperties':true},'behavior_evidence':{'type':['object','null'],'additional" as *u8) 859 w2(fd, "Properties':true},'source_binding':{'type':['object','null'],'additionalProperties':true},'api_binding':{'type':['object','null'],'additionalProperties':true},'mcp_binding':{'type':['object','null'],'additionalProperties':true}},'additionalProperties':true}},'limitations':{'type':'array','items':{'type':'string'}},'evidence_scope':{'type':'string'},'plan_source':{'type':'object" as *u8) 860 w2(fd, "','additionalProperties':true},'declared_rung_count':{'type':'integer','minimum':0},'declared_unit_rows':{'type':'array','items':{'type':'string'}},'rank_snapshot':{'type':'object','additionalProperties':true}},'additionalProperties':true,'description':'Published nx_sota_status bindings artifact. Null binding/evidence fields retain unresolved joins; declared estimates and rank " as *u8) 861 w2(fd, "snapshots are not verified savings or benchmark attainment.'}," as *u8) 862 return 0 863} 864 865func hub_bindings_path(fd: i64) -> i64 { 866 w2(fd, ",'/compare/{domain}/bindings.json':{'get':{'operationId':'getDomainBindings','summary':'Declared rung bindings and independently stamped rank observations','description':'Complete published per-domain JSON under existing Compare access policy. MCP nishi_compare arguments bindings and domain return a small public-only artifact manifest; retrieve the complete HTTP resource or bou" as *u8) 867 w2(fd, "nded existing nx_fs windows, observing reader footers and manifest limitations. Declarations and independently captured rank output do not prove function behavior, source/API/MCP bindings, realized investment or SOTA attainment.','parameters':[{'name':'domain','in':'path','required':true,'schema':{'type':'string'}}],'responses':{'200':{'description':'Complete published domain-b" as *u8) 868 w2(fd, "indings JSON artifact','content':{'application/json':{'schema':" as *u8) 869 wref(fd, "DomainBindingsReport" as *u8) 870 w2(fd, "}}},'404':{'description':'Artifact absent or domain not visible under the existing access policy'}}}}" as *u8) 871 return 0 872} 873 874func main(argc: i64, argv: *i64) -> i64 { 875 var html: i64 = 0 876 if argc >= 2 { if streq(argv[1] as *u8, "html" as *u8) == 1 { html = 1 } } 877 var jsonmode: i64 = 0 878 if argc >= 2 { if streq(argv[1] as *u8, "json" as *u8) == 1 { jsonmode = 1 } } 879 var oamode: i64 = 0 880 if argc >= 2 { if streq(argv[1] as *u8, "openapi" as *u8) == 1 { oamode = 1 } } 881 let cap: i64 = K_MAGIC_65536 882 let sbuf: *u8 = sys_mmap(cap) 883 let sn: i64 = c_read("knowledge/compare/registry" as *u8, sbuf, cap) 884 let fbuf: *u8 = sys_mmap(K_MAGIC_4096) 885 886 if oamode == 1 { 887 // OpenAPI 3.1 generated IN CODE from the same registry the endpoints serve -- SSOT, cannot drift. 888 let dbuf: *u8 = sys_mmap(256) 889 let pbuf: *u8 = sys_mmap(512) 890 w2(1, "{'openapi':'3.1.0','info':{'title':'Nishi Compare API','version':'1.2.0'," as *u8) 891 w2(1, "'summary':'Mechanically measured, liar-killed software comparisons - Nishi vs the field.'," as *u8) 892 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) 893 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) 894 w2(1, "'x-generated-by':'nx_swcompare_hub openapi (in-code SSOT)','x-generated-unix':" as *u8) 895 wn(1, sys_now_realtime_sec()) 896 w2(1, "},'servers':[{'url':'https://nishifamily.com'}],'x-available-domains':[" as *u8) 897 var i0: i64 = 0; var first0: i64 = 1 898 while i0 < sn { 899 var j0: i64 = i0 900 while j0 < sn { if sbuf[j0] == (10 as u8) { break } j0 = j0 + 1 } 901 if sbuf[i0] != (35 as u8) { if j0 > i0 { 902 let nf0: i64 = split5(sbuf, i0, j0, fbuf) 903 if nf0 >= 5 { 904 dom_of((fbuf as i64 + K_MAGIC_1024) as *u8, dbuf) 905 if dbuf[0] != (0 as u8) { if data_exists(dbuf, pbuf) == 1 { 906 if first0 == 0 { wc(1, 44) } 907 first0 = 0 908 wq(1); wj(1, dbuf); wq(1) 909 } } 910 } 911 } } 912 i0 = j0 + 1 913 } 914 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) 915 wref(1, "CompareIndex" as *u8) 916 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) 917 w2(1, "'description':'Comparison domain; see x-available-domains'}],'responses':{'200':{'description':'Matrix data','content':{'application/json':{'schema':" as *u8) 918 wref(1, "CompareMatrix" as *u8) 919 w2(1, "}}},'404':{'description':'No machine-readable data for this domain'}}}},'/compare/maturity/measurement.json':{'get':{'operationId':'getSotaBoardMeasurement','summary':'Read the published domain evidence measurement','description':'The same published artifact is available through nishi_compare with argument measurement. Generated time is distinct from cached evidence time; this is not an estate-wide maturity or SOTA score.','responses':{'200':{'description':'Domain-only measurement snapshot','content':{'application/json':{'schema':" as *u8) 920 wref(1, "SotaBoardMeasurement" as *u8) 921 w2(1, "}}},'404':{'description':'No published measurement artifact'}}}},'/compare/maturity/investment.json':{'get':{'operationId':'getTokenInvestmentReport','summary':'Read the published token investment declarations','description':'Exact nx_tokroi report artifact, also served by nishi_compare with argument investment. Ledger REALIZED labels are not verified savings; units, evidence, history and domain bindings remain unverified.','responses':{'200':{'description':'Existing token ROI ledger report with declaration limits','content':{'application/json':{'schema':" as *u8) 922 wref(1, "TokenInvestmentReport" as *u8) 923 w2(1, "}}},'404':{'description':'No published investment artifact'}}}}" as *u8) 924 hub_bindings_path(1) 925 w2(1, ",'/compare/openapi.json':{'get':{'operationId':'getOpenApi','summary':'This OpenAPI document','responses':{'200':{'description':'OpenAPI 3.1 document'}}}}}," as *u8) 926 w2(1, "'components':{'schemas':{" as *u8) 927 hub_measurement_schema(1) 928 hub_investment_schema(1) 929 hub_bindings_schema(1) 930 w2(1, "'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) 931 w2(1, "'comparisons':{'type':'array','items':" as *u8) 932 wref(1, "Comparison" as *u8) 933 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) 934 w2(1, "'kind':{'type':'string','enum':['live','radar','soon','matrix','auto']},'kind_measured':{'type':'string','description':'measured | sota | radar | live | soon -- derived from the domain data page at emit'},'group':{'type':'string'},'page':{'type':'string'},'radar':{'type':'string'},'data':{'type':'string','description':'Machine-readable matrix endpoint; present only when available'}," as *u8) 935 w2(1, "'coverage':{'type':'integer','description':'permille, from the domain tally'},'exceeds':{'type':'integer'},'present':{'type':'integer'},'absent':{'type':'integer'},'generated_unix':{'type':'integer'},'subtitle':{'type':'string'},'summary':{'type':'string'}}}," as *u8) 936 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) 937 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) 938 wref(1, "Axis" as *u8) 939 w2(1, "},'tally':" as *u8) 940 wref(1, "Tally" as *u8) 941 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) 942 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) 943 w2(1, "'exceeds':{'type':'integer'},'present':{'type':'integer'},'absent':{'type':'integer'},'total':{'type':'integer'}}}}}}" as *u8) 944 wc(1, 10) 945 sys_exit(0); return 0 946 } 947 948 // v3: the card table is built once for json / html / console 949 let cards: *u8 = sys_mmap(HUB_MAXCARDS * HUB_SLOT) 950 let cn: *i64 = sys_mmap(HUB_MAXCARDS * HN * 8) as *i64 951 let gt: *u8 = sys_mmap(HUB_MAXGROUPS * HUB_GSLOT) 952 let gcount: *i64 = sys_mmap(16) as *i64 953 gcount[0] = 0 954 let count: i64 = hub_build(sbuf, sn, cards, cn, gt, gcount) 955 let ng: i64 = gcount[0] 956 let ord: *i64 = sys_mmap(HUB_MAXCARDS * 8) as *i64 957 958 if jsonmode == 1 { 959 let pbuf: *u8 = sys_mmap(512) 960 wc(1, 123) 961 kv_n(1, "v" as *u8, 1); wc(1, 44) 962 kv_s(1, "api" as *u8, "nishi-compare" as *u8); wc(1, 44) 963 kv_n(1, "generated_unix" as *u8, sys_now_realtime_sec()); wc(1, 44) 964 kv_s(1, "resource" as *u8, "index" as *u8); wc(1, 44) 965 kv_n(1, "count" as *u8, count); wc(1, 44) 966 // THE ESTATE BAND -- the aggregate this hub never published. Every figure is summed from the SAME 967 // per-card numbers the cards render, so the page and the api cannot disagree. domains is emitted 968 // beside count so a reader can CHECK THE PARTITION rather than take it on trust. 969 let er: *i64 = sys_mmap(HR_N * 8) as *i64 970 hub_rollup(cards, cn, count, "" as *u8, er) 971 wq(1); w(1, "estate" as *u8); wq(1); wc(1, 58); wc(1, 123) 972 kv_n(1, "domains" as *u8, er[HR_DOMAINS]); wc(1, 44) 973 kv_n(1, "with_tally" as *u8, er[HR_WITH_TALLY]); wc(1, 44) 974 kv_n(1, "abstained" as *u8, er[HR_ABSTAINED]); wc(1, 44) 975 kv_n(1, "coverage_p50" as *u8, er[HR_COV_P50]); wc(1, 44) 976 kv_n(1, "coverage_p90" as *u8, er[HR_COV_P90]); wc(1, 44) 977 kv_n(1, "present" as *u8, er[HR_SUM_PRES]); wc(1, 44) 978 kv_n(1, "open" as *u8, er[HR_SUM_OPEN]); wc(1, 44) 979 kv_n(1, "exceeds" as *u8, er[HR_SUM_EXC]); wc(1, 44) 980 kv_n(1, "unjudgeable" as *u8, er[HR_SUM_UNJ]); wc(1, 44) 981 kv_n(1, "adopted_full" as *u8, er[HR_ADOPT_FULL]); wc(1, 44) 982 kv_n(1, "adopted_partial" as *u8, er[HR_ADOPT_PART]); wc(1, 44) 983 kv_n(1, "with_adoption" as *u8, er[HR_WITH_ADOPT]); wc(1, 44) 984 kv_n(1, "oldest_measured_unix" as *u8, er[HR_OLDEST]) 985 wc(1, 125); wc(1, 44) 986 wq(1); w(1, "groups" as *u8); wq(1); wc(1, 58); wc(1, 91) 987 // PER-LANE ROLLUP. The groups array carried a NAME and a COUNT and nothing else, so a lane -- the 988 // estate's only existing subdomain declaration -- could not be asked how healthy it is. Same 989 // hub_rollup as the estate band, so a lane figure and the estate figure are computed by ONE ruler 990 // and can never drift; the buffer is hoisted out of the loop rather than mapped per group. 991 let gr: *i64 = sys_mmap(HR_N * 8) as *i64 992 var g0: i64 = 0 993 while g0 < ng { 994 let gname0: *u8 = (gt as i64 + g0 * HUB_GSLOT) as *u8 995 let n0: i64 = hub_order(cards, cn, count, gname0, ord) 996 if n0 > 0 { 997 if g0 > 0 { wc(1, 44) } 998 hub_rollup(cards, cn, count, gname0, gr) 999 wc(1, 123); kv_s(1, "group" as *u8, gname0); wc(1, 44); kv_n(1, "count" as *u8, n0); wc(1, 44) 1000 kv_n(1, "coverage_p50" as *u8, gr[HR_COV_P50]); wc(1, 44) 1001 kv_n(1, "present" as *u8, gr[HR_SUM_PRES]); wc(1, 44) 1002 kv_n(1, "open" as *u8, gr[HR_SUM_OPEN]); wc(1, 44) 1003 kv_n(1, "exceeds" as *u8, gr[HR_SUM_EXC]); wc(1, 44) 1004 kv_n(1, "adopted_full" as *u8, gr[HR_ADOPT_FULL]); wc(1, 44) 1005 kv_n(1, "adopted_partial" as *u8, gr[HR_ADOPT_PART]); wc(1, 44) 1006 kv_n(1, "abstained" as *u8, gr[HR_ABSTAINED]); wc(1, 125) 1007 } 1008 g0 = g0 + 1 1009 } 1010 wc(1, 93); wc(1, 44) 1011 wq(1); w(1, "comparisons" as *u8); wq(1); wc(1, 58); wc(1, 91) 1012 var ci: i64 = 0 1013 while ci < count { 1014 if ci > 0 { wc(1, 44) } 1015 hub_card_json(cards, cn, ci, pbuf) 1016 ci = ci + 1 1017 } 1018 wc(1, 93); wc(1, 44) 1019 wq(1); w(1, "_links" as *u8); wq(1); wc(1, 58); wc(1, 123) 1020 kv_s(1, "self" as *u8, "/compare/api.json" as *u8); wc(1, 44) 1021 kv_s(1, "openapi" as *u8, "/compare/openapi.json" as *u8); wc(1, 44) 1022 kv_s(1, "html" as *u8, "/compare" as *u8) 1023 wc(1, 125); wc(1, 125); wc(1, 10) 1024 sys_exit(0); return 0 1025 } 1026 1027 if html == 1 { 1028 // shared site chrome (nav + footer) generated by nx_site_chrome from knowledge/site/surfaces.reg. 1029 // Read as self-contained fragments; graceful fallback to a minimal nav if absent. 1030 let hdrbuf: *u8 = sys_mmap(K_MAGIC_20480) 1031 var hdn: i64 = c_read("knowledge/site/chrome_header.html" as *u8, hdrbuf, K_MAGIC_20479) 1032 if hdn < 0 { hdn = 0 } 1033 hdrbuf[hdn] = 0 as u8 1034 let ftbuf: *u8 = sys_mmap(K_MAGIC_20480) 1035 var ftn: i64 = c_read("knowledge/site/chrome_footer.html" as *u8, ftbuf, K_MAGIC_20479) 1036 if ftn < 0 { ftn = 0 } 1037 ftbuf[ftn] = 0 as u8 1038 w(1, "<" as *u8); wc(1, 33); w(1, "DOCTYPE html>\n<html lang=\"en\"><head><meta charset='utf-8'><link rel='alternate' type='application/rss+xml' title='Nishi /compare daily positions and reviews' href='/compare/feed.xml'><meta name='viewport' content='width=device-width, initial-scale=1'>\n" as *u8) 1039 w(1, "<title>Nishi Compare -- sovereign, measured software comparison</title>\n<style>\n" as *u8) 1040 // ---- THEME + LAYOUT FROM THE ONE EMITTER (2026-08-31) ---- 1041 // THIS PAGE WAS THE LAST ONE ON A PRIVATE RULER, AND IT IS THE MOST-VISITED ONE. The line that 1042 // used to sit here was a THIRD design SSOT: eleven hardcoded rgb() literals defining the same 1043 // token names nx_brand_tokens already publishes, and it was DARK-ONLY -- a bare :root with no 1044 // html[data-theme='dark'] and no prefers-color-scheme block, so the /compare LANDING PAGE 1045 // ignored the viewer's theme by construction while every domain page it links to honoured it. 1046 // The body rule beside it hardcoded max-width:1180px, so a 1180px dark index linked to fluid, 1047 // theme-aware domain pages. Both are now composed from nx_swcompare_lib -- the SAME two calls 1048 // nx_swcompare_matrix and nx_swcompare_sota make. The CSS is COMPOSED, never copied: a copy is 1049 // the duplicate-ruler defect that produced six different page widths across seven generators. 1050 // sc_theme_pass is fail-closed (it exits rather than emit a zero, truncated or theme-blind 1051 // palette), so adopting it cannot silently ship this page with no colours. 1052 sc_theme_pass(1) 1053 sc_layout_pass(1) 1054 // [hidden] is NOT in sc_layout_pass and must stay here: the filter script sets el.hidden on 1055 // every card, so without this rule the no-match state renders every card instead of none. 1056 w(1, "[hidden]{display:none}\n" as *u8) 1057 // The two hub-local status hues, as var() ALIASES over SSOT tokens rather than literals, so they 1058 // follow the theme like everything else. --r is the roadmap/radar pill and --p (part) is the 1059 // estate's amber for an open item; --b is the sota pill and --ex (exceed) is the estate's 1060 // colour for a beats-the-field claim. Neither is a new colour: this file no longer owns one. 1061 w(1, ":root{--r:var(--nx-color-part);--b:var(--nx-color-exceed)}\n" as *u8) 1062 w(1, "h1{font-size:clamp(1.7rem,5vw,2.2rem);margin:0 0 6px;color:var(--fg);text-wrap:balance}.eyebrow{letter-spacing:.14em;text-transform:uppercase;font-size:.72rem;color:var(--mut);margin:22px 0 6px}.eyebrow b{color:var(--ac);font-weight:600}.sub{color:var(--mut);font-size:clamp(.95rem,2vw,1.05rem);margin:0 0 4px;max-width:var(--nx-layout-measure);text-wrap:pretty}.crumb{font-size:.82rem;margin:14px 0 2px;color:var(--mut)}a{color:var(--ac);text-decoration:none}a:hover{text-decoration:underline}\n" as *u8) 1063 // THE FOREGROUND ON AN ACCENT FILL HAD TO CHANGE WITH THE PALETTE, AND THIS IS THE ONE PLACE 1064 // ADOPTING THE SSOT COULD HAVE SHIPPED A REGRESSION. rgb(15,10,30) is a near-black that was 1065 // chosen for the OLD dark-only accent rgb(199,163,255); against the SSOT's LIGHT accent 1066 // rgb(88,64,180) it computes to about 2.4:1, i.e. it would have FAILED WCAG AA the moment this 1067 // page gained a light theme -- a contrast regression introduced BY the fix, on the skip link, 1068 // which is the one control a keyboard user meets first. var(--nx-color-bg) flips with the 1069 // theme and clears 4.5:1 in BOTH (about 6.9:1 on paper, about 7.5:1 on dark). It is also the 1070 // exact idiom nx_swcompare_matrix already uses on its own .skip-link -- the sibling had the fix. 1071 w(1, ".skip-link{position:absolute;left:-999px;top:0;background:var(--ac);color:var(--nx-color-bg);padding:12px 16px;z-index:9;border-radius:0 0 8px 0}.skip-link:focus{left:0}\n" as *u8) 1072 w(1, ".hd{border-bottom:1px solid var(--line);margin:0 0 8px}.hd nav{display:flex;gap:6px;flex-wrap:wrap;padding:10px 0}.hd a{color:var(--fg);text-decoration:none;padding:8px 12px;border-radius:8px;font-weight:600;min-height:44px;display:inline-flex;align-items:center}.hd a:hover{background:var(--soft)}\n" as *u8) 1073 // MEASURE CAP ON THE THREE PROSE BLOCKS (.sub above, .lead here, .foot below). The page is now 1074 // FLUID (--nx-layout-wrap tops out near 1760px where it used to stop at 1180px), and these are 1075 // the only three elements on the page whose text is not already constrained by a grid track -- 1076 // .lead is a ~700-character paragraph, so uncapped it would run past 240 characters per line, 1077 // about 3x the WCAG 1.4.8 (AAA) 80-character ceiling. Widening the canvas WITHOUT capping the 1078 // prose is the regression the same change already shipped on the sota pages, so it is fixed 1079 // here in the same edit that causes it. The cap reads the SSOT token rather than a fresh number. 1080 w(1, ".lead{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:14px 18px;margin:16px 0;font-size:.9rem;color:var(--mut);max-width:var(--nx-layout-measure);text-wrap:pretty}.lead b{color:var(--fg)}\n" as *u8) 1081 w(1, ".tb{position:sticky;top:0;z-index:5;background:var(--bg);padding:10px 0 8px;border-bottom:1px solid var(--line);margin:0 0 14px}.tb input{width:100%;padding:12px 16px;font-size:1rem;border:1px solid var(--line);border-radius:12px;background:var(--panel);color:var(--fg);min-height:46px}.tb input:focus{outline:3px solid var(--ac);outline-offset:1px;border-color:var(--ac)}\n" as *u8) 1082 w(1, ".chips{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0 0}.chip{display:inline-flex;align-items:center;min-height:34px;padding:2px 12px;border:1px solid var(--line);border-radius:20px;font-size:.8rem;color:var(--fg);background:var(--panel)}.chip:hover{border-color:var(--ac);text-decoration:none}.chip.on{background:var(--ac);color:var(--nx-color-bg);border-color:var(--ac);font-weight:600}.chip small{color:inherit;opacity:.7;margin-left:6px}\n" as *u8) 1083 w(1, ".tbrow{display:flex;flex-wrap:wrap;gap:10px 18px;align-items:center;margin:8px 0 0;font-size:.85rem;color:var(--mut)}.tbrow select{background:var(--panel);color:var(--fg);border:1px solid var(--line);border-radius:8px;padding:6px 10px;min-height:34px}.srh{margin:0;min-height:1.1em;color:var(--mut)}.rst{color:var(--mut);text-decoration:underline}\n" as *u8) 1084 w(1, ".jump{display:flex;flex-wrap:wrap;gap:4px 14px;font-size:.82rem;color:var(--mut);margin:0 0 6px}.grp{margin:22px 0 6px}.grp h2{font-size:1.05rem;letter-spacing:.06em;text-transform:uppercase;color:var(--mut);margin:0 0 10px;padding-bottom:6px;border-bottom:1px solid var(--line)}.grp h2 .cnt{color:var(--ac);font-weight:600;margin-left:8px}\n" as *u8) 1085 w(1, ".grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:12px}.cu{min-width:0}.card{display:block;height:100%;border:1px solid var(--line);border-radius:14px;padding:14px 16px;color:inherit;background:var(--panel)}.card:hover{border-color:var(--ac);text-decoration:none}.card h3{margin:0 0 4px;font-size:1.02rem;color:var(--ac);line-height:1.3}.card .stat{color:var(--mut);font-size:.8rem;margin-top:6px;display:-webkit-box;-webkit-line-clamp:4;-webkit-box-orient:vertical;overflow:hidden}.card .sub2{color:var(--fg);font-size:.84rem;margin-top:4px;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}\n" as *u8) 1086 w(1, ".bar{height:6px;background:var(--soft);border-radius:4px;overflow:hidden;margin:8px 0 6px}.bar i{display:block;height:100%;background:var(--y)}.nums{font-size:.78rem;color:var(--mut);font-family:var(--nx-font-mono);font-variant-numeric:tabular-nums}.nums b{color:var(--fg)}\n" as *u8) 1087 w(1, ".pill{display:inline-block;font-size:.64rem;padding:2px 8px;border-radius:20px;background:rgba(121,224,167,0.14);border:1px solid rgba(121,224,167,0.4);color:var(--y);vertical-align:middle;margin-left:6px;font-weight:600;letter-spacing:.06em;text-transform:uppercase}.pill.k-radar{background:rgba(255,209,122,0.12);border-color:rgba(255,209,122,0.4);color:var(--r)}.pill.k-soon{background:rgba(150,162,186,0.12);border-color:rgba(150,162,186,0.4);color:var(--mut)}.pill.k-sota{background:rgba(122,181,255,0.12);border-color:rgba(122,181,255,0.4);color:var(--b)}\n" as *u8) 1088 w(1, ".frl{margin:4px 0 0 6px;font-size:.8rem}.empty{color:var(--mut);padding:24px 0}.foot{margin-top:34px;color:var(--mut);font-size:.76rem;border-top:1px solid var(--line);padding-top:14px;font-family:var(--nx-font-mono);max-width:var(--nx-layout-measure);text-wrap:pretty}\n" as *u8) 1089 w(1, ":focus-visible{outline:3px solid var(--ac);outline-offset:2px}@media(prefers-reduced-motion:reduce){*{animation:none}}\n" as *u8) 1090 // THE PRINT SHEET GOES LAST (datavis DV7, 2026-09-15): order is its specificity -- see sc_print_css in nx_swcompare_lib 1091 sc_print_css(1) 1092 w(1, "</style></head><body>\n" as *u8) 1093 w(1, "<a class='skip-link' href='" as *u8); wc(1, 35); w(1, "main'>Skip to content</a>\n" as *u8) 1094 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) } 1095 w(1, "<main id='main'>\n" as *u8) 1096 w(1, "<p class='crumb'><a href='/'>Nishi Family</a> &rsaquo; Compare</p>\n<p class='eyebrow'><b>nishifamily.com</b> &middot; measured, not asserted</p>\n<h1>Nishi Compare</h1>\n" as *u8) 1097 var ngne: i64 = 0 1098 var gq: i64 = 0 1099 while gq < ng { if hub_order(cards, cn, count, (gt as i64 + gq * HUB_GSLOT) as *u8, ord) > 0 { ngne = ngne + 1 } gq = gq + 1 } 1100 w(1, "<p class='sub'>Nishi vs the field &mdash; <b>mechanically measured</b>, not analyst opinion. " as *u8); wn(1, count); w(1, " comparisons across " as *u8); wn(1, ngne); w(1, " groups.</p>\n" as *u8) 1101 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> &mdash; a faked win fails the build. The coverage number on a card is the domain's own tally (present plus exceeds over all measured axes, permille); the open count is its named build contracts, watched on every emit. No quadrants, no pay-to-play, no trackers. Measured bits-up.</div>\n" as *u8) 1102 // sticky toolbar: search + group chips + kind chips + sort + count + reset (all anchors/controls work without JS) 1103 w2(1, "<div class='tb' id='tb'><label for='cmpq' style='position:absolute;left:-999px'>Search comparisons</label><input type='search' id='cmpq' placeholder='Search comparisons -- title, group, subtitle, rival names... (press / to focus)' autocomplete='off' spellcheck='false'>\n" as *u8) 1104 w2(1, "<div class='chips' id='gchips'>" as *u8) 1105 var g1: i64 = 0 1106 while g1 < ng { 1107 let gname1: *u8 = (gt as i64 + g1 * HUB_GSLOT) as *u8 1108 let n1: i64 = hub_order(cards, cn, count, gname1, ord) 1109 if n1 > 0 { 1110 let sl1: *u8 = sys_mmap(64); hub_slugify(gname1, sl1) 1111 w(1, "<a class='chip' href='" as *u8); wc(1, 35); w(1, "g-" as *u8); w(1, sl1); w(1, "' data-g='" as *u8); w(1, sl1); w(1, "'>" as *u8); w(1, gname1); w(1, "<small>" as *u8); wn(1, n1); w(1, "</small></a>" as *u8) 1112 } 1113 g1 = g1 + 1 1114 } 1115 w2(1, "</div>\n<div class='chips' id='kchips'>" as *u8) 1116 // kind chips from the kinds actually present 1117 let kinds: *u8 = sys_mmap(8 * 40) 1118 var nk: i64 = 0 1119 var ki: i64 = 0 1120 let dk1: *u8 = sys_mmap(40) 1121 while ki < count { 1122 hub_disp_kind(cards, cn, ki, dk1) 1123 var seen: i64 = 0 1124 var s1: i64 = 0 1125 while s1 < nk { if streq((kinds as i64 + s1 * 40) as *u8, dk1) == 1 { seen = 1; s1 = nk } else { s1 = s1 + 1 } } 1126 if seen == 0 { if nk < 8 { hub_copyn((kinds as i64 + nk * 40) as *u8, dk1, 40); nk = nk + 1 } } 1127 ki = ki + 1 1128 } 1129 var kj: i64 = 0 1130 while kj < nk { 1131 let kname: *u8 = (kinds as i64 + kj * 40) as *u8 1132 var kc: i64 = 0 1133 var kx: i64 = 0 1134 while kx < count { hub_disp_kind(cards, cn, kx, dk1); if streq(dk1, kname) == 1 { kc = kc + 1 } kx = kx + 1 } 1135 w(1, "<a class='chip' href='?k=" as *u8); w(1, kname); w(1, "' data-k='" as *u8); w(1, kname); w(1, "'>" as *u8); w(1, kname); w(1, "<small>" as *u8); wn(1, kc); w(1, "</small></a>" as *u8) 1136 kj = kj + 1 1137 } 1138 w2(1, "</div>\n<div class='tbrow'><label>Sort <select id='sort'><option value='cov'>coverage</option><option value='exc'>exceeds</option><option value='upd'>recently measured</option><option value='name'>A to Z</option></select></label><p class='srh' id='srh' role='status' aria-live='polite'>" as *u8) 1139 wn(1, count); w2(1, " comparisons</p><a class='rst' id='reset' href='/compare'>reset</a></div></div>\n" as *u8) 1140 // jump nav (no-JS group navigation) 1141 w(1, "<p class='jump'>" as *u8) 1142 var g2: i64 = 0 1143 while g2 < ng { 1144 let gname2: *u8 = (gt as i64 + g2 * HUB_GSLOT) as *u8 1145 let n2: i64 = hub_order(cards, cn, count, gname2, ord) 1146 if n2 > 0 { let sl2: *u8 = sys_mmap(64); hub_slugify(gname2, sl2); w(1, "<a href='" as *u8); wc(1, 35); w(1, "g-" as *u8); w(1, sl2); w(1, "'>" as *u8); w(1, gname2); w(1, " (" as *u8); wn(1, n2); w(1, ")</a>" as *u8) } 1147 g2 = g2 + 1 1148 } 1149 w(1, "</p>\n" as *u8) 1150 // grouped grid 1151 var emitted: i64 = 0 1152 var g3: i64 = 0 1153 while g3 < ng { 1154 let gname3: *u8 = (gt as i64 + g3 * HUB_GSLOT) as *u8 1155 let n3: i64 = hub_order(cards, cn, count, gname3, ord) 1156 if n3 > 0 { 1157 let sl3: *u8 = sys_mmap(64); hub_slugify(gname3, sl3) 1158 w(1, "<section class='grp' id='g-" as *u8); w(1, sl3); w(1, "' data-g='" as *u8); w(1, sl3); w(1, "'><h2>" as *u8); w(1, gname3); w(1, "<span class='cnt'>" as *u8); wn(1, n3); w(1, "</span></h2><div class='grid'>\n" as *u8) 1159 var x: i64 = 0 1160 while x < n3 { hub_card_html(cards, cn, ord[x]); emitted = emitted + 1; x = x + 1 } 1161 w(1, "</div></section>\n" as *u8) 1162 } 1163 g3 = g3 + 1 1164 } 1165 w(1, "<p class='empty' id='empty' hidden>No comparison matches -- clear the search or a chip.</p>\n" as *u8) 1166 w(1, "<p class='foot'>Generated by nx_swcompare_hub v3 from knowledge/compare/registry plus the regen.list union, facts read from each domain's own api.json, groups from knowledge/compare/hub.groups (" as *u8); wn(1, count); w(1, " comparisons in " as *u8); wn(1, ngne); w(1, " groups; partition " as *u8); wn(1, emitted); w(1, " of " as *u8); wn(1, count); w(1, " placed). Self-assembling &mdash; a workstream that ships a comparison appends a regen.list line and reruns. Search, filters and sort are progressive enhancement: every comparison renders without JavaScript. Sovereign Nishi stack &mdash; TLS 1.3, no third-party web server, no trackers.</p>\n" as *u8) 1167 w(1, "</main>\n" as *u8) 1168 if ftn > 0 { w(1, ftbuf) } 1169 // progressive enhancement: filter / sort / URL state. No '#' and no '!' anywhere in this literal (nx_cc trap); 1170 // apostrophes become double quotes through w2, so JS strings are written single-quoted here. 1171 w2(1, "<script>(function(){var q=document.getElementById('cmpq');var sr=document.getElementById('srh');var em=document.getElementById('empty');var so=document.getElementById('sort');if(q===null){return;}var cards=[].slice.call(document.querySelectorAll('.cu'));var groups=[].slice.call(document.querySelectorAll('.grp'));var gsel='';var ksel='';\n" as *u8) 1172 w2(1, "function setChips(id,val,attr){var el=document.getElementById(id);if(el===null){return;}var cs=el.querySelectorAll('.chip');var j=0;while(j<cs.length){if(cs[j].getAttribute(attr)===val){cs[j].classList.add('on');}else{cs[j].classList.remove('on');}j=j+1;}}\n" as *u8) 1173 w2(1, "function apply(){var v=q.value.trim().toLowerCase();var n=0;var k=0;while(k<cards.length){var c=cards[k];var ok=1;if(v.length>0){var hay=(c.getAttribute('data-t')+' '+c.textContent).toLowerCase();if(hay.indexOf(v)<0){ok=0;}}if(gsel.length>0){if(c.getAttribute('data-g')===gsel){}else{ok=0;}}if(ksel.length>0){if(c.getAttribute('data-k')===ksel){}else{ok=0;}}c.hidden=(ok===0);if(ok===1){n=n+1;}k=k+1;}\n" as *u8) 1174 w2(1, "var g=0;while(g<groups.length){var vis=groups[g].querySelectorAll('.cu:not([hidden])').length;groups[g].hidden=(vis===0);var cnt=groups[g].querySelector('.cnt');if(cnt){cnt.textContent=vis;}g=g+1;}sr.textContent=n+' of '+cards.length+' comparisons';em.hidden=(n>0);\n" as *u8) 1175 w2(1, "var u=new URLSearchParams();if(v.length>0){u.set('q',v);}if(gsel.length>0){u.set('g',gsel);}if(ksel.length>0){u.set('k',ksel);}if(so.value==='cov'){}else{u.set('s',so.value);}var qs=u.toString();var url=location.pathname;if(qs.length>0){url=url+'?'+qs;}if(window.history&&window.history.replaceState){window.history.replaceState(null,'',url);}}\n" as *u8) 1176 w2(1, "function sortAll(){var key=so.value;var g=0;while(g<groups.length){var grid=groups[g].querySelector('.grid');if(grid===null){g=g+1;continue;}var arr=[].slice.call(grid.querySelectorAll('.cu'));arr.sort(function(a,b){if(key==='name'){var an=a.getAttribute('data-n');var bn=b.getAttribute('data-n');if(an<bn){return -1;}if(an>bn){return 1;}return 0;}var at=(key==='exc')?'data-x':((key==='upd')?'data-u':'data-c');return (Number(b.getAttribute(at))-Number(a.getAttribute(at)));});var i=0;while(i<arr.length){grid.appendChild(arr[i]);i=i+1;}g=g+1;}}\n" as *u8) 1177 w2(1, "function wire(id,attr,fn){var el=document.getElementById(id);if(el===null){return;}var cs=el.querySelectorAll('.chip');var j=0;while(j<cs.length){(function(c){c.addEventListener('click',function(ev){ev.preventDefault();fn(c.getAttribute(attr));});})(cs[j]);j=j+1;}}\n" as *u8) 1178 w2(1, "wire('gchips','data-g',function(v){gsel=(gsel===v)?'':v;setChips('gchips',gsel,'data-g');apply();});wire('kchips','data-k',function(v){ksel=(ksel===v)?'':v;setChips('kchips',ksel,'data-k');apply();});q.addEventListener('input',apply);so.addEventListener('change',function(){sortAll();apply();});\n" as *u8) 1179 w2(1, "function reset(){q.value='';gsel='';ksel='';so.value='cov';setChips('gchips','','data-g');setChips('kchips','','data-k');sortAll();apply();}var rs=document.getElementById('reset');if(rs){rs.addEventListener('click',function(ev){ev.preventDefault();reset();});}\n" as *u8) 1180 w2(1, "document.addEventListener('keydown',function(e){if(e.key==='/'){if(document.activeElement===q){}else{e.preventDefault();q.focus();}}if(e.key==='Escape'){reset();}});\n" as *u8) 1181 w2(1, "var p=new URLSearchParams(location.search);if(p.get('q')){q.value=p.get('q');}if(p.get('g')){gsel=p.get('g');setChips('gchips',gsel,'data-g');}if(p.get('k')){ksel=p.get('k');setChips('kchips',ksel,'data-k');}if(p.get('s')){so.value=p.get('s');}sortAll();apply();})();</script>\n" as *u8) 1182 w(1, "</body></html>\n" as *u8) 1183 sys_exit(0); return 0 1184 } 1185 1186 // console / gate: liar-kill + the v3 HUB CENSUS (regen.list domains -> carded / page / facts / grouped) 1187 w(1, "=== NX-SWCOMPARE-HUB v3 -- generate /compare hub from registry + regen.list union + per-domain facts ===\n" as *u8) 1188 var i2: i64 = 0; var n: i64 = 0 1189 while i2 < sn { 1190 var j2: i64 = i2 1191 while j2 < sn { if sbuf[j2] == (10 as u8) { break } j2 = j2 + 1 } 1192 if sbuf[i2] != (35 as u8) { 1193 if j2 > i2 { 1194 let nf: i64 = split5(sbuf, i2, j2, fbuf) 1195 if nf >= 5 { n = n + 1 } 1196 } 1197 } 1198 i2 = j2 + 1 1199 } 1200 w(1, " registry entries="); wn(1, n); w(1, " cards="); wn(1, count); w(1, " groups="); wn(1, ng); w(1, "\n" as *u8) 1201 var facts: i64 = 0; var grouped: i64 = 0; var covered: i64 = 0; var c3: i64 = 0 1202 // with_coverage NOW SPANS TWO RULERS, so it is published with its decomposition beside it rather 1203 // than as one blended number: a reader who cannot see which ruler produced a count cannot tell a 1204 // real gain from a change in what was being counted. tally+watch+none sums to with_api_json. 1205 var src_tally: i64 = 0; var src_watch: i64 = 0; var src_none: i64 = 0 1206 while c3 < count { 1207 if hub_num(cn, c3, HN_FACTS) == 1 { facts = facts + 1 1208 if hub_num(cn, c3, HN_TSRC) == HT_SRC_TALLY { src_tally = src_tally + 1 } 1209 if hub_num(cn, c3, HN_TSRC) == HT_SRC_WATCH { src_watch = src_watch + 1 } 1210 if hub_num(cn, c3, HN_TSRC) == HT_SRC_NONE { src_none = src_none + 1 } 1211 } 1212 if hub_num(cn, c3, HN_GROUPED) == 1 { grouped = grouped + 1 } 1213 if hub_num(cn, c3, HN_COV) >= 0 { covered = covered + 1 } 1214 c3 = c3 + 1 1215 } 1216 w(1, " facts: with_api_json="); wn(1, facts); w(1, " with_coverage="); wn(1, covered); w(1, " grouped="); wn(1, grouped); w(1, " ungrouped="); wn(1, count - grouped); w(1, " (facts+nofacts and grouped+ungrouped both sum to cards)\n" as *u8) 1217 w(1, " tally_source: tally="); wn(1, src_tally); w(1, " watch="); wn(1, src_watch); w(1, " none="); wn(1, src_none); w(1, " (sums to with_api_json; none = api.json read but NO tally derivable -- an abstention, not a zero)\n" as *u8) 1218 var c4: i64 = 0 1219 while c4 < count { 1220 if hub_num(cn, c4, HN_GROUPED) == 0 { w(1, " UNGROUPED dom=" as *u8); w(1, hub_slot(cards, c4, HO_DOM)); w(1, " title=" as *u8); w(1, hub_slot(cards, c4, HO_TITLE)); w(1, " -> add a knowledge/compare/hub.groups row\n" as *u8) } 1221 c4 = c4 + 1 1222 } 1223 // every regen.list renderable must be carded (the union guarantees it; a miss here is a bug in this file) 1224 let rl2: *u8 = sys_mmap(K_MAGIC_4096) 1225 let rlp2: *u8 = sys_mmap(512) 1226 hub_kcpath(rlp2, "regen.list" as *u8) 1227 let rn2: i64 = c_read(rlp2, rl2, K_MAGIC_4096 - 1) 1228 let dom2: *u8 = sys_mmap(256) 1229 let t2: *u8 = sys_mmap(256) 1230 let tb2: *u8 = sys_mmap(K_MAGIC_4096) 1231 var rdoms: i64 = 0; var renderable: i64 = 0; var carded: i64 = 0; var missing: i64 = 0 1232 var p2: i64 = 0 1233 while p2 < rn2 { 1234 var e2: i64 = p2 1235 while e2 < rn2 { if rl2[e2] == (10 as u8) { break } e2 = e2 + 1 } 1236 if e2 > p2 { if rl2[p2] != (35 as u8) { 1237 var d2: i64 = 0; var q3: i64 = p2 1238 while q3 < e2 { if d2 < 250 { dom2[d2] = rl2[q3]; d2 = d2 + 1 } q3 = q3 + 1 } 1239 dom2[d2] = 0 as u8 1240 rdoms = rdoms + 1 1241 if hub_dom_title(dom2, t2, tb2, K_MAGIC_4096) == 1 { 1242 renderable = renderable + 1 1243 var found: i64 = 0; var c5: i64 = 0 1244 while c5 < count { if streq(hub_slot(cards, c5, HO_DOM), dom2) == 1 { found = 1; c5 = count } else { c5 = c5 + 1 } } 1245 if found == 1 { carded = carded + 1 } else { missing = missing + 1; w(1, " MISSING-CARD dom=" as *u8); w(1, dom2); w(1, "\n" as *u8) } 1246 } 1247 } } 1248 p2 = e2 + 1 1249 } 1250 w(1, " regen.list: domains="); wn(1, rdoms); w(1, " renderable="); wn(1, renderable); w(1, " carded="); wn(1, carded); w(1, " missing="); wn(1, missing); w(1, " (carded+missing=renderable)\n" as *u8) 1251 let liar_reg: i64 = (sn > 0) as i64 1252 let liar_n: i64 = (n >= 1) as i64 1253 let liar_card: i64 = (missing == 0) as i64 1254 w(1, " LIAR-KILL: registry-loaded="); wn(1, liar_reg); w(1, " has-entries="); wn(1, liar_n); w(1, " every-renderable-carded="); wn(1, liar_card); w(1, "\n" as *u8) 1255 let ok: i64 = liar_reg & liar_n & liar_card 1256 w(1, "NX-SWCOMPARE-HUB entries="); wn(1, n); w(1, " cards="); wn(1, count); w(1, " verdict=") 1257 if ok == 1 { w(1, "OK -- run with 'html' to emit the hub page\n" as *u8); sys_exit(0); return 0 } 1258 w(1, "RED (registry missing or empty, or a renderable domain has no card)\n" as *u8); sys_exit(1); return 1 1259}