HarperFast / HarperFast/harper
Crash replay re-applies transactions at the log key, silently changing a replayed source fill's version
- Dominant language
- JavaScript
- Stars
- 89
- Forks
- 10
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 200
Description
## Problem
Crash replay re-applies whole transactions at the transaction-log key: `resources/replayLogs.ts` sets `transaction.timestamp` from the log key and every write in the batch is applied at that timestamp. Since #2065 separated a source fill's stored record version from its fill transaction's commit timestamp (the log key), a replayed source fill silently comes back at the commit key instead of its stored version — a crash changes a record's version without any write having occurred.
## Why it isn't a one-liner
One transaction can legitimately carry a commit-stamped side-effect write AND a source-versioned cache fill under a single log key, and `DatabaseTransaction` has a single timestamp — "apply at the entry's recordVersion" needs a designed per-write version override through the write path (`_writeUpdate` takes its version from the transaction today), not a timestamp swap.
This was explicitly scoped OUT of the stage-0 unbreak-main fix (#2409, ruling D2(i)) and promised as its own follow-up.
## Acceptance
- A red-first regression test: real on-disk restart of a genuinely unclean store where log key ≠ record version — value AND version preserved, transaction grouping still by log key.
- A red-first mixed-version same-transaction test: side-effect write at the commit stamp + fill at a distinct source version under one log key; both survive replay at their own versions.
- The audit entry already carries the record version in-band (`createAuditEntry`/`readAuditEntry`), and `AuditRecord.recordVersion` (from #2409) exposes it — the work is the per-write apply API, not the decode.
Contributor guide
Research direction
Start in resources/replayLogs.ts and trace how DatabaseTransaction applies writes from the audit entry, including createAuditEntry, readAuditEntry, and AuditRecord.recordVersion. Add red-first tests for an unclean on-disk restart and for mixed-version writes in one log-key transaction. Done means values and per-write versions survive replay while transaction grouping remains keyed by the log entry.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, node.js
- Domain
- database, testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100