HarperFast / HarperFast/harper

Crash replay re-applies transactions at the log key, silently changing a replayed source fill's version

Open
#2,411 1 comment 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.