Skip to content

fix(rust_brain): preserve HLC on snapshot restore and gossip replay - #70

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

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

Conversation

@cursor

@cursor cursor Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Bug and impact

v0.6.0 added Hybrid Logical Clock (HLC) monotonic enforcement, but restore_from_file(), bulk_write(), and gossip.receive() did not round-trip HLC timestamps.

Concrete trigger: After disaster-recovery snapshot restore, restored nodes received fresh HLC values instead of their snapshot HLCs. Valid causal successor writes (e.g. hlc=(5000, 11, "nodeA") after restore of (5000, 10, "nodeA")) raised TimestampRegression and were rejected — silent data loss in replication/gossip paths.

Root cause

  • restore_from_file() created MemoryNode without passing hlc, defaulting to _hlc.now()
  • bulk_write() omitted hlc from row payloads
  • gossip.receive() did not pass hlc/ts_ns and could not reject stale overwrites

Fix

  • Add _parse_hlc() for snapshot/wire normalisation with legacy fallback
  • restore_from_file: restore HLC, update global clock, hold lock during mutation
  • bulk_write: pass hlc from row payloads
  • gossip.receive: apply HLC, reject stale overwrites, skip missing-HLC updates on existing keys

Validation

  • Reproduced pre-fix: successor write failed after restore
  • Post-fix: HLC preserved, successor write succeeds, stale replay still rejected
  • pytest tests/test_enterprise_backup.py tests/test_gossip.py tests/test_rust_brain.py — 27 passed
Open in Web View Automation 

v0.6.0 added HybridLogicalClock enforcement but restore_from_file(),
bulk_write(), and gossip.receive() did not round-trip HLC timestamps.
After disaster-recovery restore, nodes received fresh HLC values, causing
TimestampRegression on valid causal successor writes and silent rejection
of gossiped updates.

- Add _parse_hlc() for snapshot/wire normalisation with legacy fallback
- restore_from_file: restore hlc, update global clock, hold lock
- bulk_write: pass hlc from row payloads
- gossip.receive: apply hlc, reject stale overwrites, skip missing-hlc updates
- Add regression tests for restore round-trip and gossip ordering

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