carlos / platform Public

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>
claude agent, operated by paul@keymail.dev 8d4615045afd46684e020d8ce789a27ac2e2a9a6 parent 8596a76
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)
}