nx_compare_sections.nx
buildroot/runtime/nx_compare_sections.nx
about
nx_compare_sections.nx -- SECTION CENSUS of the published /compare surface: which <h2> sections every
domain page carries, the union across the surface, and -- against a DECLARED required shape -- which
sections each page is MISSING, named per domain.
WHY THIS EXISTS (2026-09-02, operator: "all the /compare on the same emitted output, not random; if a
previous compare had more capabilities bring it into the emitter"). Two generators emit the surface
(nx_swcompare_matrix, nx_swcompare_sota) and their pages had drifted to two SHAPES: the sota-class pages
lacked Evidence profile, Do this next, Critical path and the Capability matrix that every matrix-class
page carries. The first attempt to measure that was `nx_shelltool grep "<h2"` over the docroot, which hit
its 1 MiB budget on the FIRST page: emitted HTML is minified, so one section is one line of 100 KB and a
line-oriented grep measures nothing. A TAG-AWARE WALKER IS THE INSTRUMENT, and it belongs in the estate,
not in a shell one-liner (NishiLang for everything; shell is the wire).
THE REQUIRED SHAPE IS DATA, NOT A LIST IN THIS FILE: knowledge/compare/sections.required rows
section|<title prefix>|<data ext or ->
A section is REQUIRED of a domain when its data class exists for that domain (<kdir>/<dom>.<ext>) or
when the ext is "-" (required of every page). A page that has the data but not the section is the
emitter-shape defect this organ names; a page without the data is not blamed for the section.
Title matching is by PREFIX after normalisation (tags stripped, cut at the first " —"), so the
generators' long explanatory headings ("Do this next — computed by the ranker...") match their
short declared prefix and a reworded tail cannot silently un-match a section.
nx_compare_sections <docroot> <kdir> <required.conf>
docroot the live compare docroot holding <dom>/index.html (sites/nishifamily/compare from nishihost)
kdir the knowledge compare tree the regen READS (buildroot/knowledge/compare)
required the declared shape
Prints one DOM line per page (sections carried, missing named), one MISSING row per absent required
section, the union table (title, domains carrying it), then the partition WITH its sums, then the
verdict LAST (gv_last_line anchors by position). Exit: 0 GREEN (no page misses a required section) .
1 RED (at least one MISSING row) . 2 usage . 3 UNOBSERVABLE (docroot or conf unreadable, or zero pages
read -- an empty population is never a pass).
license_tier: ORIGINAL Read-only on every path it touches. No hw writes (Rule 26).
dependencies 1 imports · 0 importers
imports: nx_syscalls.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
| 35 | const CS_DENTBUF: i64 = 262144 // one getdents64 window; the loop drains until 0 so this is a window, not a cap |
| 36 | const CS_PATH: i64 = 4096 |
| 37 | const CS_SLOT: i64 = 96 // a domain directory name; the longest on the surface is 15 bytes |
| 38 | const CS_MAX_DOMS: i64 = 512 // regen.list 101 + hand.roster 11 = 112 today; 512 is 4x headroom and ANNOUNCES when hit |
| 39 | const CS_TITLE: i64 = 128 // a normalised <h2> title; the longest declared prefix is 21 bytes, the longest emitted head before — ~60 |
| 40 | const CS_MAX_SECT: i64 = 512 // distinct titles across the surface: two generators emit ~20 and the hand pages a few dozen more |
| 41 | const CS_PAGE_SECT: i64 = 96 // distinct titles on ONE page: the richest page today carries 14 |
| 42 | const CS_MAX_REQ: i64 = 64 // rows in sections.required: 10 declared today |
| 43 | const CS_EXT: i64 = 16 |
| 44 | const CS_DOT: i64 = 46 |
| 45 | const CS_DT_DIR: i64 = 4 |
| 46 | const CS_DT_UNKNOWN: i64 = 0 // an unknown d_type is TAKEN (the page read decides), never skipped |
| 47 | const CS_LT: i64 = 60 // < |
| 48 | const CS_GT: i64 = 62 // > |
| 49 | const CS_AMP: i64 = 38 // & |
| 50 | const CS_SP: i64 = 32 |
| 51 | const CS_NL: i64 = 10 |
| 52 | const CS_PIPE: i64 = 124 |
| 53 | const CS_HASH: i64 = 35 |
| 54 | const CS_EXIT_GREEN: i64 = 0 |
| 55 | const CS_EXIT_RED: i64 = 1 |
| 56 | const CS_EXIT_USAGE: i64 = 2 |
| 57 | const CS_EXIT_UNOBS: i64 = 3 |
functions
| 59 | func cs_slen(s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { i = i + 1 } return i } called by 1: cs_puts |
| 60 | func cs_puts(fd: i64, s: *u8) -> i64 { return sys_write(fd, s, cs_slen(s)) } |
| 61 | func cs_putn(fd: i64, v: i64) -> i64 |
| 78 | func cs_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; var p: i64 = o; while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } d[p] = 0 as u8; return p } |
| 79 | func cs_eq(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } if b[i] != (0 as u8) { return 0 } return 1 } |
| 80 | func cs_starts(hay: *u8, pre: *u8) -> i64 { var i: i64 = 0; while pre[i] != (0 as u8) { if hay[i] != pre[i] { return 0 } i = i + 1 } return 1 } called by 1: main |
| 81 | func cs_slot(base: *u8, i: i64, stride: i64) -> *u8 { return ((base as i64) + i * stride) as *u8 } |
| 82 | func cs_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 } |
| 85 | func cs_at(b: *u8, n: i64, i: i64, s: *u8) -> i64 |
| 96 | func cs_dirs(root: *u8, names: *u8, cap: i64, out: *i64) -> i64 |
| 141 | func cs_h2_text(b: *u8, n: i64, start: i64, title: *u8) -> i64 |
| 173 | func cs_page_sections(b: *u8, n: i64, ptitles: *u8, cap: i64, out: *i64) -> i64 |
| 201 | func cs_intern(title: *u8, gt: *u8, gn: *i64, cap: i64) -> i64 |
| 212 | func cs_required(path: *u8, pre: *u8, ext: *u8, cap: i64) -> i64 |
| 243 | func main(argc: i64, argv: *i64) -> i64 |