nx_self_build.nx
buildroot/runtime/nx_self_build.nx
about
nx_self_build.nx -- the 3-tier SELF-BUILD POLICY + the reversible-modify
transaction (snapshot -> write -> re-gate -> AUTO-ROLLBACK).
THE NET BEFORE THE TRAPEZE. Before the engine is ever pointed at a real
source file, this organ proves -- on a DELIBERATE failed write -- that a
reversible modify either lands gated-green OR is rolled back BYTE-IDENTICAL
to the pre-write snapshot. A rollback you have not proven on a deliberate
failure is not a safety net.
============================================================================
THE OPERATOR'S 3-TIER POLICY (the spec):
TIER 1 ADDITIVE : new file / append / soft-flag is_current=0
-> ALLOW autonomously (cannot break existing code).
TIER 2 REVERSIBLE : overwrite an existing file
-> ALLOW only via SNAPSHOT -> WRITE -> RE-GATE ->
AUTO-ROLLBACK on failure. No breaking without a
proven, byte-identical rollback.
TIER 3 DESTRUCTIVE: delete / drop / overwrite WITHOUT backup / truncate
history -> DENY + require explicit operator confirm
(Cardinal #13 additive-only). FAIL-CLOSED on unknown.
============================================================================
ADDITIVE-OVER-WARDEN: the classifier never WEAKENS any warden verdict. It
can only refuse where warden refuses, or ADD the rollback discipline on top
of an overwrite that warden hard-denies. Warden stays the single source of
cardinal-truth; this is a pure composition layer (no edit to nx_warden_lib).
CRASH-SAFETY (the headline trap defended): every destructive write is done
write-temp -> fsync -> renameat2 (atomic on the same fs), NEVER truncate-in-
place. The ORIGINAL is never mutated until the new version is published; on
a gate-fail we restore from a DURABLE on-disk snapshot (not RAM-only) via the
same atomic path, then VERIFY the restored bytes rehash to the snapshot hash.
RE-GATE DECOUPLING (avoids the gate-runner's hardcoded /tmp scratch-path
collision under concurrent ticks, AND keeps this module free of the heavy
fork+exec re-gate dependency). The transaction is TWO-PHASE:
nx_self_build_begin(txn) : snapshot (durable) -> journal INTENT ->
atomic-write the new bytes. The new file now
sits on disk for the caller to GATE.
<caller runs its gate on `target`> (prod: nx_gate_runner.gr_gate;
dependencies 4 imports · 1 importers
imports: nx_syscalls.nxnx_blob_store.nxnx_journal_log.nxnx_warden_lib.nx
imported by: nx_self_build_test.nx
structs
| 110 | struct NxSelfBuild |
| 132 | struct NxSbTxn |
consts
| 64 | const SB_TIER_ADDITIVE: i64 = 1 |
| 65 | const SB_TIER_REVERSIBLE: i64 = 2 |
| 66 | const SB_TIER_DESTRUCTIVE: i64 = 3 |
| 69 | const SB_OK: i64 = 0 // write passed gate, new bytes stand |
| 70 | const SB_ROLLED_BACK: i64 = 1 // write failed gate, restored byte-ident |
| 71 | const SB_ROLLBACK_FAILED: i64 = 2 // LOUD: restore != snapshot (must NEVER) |
| 72 | const SB_DENIED: i64 = 3 // tier-3, needs explicit operator confirm |
| 73 | const SB_BAD_INPUT: i64 = 4 // null ctx / unreadable target / etc. |
| 76 | const SB_SCHEMA_INTENT: i64 = 7001 |
| 77 | const SB_SCHEMA_COMMIT: i64 = 7002 |
| 78 | const SB_SCHEMA_ROLLBACK: i64 = 7003 |
| 79 | const SB_SCHEMA_ROLLBACK_FAILED: i64 = 7004 |
| 81 | const SB_MODE: i64 = 420 // 0644 |
| 99 | const SB_SYS_RENAMEAT2: i64 = 316 |
| 100 | const SB_SYS_FSYNC: i64 = 74 |
| 103 | const SB_SYS_RENAMEAT2: i64 = 316 |
| 104 | const SB_SYS_FSYNC: i64 = 74 |
functions
| 115 | func nx_self_build_new() -> *NxSelfBuild |
| 122 | func nx_self_build_is_valid(ctx: *NxSelfBuild) -> i64 called by 3: nx_self_build_beginnx_self_build_finishmain calls 2: nx_blob_store_is_validnx_journal_log_is_valid |
| 145 | func sb_slen(s: *u8) -> i64 |
| 152 | func sb_concat(base: *u8, suffix: *u8) -> *u8 |
| 165 | func sb_fsync(fd: i64) -> i64 called by 1: sb_atomic_write |
| 170 | func sb_renameat2(old_path: *u8, new_path: *u8) -> i64 called by 1: sb_atomic_write |
| 177 | func sb_write_all(fd: i64, buf: *u8, len: i64) -> i64 |
| 194 | func sb_atomic_write(target: *u8, buf: *u8, len: i64) -> i64 |
| 207 | func nx_sb_classify(kind: i64, target: *u8, has_backup: i64, has_gate: i64) -> i64 |
| 221 | func nx_self_build_authorize(kind: i64, target: *u8, |
| 238 | func nx_sb_txn_new(ctx: *NxSelfBuild, target: *u8) -> *NxSbTxn |
| 256 | func nx_self_build_begin(txn: *NxSbTxn, new_bytes: *u8, new_len: i64) -> i64 called by 1: main calls 10: nx_self_build_is_validnx_blob_hash_newsys_mmapsys_read_filenx_blob_store_putnx_blob_store_has+4 |
| 298 | func sb_txn_snap_hash(txn: *NxSbTxn) -> *NxBlobHash |
| 315 | func nx_self_build_finish(txn: *NxSbTxn, verdict: i64) -> i64 called by 1: main calls 10: nx_self_build_is_validnx_journal_log_appendsb_slensb_txn_snap_hashsys_mmapsys_read_file+4 |