Versioned documentPlain text

Admission fsync failure evidence v1

Local fault-injection tests · 5 September 2026

On this page

Coverage and outcome

The ledger now has a test-only fault hook at nine sync boundaries: journal and directory creation, incomplete-tail truncation, journal and directory recovery, admission append, conflict append, pending rollover header, and rollover directory. Production builds always call the real sync operation; no environment variable or runtime setting can enable faults.

The matrix runs both control and reserved modes, with errors before each sync and errors reported after an actual successful sync: 36 combinations. Four additional cases restore the previously committed prefix after a before-sync failure, modeling loss of only an unacknowledged admission or conflict append. All 40 scenarios pass. Hooks are thread-local and one-shot; tests assert that the intended hook was reached.

For append failures, no new permission or conflict acknowledgement is returned; accounting is not updated in memory and the handle is poisoned. Previously issued receipts are unusable through that handle. A complete surviving record is recovered and synced before replay succeeds, without a duplicate append. If the unacknowledged tail disappears, earlier receipts survive and the operation can be retried.

Creation/recovery errors return no live ledger. A later healthy reopen succeeds. An incomplete tail is removed. Pre-rename rollover failure preserves the old journal; post-rename directory-sync failure poisons the handle and reopening the observed new policy recovers it. The old epoch cannot be opened as if it were still the stored policy. Successful sync followed by an injected error is deliberately treated as uncertain by the caller, even though the test knows the sync completed.

What this does not prove

These are real file writes and sync calls with injected error returns, not power cuts, kernel/device faults, or proof that a filesystem honors flushes. Lost-tail cases explicitly rewrite the old prefix as a model of one allowed outcome. The suite does not enumerate directory-rename loss after a crash, corrupted device writes, stalled syscalls, or rollback of already acknowledged history. Existing partial-tail and corruption tests remain separate evidence.

No protocol policy or journal encoding changed. The work adds test hooks and a thin sync wrapper, with fault state compiled out of normal builds. Public ingress remains disabled. See spec/core/INGRESS_PIPELINE.md for the proposed bounded driver, including why a writer timeout cannot be treated as cancellation of fsync.

Reproduce

SKEIN_FSYNC_REPORT=docs/results/admission-fsync-v1.json \
  cargo test --locked --offline --features peer-recovery --lib \
  admission_wire::durable::sync_tests

The report retains the 36 matrix outcomes. The four lost-tail cases run in the second test function; source/result hashes and aggregate counts are recorded in docs/results/admission-fsync-v1-manifest.json. This is local durability evidence, not complete Core conformance or a distributed availability proof.