code wiki / _hdl_build / nx_epub_art_gate.nx
nx_epub_art_gate.nx source
↩ module page · 122 lines · 7449 B
1// nx_epub_art_gate.nx -- END-TO-END liar-kill gate for R-ART: proves nx_epub_book extracts the cover + embedded
2// image assets from an EPUB, writes them to the served slug dir BYTE-EXACT, and references them in book.json
3// (cover detected, is_cover flagged, distinct content). Self-contained + sovereign (fork/exec, NO shell): regen
4// the fixture + book.json, then assert book.json asset fields AND byte-exact round-trip of the extracted files.
5// Negative control: the two extracted assets are NOT byte-identical (real distinct extraction, no duplication).
6// expect_exit: 0
7import "nx_syscalls.nx"
8import "nx_gate_verdict.nx"
9
10func ar_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
11func ar_n(v0: i64) -> i64 { var v: i64=v0; if v<0 { sys_write(1,"-" as *u8,1); v=0-v } let b: *u8=sys_mmap(24); var k: i64=0; if v==0 {b[0]=48 as u8;k=1} while v>0 {b[k]=(48+(v%10)) as u8; v=v/10; k=k+1} let o: *u8=sys_mmap(24); var j: i64=0; while j<k {o[j]=b[k-1-j];j=j+1} sys_write(1,o,k); return 0 }
12func ar_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
13
14func spawn(path: *u8, a0: *u8, a1: *u8, redir: *u8) -> i64 {
15 let pid: i64 = sys_fork()
16 if pid == 0 {
17 let fd: i64 = sys_openat_wr(redir, 420)
18 if fd >= 0 { sys_dup3(fd, 1, 0); sys_dup3(fd, 2, 0) }
19 let argv: *i64 = sys_mmap(64) as *i64
20 var n: i64 = 0
21 argv[0] = path as i64; n = 1
22 if (a0 as i64) != 0 { argv[n] = a0 as i64; n = n + 1 }
23 if (a1 as i64) != 0 { argv[n] = a1 as i64; n = n + 1 }
24 argv[n] = 0
25 let envp: *i64 = sys_mmap(16) as *i64
26 envp[0] = "PATH=/usr/bin:/bin\x00" as *u8 as i64; envp[1] = 0
27 sys_execve(path, argv, envp)
28 sys_exit(127)
29 }
30 let st: *i64 = sys_mmap(16) as *i64
31 sys_wait4(pid, st, 0)
32 return (st[0] >> 8) & 0xff
33}
34
35func ar_find(hay: *u8, hl: i64, needle: *u8) -> i64 {
36 let nl: i64 = ar_slen(needle)
37 if nl == 0 { return 0-1 }
38 var i: i64 = 0
39 while i + nl <= hl {
40 var k: i64 = 0; var hit: i64 = 1
41 while k < nl { if hay[i+k] != needle[k] { hit = 0; k = nl } else { k = k + 1 } }
42 if hit == 1 { return i }
43 i = i + 1
44 }
45 return 0-1
46}
47
48// read a whole file into a fresh mmap; sets lp[0]=len; returns ptr (0 on fail).
49func ar_read(path: *u8, lp: *i64) -> *u8 { lp[0] = 0; return sys_read_file(path, lp) }
50
51// 1 iff buf[0,n) equals the NUL-terminated literal lit exactly (length + bytes).
52func ar_eq_lit(buf: *u8, n: i64, lit: *u8) -> i64 {
53 if ar_slen(lit) != n { return 0 }
54 var i: i64 = 0
55 while i < n { if buf[i] != lit[i] { return 0 } i = i + 1 }
56 return 1
57}
58// 1 iff two byte ranges are identical (length + bytes).
59func ar_eq_bytes(a: *u8, an: i64, b: *u8, bn: i64) -> i64 {
60 if an != bn { return 0 }
61 var i: i64 = 0
62 while i < an { if a[i] != b[i] { return 0 } i = i + 1 }
63 return 1
64}
65
66func main() -> i64 {
67 ar_p("=== nx_epub_art_gate: end-to-end cover + image extraction (R-ART) ===\n" as *u8)
68 let RUNNER: *u8 = "_offc/nx_sov_build_run.elf\x00" as *u8
69 let SCRATCH: *u8 = "knowledge/status/epub_art_gate_scratch.log\x00" as *u8
70
71 spawn(RUNNER, "nx_epub_fixture_build\x00" as *u8, 0 as *u8, SCRATCH)
72 spawn(RUNNER, "nx_epub_book\x00" as *u8, 0 as *u8, SCRATCH)
73 let rc: i64 = spawn("_offc/nx_epub_book.elf\x00" as *u8, "knowledge/fixtures/nishi_fixture.epub\x00" as *u8, "nishi_fixture_art\x00" as *u8, SCRATCH)
74 ar_p(" nx_epub_book on fixture exit=" as *u8); ar_n(rc); ar_p("\n" as *u8)
75
76 var pass: i64 = 0
77 var fail: i64 = 0
78
79 // ---- book.json asset references ----
80 let lp: *i64 = sys_mmap(8) as *i64
81 let bj: *u8 = ar_read("knowledge/staging/media/reader/nishi_fixture_art/book.json\x00" as *u8, lp)
82 if (bj as i64) == 0 { ar_p("ART-GATE verdict=RED reason=book.json-missing\n" as *u8); sys_exit(1); return 1 }
83 let bn: i64 = lp[0]
84 if ar_find(bj, bn, "\"cover\":\"cover.png\"" as *u8) >= 0 { pass=pass+1 } else { fail=fail+1; ar_p(" FAIL cover-field\n" as *u8) }
85 if ar_find(bj, bn, "\"nassets\":2" as *u8) >= 0 { pass=pass+1 } else { fail=fail+1; ar_p(" FAIL nassets=2\n" as *u8) }
86 if ar_find(bj, bn, "\"file\":\"cover.png\",\"bytes\":93,\"fp\":" as *u8) >= 0 { pass=pass+1 } else { fail=fail+1; ar_p(" FAIL cover-asset-entry\n" as *u8) }
87 if ar_find(bj, bn, "\"file\":\"fig1.png\"" as *u8) >= 0 { pass=pass+1 } else { fail=fail+1; ar_p(" FAIL fig-asset-entry\n" as *u8) }
88 if ar_find(bj, bn, "\"is_cover\":1" as *u8) >= 0 { pass=pass+1 } else { fail=fail+1; ar_p(" FAIL is_cover-flag\n" as *u8) }
89
90 // ---- byte-exact round-trip of the extracted files (content integrity = the real proof) ----
91 let lpc: *i64 = sys_mmap(8) as *i64
92 let cov: *u8 = ar_read("knowledge/staging/media/reader/nishi_fixture_art/cover.png\x00" as *u8, lpc)
93 let cn: i64 = lpc[0]
94 let lpf: *i64 = sys_mmap(8) as *i64
95 let fig: *u8 = ar_read("knowledge/staging/media/reader/nishi_fixture_art/fig1.png\x00" as *u8, lpf)
96 let fn: i64 = lpf[0]
97 ar_p(" extracted cover.png bytes=" as *u8); ar_n(cn); ar_p(" fig1.png bytes=" as *u8); ar_n(fn); ar_p("\n" as *u8)
98 if (cov as i64) != 0 { if ar_eq_lit(cov, cn, "NISHI-FIXTURE-COVER-IMAGE-BYTES-v1-DISTINCTIVE-PLACEHOLDER-FOR-CID-ROUNDTRIP-0123456789abcdef" as *u8) == 1 { pass=pass+1 } else { fail=fail+1; ar_p(" FAIL cover-roundtrip\n" as *u8) } } else { fail=fail+1; ar_p(" FAIL cover-file-missing\n" as *u8) }
99 if (fig as i64) != 0 { if ar_eq_lit(fig, fn, "NISHI-FIXTURE-FIG1-INLINE-ILLUSTRATION-BYTES-v1-DISTINCTIVE-PLACEHOLDER-fedcba9876543210" as *u8) == 1 { pass=pass+1 } else { fail=fail+1; ar_p(" FAIL fig-roundtrip\n" as *u8) } } else { fail=fail+1; ar_p(" FAIL fig-file-missing\n" as *u8) }
100
101 // ---- R-ART-2: the inline <img> position is preserved as a marker in the chapter text (ch2 = chap1.txt) ----
102 let lpm: *i64 = sys_mmap(8) as *i64
103 let ch1: *u8 = ar_read("knowledge/staging/media/reader/nishi_fixture_art/chap1.txt\x00" as *u8, lpm)
104 if (ch1 as i64) != 0 { if ar_find(ch1, lpm[0], "[[nximg:fig1.png]]" as *u8) >= 0 { pass=pass+1 } else { fail=fail+1; ar_p(" FAIL inline-img-marker\n" as *u8) } } else { fail=fail+1; ar_p(" FAIL chap1-missing\n" as *u8) }
105
106 // ---- NEG control: the two assets are NOT identical (distinct extraction, no duplication/fabrication) ----
107 if (cov as i64) != 0 { if (fig as i64) != 0 { if ar_eq_bytes(cov, cn, fig, fn) == 0 { pass=pass+1 } else { fail=fail+1; ar_p(" FAIL assets-identical(dup)\n" as *u8) } } }
108 // teeth: a bogus cover name must be ABSENT
109 if ar_find(bj, bn, "\"cover\":\"WRONG.png\"" as *u8) < 0 { pass=pass+1 } else { fail=fail+1; ar_p(" FAIL teeth\n" as *u8) }
110 if rc == 0 { pass=pass+1 } else { fail=fail+1; ar_p(" FAIL book-exit\n" as *u8) }
111
112 ar_p("EPUB-ART-GATE pass=" as *u8); ar_n(pass); ar_p(" fail=" as *u8); ar_n(fail)
113 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
114 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
115 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
116 let ctr__dry: *i64 = gv_ctr()
117 ctr__dry[0] = pass
118 ctr__dry[1] = pass + fail
119 let rc__dry: i64 = gv_verdict("EPUB-ART-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
120 sys_exit(rc__dry)
121 return rc__dry
122}