code wiki / _hdl_build / nx_kindle_reextract_gate.nx

nx_kindle_reextract_gate.nx source

↩ module page · 90 lines · 6162 B

1import "nx_gate_gn.nx" 2// nx_kindle_reextract_gate.nx -- liar-kill gate for the MOBI "© still there" root cause: the cache-heal correctly 3// DECIDES to re-extract a stale (pre-rfix) kindle cache, but ms_handle_open's kf8->mobi chain was fooled by the 4// LEFTOVER stale book.json -- nx_kf8_book DECLINES a MOBI6 file without writing book.json, so the stale file's mere 5// existence made ms_run_extractor report "kf8 succeeded" and nx_mobi_book never ran -> stale mojibake served forever. 6// FIX = unlink the stale book.json BEFORE the chain. This gate reproduces BOTH: (A) the bug (no unlink -> stale 7// survives, no rfix) and (B) the fix (unlink -> mobi runs -> fresh book.json carries rfix). Uses the REAL extractors 8// on the real mobi fixture. expect_exit: 0 license_tier: ORIGINAL 9import "nx_syscalls.nx" 10 11func gp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 12func gslen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 13func ensure_dir(path: *u8) -> i64 { __syscall(258, 0-100, path, 0x1ed, 0, 0, 0); return 0 } 14func gunlink(path: *u8) -> i64 { __syscall(263, 0-100, path, 0, 0, 0, 0); return 0 } 15 16func spawn(path: *u8, a0: *u8, a1: *u8, redir: *u8) -> i64 { 17 let pid: i64 = sys_fork() 18 if pid == 0 { 19 let fd: i64 = sys_openat_wr(redir, 420) 20 if fd >= 0 { sys_dup3(fd, 1, 0); sys_dup3(fd, 2, 0) } 21 let argv: *i64 = sys_mmap(64) as *i64 22 argv[0] = path as i64; var n: i64 = 1 23 if (a0 as i64) != 0 { argv[n] = a0 as i64; n = n + 1 } 24 if (a1 as i64) != 0 { argv[n] = a1 as i64; n = n + 1 } 25 argv[n] = 0 26 let envp: *i64 = sys_mmap(16) as *i64; 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} 34func exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd >= 0 { sys_close(fd); return 1 } return 0 } 35func file_has(path: *u8, needle: *u8) -> i64 { 36 let lp: *i64 = sys_mmap(8) as *i64; lp[0] = 0 37 let b: *u8 = sys_read_file(path, lp) 38 if (b as i64) == 0 { return 0 } 39 let n: i64 = lp[0]; let nl: i64 = gslen(needle) 40 var i: i64 = 0 41 while i + nl <= n { var k: i64=0; var hit: i64=1; while k<nl { if (b[i+k]&0xff)!=(needle[k]&0xff){hit=0;k=nl}else{k=k+1} } if hit==1 {return 1} i=i+1 } 42 return 0 43} 44func write_stale(path: *u8) -> i64 { 45 let fd: i64 = sys_openat_wr(path, 0x1a4) 46 if fd < 0 { return 0-1 } 47 let s: *u8 = "{\"title\":\"STALE-PRE-RFIX\",\"author\":\"x\",\"format\":\"mobi\",\"chapters\":[{\"idx\":0,\"title\":\"x\",\"file\":\"chap0.txt\",\"chars\":9,\"is_nav\":0,\"fn\":[]}],\"nchapters\":1}\x00" as *u8 48 sys_write(fd, s, gslen(s)); sys_close(fd) 49 return 0 50} 51 52func main() -> i64 { 53 gp("=== nx_kindle_reextract_gate: stale MOBI cache must RE-EXTRACT (kf8 declines -> mobi runs) ===\n" as *u8) 54 let RUNNER: *u8 = "_offc/nx_sov_build_run.elf\x00" as *u8 55 let SCRATCH: *u8 = "knowledge/status/kindle_reextract_scratch.log\x00" as *u8 56 let FIX: *u8 = "knowledge/fixtures/nishi_mobi_fixture.mobi\x00" as *u8 57 let DIR: *u8 = "knowledge/staging/media/reader/kindle_reextract_test\x00" as *u8 58 let BJ: *u8 = "knowledge/staging/media/reader/kindle_reextract_test/book.json\x00" as *u8 59 60 // rebuild the real extractors so we test current source 61 spawn(RUNNER, "nx_kf8_book\x00" as *u8, 0 as *u8, SCRATCH) 62 spawn(RUNNER, "nx_mobi_book\x00" as *u8, 0 as *u8, SCRATCH) 63 ensure_dir("knowledge/staging/media/reader\x00" as *u8) 64 ensure_dir(DIR) 65 66 let pf: *i64 = sys_mmap(16) as *i64; pf[0]=0; pf[1]=0 67 68 // ---- PART A: reproduce the BUG (old chain, NO unlink) ---- 69 write_stale(BJ) 70 spawn("_offc/nx_kf8_book.elf\x00" as *u8, FIX, "kindle_reextract_test\x00" as *u8, SCRATCH) // declines MOBI6, writes nothing 71 var haveA: i64 = exists(BJ) // old ms_run_extractor: book.json exists? -> "success" 72 // the buggy outcome: kf8 "succeeds" (stale json present) so mobi is skipped -> json is STILL the stale one 73 if haveA == 1 { if file_has(BJ, "\"rfix\":1" as *u8) == 0 { gp(" PART A (bug reproduced): stale json survives kf8-decline, NO rfix -> mobi would be skipped PASS\n" as *u8); pf[0]=pf[0]+1 } else { gp(" PART A unexpected: rfix already present\n" as *u8); pf[1]=pf[1]+1 } } 74 else { gp(" PART A unexpected: book.json missing\n" as *u8); pf[1]=pf[1]+1 } 75 76 // ---- PART B: the FIX (unlink stale FIRST, then the chain) ---- 77 write_stale(BJ) 78 gunlink(BJ) // THE FIX 79 spawn("_offc/nx_kf8_book.elf\x00" as *u8, FIX, "kindle_reextract_test\x00" as *u8, SCRATCH) // declines, writes nothing 80 var haveB: i64 = exists(BJ) // book.json exists? -> NO (unlinked + kf8 declined) 81 if haveB == 0 { gp(" after unlink+kf8-decline: book.json absent -> mobi WILL run PASS\n" as *u8); pf[0]=pf[0]+1 } else { gp(" FAIL: book.json present after kf8 decline (unlink didn't take)\n" as *u8); pf[1]=pf[1]+1 } 82 spawn("_offc/nx_mobi_book.elf\x00" as *u8, FIX, "kindle_reextract_test\x00" as *u8, SCRATCH) // MOBI6 -> writes fresh book.json (rfix:1) 83 if exists(BJ) == 1 { gp(" mobi ran: book.json present PASS\n" as *u8); pf[0]=pf[0]+1 } else { gp(" FAIL: mobi did not write book.json\n" as *u8); pf[1]=pf[1]+1 } 84 if file_has(BJ, "\"rfix\":1" as *u8) == 1 { gp(" FRESH cache carries rfix:1 (re-extracted, mojibake-repaired) PASS\n" as *u8); pf[0]=pf[0]+1 } else { gp(" FAIL: rfix:1 absent -> NOT re-extracted\n" as *u8); pf[1]=pf[1]+1 } 85 if file_has(BJ, "STALE-PRE-RFIX" as *u8) == 0 { gp(" stale content gone PASS\n" as *u8); pf[0]=pf[0]+1 } else { gp(" FAIL: stale content survived\n" as *u8); pf[1]=pf[1]+1 } 86 87 gp("KINDLE-REEXTRACT-GATE pass="); gn(pf[0]); gp(" fail="); gn(pf[1]) 88 if pf[1] == 0 { gp(" verdict=GREEN\n" as *u8); sys_exit(0); return 0 } 89 gp(" verdict=RED\n" as *u8); sys_exit(1); return 1 90}