v0.99.41
One backup-DR fix — backup compact no longer refuses an ordinary rotated backup stream chain when a rotation-born segment never received a rollover commit in its creating session (the "rotate on a timer, stop while idle" workflow, or a crash/end at a rotation boundary). The bug always failed LOUDLY with zero data loss — it just made the compact DR-maintenance feature unusable across that one boundary, blaming "a pre-ADR-0067, imported, or corrupted lineage" for a chain its own rotation produced. Drop-in from v0.99.40 — no flag, default, or invocation changes; no re-verification of any prior backup needed.
Fixed
backup compact(naive AND--smart-compaction) now splits a merge group at a rotation-boundary coverage gap instead of refusing the whole run (Bug 139, ADR-0087). A rotation-born segment whose creating session never committed an incremental carries noincremental_coverage_startstamp, so it resolves to its full's snapshot anchorS— which lands a few WAL bytes past the prior segment'send_position(P_N). That delta IS the gap. Pre-fix, compact read it as a position gap and refused the ENTIRE run with a message blaming "a pre-ADR-0067, imported, or corrupted lineage" — and a later resume never healed it, so the boundary stayed permanently un-compactable. Compact now subdivides the merge group at every coverage-gap boundary (subdivideAtCoverageGaps): the stamp-less segment stays its own group (one operator-accurate WARN naming the boundary; no data lost, chain fully restorable) while every contiguous run around it still merges — naive,--smart-compaction, and--dry-runall produce the same subdivided plan. Separately, the nextbackup stream/backup incrementalresume that lands on a rotation-born zero-incremental open segment now replays from the prior segment'send_position(P_N), so its first incremental honestly stampsincremental_coverage_start = P_Nand the boundary heals — the chain becomes fully compactable (N→1). Neither half ever stamps coverage that no committed incremental proves (creation-time stamping and resume-backfill were deliberately REJECTED — a crash or walsender lag can leave real events in(P_N, S]that live only in the new segment's full, which compact drops; a fabricated stamp would convert today's loud refusal into silent DR loss). Affected releases: v0.88.0 through v0.99.40 — the strict contiguous-rotation handoff that produces theS > P_Nboundary shipped with ADR-0067 (Bug 95) at v0.88.0; before that, rotated chains were refused by design, not by this false-positive. The byte-identical refusal was reproducible on v0.99.39/v0.99.40 and with--smart-compactionoff. Pinned by the compact-split unit matrix (trailing OPEN/CAPPED, mid-chain stamp-less, multi-gap, contiguous-still-merges-4-to-1, dry-run), the resume-rule unit test (resumes atP_N; first incremental stampsP_N; negative cases keep prior behavior), and a PG idle-stop integration repro (naive + smart split + restore == oracle; resume-heal → whole-chain N→1 + restore == oracle).
Compatibility
- No breaking changes. Drop-in from v0.99.40 — no flag, default, or invocation changes.
migrate,sync,backup full, and CDC behavior are entirely unchanged. The only behavioral change is thatbackup compactsucceeds (with a split + WARN) on a chain it previously refused, and that a rotation-boundary resume now replays fromP_Nso the first committed incremental stamps the coverage honestly and the boundary becomes compactable. - No chunk-format or on-disk change. Existing chains are not rewritten. A chain that today straddles the rotation boundary will compact with a split (the stamp-less segment stays its own group); it heals to fully compactable on its next resumed write, with no manual intervention.
- Both engines, both compaction strategies. The fix covers naive compaction and
--smart-compaction, on PG and MySQL chains; the resume rule was verified strictly-after on both engines (a freshStreamChanges(P_N)with no skip-through, sound on WAL retention + ADR-0010 idempotent overlap replay).
Who needs this — action required
- Nobody needs to re-verify or re-run any prior backup. This was a LOUD refusal with zero data loss — no backup ever completed with wrong or missing data because of it. Every artifact compact previously refused to merge is intact and independently restorable.
- Anyone whose
backup compactfailed across a rotation boundary with "a pre-ADR-0067, imported, or corrupted lineage" on a chain their ownbackup streamproduced (rotate-on-timer + idle stop, or a crash/end at a rotation boundary) — upgrade and re-run compact. It now succeeds: the boundary segment is split into its own group (one WARN) and everything around it merges. No chain rewrite is required. - Operators running rotated
backup streamchains long-term — once on v0.99.41, existing straddling chains compact with a split immediately, and heal to fully compactable (no split, no WARN) on their next resumed write. No flag to set, no migration to run; just upgrade.
Install: brew install sluicesync/tap/sluice · go install sluicesync.dev/sluice/cmd/sluice@v0.99.41 · Container: ghcr.io/sluicesync/sluice:0.99.41
Full changelog: https://github.com/sluicesync/sluice/blob/main/CHANGELOG.md