carlos / platform Public

plan: offline move manifest has Owner and Source; transition names OfflineOpenTransition and OfflineFinishingTransition

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev bf59a3c4a80bb9ac56b9e65e454a96f1f7fa7ee7 parent 8cbf503
1 file changed, +5 −3
  • docs/superpowers/plans/2026-10-20-offline-operator-move.md +5 −3
diff --git a/docs/superpowers/plans/2026-10-20-offline-operator-move.md b/docs/superpowers/plans/2026-10-20-offline-operator-move.md
index 2d98a7c1b..ce49ded67 100644
--- a/docs/superpowers/plans/2026-10-20-offline-operator-move.md
+++ b/docs/superpowers/plans/2026-10-20-offline-operator-move.md
@@ -67,6 +67,8 @@ Three layers, in this order, each checked by evidence before the next step. Fabl
| `receipts` | `move-receipts/<host>.json` in the source bucket | cleared at `finish` (`clearMoveReceipts`) | none needed (self-checking) |
| `class` | kind, addr, fleet, pool, hibernate, replica, replicas, steering, unit, seed, open run | refused at the door (`moveGate` plus the transition) | door tests |
+Each row has two fields. `Owner` is the step that proves the item where it must end up, and exactly one step owns each row; the `open` door requires every `landing`-owned item OK in the target's report. `Source` is the step that reports the item's expected value on the source side; the `flip` door requires every `Source: seal` item OK in the sealer's report (`SourceItemsOK`). The carried outage items (`db`, `lease`, `files`, `env`, `timers`, `next-due`, `replication`) are `Owner: landing, Source: seal`: the sealer records what it copied and the target proves it arrived equal, so `open` cannot pass on a target that lacks them. `db-tail`, `build-state` and `sidecar` are `Owner: seal` (only the source can say). `TestOfflineManifestIsCovered` pins each id's pair.
+
## States, failures, and what the operator runs
`record.move` is `{kind: "offline", id, from, to, state, sealer, boxes, source{...}, requested_by, requested_at, updated_at}`. All fields are additive.
@@ -289,13 +291,13 @@ func OfflineSeal(id, sealer string, boxes []string) func(*Record) error
func OfflineSealedBy(id, sealer string, src MoveSource) func(*Record) error
func OfflineFlip(id string) func(*Record) error // Region = To
func OfflineLandedBy(id, to string) func(*Record) error // guarded by record region == to
-func OfflineOpen(id string) func(*Record) error
-func OfflineFinishing(id string) func(*Record) error // from open
+func OfflineOpenTransition(id string, now time.Time) func(*Record) error // the state constant owns the name OfflineOpen
+func OfflineFinishingTransition(id string) func(*Record) error // from open; the state constant owns OfflineFinishing
func OfflineAbort(id string) func(*Record) error // landing/landed: Region = From
func OfflineFinish(id string, now time.Time) func(*Record) error // from finishing (done) or reverting (aborted); LastMove set
// moves
-type OfflineItem struct{ ID, Item, Disposition, Owner string } // Owner: door|seal|landing|none
+type OfflineItem struct{ ID, Item, Disposition, Owner, Source string } // Owner: door|seal|landing|none; Source: seal or ""
var OfflineManifest []OfflineItem
type OfflineReport struct {
V int; Op, Host, Box, Role, Phase string // role: source|sealer|target; phase: stopped|sealed|landed|opened|parked|gone|lifted|reverted|failed