nx_swcompare_hub.nx
buildroot/runtime/nx_swcompare_hub.nx
about
nx_swcompare_hub.nx -- GENERATOR for the /compare hub. Reads knowledge/compare/registry (data, one line per
comparison: title|kind|href|radar-href-or-dash|stat) and emits the SoftwareCompare landing HTML. This RETIRES
the hand-authored hub -> the surface is self-assembling: a workstream that ships a comparison just appends a
registry line + reruns this. Kills the multi-session hub-clobber problem (the registry is the SSOT; the hub is
always regenerated from it). Modes: no-arg = console + liar-kill (gate); "html" = emit /compare/index.html.
NOTE: no '#'/'!' in string literals (nx_cc trap) -> rgb() + emit '!' byte. license_tier: ORIGINAL expect_exit:0
v3 (2026-08-24, operator: "the hub is just a big long scroll list without search or filtering or anything else
I'd expect from a hub page"): HUB-GRADE USABILITY, ALL DATA-DRIVEN, ALL PROGRESSIVE.
* every card carries MEASURED FACTS read at emit from the domain's own emitted api.json (coverage permille,
exceeds, present, open contracts, measured date, kind, subtitle) -- the registry's prose stays as the
curated line; a domain with no registry row gets a full card from its facts, never a placeholder.
* cards are GROUPED by knowledge/compare/hub.groups (dom|group, data); a domain with no row lands in
"Ungrouped", printed by name in console mode (a count without a worklist is not actionable).
* sticky toolbar: search (kept), group chips, kind chips, sort (coverage / exceeds / recently measured /
A-Z), live result count, reset, "/" focuses search, Esc clears, filter state in the URL (?q=&g=&k=&s=).
* responsive grid, coverage bar per card, jump-nav of groups with counts, footer partition (groups sum to cards).
* NO JavaScript required: without it the page is the grouped grid with anchor chips; JS only filters/sorts.
* json mode is ADDITIVE: every comparison now also carries kind_measured, group, coverage, exceeds, present,
absent, generated_unix, subtitle when known (old fields untouched -- Rule 19 contract stability).
* console mode prints the HUB CENSUS: regen.list domains -> carded / page / facts / grouped, ungrouped NAMED.
Verdict RED only on the liar-kill and on a renderable domain that produced no card (a bug in this file).
v4 (2026-08-31): TWO DEFECTS, BOTH OF THEM "A FIX THAT LIVES IN ONE ORGAN AND NOT ITS SIBLING".
* LAYOUT + THEME NOW COME FROM THE ONE EMITTER. This file carried its OWN :root palette (eleven
hardcoded rgb() literals, DARK-ONLY -- no html[data-theme] and no prefers-color-scheme block) and
its OWN body rule at max-width:1180px. That made the LANDING PAGE the last page in the family
still on a private ruler: a 1180px dark index linking to fluid, theme-aware domain pages. It now
composes sc_theme_pass + sc_layout_pass from nx_swcompare_lib, exactly as nx_swcompare_matrix and
nx_swcompare_sota do. THE CSS IS NOT COPIED -- copying it is the duplicate-ruler defect this whole
change exists to remove.
* THE SOTA TALLY IS NO LONGER SILENTLY OMITTED (see hub_tally_from_watch).
Importing nx_swcompare_lib also DELETES ten helpers this file had hand-copied from it (w, wc, wn, wj,
wq, kv_s, kv_n, c_read, streq, scopy -- byte-identical, so the deletion is provable, not judged).
dependencies 2 imports · 0 importers
imports: nx_syscalls.nxnx_swcompare_lib.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 37 | const K_MAGIC_65536: i64 = 65536 |
| 38 | const K_MAGIC_4096: i64 = 4096 |
| 39 | const K_MAGIC_1024: i64 = 1024 |
| 40 | const K_MAGIC_1536: i64 = 1536 |
| 41 | const K_MAGIC_2048: i64 = 2048 |
| 42 | const K_MAGIC_20480: i64 = 20480 |
| 43 | const K_MAGIC_20479: i64 = 20479 |
| 45 | const HUB_MAXCARDS: i64 = 256 |
| 46 | const HUB_SLOT: i64 = 3072 |
| 47 | const HO_TITLE: i64 = 0 // 256 |
| 48 | const HO_KIND: i64 = 256 // 32 registry kind (live/radar/soon/matrix/auto) |
| 49 | const HO_HREF: i64 = 288 // 256 |
| 50 | const HO_RADAR: i64 = 544 // 256 |
| 51 | const HO_STAT: i64 = 800 // 1024 registry prose |
| 52 | const HO_DOM: i64 = 1824 // 64 domain atom (or href key for /modelcard-style pages) |
| 53 | const HO_GROUP: i64 = 1888 // 64 |
| 54 | const HO_SUB: i64 = 1952 // 512 subtitle from api.json (or the file's @sub) |
| 55 | const HO_MKIND: i64 = 2464 // 32 measured kind from api.json (matrix/sota/frontier-radar) or empty |
| 56 | const HO_SLUG: i64 = 2496 // 64 group slug |
| 57 | const HN: i64 = 12 // numeric fields per card (i64 each); the cn mmap derives its size from this |
| 58 | const HN_COV: i64 = 0 |
| 59 | const HN_EXC: i64 = 1 |
| 60 | const HN_PRES: i64 = 2 |
| 61 | const HN_ABS: i64 = 3 |
| 62 | const HN_TOT: i64 = 4 |
| 63 | const HN_GEN: i64 = 5 |
| 64 | const HN_FACTS: i64 = 6 // 1 = api.json was read |
| 65 | const HN_GROUPED: i64 = 7 // 1 = a hub.groups row matched |
| 66 | const HN_UNJ: i64 = 8 // watch rows carrying no judgeable contract -- neither present nor open |
| 67 | const HN_ADOPT_FULL: i64 = 10 // api.json adopted_full: organs behind this card's rows at FULL adoption |
| 68 | const HN_ADOPT_PART: i64 = 11 // api.json adopted_partial: built-unpromoted, promoted-unregistered, registered-dark... |
| 69 | const HN_TSRC: i64 = 9 // which ruler produced this card's tally: HT_SRC_* |
| 74 | const HT_SRC_NONE: i64 = 0 // read, and NEITHER ruler could produce a tally -- abstain, never acquit |
| 75 | const HT_SRC_TALLY: i64 = 1 // matrix-class: the tally block, axis coverage |
| 76 | const HT_SRC_WATCH: i64 = 2 // sota-class: derived from the MEASURED watch[] statuses |
| 77 | const HUB_API_CAP: i64 = 262144 |
| 78 | const HUB_MAXGROUPS: i64 = 32 |
| 79 | const HUB_GSLOT: i64 = 128 |
| 80 | const HUB_SECS_PER_DAY: i64 = 86400 |
| 81 | const HUB_DAYS_TO_CIVIL: i64 = 719468 |
| 82 | const HUB_ERA_DAYS: i64 = 146097 |
| 84 | const HUB_DAYS_4Y: i64 = 1460 |
| 85 | const HUB_DAYS_100Y: i64 = 36524 |
| 86 | const HUB_DAYS_ERA_LESS1: i64 = 146096 |
| 87 | const HUB_STAT_CAP: i64 = 1024 |
| 88 | const HUB_PERMILLE: i64 = 1000 |
| 730 | const HR_DOMAINS: i64 = 0 |
| 731 | const HR_WITH_TALLY: i64 = 1 |
| 732 | const HR_COV_P50: i64 = 2 |
| 733 | const HR_COV_P90: i64 = 3 |
| 734 | const HR_SUM_PRES: i64 = 4 |
| 735 | const HR_SUM_OPEN: i64 = 5 |
| 736 | const HR_SUM_EXC: i64 = 6 |
| 737 | const HR_SUM_UNJ: i64 = 7 |
| 738 | const HR_OLDEST: i64 = 8 |
| 739 | const HR_ABSTAINED: i64 = 9 |
| 740 | const HR_ADOPT_FULL: i64 = 10 |
| 741 | const HR_ADOPT_PART: i64 = 11 |
| 742 | const HR_WITH_ADOPT: i64 = 12 |
| 743 | const HR_N: i64 = 13 |
functions
| 94 | func split5(buf: *u8, ls: i64, le: i64, fbuf: *u8) -> i64 |
| 107 | func c_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 } |
| 108 | func 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 } called by 1: hub_key_of |
| 111 | func w2(fd: i64, s: *u8) -> i64 called by 6: wrefhub_measurement_schemahub_investment_schemahub_bindings_schemahub_bindings_pathmain calls 1: wc |
| 117 | func wref(fd: i64, nm: *u8) -> i64 |
| 125 | func hub_kc(out: *u8) -> i64 |
| 130 | func 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 } |
| 134 | func data_exists(dbuf: *u8, pbuf: *u8) -> i64 |
| 152 | func hub_reg_has(sbuf: *u8, sn: i64, dom: *u8) -> i64 |
| 176 | func hub_dom_line(dom: *u8, pfx: *u8, plen: i64, tout: *u8, tbuf: *u8, tcap: i64) -> i64 |
| 210 | func hub_dom_title(dom: *u8, tout: *u8, tbuf: *u8, tcap: i64) -> i64 |
| 217 | func hub_slot(cards: *u8, idx: i64, off: i64) -> *u8 { return (cards as i64 + idx * HUB_SLOT + off) as *u8 } |
| 218 | func hub_num(cn: *i64, idx: i64, f: i64) -> i64 { return cn[idx * HN + f] } |
| 219 | func hub_setnum(cn: *i64, idx: i64, f: i64, v: i64) -> i64 { cn[idx * HN + f] = v; return 0 } |
| 220 | func 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 } |
| 222 | func hub_key_of(href: *u8, out: *u8) -> i64 |
| 233 | func hub_find(buf: *u8, n: i64, nd: *u8, nlen: i64) -> i64 |
| 245 | func jnum(buf: *u8, n: i64, key: *u8) -> i64 |
| 268 | func jstr(buf: *u8, n: i64, key: *u8, out: *u8, cap: i64) -> i64 |
| 304 | func hub_wis(buf: *u8, n: i64, at: i64, lit: *u8) -> i64 called by 1: hub_wcount |
| 325 | func hub_wcount(buf: *u8, n: i64, cnt: *i64) -> i64 |
| 363 | func hub_tsrc_name(t: i64) -> *u8 called by 1: hub_card_json |
| 370 | func hub_facts(cards: *u8, cn: *i64, idx: i64, abuf: *u8, pbuf: *u8) -> i64 |
| 433 | func hub_group(gbuf: *u8, gn: i64, key: *u8, out: *u8) -> i64 |
| 455 | func hub_slugify(src: *u8, out: *u8) -> i64 |
| 471 | func wa(fd: i64, s: *u8) -> i64 |
| 480 | func wlower(fd: i64, s: *u8) -> i64 |
| 486 | func wdate(fd: i64, t: i64) -> i64 |
| 503 | func hub_add(cards: *u8, cn: *i64, count: i64, title: *u8, kind: *u8, href: *u8, radar: *u8, stat: *u8) -> i64 |
| 520 | func hub_disp_kind(cards: *u8, cn: *i64, idx: i64, out: *u8) -> i64 |
| 533 | func hub_card_html(cards: *u8, cn: *i64, idx: i64) -> i64 |
| 581 | func hub_card_json(cards: *u8, cn: *i64, idx: i64, pbuf: *u8) -> i64 |
| 620 | func hub_build(sbuf: *u8, sn: i64, cards: *u8, cn: *i64, gt: *u8, gcount: *i64) -> i64 |
| 744 | func hub_rollup(cards: *u8, cn: *i64, count: i64, gname: *u8, out: *i64) -> i64 |
| 800 | func hub_order(cards: *u8, cn: *i64, count: i64, gname: *u8, ord: *i64) -> i64 |
| 822 | func hub_measurement_schema(fd: i64) -> i64 calls 1: w2 |
| 839 | func hub_investment_schema(fd: i64) -> i64 calls 1: w2 |
| 854 | func hub_bindings_schema(fd: i64) -> i64 calls 1: w2 |
| 865 | func hub_bindings_path(fd: i64) -> i64 |
| 874 | func main(argc: i64, argv: *i64) -> i64 |