Skip to content

feat(persistence): add crash-safe versioned conference persistence - #4

Merged
Nixort merged 6 commits into
Nixort:mainfrom
itachicoders:feat/versioned-persistence-boundary
Aug 20, 2026
Merged

Nixort merged 6 commits into
Nixort:mainfrom
itachicoders:feat/versioned-persistence-boundary

Conversation

@itachicoders

@itachicoders itachicoders commented Aug 20, 2026

Copy link
Copy Markdown

Problem and scope

Conference previously had no durability boundary: restarting a process lost identity, protocol history, ratchets, replay protection, and pending control output. This PR adds a std-only persistence API and the minimum internal state codecs needed to resume the same conference safely. It does not change the protocol wire format or release metadata.

Persistence model

  • Adds cfr::persistence::PersistentConference with explicit create, join, and open paths; open never creates missing state.
  • Persists the complete core and media security state, including identity/session binding, DAG and membership state, prekeys/channels, key versions, sender counters, receiver ratchets, and replay windows.
  • Uses separate internal version tags: logical persistence schema 1 and snapshot/WAL envelope format 1. Unknown versions fail with a typed UnsupportedVersion; no synthetic legacy migrations or format guessing are included.
  • Rebuilds only derived caches after bounded decoding and validates cross-layer identity, session, roster, key-version, ordering, ID, and delivery-key invariants.

Transactions, inbound idempotency, and outbox

  • Every mutating Conference operation is applied to an isolated candidate state.
  • The complete candidate is appended to the WAL and sync_data completes before it becomes live or its result is returned.
  • handle_inbound accepts a transport-provided InboundId. A repeated ID with identical bytes returns a duplicate result without mutation; different bytes return IdempotencyConflict.
  • Resulting control messages enter the durable outbox in the same transaction, with monotonic OutboundIds and deterministic delivery keys. Acknowledgement is a separate durable, idempotent transaction.
  • Idempotency and outbox capacities are bounded; exhaustion fails before protocol or in-memory state changes.

Crash recovery and limits

  • Snapshot and WAL envelopes carry magic, envelope version, sequence, bounded length, checksum, and commit markers.
  • Recovery replays only strictly consecutive complete records. An incomplete final WAL tail is truncated to the last valid record; complete corruption, invalid markers/checksums, gaps, and invariant failures fail closed.
  • Full-state WAL records allow recovery from a damaged snapshot when a newer valid WAL state exists.
  • Snapshot checkpoints use an owner-only temporary file, sync, atomic rename, and directory sync. WAL replacement follows only after the committed snapshot is durable.
  • Projected WAL size is overflow-checked. A crash-safe checkpoint occurs before a configured threshold/limit crossing, and an unrepresentable record is rejected before mutation.
  • A held OS advisory lock enforces one writer per state directory. Unix directories/files use 0700/0600.

Security boundary and known limitations

  • Persisted state contains identity seeds and live protocol/media keys in plaintext. Filesystem permissions are defense in depth; deployments requiring confidentiality at rest must protect the state directory with OS/storage encryption and access controls.
  • Checksums detect accidental/torn corruption and are not authentication against an attacker who can rewrite the directory.
  • Advisory locking assumes cooperating processes, and filesystem snapshots/backups can retain older secret material beyond in-process erasure.

Local validation

All available local checks completed with exit code 0:

cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
cargo build --workspace --all-features --locked
cargo test --workspace --all-features --locked --lib --bins
cargo test --workspace --all-features --locked --tests
cargo test --locked -p cfr --test persistence
cargo test --locked -p cfr --test persistence_snapshot
make check
cargo build --release --workspace --all-features --locked
cargo doc --workspace --all-features --no-deps --locked
cargo package --allow-dirty --locked --no-verify -p cfr-crypto
cargo check -p cfr --no-default-features --features cfr-crypto/portable --locked
rustup run 1.85.0 cargo check --workspace --all-features --locked
rustup run 1.85.0 cargo fmt --all -- --check
rustup run 1.85.0 cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
cargo-audit 0.22.2 audit --deny warnings
cargo-deny 0.20.2 check all
git diff --check

The persistence integration suites contain 21 real-filesystem restart/recovery tests and no ignored tests. Rust 1.85.0, cargo-audit 0.22.2, and cargo-deny 0.20.2 were installed into temporary directories from their official distributions to reproduce the pinned CI checks. The only ignored test in the full workspace output is the pre-existing timing/reference profile test.

Commits

  • d66e5bd feat(persistence): add bounded protocol state codecs
  • f0e3926 feat(persistence): add crash-safe durable conference boundary
  • 472f1c4 fix(persistence): harden recovery and failed commits
  • 6ca65dc test(persistence): cover restart and corruption paths
  • 393e9e1 fix(crypto): keep attached AEAD no-std compatible
  • 1439698 docs(persistence): document durability and recovery contract

Explicitly unchanged

  • CFR control/media wire formats
  • package/release versions
  • fake legacy decoders or migration paths
  • HTTP, deployment, daemon, UI, or unrelated release functionality

CI status

All required PR checks passed:

  • Stable quality gate
  • MSRV 1.85 locked build
  • Package readiness
  • Advisory database audit
  • License and source policy
  • LLVM coverage
  • CodeQL Rust analysis and CodeQL result check

The tagged-release validation job is intentionally skipped because this is a pull request, not a release tag.

@Nixort

Nixort commented Aug 20, 2026

Copy link
Copy Markdown
Owner

wtf? My email...

@itachicoders

Copy link
Copy Markdown
Author

wtf? My email...

I'm sorry, I forgot to change

@Nixort
Nixort merged commit b5916db into Nixort:main Aug 20, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants