nx_jrnl_archive_lib.nx
buildroot/runtime/nx_jrnl_archive_lib.nx
about
nx_jrnl_archive_lib.nx -- THE SANCTIONED "ARCHIVE IT DELIBERATELY" VERB for an append-only
status journal that has reached its budget (2026-08-23, lane L).
WHY THIS EXISTS. nx_compare_regen refuses receipts once knowledge/status/comparepub.jrnl passes its
budget and tells the reader to "archive it deliberately" -- and no organ in the estate could do that
(nx_spendgate: name free, no incumbent). Rotation was rejected by design: a silent rotator is a
duplicate ruler beside nx_sizeguard and a SHRINKING journal is exactly what nx_jrnlguard calls a
clobber. So the archive is a VERB a seat runs on purpose, and it is preserve-before-remove BY
CONSTRUCTION: the live journal is reset ONLY after the archived copy has been re-read from disk and
hashed equal to the original. A write that fails, a verify that mismatches, or a journal that
cannot be read leaves the live file byte-for-byte untouched.
Contract (ja_archive): 0 OK archived+reset | 1 OK nothing-to-archive (empty journal, no file made)
| 3 cannot read journal | 4 cannot create archive dir / write archive | 5 VERIFY MISMATCH (archive
kept, live NOT reset) | 6 reset failed (archive verified, live unchanged).
Every outcome prints one NX-JRNL-ARCHIVE line naming src, bytes, sha256, the archive path, and
verified=/reset= so the announcement IS the audit row. The archive name is <dir>/<base>.<epoch>.
jrnlguard: the estate's twelve jg_*.base baselines do not cover comparepub.jrnl (measured
2026-08-23); a journal that IS baselined must be re-snapshotted after an archive (jg's own rule).
dependencies 2 imports · 3 importers
imports: nx_syscalls.nxnx_sha256.nx
imported by: nx_compare_receipt_lib.nxnx_jrnl_archive.nxnx_jrnl_archive_gate.nx
structs
| none |
consts
| 23 | const JA_DIGEST_BYTES: i64 = 32 |
| 24 | const JA_ARCH_MODE: i64 = 0x1a4 // rw-r--r-- for the archived copy |
| 25 | const JA_DIR_MODE: i64 = 0x1ed // rwxr-xr-x for the archive dir |
| 26 | const JA_PATH_MAX: i64 = 4096 // PATH_MAX: the kernel bound on a path, the only constant a path needs |
functions
| 28 | func ja_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } |
| 29 | func ja_puts(s: *u8) -> i64 { sys_write(1, s, ja_slen(s)); return 0 } |
| 30 | func ja_pn(v: i64) -> i64 |
| 43 | func ja_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; var p: i64 = o; while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } d[p] = 0 as u8; return p } |
| 44 | func ja_catn(d: *u8, o: i64, v: i64) -> i64 |
| 56 | func ja_hex(d: *u8, out: *u8) -> i64 |
| 70 | func ja_basename(p: *u8) -> *u8 called by 1: ja_archive |
| 76 | func ja_dirname(p: *u8, out: *u8) -> i64 |
| 87 | func ja_write_all(path: *u8, buf: *u8, n: i64, mode: i64) -> i64 |
| 101 | func ja_announce(src: *u8, bytes: i64, hex: *u8, arch: *u8, verified: i64, reset: i64, rc: i64, why: *u8, rep: *i64) -> i64 |
| 114 | func ja_archive(journal: *u8, archive_dir: *u8, epoch: i64, rep: *i64) -> i64 |
| 161 | func ja_lock(journal: *u8) -> i64 |
| 175 | func ja_unlock(fd: i64) -> i64 { return sys_close(fd) } |