Skip to content

fix(rust_brain): preserve HLC on snapshot restore, bulk_write, and gossip - #77

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

fix(rust_brain): preserve HLC on snapshot restore, bulk_write, and gossip#77
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/critical-bug-investigation-2cb6

Conversation

@cursor

@cursor cursor Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Bug and impact

restore_from_file(), bulk_write(), and gossip.receive() did not preserve Hybrid Logical Clock (HLC) timestamps introduced in v0.6.0. After disaster recovery from a snapshot, any write with a causally valid HLC was rejected with TimestampRegression — causing silent data loss in production restore and gossip paths.

Concrete trigger: Snapshot a node with hlc=(5000, 10, "nodeA"), restore, then attempt a legitimate update with hlc=(5000, 11, "nodeA"). Restore assigns a fresh wall-clock HLC, so the successor write is rejected.

Root cause

v0.6.0 added HLC-based monotonic enforcement but restore_from_file() created MemoryNode without restoring the hlc field (defaulting to _hlc.now()). bulk_write() and gossip.receive() also omitted HLC passthrough.

Fix

  • Add _parse_hlc() for wire/snapshot normalization (with legacy ts_ns fallback)
  • Restore HLC values and advance the global clock during snapshot restore (under lock)
  • Pass HLC through bulk_write() rows
  • Apply HLC in gossip.receive() with stale-update rejection and skip missing-HLC updates on existing keys

Validation

  • Reproduced bug before fix; successor write succeeds after fix
  • 38 targeted tests pass: test_hlc_snapshot_gossip.py, test_enterprise_backup.py, test_gossip.py, test_rust_brain.py, test_rust_brain_concurrency.py
Open in Web View Automation 

…ssip

restore_from_file() assigned fresh HLC timestamps instead of restoring
the snapshot values added in v0.6.0. After disaster recovery, any write
with a causally valid HLC was rejected with TimestampRegression — silent
data loss in production restore/gossip paths.

- Add _parse_hlc() for wire/snapshot normalization
- Restore HLC and advance global clock on snapshot restore
- Pass HLC through bulk_write rows
- Apply HLC in gossip.receive() with stale-update rejection
- Add regression tests in test_hlc_snapshot_gossip.py

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