Skip to content

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

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

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

Conversation

@cursor

@cursor cursor Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Bug and impact

Critical data-loss bug in v0.6.0 HLC enforcement.

After restore_from_file(), restored nodes received fresh HLC timestamps instead of the values stored in the snapshot. Causal successor writes from the original writer (e.g. gossip replay or post-crash replication with hlc=(5000, 11, "nodeA")) were rejected as stale, causing silent data loss. Separately, gossip.receive() ignored HLC entirely, allowing gossip events without HLC to overwrite fresher local data.

Concrete trigger: snapshot → restore → remember(key, v2, hlc=successor) raises TimestampRegression and the update is dropped.

Root cause

  • restore_from_file() constructed MemoryNode without restoring the hlc field from snapshot JSON.
  • gossip.receive() called remember() without passing hlc, ts_ns, or edges.
  • bulk_write() did not pass through hlc from row payloads.

Fix

  • Add _parse_hlc() for snapshot/wire normalization with legacy ts_ns fallback.
  • restore_from_file(): restore hlc per node and advance global _hlc.
  • bulk_write(): pass through hlc when present.
  • gossip.receive(): apply hlc, reject stale updates, skip missing-HLC overwrites on existing keys.

Validation

  • Reproduced pre-fix: restored HLC mismatch caused successor write rejection.
  • Added tests: test_restore_preserves_hlc_for_replication, 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