code wiki / _hdl_build / nx_papers_index.nx
nx_papers_index.nx source
↩ module page · 321 lines · 20689 B
1// nx_papers_index.nx -- the Research Repository landing page, COMPILED FROM A REGISTRY (F1130).
2//
3// ★WHAT CHANGED AND WHY. This organ used to emit the index with one hardcoded paper_row()
4// call per paper, baked into the source. That is a rule-11 violation (data belongs in data,
5// not code): the list went stale on 2026-06-17, and adding a paper meant editing and
6// recompiling an organ. It also linked every paper into /wiki/, which is AUTH-GATED -- so
7// the "public research repository" was not publicly readable at all, and nothing that lives
8// only behind a login is citable.
9//
10// Now: rows come from a TSV registry and each row declares its own ACCESS. Adding a paper is
11// a data edit. Internal papers are listed honestly as access-controlled rather than rendered
12// as links that a reader cannot follow.
13//
14// nx_papers_index <registry.tsv> <out.html>
15// registry row: id \t access(public|internal) \t href \t title \t abstract \t result \t gates
16//
17// FAIL-CLOSED: an unreadable or empty registry REFUSES (exit 3) rather than emitting an empty
18// repository page -- a page saying "no papers" is indistinguishable from a broken read, and
19// silently publishing one would erase the repository.
20//
21// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
22import "nx_syscalls.nx"
23import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
24
25const PX_COLS: i64 = 7
26const PX_CAP: i64 = 262144
27const PX_OUT: i64 = 524288
28const PX_TAB: i64 = 9
29const PX_NL: i64 = 10
30
31func px_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
32func px_puts(s: *u8) -> i64 { sys_write(1, s, px_len(s)); return 0 }
33// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
34// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
35// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
36// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
37func px_num(v: i64) -> i64 { nxi_out(v); return 0 }
38func px_read(path: *u8, buf: *u8, cap: i64) -> i64 {
39 let fd: i64 = sys_openat_rd(path)
40 if fd < 0 { return 0 - 1 }
41 var n: i64 = 0
42 var go: i64 = 1
43 while go == 1 {
44 let base: i64 = buf as i64
45 let r: i64 = sys_read(fd, (base + n) as *u8, cap - n)
46 if r <= 0 { go = 0 } else { n = n + r }
47 if n >= cap { go = 0 }
48 }
49 sys_close(fd)
50 return n
51}
52// append a NUL-terminated literal
53func px_app(dst: *u8, off: i64, s: *u8) -> i64 {
54 var i: i64 = 0
55 var o: i64 = off
56 while s[i] != (0 as u8) { dst[o] = s[i]; o = o + 1; i = i + 1 }
57 return o
58}
59// append src[a..b)
60func px_appn(dst: *u8, off: i64, src: *u8, a: i64, b: i64) -> i64 {
61 var i: i64 = a
62 var o: i64 = off
63 while i < b { dst[o] = src[i]; o = o + 1; i = i + 1 }
64 return o
65}
66func px_eol(buf: *u8, n: i64, i: i64) -> i64 {
67 var e: i64 = i
68 var s: i64 = 1
69 while s == 1 {
70 if e >= n { s = 0 } else { if buf[e] == (PX_NL as u8) { s = 0 } else { e = e + 1 } }
71 }
72 return e
73}
74// split line [ls,le) into PX_COLS ranges; col[c*2],col[c*2+1]. Returns columns found.
75func px_cols(buf: *u8, ls: i64, le: i64, col: *i64) -> i64 {
76 var c: i64 = 0
77 var p: i64 = ls
78 while c < PX_COLS {
79 var q: i64 = p
80 var s: i64 = 1
81 while s == 1 {
82 if q >= le { s = 0 } else { if buf[q] == (PX_TAB as u8) { s = 0 } else { q = q + 1 } }
83 }
84 col[c*2] = p
85 col[c*2+1] = q
86 if q >= le {
87 c = c + 1
88 while c < PX_COLS { col[c*2] = le; col[c*2+1] = le; c = c + 1 }
89 return c
90 }
91 p = q + 1
92 c = c + 1
93 }
94 return c
95}
96func px_is(buf: *u8, a: i64, b: i64, lit: *u8) -> i64 {
97 let l: i64 = px_len(lit)
98 if b - a != l { return 0 }
99 var i: i64 = 0
100 while i < l { if buf[a+i] != lit[i] { return 0 } i = i + 1 }
101 return 1
102}
103
104// Append a non-negative integer INTO the page buffer. px_num writes to stdout, which cannot serve a
105// masthead that states the repository's own counts -- and a hand-typed count in a generated index is
106// exactly the kind of number that goes stale silently.
107func px_appnum(out: *u8, pos: i64, v: i64) -> i64 {
108 let t: *u8 = sys_mmap(28)
109 var m: i64 = v
110 var k: i64 = 0
111 if m <= 0 { t[0] = 48 as u8; k = 1 } else {
112 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
113 }
114 var p: i64 = pos
115 var i: i64 = 0
116 while i < k { out[p] = t[k-1-i]; p = p + 1; i = i + 1 }
117 return p
118}
119
120// Find `lit` inside buf[a..b); returns its start index, or -1.
121// WHY THIS EXISTS: almost every findings row in the registry contains a literal HONEST: clause -- the
122// author's own statement of where the work is behind. Rendered as one undifferentiated paragraph, that
123// clause reads as a footnote to a boast. Splitting on it gives the limitation its OWN channel, which is
124// the only page decision here that could not be lifted from a generic template: it is derived from the
125// estate's cardinal discipline that a caveat is a first-class result, not a disclaimer. A paper with no
126// such clause is then conspicuous by its absence, which is the pressure we want on the next author.
127func px_find(buf: *u8, a: i64, b: i64, lit: *u8) -> i64 {
128 let l: i64 = px_len(lit)
129 if l <= 0 { return 0 - 1 }
130 if b - a < l { return 0 - 1 }
131 var i: i64 = a
132 while i <= b - l {
133 var j: i64 = 0
134 var m: i64 = 1
135 while j < l { if buf[i+j] != lit[j] { m = 0; j = l } else { j = j + 1 } }
136 if m == 1 { return i }
137 i = i + 1
138 }
139 return 0 - 1
140}
141
142func main(argc: i64, argv: *i64) -> i64 {
143 if argc < 3 {
144 px_puts("usage: nx_papers_index <registry.tsv> <out.html>\n" as *u8)
145 sys_exit(2); return 2
146 }
147 let reg: *u8 = sys_mmap(PX_CAP)
148 let rn: i64 = px_read(argv[1] as *u8, reg, PX_CAP - 16)
149 if rn <= 0 {
150 // FAIL-CLOSED: never publish an empty repository over a real one.
151 px_puts("PAPERS-INDEX REFUSED: registry unreadable or empty -> " as *u8)
152 px_puts(argv[1] as *u8)
153 px_puts("\n (an empty index is indistinguishable from a broken read; refusing to emit)\n" as *u8)
154 sys_exit(3); return 3
155 }
156 let out: *u8 = sys_mmap(PX_OUT)
157 var o: i64 = 0
158 o = px_app(out, o, "<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n" as *u8)
159 o = px_app(out, o, "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n" as *u8)
160 o = px_app(out, o, "<title>Nishi Research Repository</title>\n" as *u8)
161 o = px_app(out, o, "<meta name=\"description\" content=\"Papers compiled from measured gates. Every quantitative claim cites a re-runnable gate.\">\n" as *u8)
162 // ---- STYLESHEET (rebuilt 2026-08-06 to the estate's polish bar) --------------------------------
163 // The palette is SEMANTIC, not decorative: proof/open/hold each carry a paired foreground+wash so a
164 // paper's ACCESS STATE is legible as colour and not only as words. Three type roles do real work --
165 // a serif for reading, a sans for chrome, and a mono reserved for identifiers, labels and figures,
166 // which is what keeps a repository of measured claims from reading like a blog. Both themes are
167 // authored, and the data-theme overrides win over the media query in BOTH directions.
168 o = px_app(out, o, "<style>\n" as *u8)
169 o = px_app(out, o, ":root{--ground:#EEEFEA;--sunk:#E4E6DF;--card:#F7F8F3;--ink:#191C1A;--ink-soft:#4B4F4A;--ink-faint:#767B73;--proof:#3D6350;--proof-wash:#E0EAE4;--open:#2B3F6E;--open-wash:#E1E5EF;--hold:#8A4436;--hold-wash:#F1E3DF;--rule:#D8D5C8;--edge:#B4AF9C;--serif:\"Iowan Old Style\",\"Palatino Linotype\",Palatino,\"Book Antiqua\",Georgia,serif;--sans:ui-sans-serif,system-ui,-apple-system,\"Segoe UI\",Roboto,sans-serif;--mono:ui-monospace,\"SF Mono\",\"Cascadia Mono\",\"Roboto Mono\",Consolas,monospace;--measure:68ch;--page:1080px}\n" as *u8)
170 o = px_app(out, o, "@media (prefers-color-scheme:dark){:root{--ground:#13161A;--sunk:#0F1215;--card:#1B1E23;--ink:#E4E3DB;--ink-soft:#AEB0A7;--ink-faint:#7D807A;--proof:#84B096;--proof-wash:#19241D;--open:#94A8DC;--open-wash:#1D2534;--hold:#CE8577;--hold-wash:#2A1D1A;--rule:#33362F;--edge:#4A4D45}}\n" as *u8)
171 o = px_app(out, o, ":root[data-theme=\"dark\"]{--ground:#13161A;--sunk:#0F1215;--card:#1B1E23;--ink:#E4E3DB;--ink-soft:#AEB0A7;--ink-faint:#7D807A;--proof:#84B096;--proof-wash:#19241D;--open:#94A8DC;--open-wash:#1D2534;--hold:#CE8577;--hold-wash:#2A1D1A;--rule:#33362F;--edge:#4A4D45}\n" as *u8)
172 o = px_app(out, o, ":root[data-theme=\"light\"]{--ground:#EEEFEA;--sunk:#E4E6DF;--card:#F7F8F3;--ink:#191C1A;--ink-soft:#4B4F4A;--ink-faint:#767B73;--proof:#3D6350;--proof-wash:#E0EAE4;--open:#2B3F6E;--open-wash:#E1E5EF;--hold:#8A4436;--hold-wash:#F1E3DF;--rule:#D8D5C8;--edge:#B4AF9C}\n" as *u8)
173 o = px_app(out, o, "*{box-sizing:border-box}body{margin:0;background:var(--ground);color:var(--ink);font-family:var(--sans);font-size:17px;line-height:1.65;-webkit-font-smoothing:antialiased}\n" as *u8)
174 o = px_app(out, o, ".wrap{max-width:var(--page);margin:0 auto;padding:0 28px 110px}\n" as *u8)
175 o = px_app(out, o, ".mast{padding:72px 0 36px;border-bottom:2px solid var(--ink)}\n" as *u8)
176 o = px_app(out, o, ".mast-eyebrow{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-faint);margin:0 0 22px}\n" as *u8)
177 o = px_app(out, o, "h1{font-family:var(--serif);font-weight:400;font-size:clamp(2.3rem,5.4vw,3.9rem);line-height:1.05;letter-spacing:-.015em;text-wrap:balance;margin:0 0 22px;max-width:18ch}h1 em{font-style:italic;color:var(--open)}\n" as *u8)
178 o = px_app(out, o, ".thesis{font-family:var(--serif);font-size:clamp(1.08rem,2vw,1.3rem);line-height:1.5;color:var(--ink-soft);max-width:58ch;margin:0 0 30px}\n" as *u8)
179 o = px_app(out, o, ".mast-meta{display:flex;flex-wrap:wrap;gap:10px 30px;font-family:var(--mono);font-size:11.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-faint)}.mast-meta b{color:var(--ink-soft);font-weight:600}\n" as *u8)
180 o = px_app(out, o, ".paper{padding:34px 0;border-bottom:1px solid var(--rule);display:grid;grid-template-columns:92px 1fr;gap:0 20px}\n" as *u8)
181 o = px_app(out, o, ".pid{font-family:var(--mono);font-size:11px;letter-spacing:.12em;color:var(--edge);padding-top:8px}.pbody{min-width:0}\n" as *u8)
182 o = px_app(out, o, ".paper h2{font-family:var(--serif);font-weight:400;font-size:clamp(1.25rem,2.4vw,1.6rem);line-height:1.2;letter-spacing:-.01em;margin:0 0 10px;text-wrap:balance}\n" as *u8)
183 o = px_app(out, o, ".paper h2 a{color:var(--ink);text-decoration-thickness:1px;text-underline-offset:3px}.paper h2 a:hover{color:var(--open)}\n" as *u8)
184 o = px_app(out, o, ".tag{display:inline-block;font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;font-weight:600;padding:3px 8px;border-radius:2px;margin-left:8px;vertical-align:.28em;white-space:nowrap;background:var(--hold-wash);color:var(--hold)}.tag.open{background:var(--open-wash);color:var(--open)}\n" as *u8)
185 o = px_app(out, o, ".paper p{max-width:var(--measure);margin:0 0 12px;color:var(--ink-soft);font-size:.97rem}\n" as *u8)
186 o = px_app(out, o, ".lbl{display:block;font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-faint);margin-bottom:5px}\n" as *u8)
187 o = px_app(out, o, ".res{border-left:3px solid var(--proof);padding-left:16px;margin:16px 0 14px;max-width:var(--measure)}.res p{margin:0;color:var(--ink)}\n" as *u8)
188 o = px_app(out, o, ".limit{border-left:3px solid var(--hold);padding-left:16px;margin:14px 0;max-width:var(--measure)}.limit p{margin:0;color:var(--ink-soft);font-size:.93rem}.limit .lbl{color:var(--hold)}\n" as *u8)
189 o = px_app(out, o, ".nolimit{font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--edge);margin:14px 0}\n" as *u8)
190 o = px_app(out, o, ".gate{font-size:.86rem;color:var(--ink-faint)}.gate code{font-family:var(--mono);font-size:.92em}\n" as *u8)
191 o = px_app(out, o, "a{color:var(--open);text-decoration-thickness:1px;text-underline-offset:2px}a:focus-visible{outline:2px solid var(--open);outline-offset:3px;border-radius:2px}\n" as *u8)
192 o = px_app(out, o, "footer{margin-top:44px;padding-top:22px;border-top:2px solid var(--ink);color:var(--ink-faint);font-size:.86rem}footer p{max-width:var(--measure);margin:0 0 12px}footer strong{color:var(--ink-soft)}\n" as *u8)
193 o = px_app(out, o, "@media (max-width:640px){.wrap{padding:0 20px 72px}.mast{padding-top:48px}.paper{grid-template-columns:1fr;gap:8px}.pid{padding-top:0}}\n" as *u8)
194 // <main>, not <div>: nx_page_verify flagged the missing landmark when this was a bare div, and a
195 // repository that grades everyone else's honesty does not get to ship an accessibility regression.
196 o = px_app(out, o, "</style>\n</head>\n<body>\n<main class=\"wrap\">\n" as *u8)
197 let col: *i64 = sys_mmap(PX_COLS * 2 * 8) as *i64
198
199 // PRE-PASS. The masthead states the repository's OWN counts, so they must be known before it is
200 // emitted. Counting the registry twice is cheaper than buffering the header, and it keeps the
201 // figures DERIVED -- a hand-typed count inside a generated page is a number that goes stale in
202 // silence, which is the one thing this repository exists to refuse.
203 var pre_rows: i64 = 0
204 var pre_pub: i64 = 0
205 var pre_lim: i64 = 0
206 var pi: i64 = 0
207 while pi < rn {
208 let ple: i64 = px_eol(reg, rn, pi)
209 if ple > pi {
210 px_cols(reg, pi, ple, col)
211 if col[1] > col[0] {
212 pre_rows = pre_rows + 1
213 if px_is(reg, col[2], col[3], "public" as *u8) == 1 { pre_pub = pre_pub + 1 }
214 if px_find(reg, col[10], col[11], "HONEST:" as *u8) >= 0 { pre_lim = pre_lim + 1 }
215 }
216 }
217 pi = ple + 1
218 }
219
220 o = px_app(out, o, "<header class=\"mast\">\n<p class=\"mast-eyebrow\">Nishi Research · compiled from measured gates</p>\n" as *u8)
221 o = px_app(out, o, "<h1>Every number here <em>re-runs</em>.</h1>\n" as *u8)
222 o = px_app(out, o, "<p class=\"thesis\">Each quantitative claim in this repository cites a re-runnable sovereign gate. No claim exceeds its measurement, every paper states plainly where it is behind, and this index is generated from a registry rather than hand-maintained.</p>\n" as *u8)
223 o = px_app(out, o, "<div class=\"mast-meta\"><span><b>Papers</b> " as *u8)
224 o = px_appnum(out, o, pre_rows)
225 o = px_app(out, o, "</span><span><b>Publicly citable</b> " as *u8)
226 o = px_appnum(out, o, pre_pub)
227 o = px_app(out, o, "</span><span><b>Declaring a limitation</b> " as *u8)
228 o = px_appnum(out, o, pre_lim)
229 o = px_app(out, o, " of " as *u8)
230 o = px_appnum(out, o, pre_rows)
231 o = px_app(out, o, "</span><span><b>Compiled by</b> nx_papers_index</span><span><b>Source</b> registry, not hand-kept</span></div>\n</header>\n" as *u8)
232 var i: i64 = 0
233 var rows: i64 = 0
234 var pub: i64 = 0
235 while i < rn {
236 let le: i64 = px_eol(reg, rn, i)
237 if le > i {
238 px_cols(reg, i, le, col)
239 if col[1] > col[0] {
240 rows = rows + 1
241 let isPublic: i64 = px_is(reg, col[2], col[3], "public" as *u8)
242 if isPublic == 1 { pub = pub + 1 }
243 // The paper ID rides its own left rail rather than being glued to the title. That is a
244 // structural device carrying real information -- a citable identifier -- not decoration,
245 // and it lets the title be read as a sentence. BOTH access states get a semantic pill;
246 // marking only the restricted ones leaves the reader inferring the default.
247 o = px_app(out, o, "<section class=\"paper\">\n<div class=\"pid\">" as *u8)
248 o = px_appn(out, o, reg, col[0], col[1])
249 o = px_app(out, o, "</div>\n<div class=\"pbody\">\n<h2>" as *u8)
250 if isPublic == 1 {
251 o = px_app(out, o, "<a href=\"" as *u8)
252 o = px_appn(out, o, reg, col[4], col[5])
253 o = px_app(out, o, "\">" as *u8)
254 o = px_appn(out, o, reg, col[6], col[7])
255 o = px_app(out, o, "</a><span class=\"tag open\">public</span>" as *u8)
256 } else {
257 o = px_appn(out, o, reg, col[6], col[7])
258 o = px_app(out, o, "<span class=\"tag\">access-controlled</span>" as *u8)
259 }
260 o = px_app(out, o, "</h2>\n<p>" as *u8)
261 o = px_appn(out, o, reg, col[8], col[9])
262 o = px_app(out, o, "</p>\n" as *u8)
263 // Split the findings at the author's own HONEST: marker. What precedes it is the result;
264 // what follows is the limitation, and it gets its own block rather than trailing the
265 // sentence that boasts. A row with no marker prints a quiet mono line saying so -- an
266 // absent caveat should be VISIBLE, not indistinguishable from a modest one.
267 let hpos: i64 = px_find(reg, col[10], col[11], "HONEST:" as *u8)
268 var resEnd: i64 = col[11]
269 var limStart: i64 = col[11]
270 if hpos >= 0 {
271 // Trim the seam BOTH ways. Splitting on a marker leaves the result with a trailing
272 // space and the limitation with a leading one; rendered as separate blocks that reads
273 // as a typo rather than a cut. The marker is 7 bytes.
274 resEnd = hpos
275 var tw: i64 = 1
276 while tw == 1 {
277 if resEnd <= col[10] { tw = 0 } else {
278 if reg[resEnd-1] == (32 as u8) { resEnd = resEnd - 1 } else { tw = 0 }
279 }
280 }
281 limStart = hpos + 7
282 var lw: i64 = 1
283 while lw == 1 {
284 if limStart >= col[11] { lw = 0 } else {
285 if reg[limStart] == (32 as u8) { limStart = limStart + 1 } else { lw = 0 }
286 }
287 }
288 }
289 o = px_app(out, o, "<div class=\"res\"><span class=\"lbl\">Headline measured result</span><p>" as *u8)
290 o = px_appn(out, o, reg, col[10], resEnd)
291 o = px_app(out, o, "</p></div>\n" as *u8)
292 if hpos >= 0 {
293 o = px_app(out, o, "<div class=\"limit\"><span class=\"lbl\">Where this is behind</span><p>" as *u8)
294 o = px_appn(out, o, reg, limStart, col[11])
295 o = px_app(out, o, "</p></div>\n" as *u8)
296 } else {
297 o = px_app(out, o, "<p class=\"nolimit\">No limitation clause declared</p>\n" as *u8)
298 }
299 o = px_app(out, o, "<p class=\"gate\"><span class=\"lbl\">Reproducibility</span>" as *u8)
300 o = px_appn(out, o, reg, col[12], col[13])
301 o = px_app(out, o, " — sovereign gates (<code>nx_cc</code> to <code>nxasm</code>, no gcc); re-run to reproduce every number.</p>\n</div>\n</section>\n" as *u8)
302 }
303 }
304 i = le + 1
305 }
306
307 o = px_app(out, o, "<footer>\n<p><strong>Doctrine.</strong> Compiled from measured gates; cite-or-refuse; no claim exceeds its gate; honest about where we are behind. For a non-novel capability the bar is stricter: the implementation is fully sovereign <em>and</em> the open step is a head-to-head against an independent reference, named rather than skipped.</p>\n" as *u8)
308 o = px_app(out, o, "<p>Papers marked <em>access-controlled</em> live behind the internal wiki and are listed for completeness; they are not publicly citable until republished.</p>\n" as *u8)
309 o = px_app(out, o, "<p>Generated by <code>nx_papers_index</code> from <code>knowledge/registry/papers_index.tsv</code>. Adding a paper is a data edit, not a code change.</p>\n</footer>\n</main>\n</body>\n</html>\n" as *u8)
310
311 let fd: i64 = sys_openat_wr(argv[2] as *u8, 0x1a4)
312 if fd < 0 { px_puts("PAPERS-INDEX IO: cannot open output\n" as *u8); sys_exit(4); return 4 }
313 sys_write(fd, out, o)
314 sys_close(fd)
315 px_puts("PAPERS-INDEX OK rows=" as *u8); px_num(rows)
316 px_puts(" public=" as *u8); px_num(pub)
317 px_puts(" bytes=" as *u8); px_num(o)
318 px_puts(" -> " as *u8); px_puts(argv[2] as *u8); px_puts("\n" as *u8)
319 sys_exit(0)
320 return 0
321}