docs release evidence p15 t04 expiry restore - AlexandreZanata/Abastevo GitHub Wiki
P15-T04 — Expiry deletion and restore enforcement
Status: LOCAL_DONE on codex/phase-15-lightweight-photos (phase PR
#39, draft). Issue: #37 (slice 4 of 5; issue stays open until the
phase PR merges). No camera, storage-config or live-provider
contact in this slice.
Slice acceptance (frozen before coding)
- T04 (this commit) — all-copy 24 h enforcement replacing the
14-day default / 30-day case cap for photo bytes (M01/M04):
append-only
000029(received_atfirst-receipt stamp, backfilled fromcreated_at, sweep index; old media goes overdue on the next pass, no deadline reset);RecordVerifiedpersists the VERIFYING instant; sweeper deletes finals past first-receipt + 24 h (extensions no longer move bytes; their columns stay as audit history); quarantine 24 h and 90-day hash purge unchanged (hashes under the separate privacy review, M06); at-deadline read denial inops evidence-urleven when bytes still exist;AuditOverduefailing-policy signal + reserve intake breaker (503 while overdue copies exist); restore replays the same convergent sweep before traffic (recovery runbook already requires retention first); DB backups carry keys/hashes only — photo bytes live in object storage outside backup scope by construction.
What changed
000029_evidence_received_at.sql+sqlc.yamlevidence stanza +evidence.sql(InsertObject.received_at,StaleFinalCandidates/OverdueFinalsonCOALESCE(received_at, created_at),GetObject.received_at).domain.ObjectRef.ReceivedAt+ReceivedOrCreated.adapters/store.go—ObjectData.ReceivedAt,RecordVerifiedpersists it,StaleFinalCandidatesmaps it, newOverdueFinals.application/sweep.go—CopyRetention24 h single deadline,FinalDueon first receipt ignoring extensions, newAuditOverdue/OverdueReport.application/reserve.go— optionalPorts.Enforcementbreaker before quota burn +ErrEnforcementUnhealthy.adapters/http/http.go— 503evidence.enforcement-unhealthymapping.adapters/jobs/verify.go—ReceivedAt: sess.UpdatedAt(completion intent = first receipt).cmd/api/main.go— breaker wired toOverdueFinalslimit 1.cmd/ops/evidence.go—evidenceCopyExpireddenial +evidence_test.go(deadline edges, backfill fallback, zero-stamp open).docs/operator/retention.md— hourly sweep row now reads every-copy 24 h.- Tests: rewritten
TestFinalDuePolicy(24 h, deadline edge, extension ignored, backfill fallback),TestAuditOverdue, breaker test, PGTestPGReceivedAtAnchorsDeadline(stale + overdue select, delete convergence) andTestPGReceivedAtFallsBackToCreated(NULL stamp path).
RED → GREEN
- RED proven by restoring the old 14-day
FinalDuerule: the 25-hour-due, extension-ignored and backfill cases fail; GREEN on restore.
Validation (exact commands, this host)
cd backend && GOTOOLCHAIN=go1.27.1 go build ./... && sqlc vet && sqlc generate
gofmt -l internal/modules/evidence cmd/api cmd/ops
GOTOOLCHAIN=go1.27.1 go vet ./internal/modules/evidence/... ./cmd/ops/ ./cmd/api/
GOTOOLCHAIN=go1.27.1 go test -count=1 ./internal/modules/evidence/... ./cmd/ops/
export ANPFUEL_TEST_DATABASE_URL=postgres://anpfuel:[email protected]:5434/anpfuel?sslmode=disable
GOTOOLCHAIN=go1.27.1 go test -count=1 -race -tags=integration ./internal/modules/evidence/...
git diff --check
Outcome: build + sqlc vet clean (sqlc generate no diff
beyond the new queries); unit green (rewritten policy,
audit, breaker, ops expiry); -race integration green
(incl. received-at select/overdue/convergence + NULL
fallback); gofmt/vet/diff --check clean; secrets scan
clean.
Limits (not claimed)
- Worker-RSS matrix on P12 devices stays release-horizon (host-RSS evidence in T03).
- Hash 90-day bound unchanged (separate privacy review, M06).
- No live-R2 overdue drill (synthetic storage fakes + PG).
Rollback
Migration 000029 is additive (column + index + backfill);
code rollback = revert policy/store/read/breaker additions and
docs. Old columns stay; v1 14/30-day semantics do NOT return
without a new reviewed change.
Next
P15-T05 media privacy and device acceptance (#38, same branch). Issue #37 stays open until the phase PR merges.