code wiki / _hdl_build / nx_epub_book_toc_gate.nx

nx_epub_book_toc_gate.nx source

↩ module page · 96 lines · 5933 B

1// nx_epub_book_toc_gate.nx -- END-TO-END liar-kill gate for R-TOC: proves nx_epub_book locates the EPUB nav 2// document and emits the correct HIERARCHICAL toc[] in book.json (not the flat spine). Self-contained + sovereign 3// (fork/exec, NO shell): rebuilds the fixture + nx_epub_book via the runner, runs nx_epub_book on the fixture, 4// reads the emitted book.json, asserts the nested TOC + href->chapter-idx resolution. Negative control: NO toc 5// entry is unresolved (idx:-1 absent) and a bogus marker is absent (discrimination teeth). expect_exit: 0 6import "nx_syscalls.nx" 7import "nx_gate_verdict.nx" 8 9func gt_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 10func gt_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 } 11func gt_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 12 13// spawn path with up to 2 args, child stdout+stderr -> redir (truncate). returns child exit code. 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 gt_find(hay: *u8, hl: i64, needle: *u8) -> i64 { 36 let nl: i64 = gt_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 48func main() -> i64 { 49 gt_p("=== nx_epub_book_toc_gate: end-to-end hierarchical TOC from nav-doc (R-TOC) ===\n" as *u8) 50 let RUNNER: *u8 = "_offc/nx_sov_build_run.elf\x00" as *u8 51 let SCRATCH: *u8 = "knowledge/status/epub_toc_gate_scratch.log\x00" as *u8 52 53 // 1. rebuild fixture + nx_epub_book (the runner's own nx_epub_book run fails on the NAS default; we only need the fresh elf) 54 spawn(RUNNER, "nx_epub_fixture_build\x00" as *u8, 0 as *u8, SCRATCH) 55 spawn(RUNNER, "nx_epub_book\x00" as *u8, 0 as *u8, SCRATCH) 56 57 // 2. emit book.json from the fixture (argv-driven) 58 let rc: i64 = spawn("_offc/nx_epub_book.elf\x00" as *u8, "knowledge/fixtures/nishi_fixture.epub\x00" as *u8, "nishi_fixture_gate\x00" as *u8, SCRATCH) 59 gt_p(" nx_epub_book on fixture exit=" as *u8); gt_n(rc); gt_p("\n" as *u8) 60 61 // 3. read the emitted book.json 62 let lp: *i64 = sys_mmap(8) as *i64; lp[0] = 0 63 let buf: *u8 = sys_read_file("knowledge/staging/media/reader/nishi_fixture_gate/book.json\x00" as *u8, lp) 64 if (buf as i64) == 0 { gt_p("EPUB-BOOK-TOC-GATE verdict=RED reason=book.json-missing\n" as *u8); sys_exit(1); return 1 } 65 let n: i64 = lp[0] 66 gt_p(" book.json bytes=" as *u8); gt_n(n); gt_p("\n" as *u8) 67 68 var pass: i64 = 0 69 var fail: i64 = 0 70 // nav doc located + parsed 71 if gt_find(buf, n, "\"toc_source\":\"nav-xhtml\"" as *u8) >= 0 { pass=pass+1 } else { fail=fail+1; gt_p(" FAIL toc_source\n" as *u8) } 72 if gt_find(buf, n, "\"ntoc\":4" as *u8) >= 0 { pass=pass+1 } else { fail=fail+1; gt_p(" FAIL ntoc=4\n" as *u8) } 73 // hierarchy: nested entry at depth 1 resolved to the right chapter (fragment stripped for mapping) 74 if gt_find(buf, n, "\"depth\":1,\"title\":\"2.1 The Pool of Tears\",\"idx\":1" as *u8) >= 0 { pass=pass+1 } else { fail=fail+1; gt_p(" FAIL nested-2.1->ch idx1\n" as *u8) } 75 if gt_find(buf, n, "\"depth\":1,\"title\":\"Chapter Three\",\"idx\":2" as *u8) >= 0 { pass=pass+1 } else { fail=fail+1; gt_p(" FAIL nested-ChapterThree->idx2\n" as *u8) } 76 if gt_find(buf, n, "\"depth\":0,\"title\":\"Part Two\",\"idx\":1" as *u8) >= 0 { pass=pass+1 } else { fail=fail+1; gt_p(" FAIL parent-PartTwo->idx1\n" as *u8) } 77 // spine chapters[] still present (reading order intact) 78 if gt_find(buf, n, "\"chapters\":[" as *u8) >= 0 { pass=pass+1 } else { fail=fail+1; gt_p(" FAIL chapters-present\n" as *u8) } 79 // NEG control: NO toc entry left unresolved (every nav href mapped to a real chapter) 80 if gt_find(buf, n, "\"idx\":-1" as *u8) < 0 { pass=pass+1 } else { fail=fail+1; gt_p(" FAIL unresolved-idx(-1)-present\n" as *u8) } 81 // teeth: a bogus marker must be ABSENT (proves the substring checks discriminate) 82 if gt_find(buf, n, "\"toc_source\":\"WRONG\"" as *u8) < 0 { pass=pass+1 } else { fail=fail+1; gt_p(" FAIL teeth\n" as *u8) } 83 // the book elf must have succeeded 84 if rc == 0 { pass=pass+1 } else { fail=fail+1; gt_p(" FAIL book-exit\n" as *u8) } 85 86 gt_p("EPUB-BOOK-TOC-GATE pass=" as *u8); gt_n(pass); gt_p(" fail=" as *u8); gt_n(fail) 87 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 88 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 89 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 90 let ctr__dry: *i64 = gv_ctr() 91 ctr__dry[0] = pass 92 ctr__dry[1] = pass + fail 93 let rc__dry: i64 = gv_verdict("EPUB-BOOK-TOC-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 94 sys_exit(rc__dry) 95 return rc__dry 96}