- prune expired recovery items on load/save and reject expired restores at worker boundary - add restoreExpired and restoreConflict protocol/application error mapping - disable expired restore actions in History and reload persisted state after restore failures - add recovery expiry/conflict coverage plus sync protocol, architecture, state-machine, and recovery contract docs - wire AtlasAppTests into the shared Xcode scheme and add app-layer regression coverage for expired restore reload behavior Refs: ATL-221 ATL-222 ATL-223 ATL-224 ATL-225, vibe-kanban SID-9
33 lines
2.0 KiB
Markdown
33 lines
2.0 KiB
Markdown
# ADR-007: Recovery Retention Enforcement
|
|
|
|
## Status
|
|
|
|
Accepted
|
|
|
|
## Context
|
|
|
|
Atlas already documents a retention-window recovery model, including `RecoveryItem.expiresAt`, the `expired` task-state concept, and `restore_expired` in the error-code registry. The shipped worker, however, still restores items solely by presence in `snapshot.recoveryItems`. That means an expired entry can remain visible and restorable if it has not yet been pruned from persisted state.
|
|
|
|
This creates a trust gap in a release-sensitive area: History and Recovery can claim that items are available only while the retention window remains open, while the implementation still allows restore after expiry.
|
|
|
|
## Decision
|
|
|
|
- Atlas must treat expiry as an enforced worker and persistence boundary, not only as UI copy.
|
|
- `AtlasWorkspaceRepository` must prune expired `RecoveryItem`s on load and save so stale entries do not remain in active recovery state across launches.
|
|
- `AtlasScaffoldWorkerService.restoreItems` must recheck expiry at request time and fail closed before any restore side effect.
|
|
- Restore rejections must use stable restore-specific protocol codes for expiry and restore conflicts.
|
|
- Presentation may add defensive restore disabling for expired entries, but worker enforcement remains authoritative.
|
|
|
|
## Consequences
|
|
|
|
- Recovery behavior now matches the documented retention contract.
|
|
- Expired entries stop appearing as active recovery inventory after repository normalization.
|
|
- Restore batches remain fail closed: if any selected item is expired, the batch is rejected before mutation.
|
|
- Protocol consumers must handle the additional restore-specific rejection codes.
|
|
|
|
## Alternatives Considered
|
|
|
|
- Narrow docs to match current behavior: rejected because it preserves an avoidable trust gap.
|
|
- Enforce expiry only in the restore command: rejected because stale entries would still persist in active recovery state.
|
|
- Fix only in UI: rejected because restore is ultimately a worker-boundary guarantee.
|