console: ConvertRetirementKind, the durable change of a pending normal retirement into a cleanup one
Only normal -> cleanup, only while the row is pending, carrying the corrupt body's ETag: the body a retirement was about to tombstone turned out corrupt, so the slot retires first and the body is removed on that ETag.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+14
−0
internal/console/lifetimes_store.go+14 −0
diff --git a/internal/console/lifetimes_store.go b/internal/console/lifetimes_store.go| index 19f3cfbda..cde3094dd 100644 |
| --- a/internal/console/lifetimes_store.go |
| +++ b/internal/console/lifetimes_store.go |
| @@ -248,6 +248,20 @@ func (s *Store) BeginCancellingRetirement(r Retirement, voidAllocation string) e |
| return tx.Commit() |
| } |
| +// ConvertRetirementKind is the durable change of a pending normal retirement |
| +// into a cleanup one, carrying the corrupt body's ETag (self-serve moves plan |
| +// 1, Task 4): the body that was to be tombstoned turned out corrupt, so the |
| +// slot retires first and the body is removed on that ETag. Only normal -> |
| +// cleanup is allowed, and only while the row is pending. |
| +func (s *Store) ConvertRetirementKind(opID, kind, recordETag string) error { |
| + if kind != retireCleanup { |
| + return fmt.Errorf("console: a retirement converts only to %s, not %q", retireCleanup, kind) |
| + } |
| + res, err := s.db.Exec(`UPDATE record_retirements SET kind = ?, record_etag = ? WHERE op_id = ? AND state = ? AND kind = ?`, |
| + kind, recordETag, opID, lifetimePending, retireNormal) |
| + return oneRow(res, err, "pending normal record_retirements", opID) |
| +} |
| + |
| func (s *Store) SetRetirementState(opID, state string) error { |
| return s.setState("record_retirements", opID, state) |
| } |