Skip to content

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

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

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

Conversation

@cursor

@cursor cursor Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Bug and impact

Critical data-loss bug in disaster recovery and multi-node sync paths.

restore_from_file() rebuilt MemoryNode without the stored hlc field, assigning a fresh local HLC. After snapshot restore, causal writes from the original cluster (gossip replay, bulk replication) were rejected with TimestampRegression — silent data loss during failover.

GossipProtocol.receive() also omitted hlc, allowing stale remote events to overwrite fresher local state.

Concrete trigger

  1. Node A writes remember("session:1", data, hlc=(5000, 10, "nodeA"))
  2. Snapshot taken and restored to Node B after crash
  3. Node A gossips update with hlc=(5000, 11, "nodeA")rejected (restored node has fresh HLC)
  4. Or gossip without HLC overwrites fresher local data

Root cause

v0.6.0 added HLC monotonic enforcement but restore_from_file() and gossip.receive() were not updated to preserve/apply HLC timestamps.

Fix

  • Add _parse_hlc() for snapshot/wire normalisation with legacy fallback
  • Restore hlc and advance global _hlc during snapshot restore
  • Pass hlc through bulk_write; lock restore and gc_expired
  • Gossip: propagate hlc, reject stale updates, skip missing-hlc overwrites on existing keys

Validation

  • test_restore_preserves_hlc_for_replication — HLC round-trip + causal successor write
  • 4 new gossip HLC tests
  • 28 related tests pass (test_enterprise_backup, test_gossip, test_rust_brain)
Open in Web View Automation 

restore_from_file() was rebuilding MemoryNode without the stored hlc field,
assigning a fresh local HLC instead. After disaster recovery, causal writes
from the original cluster (gossip replay, bulk_write) were rejected with
TimestampRegression — silent data loss in production failover paths.

Gossip receive() also omitted hlc, allowing stale remote events to overwrite
fresher local state when monotonic enforcement compared against a fresh HLC.

- Add _parse_hlc() for snapshot/wire normalisation with legacy fallback
- Restore hlc and advance global _hlc during snapshot restore
- Pass hlc through bulk_write; lock restore and gc_expired
- Gossip: propagate hlc, reject stale updates, skip missing-hlc overwrites
- Tests for restore round-trip and gossip HLC semantics

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