code wiki / (root) / nx_product_board.nx

nx_product_board.nx source

↩ module page · 264 lines · 15573 B

1// nx_product_board.nx -- THE PRODUCT CATALOG + ROADMAP, rendered from the `products-` information plane 2// into the ALREADY-GATED wiki tree (sites/nishifamily/wiki/products.html -> /wiki/products.html). 3// 4// WHY THIS EXISTS: nx_wiki_products_page claimed in its header AND on the rendered page that it was 5// "Sourced from knowledge/registry/product_catalog.tsv", but it contained NO file read at all -- all 10 6// families were hardcoded string literals, so every catalog edit was invisible to the page (debt 7// 1785625149). There was no reader to repoint; the reader never existed. This organ is the reader. 8// 9// A product is an OUTCOME, and products live in FAMILIES (games contains checkers and chess). Families 10// are NOT hardcoded here either: they are the DISTINCT values of the family column in first-seen order, 11// so a new family appears by adding ONE plane row -- the same property that makes nx_research_ocean 12// free to extend. Adding a product must cost a data row, never code (the gen-2 golden-path bar). 13// 14// GATING: this writes INTO /wiki, which is OPAQUE-gated by nx_sites_daemon_v2 (no X-Nishi-Session + 15// text/html -> login bootstrap; else proxy to the session-validating gateway, fail-closed). Product 16// strategy is therefore behind the wall BY PLACEMENT, using the wall that already exists rather than 17// standing up a second one. Research stays public in its own rivers. 18// 19// Reads with sts_load_honest so a stale q:n cannot silently truncate the catalog and present a partial 20// board as complete; declared/loaded/rendered are printed on the page itself. 21// 22// Plane row (8 col): id family product arc status governance evidence rung 23// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 24import "nx_store_seed_lib.nx" 25import "nx_seg_store.nx" 26import "nx_syscalls.nx" 27 28const PB_PLANE: *u8 = "knowledge/store/products-" 29const PB_OUT: *u8 = "sites/nishifamily/wiki/products.html" 30const PB_RCAP: i64 = 262144 31const PB_HCAP: i64 = 524288 32const PB_NL: i64 = 10 33const PB_TAB: i64 = 9 34const PB_MAXCOL: i64 = 16 35const PB_PAIR: i64 = 2 36const PB_SPB: i64 = 256 37const PB_MAXFAM: i64 = 32 38const PB_FAMB: i64 = 512 39const PB_FLAGB: i64 = 64 40const PB_C_FAM: i64 = 1 41const PB_C_PROD: i64 = 2 42const PB_C_ARC: i64 = 3 43const PB_C_STATUS: i64 = 4 44const PB_C_GOV: i64 = 5 45const PB_C_EV: i64 = 6 46const PB_C_RUNG: i64 = 7 47const PB_NCOL: i64 = 8 48const PB_MODE: i64 = 0x1a4 49const PB_ERRFD: i64 = 2 50const PB_EXIT_IO: i64 = 1 51const PB_EXIT_EMPTY: i64 = 3 52const PB_LT: i64 = 60 53const PB_GT: i64 = 62 54const PB_AMP: i64 = 38 55 56func pb_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 57func pb_werr(s: *u8) -> i64 { sys_write(PB_ERRFD, s, pb_slen(s)); return 0 } 58func pb_slice_eqs(q: *u8, a: i64, b: i64, s: *u8) -> i64 { 59 let sn: i64 = pb_slen(s) 60 if b - a != sn { return 0 } 61 var i: i64 = 0 62 while i < sn { if q[a+i] != s[i] { return 0 } i = i + 1 } 63 return 1 64} 65func pb_slice_eq(q: *u8, a: i64, b: i64, r: *u8, c: i64, d: i64) -> i64 { 66 if b - a != d - c { return 0 } 67 var i: i64 = 0 68 while a + i < b { if q[a+i] != r[c+i] { return 0 } i = i + 1 } 69 return 1 70} 71func pb_cols(q: *u8, ls: i64, le: i64, sp: *i64) -> i64 { 72 var c: i64 = 0 73 var p: i64 = ls 74 while c < PB_MAXCOL { 75 var e: i64 = p 76 var s: i64 = 1 77 while s == 1 { if e >= le { s = 0 } else { if q[e] == (PB_TAB as u8) { s = 0 } else { e = e + 1 } } } 78 sp[c*PB_PAIR] = p 79 sp[c*PB_PAIR+1] = e 80 c = c + 1 81 if e >= le { return c } 82 p = e + 1 83 } 84 return c 85} 86func pb_cat_esc(d: *u8, o: i64, q: *u8, a: i64, b: i64) -> i64 { 87 var oo: i64 = o 88 var i: i64 = a 89 while i < b { 90 let c: i64 = q[i] as i64 91 if c == PB_LT { oo = ss_cat(d, oo, "&lt;" as *u8) } 92 else { if c == PB_GT { oo = ss_cat(d, oo, "&gt;" as *u8) } 93 else { if c == PB_AMP { oo = ss_cat(d, oo, "&amp;" as *u8) } 94 else { d[oo] = q[i]; oo = oo + 1 } } } 95 i = i + 1 96 } 97 return oo 98} 99 100func main() -> i64 { 101 let buf: *u8 = sts_mm(PB_RCAP) 102 let flags: *i64 = sts_mm(PB_FLAGB) as *i64 103 let n: i64 = sts_load_honest(PB_PLANE, buf, PB_RCAP, flags) 104 if n <= 0 { 105 pb_werr("PRODUCTBOARD-RED plane EMPTY / unseeded: knowledge/store/products-\n" as *u8) 106 sys_exit(PB_EXIT_EMPTY) 107 return PB_EXIT_EMPTY 108 } 109 let h: *u8 = sts_mm(PB_HCAP) 110 let sp: *i64 = sts_mm(PB_SPB) as *i64 111 let sp2: *i64 = sts_mm(PB_SPB) as *i64 112 let fam: *i64 = sts_mm(PB_FAMB) as *i64 113 let now: i64 = sys_now_realtime_sec() 114 115 // pass 1: distinct families, first-seen order -- this is what makes a new family free 116 var nf: i64 = 0 117 var i: i64 = 0 118 while i < n { 119 var le: i64 = i 120 var s: i64 = 1 121 while s == 1 { if le >= n { s = 0 } else { if buf[le] == (PB_NL as u8) { s = 0 } else { le = le + 1 } } } 122 if le > i { 123 let nc: i64 = pb_cols(buf, i, le, sp) 124 if nc > PB_C_FAM { 125 let fa: i64 = sp[PB_C_FAM*PB_PAIR] 126 let fb: i64 = sp[PB_C_FAM*PB_PAIR+1] 127 var seen: i64 = 0 128 var k: i64 = 0 129 while k < nf { if pb_slice_eq(buf, fa, fb, buf, fam[k*PB_PAIR], fam[k*PB_PAIR+1]) == 1 { seen = 1 } k = k + 1 } 130 if seen == 0 { if nf < PB_MAXFAM { fam[nf*PB_PAIR] = fa; fam[nf*PB_PAIR+1] = fb; nf = nf + 1 } } 131 } 132 } 133 i = le + 1 134 } 135 136 var w: i64 = 0 137 w = ss_cat(h, w, "<!doctype html>\n<html lang='en'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'>\n<title>Product catalog and roadmap - Nishi</title>\n<style>\n" as *u8) 138 w = ss_cat(h, w, ":root{--bg:#fff;--sf:#f6f8fb;--br:#dfe4ec;--ink:#232936;--mut:#68748a;--acc:#1a5dc8;--acc2:#2e8555;--hd:#111726;--hov:#f0f4fa;--amb:#a8792e}\n" as *u8) 139 w = ss_cat(h, w, "@media(prefers-color-scheme:dark){:root{--bg:#0d1017;--sf:#131826;--br:#252d40;--ink:#dbe2ec;--mut:#8a94a8;--acc:#5aa7f0;--acc2:#86c793;--hd:#eef2f8;--hov:#141a28;--amb:#d0a24e}}\n" as *u8) 140 w = ss_cat(h, w, "*{box-sizing:border-box}body{font-family:system-ui,'Segoe UI',sans-serif;margin:0;background:var(--bg);color:var(--ink);padding:22px 30px 40px;line-height:1.55}\n" as *u8) 141 w = ss_cat(h, w, "main{max-width:1120px;margin:0 auto}a{color:var(--acc);text-decoration:none}a:hover{text-decoration:underline}\n" as *u8) 142 w = ss_cat(h, w, "h1{font-size:1.55em;color:var(--hd);margin:2px 0 6px;letter-spacing:-.01em}\n" as *u8) 143 w = ss_cat(h, w, "h2{font-size:1.05em;color:var(--hd);margin:28px 0 8px;padding-bottom:5px;border-bottom:1px solid var(--br)}\n" as *u8) 144 w = ss_cat(h, w, "table{border-collapse:collapse;width:100%;margin:8px 0}td,th{padding:6px 10px;border-bottom:1px solid var(--br);text-align:left;vertical-align:top;font-size:.88em}th{color:var(--mut);font-size:.82em}tr:hover td{background:var(--hov)}\n" as *u8) 145 w = ss_cat(h, w, ".muted{color:var(--mut)}.n{text-align:right;font-variant-numeric:tabular-nums}\n" as *u8) 146 w = ss_cat(h, w, ".nar{background:var(--sf);border:1px solid var(--br);border-left:3px solid var(--acc2);border-radius:8px;padding:12px 16px;font-size:.92em;margin:12px 0}\n" as *u8) 147 w = ss_cat(h, w, ".st{font-weight:600;font-size:.8em;white-space:nowrap}.go{color:var(--acc2)}.wip{color:var(--amb)}.plan{color:var(--mut)}\n" as *u8) 148 w = ss_cat(h, w, "code{font-family:ui-monospace,Consolas,monospace;font-size:.85em}\nfooter{margin-top:36px;padding-top:10px;border-top:1px solid var(--br);font-size:.8em;color:var(--mut)}\n" as *u8) 149 w = ss_cat(h, w, "</style></head><body><main>\n<p class='muted'><a href='/wiki/index.html'>nishi wiki</a> / products &middot; public front door: <a href='/product'>/product</a></p>\n<h1>Product catalog and roadmap</h1>\n" as *u8) 150 w = ss_cat(h, w, "<p class='muted'>A product is an <b>outcome</b>, and products live in <b>families</b>. Every product inherits its family's governance contract by construction. Generated by <code>nx_product_board</code> from the <code>products-</code> information plane at epoch=" as *u8) 151 w = ss_catn(h, w, now) 152 w = ss_cat(h, w, ".</p>\n" as *u8) 153 w = ss_cat(h, w, "<div class='nar'><b>This page is data, not prose.</b> Families and products are read from the plane at render time &mdash; adding a product costs ONE data row and no code. Its predecessor claimed to be sourced from a catalog file and in fact hardcoded every family as a string literal, so edits to the catalog were invisible here for as long as that was true (debt 1785625149). If a number on this page looks wrong, fix the plane row; the page cannot disagree with it.</div>\n" as *u8) 154 w = ss_cat(h, w, "<div class='nar'><b>Why this is behind the wall.</b> Research is public &mdash; see <a href='/wiki/research'>the research ocean</a>. What we are building, in what order, and why is not. This page sits inside the gated <code>/wiki</code> tree deliberately, reusing the access wall that already exists rather than standing up a second one.</div>\n" as *u8) 155 156 var f: i64 = 0 157 var total: i64 = 0 158 var nrung: i64 = 0 159 while f < nf { 160 let fa: i64 = fam[f*PB_PAIR] 161 let fb: i64 = fam[f*PB_PAIR+1] 162 w = ss_cat(h, w, "<h2>" as *u8) 163 w = pb_cat_esc(h, w, buf, fa, fb) 164 w = ss_cat(h, w, "</h2>\n<table><tr><th>Product</th><th>Arc</th><th class='st'>Status</th><th>Governance inherited</th><th>Evidence</th><th>Next rung &mdash; exit criterion</th></tr>\n" as *u8) 165 var rows: i64 = 0 166 var j: i64 = 0 167 while j < n { 168 var le2: i64 = j 169 var s2: i64 = 1 170 while s2 == 1 { if le2 >= n { s2 = 0 } else { if buf[le2] == (PB_NL as u8) { s2 = 0 } else { le2 = le2 + 1 } } } 171 if le2 > j { 172 let nc2: i64 = pb_cols(buf, j, le2, sp2) 173 if nc2 >= PB_NCOL { 174 if pb_slice_eq(buf, sp2[PB_C_FAM*PB_PAIR], sp2[PB_C_FAM*PB_PAIR+1], buf, fa, fb) == 1 { 175 let sa: i64 = sp2[PB_C_STATUS*PB_PAIR] 176 let sb: i64 = sp2[PB_C_STATUS*PB_PAIR+1] 177 w = ss_cat(h, w, "<tr><td><b>" as *u8) 178 w = pb_cat_esc(h, w, buf, sp2[PB_C_PROD*PB_PAIR], sp2[PB_C_PROD*PB_PAIR+1]) 179 w = ss_cat(h, w, "</b></td><td class='muted'><code>" as *u8) 180 w = pb_cat_esc(h, w, buf, sp2[PB_C_ARC*PB_PAIR], sp2[PB_C_ARC*PB_PAIR+1]) 181 w = ss_cat(h, w, "</code></td><td class='st " as *u8) 182 if pb_slice_eqs(buf, sa, sb, "ROADMAP" as *u8) == 1 { w = ss_cat(h, w, "plan" as *u8) } else { 183 if pb_slice_eqs(buf, sa, sb, "DONE" as *u8) == 1 { w = ss_cat(h, w, "go" as *u8) } else { 184 if pb_slice_eqs(buf, sa, sb, "LIVE" as *u8) == 1 { w = ss_cat(h, w, "go" as *u8) } else { w = ss_cat(h, w, "wip" as *u8) } 185 } 186 } 187 w = ss_cat(h, w, "'>" as *u8) 188 w = pb_cat_esc(h, w, buf, sa, sb) 189 w = ss_cat(h, w, "</td><td class='muted'>" as *u8) 190 w = pb_cat_esc(h, w, buf, sp2[PB_C_GOV*PB_PAIR], sp2[PB_C_GOV*PB_PAIR+1]) 191 w = ss_cat(h, w, "</td><td class='muted'>" as *u8) 192 w = pb_cat_esc(h, w, buf, sp2[PB_C_EV*PB_PAIR], sp2[PB_C_EV*PB_PAIR+1]) 193 w = ss_cat(h, w, "</td><td>" as *u8) 194 // a rung of "-" means NO measured next rung has been declared. Say so plainly rather 195 // than printing a dash that reads like a decision -- an empty roadmap cell is a gap. 196 if pb_slice_eqs(buf, sp2[PB_C_RUNG*PB_PAIR], sp2[PB_C_RUNG*PB_PAIR+1], "-" as *u8) == 1 { 197 w = ss_cat(h, w, "<span class='muted'>none declared</span>" as *u8) 198 } else { 199 w = pb_cat_esc(h, w, buf, sp2[PB_C_RUNG*PB_PAIR], sp2[PB_C_RUNG*PB_PAIR+1]) 200 nrung = nrung + 1 201 } 202 w = ss_cat(h, w, "</td></tr>\n" as *u8) 203 rows = rows + 1 204 total = total + 1 205 } 206 } 207 } 208 j = le2 + 1 209 } 210 w = ss_cat(h, w, "</table>\n<p class='muted'>" as *u8) 211 w = ss_catn(h, w, rows) 212 w = ss_cat(h, w, " products in this family.</p>\n" as *u8) 213 f = f + 1 214 } 215 216 w = ss_cat(h, w, "<h2>Coverage of this board</h2>\n<table><tr><th>Measure</th><th class='n'>Count</th><th>Meaning</th></tr>\n" as *u8) 217 w = ss_cat(h, w, "<tr><td>Families</td><td class='n'>" as *u8) 218 w = ss_catn(h, w, nf) 219 w = ss_cat(h, w, "</td><td class='muted'>distinct family values in the plane</td></tr>\n<tr><td>Declared by the plane</td><td class='n'>" as *u8) 220 w = ss_catn(h, w, flags[0]) 221 w = ss_cat(h, w, "</td><td class='muted'>the plane's own row count</td></tr>\n<tr><td>Loaded</td><td class='n'>" as *u8) 222 w = ss_catn(h, w, flags[1]) 223 w = ss_cat(h, w, "</td><td class='muted'>rows actually read back</td></tr>\n<tr><td>Rendered</td><td class='n'>" as *u8) 224 w = ss_catn(h, w, total) 225 w = ss_cat(h, w, "</td><td class='muted'>rows on this page &mdash; must equal Loaded, else a row is malformed</td></tr>\n<tr><td>With a declared next rung</td><td class='n'>" as *u8) 226 w = ss_catn(h, w, nrung) 227 w = ss_cat(h, w, "</td><td class='muted'>the rest have NO falsifiable next step declared &mdash; that gap is the roadmap's real backlog</td></tr>\n<tr><td>Reachable beyond the count</td><td class='n'>" as *u8) 228 w = ss_catn(h, w, flags[2]) 229 w = ss_cat(h, w, "</td><td class='muted'>records past the declared count; non-zero means reconcile</td></tr>\n</table>\n" as *u8) 230 if flags[1] != total { w = ss_cat(h, w, "<p class='nar'><b>WARNING:</b> loaded and rendered disagree &mdash; at least one plane row is malformed and is missing above. This board is INCOMPLETE.</p>\n" as *u8) } 231 if flags[2] > 0 { w = ss_cat(h, w, "<p class='nar'><b>WARNING:</b> records exist past the declared count; this board may be under-reporting.</p>\n" as *u8) } 232 233 w = ss_cat(h, w, "<footer>Generated sovereignly by <code>nx_product_board</code> from <code>knowledge/store/products-</code>. Add a product or a family by adding a plane row &mdash; this page needs no edit. Research: <a href='/wiki/research'>the ocean</a> &middot; <a href='/product/research'>product research</a> &middot; <a href='/code/research'>code research</a>.</footer>\n</main></body></html>\n" as *u8) 234 235 let fd: i64 = sys_openat_wr(PB_OUT, PB_MODE) 236 if fd < 0 { 237 pb_werr("PRODUCTBOARD-RED cannot open sites/nishifamily/wiki/products.html for write\n" as *u8) 238 sys_exit(PB_EXIT_IO) 239 return PB_EXIT_IO 240 } 241 sys_write(fd, h, w) 242 sys_close(fd) 243 244 let m: *u8 = sts_mm(512) 245 var o: i64 = ss_cat(m, 0, "PRODUCTBOARD-GREEN families=" as *u8) 246 o = ss_catn(m, o, nf) 247 o = ss_cat(m, o, " rendered=" as *u8) 248 o = ss_catn(m, o, total) 249 o = ss_cat(m, o, " declared=" as *u8) 250 o = ss_catn(m, o, flags[0]) 251 o = ss_cat(m, o, " loaded=" as *u8) 252 o = ss_catn(m, o, flags[1]) 253 o = ss_cat(m, o, " with_rung=" as *u8) 254 o = ss_catn(m, o, nrung) 255 o = ss_cat(m, o, " beyond=" as *u8) 256 o = ss_catn(m, o, flags[2]) 257 o = ss_cat(m, o, " bytes=" as *u8) 258 o = ss_catn(m, o, w) 259 m[o] = PB_NL as u8 260 o = o + 1 261 sys_write(1, m, o) 262 sys_exit(0) 263 return 0 264}