---
id: w2/m10/t001
title: Deploys rows record a rollback target — image ref/digest + restorable spec fields
worker: worker2
status: todo
estimate: 30m
depends_on: []
---

## Objective

A rollback needs something to roll back **to**: extend the deploys table so every new deploy records its target — the resolved image reference (digest-pinned where the build pipeline knows it; tag otherwise, honestly marked) plus the spec fields a rollback must restore (image/repo+revision, env-relevant knobs the deploy snapshot owns — decide and document the exact set; keep it minimal: rollback restores *what ran*, not workspace config). Migration + capture at deploy-creation time in the existing recording path.

## Context

- `lego/backend/internal/deploys/` (m5's recorder) + `internal/store/migrations/` (next free migration number — scan first).
- Build-from-git deploys: the BuildKit path pushes to Zot — record the pushed reference; the digest is available from the push. Image-backed deploys: record the spec's image as-is.
- Old rows predate the column — rollback to them is refused with a clear error (no fabricated targets).

## Steps

1. Migration: `rollback_target` columns (or a JSONB doc — pick, justify in the migration comment).
2. Capture in the deploy-recording path for both build-from-git and image deploys.
3. Typed read accessor for t003.

## Files

- `lego/backend/internal/store/` (migration + row model)
- `lego/backend/internal/deploys/` (capture)

## Acceptance criteria

- [ ] New deploys carry a non-empty target (digest-pinned when the build knows it); pre-migration rows read as target-less and are refused by rollback with a named error.

## Out of scope

- The verbs (t002/t003); retention interplay (targets live and die with their deploy rows).
