Skip to content

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

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

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

Conversation

@cursor

@cursor cursor Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Bug and impact

restore_from_file() and gossip.receive() did not preserve or apply HLC timestamps added in v0.6.0. After a snapshot restore, the store assigned fresh HLC values instead of the saved ones. Any post-crash causal write or gossip replay carrying the pre-crash HLC was rejected with TimestampRegressionsilent data loss in disaster-recovery and multi-node replication paths. Conversely, gossip events without HLC could overwrite fresher local data.

Concrete trigger: snapshot a node with hlc=(5000, 10, "nodeA"), restore, then apply the causal successor hlc=(5000, 11, "nodeA") → rejected because restore assigned a fresh wall-clock HLC.

Root cause

v0.6.0 added HLC to MemoryNode and monotonic enforcement in remember(), but restore_from_file() rebuilt nodes without reading the hlc field from the snapshot JSON, and gossip.receive() did not pass HLC through on writes.

Fix

  • Add _parse_hlc() for snapshot/wire normalisation with legacy fallback for pre-v0.6.0 snapshots
  • restore_from_file: restore hlc per node and advance the global _hlc clock
  • bulk_write: pass through hlc from row payloads
  • gossip.receive: apply HLC, reject stale updates, skip missing-HLC overwrites on existing keys

Validation

  • Reproduced the bug before fix (successor write raised TimestampRegression)
  • Added regression tests for snapshot HLC round-trip and gossip stale/new/missing-HLC cases
  • Full suite: 192 passed, 8 skipped
Open in Web View Automation 

restore_from_file dropped hlc fields added in v0.6.0, assigning fresh
timestamps on restore. Post-crash causal writes and gossip replays with
pre-crash HLC were rejected (silent data loss), while gossip events
without HLC could overwrite fresher data.

- Add _parse_hlc() for snapshot/wire normalisation with legacy fallback
- restore_from_file: restore hlc and advance global _hlc per node
- bulk_write: pass through hlc from row payloads
- gossip.receive: apply hlc, reject stale updates, skip missing-hlc
  overwrites on existing keys
- Tests: snapshot HLC round-trip, gossip stale/new/missing-hlc cases

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