Problem
Replica.EnforceRetention(context.Context) is a public method whose implementation on main unconditionally panics:
func (r *Replica) EnforceRetention(ctx context.Context) (err error) {
panic("TODO(ltx): Re-implement after multi-level compaction")
}
This is reachable by library callers and is also adjacent to the one-shot replicate -enforce-retention path. The previous single-level implementation is retained only as commented code.
Current code path
replica.go:316-350: public Replica.EnforceRetention panics.
store.go:833-853: current retention is implemented at the Store/DB boundary by enforcing snapshot retention and cascading a TXID floor through configured non-L0 levels.
compactor.go:238-336: level-aware snapshot and TXID retention primitives.
cmd/litestream/replicate.go:422-428: -once -enforce-retention calls Store.EnforceSnapshotRetention, not the panicking Replica method.
Reproduction
A caller using the public library API can trigger the panic with a configured Replica:
var r *litestream.Replica = ...
_ = r.EnforceRetention(context.Background())
The method cannot be repaired by restoring the old body mechanically: the current architecture has no retention configuration on Replica, and retention must account for configured multi-level compaction, snapshot floors, in-flight restore plans, local-file cleanup, and the RetentionEnabled policy.
Design questions
- Should
Replica.EnforceRetention be removed in a breaking release, deprecated, or retained as a compatibility wrapper?
- If retained, should it delegate to a Store/DB-level API, and where should retention configuration and compaction levels come from?
- What behavior is expected for standalone
Replica library callers and for retention-disabled configurations?
Proposed follow-up
After the API/ownership decision, add a focused regression test proving the chosen behavior and update the public API documentation. The implementation should preserve the existing Store/Compactor multi-level retention semantics rather than reintroducing the obsolete single-level algorithm.
This issue is intentionally a design discussion before code changes because the correct fix is not mechanically safe.
Problem
Replica.EnforceRetention(context.Context)is a public method whose implementation onmainunconditionally panics:This is reachable by library callers and is also adjacent to the one-shot
replicate -enforce-retentionpath. The previous single-level implementation is retained only as commented code.Current code path
replica.go:316-350: publicReplica.EnforceRetentionpanics.store.go:833-853: current retention is implemented at the Store/DB boundary by enforcing snapshot retention and cascading a TXID floor through configured non-L0 levels.compactor.go:238-336: level-aware snapshot and TXID retention primitives.cmd/litestream/replicate.go:422-428:-once -enforce-retentioncallsStore.EnforceSnapshotRetention, not the panicking Replica method.Reproduction
A caller using the public library API can trigger the panic with a configured
Replica:The method cannot be repaired by restoring the old body mechanically: the current architecture has no retention configuration on
Replica, and retention must account for configured multi-level compaction, snapshot floors, in-flight restore plans, local-file cleanup, and theRetentionEnabledpolicy.Design questions
Replica.EnforceRetentionbe removed in a breaking release, deprecated, or retained as a compatibility wrapper?Replicalibrary callers and for retention-disabled configurations?Proposed follow-up
After the API/ownership decision, add a focused regression test proving the chosen behavior and update the public API documentation. The implementation should preserve the existing Store/Compactor multi-level retention semantics rather than reintroducing the obsolete single-level algorithm.
This issue is intentionally a design discussion before code changes because the correct fix is not mechanically safe.