# Seeded Instances Implementation Plans: Index

> **For agentic workers:** this file is the map. Each plan it names is a
> self-contained implementation plan with the superpowers header; execute
> them in the order below with superpowers:subagent-driven-development or
> superpowers:executing-plans. Do not start a plan whose dependencies are
> not merged on `main`.

**Goal:** Build `carlos instances create --from` (#260) and the import door
(#261) from the seeded-instances design, as an ordered series of plans that
each produce working, tested, mergeable software.

**Spec:** `docs/superpowers/specs/2026-10-08-seeded-instances-design.md` rev
7 (Astra accepted round 7, `CODEX-FINDINGS-RUN-AND-SEEDED-R7.md`; Paul
approved). Every disposition in its §11 to §16 is a requirement here. The
companion `2026-10-08-carlos-run-design.md` (#259) is built by its own
series (`2026-10-08-carlos-run-*.md`).

**Build target:** `main` at 4a51a6da or later. Every name these plans cite
was read at that commit on 2026-10-08.

**Copy deck:** `2026-10-08-seeded-instances-copy.md`. Plan 1 puts it through
Paul's copy review. No later plan wires a string before that review lands.

## The switch: the seeds floor

There is no feature flag. The seeds floor (spec §3.3) is the switch:

- every console door that writes seed state first checks that every box in
  the home region reports the floor armed, `carlos.prev` excluded or
  seed-capable, the nested layout and no claim control (Plan 3 Task 5); the
  import door also requires a one-box region (a deviation, Plan 3 Task 5);
- a box reports `seeds_protocol` from `seeds.ProtocolVersion`, which Plan 3
  introduces at **0** and Plan 8's Task 6 raises to **1**, once the box
  can place, swap and roll back, refuses moves of an unplaced or
  uncommitted seed, and the console sweeps and assigns;
- the console requires `seeds_protocol >= 1` from every box.

So Plans 2 to 7 merge dark: no box running their builds can claim to be
seed-capable, and no operator can publish a floor that a box would arm in a
way that lets a door through. Plan 8 completes the console side. Rollout
(spec §10) needs Paul.

## The series

| # | plan | produces | depends on |
|---|---|---|---|
| 1 | [`2026-10-08-seeded-instances-1-copy-deck.md`](2026-10-08-seeded-instances-1-copy-deck.md) | the copy gate `approved_seeded_copy_test.go`, Paul's review of the deck, every row approved | nothing |
| 2 | [`2026-10-08-seeded-instances-2-record.md`](2026-10-08-seeded-instances-2-record.md) | `internal/seeds` (ids, keys, states, the verify token), `provision.SeedSource` on the record, the guarded seed transitions, the field protected from ordinary writers, the move and run predicates | 1 |
| 3 | [`2026-10-08-seeded-instances-3-floor.md`](2026-10-08-seeded-instances-3-floor.md) | `control/seeds-protocol.json`, the box's local seeds floor and `carlos.prev` verdict, both system units, the activation rule, the edges-file fields, the console's region readiness check, `carlos system seeds-floor publish` | 1, 2 |
| 4 | [`2026-10-08-seeded-instances-4-placement.md`](2026-10-08-seeded-instances-4-placement.md) | the registry's `seed_source` column, reconcile's seed-state dispatch for `--from` records, the plain-path restore fallback with the `<db>.seed` marker and the purge, the first-upload `placed` CAS and the seed-ID-scoped snapshot delete, refusal on flat and claim-armed boxes | 2 |
| 5 | [`2026-10-08-seeded-instances-5-from.md`](2026-10-08-seeded-instances-5-from.md) | `resolveDBSource`, the instance-role gate, `RestoreTo` with a TXID target, the last-LTX-header size, the scratch reservation pool and shared limits, reserve then upload then publish, private-storage rules with the seed ID on the store, `--from` and `--at` in the CLI, the list cell | 2, 3 |
| 6 | [`2026-10-08-seeded-instances-6-import-door.md`](2026-10-08-seeded-instances-6-import-door.md) | begin, upload, stopped, commit and abort, the delete refusal, the console's finish of an abandoned seed (`finishSeed`: seed-ID-guarded store teardown, record deleted last), `carlos instances import` with `--verify`, `import commit` and `import abort` | 2, 3, 5; Task 5 also needs the run series' `Record.ActiveRun` |
| 7 | [`2026-10-08-seeded-instances-7-swap-rollback.md`](2026-10-08-seeded-instances-7-swap-rollback.md) | `import_gate` and the `import_journal` table, the operator assignment reader, the journal-first dispatch, the swap transaction with every predicate, crash resume, the gate at the edge and door and in the schedule runner, commit's clear, the fenced rollback, and `cleanup-pending` (the protocol stays 0) | 2, 4 |
| 8 | [`2026-10-08-seeded-instances-8-finish-sweeps.md`](2026-10-08-seeded-instances-8-finish-sweeps.md) | the seeds sweep (stale reservations and imports abandoned by CAS, rolled-back seeds finished, unreferenced snapshots deleted), the move door and worker refusals, `carlos system legacy-routes assign`, `seeds.ProtocolVersion = 1`, the series' last copy-gate check | 5, 6, 7 |

```
main ─► Plan 1 ─► Plan 2 ─┬─► Plan 3 ─┬─► Plan 5 ─► Plan 6 ─┐
                          │           │                      ├─► Plan 8
                          └─► Plan 4 ─┴──────► Plan 7 ───────┘
```

Plans 3 and 4 are independent of each other once Plan 2 lands. Plan 7 needs
Plan 4's registry column and dispatch. Plan 8 needs everything.

## Interfaces shared across plans

Defined once, in the plan named, and used with exactly these names after.

**Plan 2, package `internal/seeds`:**

- `seeds.KindReplica = "replica"`, `seeds.KindImport = "import"`.
- States: `StateReserving`, `StateAwaitingUpload`, `StateUploaded`,
  `StateReady`, `StateSwapped`, `StatePlaced`, `StateCommitted`,
  `StateRefused`, `StateAborted`, `StateRolledBack` with the spec's strings.
- `seeds.MaxBytes int64 = 4 << 30`.
- `seeds.NewID() (string, error)` (`sd_` and 26 lowercase base32 characters),
  `seeds.ValidID(string) bool`.
- `seeds.HostPrefix(host) string` (`seeds/<host>/`),
  `seeds.SnapshotPrefix(host, id) string` (`seeds/<host>/<id>/`),
  `seeds.SnapshotKey(host, id) string` (`seeds/<host>/<id>/snapshot.db`),
  `seeds.ParseSnapshotKey(key) (host, id string, ok bool)`.
- `seeds.NewVerifyToken() (token, hash string, err error)`,
  `seeds.TokenMatches(hash, token string) bool`, `seeds.ClosedGate`.
- `seeds.RowSeed{ID, Kind, SHA256 string; Bytes int64; State string}`,
  `(RowSeed).Encode() string`, `seeds.ParseRowSeed(string) (*RowSeed, error)`,
  `(RowSeed).Placeable() bool` (ready, swapped or placed).

**Plan 2, package `internal/provision`:**

- `Record.Seed *SeedSource` (`json:"seed,omitempty"`) and `SeedSource` with
  every spec §3.2 field.
- `(*SeedSource).Import() bool`, `(*SeedSource).Abandoned() bool`,
  `(*SeedSource).BlocksRun() bool` (an import not yet `committed`; for the run
  series' admission, run spec §5.1 step 9), `(*SeedSource).MoveBlock() string`
  returning `""`, `SeedMoveUnplaced` or `SeedMoveUncommitted` (Plan 8 gives
  each its sentence).
- `ErrSeedConflict`, `ErrSeedProtected`.
- `SetRecordSeed(ctx, s, acct, app, host, mut) (*Record, error)`: one CAS
  on the record's etag, retried once; a retried transition re-checks the
  state, so a commit and an abort racing end with exactly one winner.
- Transitions: `SeedPublishReplica(id, txid, sha string, bytes int64)`,
  `SeedUploaded(id)`, `SeedStopped(id)`, `SeedSwapped(id)`, `SeedPlace(id)`,
  `SeedCommit(id)`, `SeedRefuse(id, reason)`, `SeedAbort(id)`,
  `SeedRolledBack(id)`, `SeedRolledBackBeforeSwap(id)`.
- `SeedColumn(rec Record) string` (Plan 4 uses it for the registry column).

**Plan 3:** `seeds.ProtocolVersion`, `seeds.FloorKey`, `seeds.ReadFloor`,
`seeds.PublishFloor`, the box files `.moves/seeds-floor.json`,
`.moves/seeds-floor.min-release` and `/opt/carlos/carlos.prev.seeds-allowed`,
the edges-file fields `seeds_protocol`, `seeds_floor_min_release`,
`prev_seeds_allowed_for`, and `(s *Server) seedRegionReady(ctx, region string, oneBox bool) *doorRefusal`.

**Plan 4:** `registry.Route.SeedSource` (column `seed_source`),
`(*Registry).SetSeedSource`, `lease.HasReplica`, `release.NewS3StoreIn`,
`activator.SeedObjects`, `ExecBackend.Seeds`, `ExecBackend.ClaimArmed`,
`ExecBackend.OnSeedPlaced`, `activator.SeedPlacementError`,
`activator.SeedMarkerSuffix`, `provision.SeedHooks{Data}` on
`ReconcileConfig.Seeds`.

**Plan 5:** `(s *Server) resolveDBSource`, `dbdoor.RestoreToTarget`,
`dbdoor.PlanRestore`, `dbdoor.ErrHistoryGone`, `seedScratch`, `replicaDoer`,
`Config.SeedData`, `Config.SeedScratchDir`, `objstore.Declared.Seed`,
`seedCreate`, `seedStoreRefusal`, `abortSeedQuietly`.

**Plan 6:** `(s *Server) finishSeed(ctx, sqid, app, host, seedID string) error`.

**Plan 7:** `registry.Route.ImportGate` (column `import_gate`), the
`import_journal` table with `registry.ImportJournal` and its five
transactions, `registry.OpsAccountSqid`, `registry.ImportGateClosed`,
`seeds.LegacyOwnersKey`, `seeds.ReadLegacyOwners`, the `SeedHooks` swap and
rollback hooks.

**From the run series (#259):** `provision.Record.ActiveRun *RunState` with
`RunState.State` in `queued | picked | cancel | done | cancelled | expired`
(run spec §5.1). Plan 6 Task 5 reads it; if the run series' record task has
not merged, Plan 6 Task 5 waits for it. The run series uses
`(*SeedSource).BlocksRun()` from Plan 2. If the run series lands a minimal
`SeedSource` first, Plan 2 Task 2 extends that type instead of declaring it.

## What these plans do not build

- The claim algorithm of spec §3.4 (#250). Every claim-armed box and console
  refuses.
- `--at <time>` (spec §4 step 4, codex R2-18).
- Titogo's half of the conversion (spec §10 step 5).
- Rollout steps (spec §10), which need Paul's go at each step.
