Skip to content

fix(rust_brain): preserve HLC on snapshot restore and gossip receive#45

Draft
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/critical-bug-investigation-d9b3
Draft

fix(rust_brain): preserve HLC on snapshot restore and gossip receive#45
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/critical-bug-investigation-d9b3

Conversation

@cursor

@cursor cursor Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Bug and impact

restore_from_file() and gossip.receive() did not preserve or apply Hybrid Logical Clock (HLC) timestamps introduced in v0.6.0. After disaster recovery or cross-node gossip, restored nodes received fresh HLC values instead of their original causal timestamps.

Concrete trigger: Write a node with hlc=(5000, 10, "nodeA"), snapshot, restore, then attempt a causal successor write with hlc=(5000, 11, "nodeA"). The write raises TimestampRegression and is silently dropped — causing data loss on replication and gossip replay.

Root cause

  • restore_from_file() constructed MemoryNode without reading hlc from the snapshot dict, so each restored node got a fresh wall-clock HLC.
  • gossip.receive() called remember() without passing hlc from gossip events.
  • bulk_write() also omitted HLC passthrough.

Fix

  • Add _parse_hlc() to normalise HLC from snapshot/wire form (list/tuple) with legacy fallback.
  • Restore HLC on snapshot load and advance the global HLC via _hlc.update().
  • Pass HLC through bulk_write() and gossip.receive() with stale-overwrite rejection.
  • Lock gc_expired() and restore mutations for thread safety.

Validation

  • Reproduced the bug before fix (causal successor write rejected after restore).
  • Added regression tests for snapshot HLC round-trip and gossip HLC handling.
  • Full suite: 192 passed, 8 skipped.
Open in Web View Automation 

restore_from_file() assigned fresh HLC timestamps instead of reading
the values embedded in snapshots. After disaster recovery, any write
with the pre-crash causal order was rejected with TimestampRegression,
causing silent data loss on replication and gossip replay.

- Add _parse_hlc() for snapshot/wire normalisation
- Restore HLC and advance global clock on snapshot restore
- Pass HLC through bulk_write and gossip.receive()
- Reject stale gossip overwrites; skip missing-HLC updates on existing keys
- Lock gc_expired and restore mutations for thread safety

Co-authored-by: Daniel <DJLougen@users.noreply.github.com>
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.

1 participant