NagyZoltanPeter a1147c96af
refactor(persistence): strip legacy interface from protocol path; migrate tests to V2 (phase 2B+2C+2D)
End-state of phase 2: the protocol code no longer issues any legacy
fine-grained Persistence calls. All state survives via the snapshot-based
PersistenceV2 interface — one trySaveMeta per op end, plus tryUpdateHistory
batched inside addToHistory. The legacy Persistence field on
ReliabilityManager remains for backwards compatibility; phase 3 deletes it.

Protocol changes (sds.nim, sds/sds_utils.nim):
- reviewAckStatus, processIncomingBuffer, updateLamportTimestamp →
  pure in-memory; no per-mutation persistence.
- addToHistory: replaces appendLogEntry+removeLogEntry with a single
  tryUpdateHistory call carrying (append, evict) atomically.
- getRecentHistoryEntries: setRetrievalHint switched to V2; non-fatal.
- wrapOutgoingMessage, unwrapReceivedMessage, markDependenciesMet:
  all per-row saveOutgoing / removeOutgoing / saveIncoming /
  removeIncoming / saveOutgoingRepair / removeOutgoingRepair /
  saveIncomingRepair / removeIncomingRepair calls removed (16 call
  sites in total). State is captured by the op-end trySaveMeta added
  in phase 2A.
- getOrCreateChannel: bootstraps from persistenceV2.loadChannel.
- dropChannelFromPersistence: uses persistenceV2.dropChannel.

Failure policy (PLAN_SNAPSHOT_PERSISTENCE.md §8):
- Foreground ops (wrap, unwrap, markDeps, sweeps): non-fatal —
  trySaveMeta / tryUpdateHistory log and continue; the protocol op
  returns ok regardless of disk failure. In-memory state is the source
  of truth; the next op re-issues a complete snapshot and disk catches
  up automatically.
- Durability-intent ops (removeChannel, resetReliabilityManager via
  dropChannelFromPersistence; getOrCreateChannel via loadChannel):
  still propagate rePersistenceError, because the caller asked us to
  confirm a disk operation and we cannot silently lie.

Test infrastructure:
- tests/in_memory_persistence_v2.nim: new V2 adapter mock that
  decomposes the meta blob into the existing InMemoryStore shape so
  test assertions on store.outgoing / store.incoming / etc. continue to
  work without change.
- tests/test_persistence.nim: 17 tests, all rewritten against V2.
  - 13 state-survival tests carry over with identical assertions.
  - "loadChannel failure surfaces as err on bootstrap" — bootstrap
    keeps durability-intent semantics.
  - "saveChannelMeta failure during send does NOT surface" — deliberate
    inversion of the legacy "write failure surfaces as err" test. Asserts
    the new non-fatal policy: op returns ok, in-memory state correct,
    disk re-syncs on the next op.
  - "updateHistory failure during send does NOT surface" — same policy
    applied to the history path.
  - "dropChannel failure during removeChannel surfaces as err" — kept.
- All 17 tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 13:13:58 +02:00
2026-04-10 14:23:30 +02:00
2026-04-10 14:23:30 +02:00
2026-02-03 19:05:46 +00:00

nim-sds

Nim implementation of the e2e reliability protocol.

Prerequisites

  • Nix package manager

Quick start

git clone https://github.com/logos-messaging/nim-sds.git
cd nim-sds

# Build the shared library
nix build '.#libsds'

# Run tests
nix develop --command nimble test

Building

Desktop

nix build --print-out-paths '.#libsds'

Android

nix build --print-out-paths '.#libsds-android-arm64'
nix build --print-out-paths '.#libsds-android-amd64'
nix build --print-out-paths '.#libsds-android-x86'
nix build --print-out-paths '.#libsds-android-arm'

iOS

nix build --print-out-paths '.#libsds-ios'
Development shell

Enter the dev shell:

nix develop

Build using nimble tasks:

# Dynamic library (auto-detects OS)
nimble libsdsDynamicMac    # macOS
nimble libsdsDynamicLinux  # Linux
nimble libsdsDynamicWindows # Windows

# Static library
nimble libsdsStaticMac     # macOS
nimble libsdsStaticLinux   # Linux
nimble libsdsStaticWindows # Windows

Run tests:

nimble test

The built library is output to build/.

Android (without Nix)

Download the latest Android NDK:

cd ~
wget https://dl.google.com/android/repository/android-ndk-r27c-linux.zip
unzip android-ndk-r27c-linux.zip

Add to ~/.bashrc:

export ANDROID_NDK_ROOT=$HOME/android-ndk-r27c
export PATH=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH

Then build:

ARCH=arm64 nimble libsdsAndroid
Architecture Command
arm64 ARCH=arm64 nimble libsdsAndroid
amd64 ARCH=amd64 nimble libsdsAndroid
x86 ARCH=x86 nimble libsdsAndroid

The library is output to build/libsds.so.

Dependency management

Dependencies are managed by Nimble and pinned via nimble.lock.

To set up dependencies locally:

nimble setup -l

To update dependencies:

nimble lock

After updating nimble.lock, the Nix outputHash in nix/deps.nix must be recalculated by running nix build and updating the hash from the error output.

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.

Description
Nim implementation of the e2e reliability protocol
Readme
Languages
Nim 91.9%
Nix 5.9%
Shell 1.5%
C 0.7%