diff --git a/docs/plans/2026-04-17-deploy-pipeline-multi-env-design.md b/docs/plans/2026-04-17-deploy-pipeline-multi-env-design.md index 07ddcc8b..21a3d3d8 100644 --- a/docs/plans/2026-04-17-deploy-pipeline-multi-env-design.md +++ b/docs/plans/2026-04-17-deploy-pipeline-multi-env-design.md @@ -161,3 +161,4 @@ D2, D3, D4 all gated on D1 merging. D3 runs before D4 so any tutorial gaps surfa - Full prod in DND. - Approval-gated promotion pattern docs and example. - GHCR publish removal in BMW (post two clean prod deploys). +- **Native image-registry retention in `wfctl infra`.** Downstream consumers (buymywishlist, workflow-dnd, core-dump) currently run per-repo `.github/workflows/registry-retention.yml` workflows that call `doctl registry garbage-collection start` + tag-pruning bash + `actions/delete-package-versions@v5` for GHCR. This logic is duplicated across every consumer repo and re-implemented per provider. Engine work: add retention fields to `infra.registry` module schema (`retention_policy: { keep_latest: 20, untagged_ttl: 168h, schedule: "0 7 * * 0" }`), wire `wfctl infra gc` or a scheduled `step.registry_gc` that calls the provider-native GC endpoint (DO, ECR, GCR, ACR) plus tag pruning based on `keep_latest`. Downstream consumers then drop their retention workflow and declare retention in `infra.yaml`. DO's `doctl registry garbage-collection start --force --include-untagged-manifests` maps cleanly; ECR has lifecycle policies (JSON); GCR has retention policies (JSON). Schema should be provider-agnostic and delegate to plugin.