code wiki / _hdl_build / nx_pub_reader_handoff.nx
nx_pub_reader_handoff.nx source
↩ module page · 128 lines · 9483 B
1// nx_pub_reader_handoff.nx -- push the ZERO-JS reader + library shelf updates to the Nishi Publisher (operator
2// 2026-06-21: "push the updates to the publisher, don't directly do"). The reader workstream REQUESTS; the
3// publisher SHIPS (no direct push -- the sites.elf-outage law). Mirrors nx_pub_library_handoff exactly: import the
4// real publisher, pub_submit each artifact to an ISOLATED reader queue, then run the publisher's full pipeline
5// (serialize -> idempotent sha-skip -> stage -> VERIFY-sha -> ATOMIC-promote -> ledger) to a LOCAL liveroot.
6// Artifacts = the new sovereign zero-JS surfaces: the library shelf + a representative reader page.
7// The OUTWARD transport liveroot -> nishifamily.com is OPERATOR-GATED (publisher R6 policy=outward + R8 transport)
8// and needs the REAL book content (NAS) -- NOT run in-sandbox. license_tier: ORIGINAL
9import "nx_publisher.nx"
10import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
11import "nx_syscalls.nx"
12const K_MAGIC_1024: i64 = 1024
13const K_MAGIC_65536: i64 = 65536
14
15func rh_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != 0 as u8 { n = n + 1 } sys_write(1, s, n); return 0 }
16// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
17// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
18// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
19// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
20func rh_putn(v: i64) -> i64 { nxi_out(v); return 0 }
21func rh_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 }
22func rh_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){d[o+i]=s[i];i=i+1} return o+i }
23// submit reader/<slug>/cover.<ext> if it exists (dest mirrors the served path). returns 1 if submitted.
24func rh_cover(q: *u8, slug: *u8, ext: *u8) -> i64 {
25 let src: *u8 = sys_mmap(K_MAGIC_1024); var k: i64 = rh_cat(src,0,"knowledge/staging/media/reader/" as *u8); k=rh_cat(src,k,slug); k=rh_cat(src,k,"/cover." as *u8); k=rh_cat(src,k,ext); src[k]=0 as u8
26 if rh_exists(src) == 0 { return 0 }
27 let dst: *u8 = sys_mmap(K_MAGIC_1024); var d: i64 = rh_cat(dst,0,"reader/" as *u8); d=rh_cat(dst,d,slug); d=rh_cat(dst,d,"/cover." as *u8); d=rh_cat(dst,d,ext); dst[d]=0 as u8
28 pub_submit_to(q, src, dst, "nishifamily\x00" as *u8, "nishi-reader\x00" as *u8, "internal\x00" as *u8)
29 return 1
30}
31// publish one rendered book: its reader_static page + whatever cover it carries. returns count submitted.
32func rh_pub_slug(q: *u8, slug: *u8) -> i64 {
33 var n: i64 = 0
34 let rp: *u8 = sys_mmap(K_MAGIC_1024); var k: i64 = rh_cat(rp,0,"knowledge/staging/media/reader_static_" as *u8); k=rh_cat(rp,k,slug); k=rh_cat(rp,k,".html" as *u8); rp[k]=0 as u8
35 if rh_exists(rp) == 1 {
36 let dn: *u8 = sys_mmap(K_MAGIC_1024); var d: i64 = rh_cat(dn,0,"reader_static_" as *u8); d=rh_cat(dn,d,slug); d=rh_cat(dn,d,".html" as *u8); dn[d]=0 as u8
37 pub_submit_to(q, rp, dn, "nishifamily\x00" as *u8, "nishi-reader\x00" as *u8, "internal\x00" as *u8); n = n + 1
38 }
39 n = n + rh_cover(q, slug, "jpg" as *u8)
40 n = n + rh_cover(q, slug, "gif" as *u8)
41 n = n + rh_cover(q, slug, "png" as *u8)
42 return n
43}
44
45func main() -> i64 {
46 rh_puts("=== NISHI PUBLISHER <- reader/shelf handoff: REQUEST (pub_submit) then the publisher SHIPS ===\n")
47 let shelf: *u8 = "knowledge/staging/media/library_shelf.html\x00" as *u8
48 let reader: *u8 = "knowledge/staging/media/reader_static_nishi_fixture.html\x00" as *u8
49 let q: *u8 = "knowledge/publish/reader-queue.tsv\x00" as *u8
50 let led: *u8 = "knowledge/publish/reader-ledger.tsv\x00" as *u8
51 let stageroot: *u8 = "knowledge/publish/reader-stage\x00" as *u8
52 let liveroot: *u8 = "knowledge/publish/reader-live\x00" as *u8
53 let live_shelf: *u8 = "knowledge/publish/reader-live/library_shelf.html\x00" as *u8
54 let live_reader: *u8 = "knowledge/publish/reader-live/reader_static_nishi_fixture.html\x00" as *u8
55
56 if rh_exists(shelf) == 0 { rh_puts(" FATAL: shelf not emitted -- run nx_library_shelf first\n"); sys_exit(1); return 1 }
57 if rh_exists(reader) == 0 { rh_puts(" FATAL: reader not emitted -- run nx_reader_render first\n"); sys_exit(1); return 1 }
58 pub_init()
59 sys_mkdir(stageroot, 0x1ed)
60 sys_mkdir(liveroot, 0x1ed)
61
62 // 1. REQUEST -- the reader workstream submits two publish requests (sha256 of content); decoupled, durable.
63 let s1: i64 = pub_submit_to(q, shelf, "library_shelf.html\x00" as *u8, "nishifamily\x00" as *u8, "nishi-reader\x00" as *u8, "internal\x00" as *u8)
64 rh_puts(" [reader] pub_submit shelf -> "); rh_putn(s1); rh_puts("\n")
65 let s2: i64 = pub_submit_to(q, reader, "reader_static_nishi_fixture.html\x00" as *u8, "nishifamily\x00" as *u8, "nishi-reader\x00" as *u8, "internal\x00" as *u8)
66 rh_puts(" [reader] pub_submit reader -> "); rh_putn(s2); rh_puts("\n")
67 // image assets carry SUBDIR dests (reader/<slug>/<file>) -- a complete reader bundle needs them at the served root.
68 let cover_src: *u8 = "knowledge/staging/media/reader/nishi_fixture/cover.png\x00" as *u8
69 let fig_src: *u8 = "knowledge/staging/media/reader/nishi_fixture/fig1.png\x00" as *u8
70 let s3: i64 = pub_submit_to(q, cover_src, "reader/nishi_fixture/cover.png\x00" as *u8, "nishifamily\x00" as *u8, "nishi-reader\x00" as *u8, "internal\x00" as *u8)
71 rh_puts(" [reader] pub_submit cover -> "); rh_putn(s3); rh_puts("\n")
72 let s4: i64 = pub_submit_to(q, fig_src, "reader/nishi_fixture/fig1.png\x00" as *u8, "nishifamily\x00" as *u8, "nishi-reader\x00" as *u8, "internal\x00" as *u8)
73 rh_puts(" [reader] pub_submit fig -> "); rh_putn(s4); rh_puts("\n")
74
75 // 1b. AUTO-ENUMERATE -- publish EVERY rendered book (reader_static_<slug>.html) + the cover it carries, so each
76 // new capability goes live as it lands (operator: "make sure this stuff is pushed live as we gain capabilities").
77 // getdents64 over reader/<slug>/ -- the same enumeration the shelf uses; idempotent (sha-skip) so re-runs are free.
78 let rdir: *u8 = "knowledge/staging/media/reader\x00" as *u8
79 let edfd: i64 = __syscall(257, 0-100, rdir, 0x10000, 0, 0, 0) // openat AT_FDCWD O_RDONLY|O_DIRECTORY
80 var auto: i64 = 0
81 if edfd >= 0 {
82 let buf: *u8 = sys_mmap(K_MAGIC_65536); let nm: *u8 = sys_mmap(512)
83 var go: i64 = 1
84 while go == 1 {
85 let nread: i64 = __syscall(217, edfd, buf, K_MAGIC_65536, 0, 0, 0) // getdents64
86 if nread <= 0 { go = 0 } else {
87 var pos: i64 = 0
88 while pos < nread {
89 let reclen: i64 = (buf[pos+16] as i64) | ((buf[pos+17] as i64) << 8)
90 let dtype: i64 = buf[pos+18] as i64
91 var nl: i64 = 0
92 while buf[pos+19+nl] != (0 as u8) { nm[nl]=buf[pos+19+nl]; nl=nl+1 } nm[nl]=0 as u8
93 var skip: i64 = 0
94 if nl==0 { skip=1 }
95 if nl==1 { if nm[0]==(0x2e as u8) { skip=1 } }
96 if nl==2 { if nm[0]==(0x2e as u8) { if nm[1]==(0x2e as u8) { skip=1 } } }
97 if dtype != 4 { skip=1 } // DT_DIR only
98 if skip == 0 { auto = auto + rh_pub_slug(q, nm) }
99 if reclen <= 0 { pos=nread } else { pos=pos+reclen }
100 }
101 }
102 }
103 sys_close(edfd)
104 }
105 rh_puts(" [reader] auto-enumerated (reader pages + covers) submitted = "); rh_putn(auto); rh_puts("\n")
106
107 // 2. SHIP -- the publisher owns this: serialize -> idempotent -> stage -> VERIFY-sha -> ATOMIC-promote -> ledger.
108 let pubd: i64 = pub_run_full(q, led, stageroot, liveroot, "publish:reader\x00" as *u8)
109 rh_puts(" [publisher] pub_run_full -> published_this_pass="); rh_putn(pubd); rh_puts("\n")
110
111 let live_cover: *u8 = "knowledge/publish/reader-live/reader/nishi_fixture/cover.png\x00" as *u8
112 var ok: i64 = 0
113 if rh_exists(live_shelf) == 1 { ok = ok + 1 }
114 if rh_exists(live_reader) == 1 { ok = ok + 1 }
115 if rh_exists(live_cover) == 1 { ok = ok + 1 }
116 rh_puts(" landed_in_liveroot="); rh_putn(ok); rh_puts(" / 3 (shelf, reader, cover-asset)\n")
117 // the real liberated Kindle covers, live (proof the auto-enumeration shipped the new capability)
118 if rh_exists("knowledge/publish/reader-live/reader/real_huffdic/cover.jpg\x00" as *u8) == 1 { rh_puts(" LIVE: reader/real_huffdic/cover.jpg (real MOBI cover, extracted offline)\n") }
119 if rh_exists("knowledge/publish/reader-live/reader/real_kf8/cover.jpg\x00" as *u8) == 1 { rh_puts(" LIVE: reader/real_kf8/cover.jpg (real KF8 cover, extracted offline)\n") }
120 if rh_exists(live_cover) == 0 { rh_puts(" ^ ASSET-IN-SUBDIR did NOT land -- publisher pub_deploy doesn't mkdir dest subdirs (the rung to build)\n") }
121 if ok == 3 {
122 rh_puts(" SHIPPED by the Nishi Publisher -> knowledge/publish/reader-live/ (sha-verified, ledgered, isolated reader queue)\n")
123 rh_puts(" COORDINATED: reader REQUESTED, publisher SHIPPED (NO direct push). OUTWARD live-root -> nishifamily.com = OPERATOR-GATED (R6 policy=outward + R8 transport) + needs real NAS book content.\n")
124 sys_exit(0); return 0
125 }
126 rh_puts(" publisher did not promote both (idempotent if already live, or a verify hold)\n")
127 sys_exit(1); return 1
128}