Files
artifact-store/workplans/ARTIFACT-STORE-WP-0003-retention-lifecycle.md
tegwick 8eee5a1c1c chore(consistency): sync new task and workstream IDs from DB [auto]
fix-consistency assigned state_hub_task_id and state_hub_workstream_id UUIDs
to the tasks and workplans added in 747afc2.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 21:26:08 +02:00

138 lines
3.9 KiB
Markdown

---
id: ARTIFACT-STORE-WP-0003
type: workplan
title: "Retention Lifecycle: Defaults, Extensions, Holds, Deletion Eligibility"
repo: artifact-store
domain: stack
status: planned
owner: codex
topic_slug: stack
planning_priority: high
planning_order: 3
created: "2026-05-15"
updated: "2026-05-15"
state_hub_workstream_id: "84930f4c-3bcf-415e-a94c-bfa854a15871"
---
# ARTIFACT-STORE-WP-0003: Retention Lifecycle
## Purpose
Implement the retention engine. By the end of this workplan, every
package has a computed `expires_at`, operators can extend retention or
apply / release holds, and the system can mark expired packages as
eligible for deletion — without actually deleting bytes (GC is
WP-0006).
## Constraints
- ADR-0002 (every retention change is an event).
- `docs/ARCHITECTURE-BLUEPRINT.md` retention sections.
## Prerequisites
- WP-0001 done (`retention_classes` seeded, `retention_state` view
exists).
- WP-0002 done (HTTP surface exists to attach the new endpoints to).
## D3.1 - Default Retention Application
```task
id: ARTIFACT-STORE-WP-0003-T001
status: todo
priority: high
state_hub_task_id: "2d6cbd83-c348-45ad-a223-7870a3412225"
```
Acceptance:
- On `POST /packages`, the requested `retention_class` is validated
and the `v1.retention.default_applied` event is written with the
computed `expires_at`.
- Default durations per class are operator-configurable via a
config file (TOML); the file path is documented in `OPERATOR.md`.
- `permanent-record` packages have `expires_at = NULL` and
`eligible_for_deletion = false`.
## D3.2 - Retention Extensions
```task
id: ARTIFACT-STORE-WP-0003-T002
status: todo
priority: high
state_hub_task_id: "66576e53-af4c-48dc-8dc3-cf8223a821c7"
```
Acceptance:
- `POST /packages/{id}/retention/extensions` accepts
`{new_expires_at, reason}`. The new value must be strictly later
than the current; reason is mandatory.
- Each extension writes a `v1.retention.extended` event;
`retention_state.current_expires_at` updates on the same
transaction.
- A package's full extension history is recoverable from `events`.
## D3.3 - Holds (Apply And Release)
```task
id: ARTIFACT-STORE-WP-0003-T003
status: todo
priority: high
state_hub_task_id: "8164e448-0e90-41aa-a973-77f8f607a0b3"
```
Acceptance:
- `POST /packages/{id}/retention/holds` records a hold with a reason
and actor; emits `v1.retention.hold_applied`.
- A package with at least one active hold is never
`eligible_for_deletion` regardless of `expires_at`.
- `POST /packages/{id}/retention/holds/{hold_id}/release` requires a
reason; emits `v1.retention.hold_released`.
- Test: hold applied → expiry passes → eligibility stays `false`;
hold released → eligibility flips to `true`.
## D3.4 - Deletion Eligibility Sweeper
```task
id: ARTIFACT-STORE-WP-0003-T004
status: todo
priority: medium
state_hub_task_id: "fe13cd0d-aab7-4e0a-a7df-e6e535d4099b"
```
Acceptance:
- A scheduled task (cron-style configurable interval; default 1 hour)
scans packages whose `expires_at` has passed and no active hold
exists, and emits `v1.retention.deletion_eligible` events.
- The sweeper is idempotent: events are emitted at most once per
package per eligibility transition.
- The sweeper is invokable as a CLI subcommand for tests:
`artifactstore retention sweep`.
## D3.5 - Audit Surface For Retention
```task
id: ARTIFACT-STORE-WP-0003-T005
status: todo
priority: medium
state_hub_task_id: "7dce0c92-76d6-4bfc-bbc5-8e18b96139d2"
```
Acceptance:
- `GET /packages/{id}/retention/history` returns the ordered list of
retention events for a package.
- The default response is the JCS projection; CBOR is available via
`Accept: application/cbor`.
## Success criteria
- A guide-board run can be ingested, given `release-evidence`, later
extended once, held for a quarter, released, swept, and marked
eligible — all visible through both `retention_state` and the
event log.
- No bytes are deleted by this workplan; that is WP-0006.