carlos / platform Public
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.prevexcluded 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_protocolfromseeds.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 >= 1from 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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,StateRolledBackwith 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") andSeedSourcewith every spec §3.2 field.(*SeedSource).Import() bool,(*SeedSource).Abandoned() bool,(*SeedSource).BlocksRun() bool(an import not yetcommitted; for the run series' admission, run spec §5.1 step 9),(*SeedSource).MoveBlock() stringreturning"",SeedMoveUnplacedorSeedMoveUncommitted(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.