HarperFast / HarperFast/harper-pro
Replication: force bounded base-copy resync when a peer is behind > audit retention
- Dominant language
- JavaScript
- Stars
- 3
- Forks
- 0
- Avg merge
- 1d 21h
- Merged PRs (30d)
- 80
Description
## Context
Transaction-log retention is **time-based** (default 1 day): old log files are purged by file mtime. When a peer falls behind by **more than the retention window**, the entries it needs have already been purged at the source, so it cannot catch up incrementally.
This is the **item-2 follow-up** to HarperFast/harper#1115. The corollary core fix (early-recovery purge) landed in HarperFast/harper#1117; the primary heap-bounding of the audit walk is HarperFast/harper#1114 / PR #1116.
## The gap
When the **sender** computes a peer's stream start position, there is **no check** that the requested start predates the oldest retained log entry. Today that means one of two bad outcomes:
1. **Silent data loss** — audit replay skips to the first surviving entry after the purge cutoff; or
2. **Unbounded full replay** — for a leader peer, it falls into the full-history replay path, which is the heap-unbounded path that OOMs (HarperFast/harper#1114).
## What already exists (good news)
A **heap-bounded base-copy / snapshot path already exists** in `replication/replicationConnection.ts`:
- Triggered by `startTime = 0`.
- Iterates the **primary store table-by-table** (not the audit history), checkpointing every `COPY_CHECKPOINT_RECORDS` and resumable via a persisted `copyCursor`.
- Receiver applies per-transaction backpressure (`whenNextTransaction`) so the worker heap stays bounded.
So the bounded resync machinery is built and tested — **only the trigger/decision is missing.**
## Proposed change (to scope/review)
At the seam where the sender determines the peer's `startTime` (~`replicationConnection.ts:2425–2469`):
1. Query the **oldest available** transaction-log timestamp (cheap `getRange({ limit: 1 })` or a dedicated accessor).
2. If the peer's requested `startTime < oldestAvailable`, set `startTime = 0` to route it through the **existing** base-copy path instead of incremental replay.
3. Log a warning that the peer fell behind retention and is being force-resynced.
## Caveats to resolve during design
- Need a cheap "oldest retained timestamp" query.
- Confirm the base-copy path fully covers everything incremental audit replay currently delivers (residency, blobs, structures, deletes).
- Interaction with the `isLeader` branch already present at the same seam.
- *Line numbers above are from a read-only scout pass — verify at implementation time.*
This is a larger, protocol-decision-path change than the core #1115 fix, so it warrants its own PR and review.
— Investigation/proposal assisted by Claude Opus 4.8 (Claude Code).
Contributor guide
Assessment
This issue has not been assessed yet.