carlos / platform Public
| Finding | Disposition at fc86ce19 | |---|---| | R2-4 — Rollback fence retry and cold-host stop proof | Fixed at spec level. Seeded §5.6 distinguishes its own fence, defers on another operation’s fence, and defines the evidence required for a cold host. | | R3-1 — Rollback forgets unfinished replica cleanup | Fixed for the reported crash gap. cleanup-pending retains recovery until bucket cleanup finishes. A separate hostname-reuse race appears below. | | R3-2 — Sweep deletes a snapshot during creation | Fixed. Seeded §4 reserves the record before uploading; §3.1 requires a terminal CAS before abandoning that reservation. | | R3-3 — Disconnected caller leaves queued work open | Fixed. Run §5.8 assigns queued expiry, audit completion and reservation release to the console sweep. |
- P1 — Seeded §§5.6–5.7: resumed rollback can delete a replacement import’s snapshot.
Abort import A. Complete bucket cleanup and delete A’s record, then crash before deleting its journal—between steps 7 and 8. While the box is down, begin import B at the same hostname and upload its snapshot. On restart, A’s cleanup-pending journal resumes at step 6 and deletes seeds/<host>/, including B’s accepted snapshot. The seed-ID check at step 7 protects B’s record only; its data has already been deleted.
This reuse is possible against the existing creation code: the leftover check examines replica and move-staging prefixes (createleftovers.go:69), while CreateRecord conditionally creates the bucket record without consulting a box-local journal (provision.go:845). Once A’s record and replica are gone, neither check prevents B.
Fix: keep the aborted record as the hostname reservation until cleanup authority has been retired. Complete bucket cleanup, retire the journal, then delete the matching record last. Recovery after journal retirement must remain safe and idempotent. Alternatively, scope every cleanup deletion to immutable objects belonging to A’s seed ID.
- P2 — Seeded §§2.3, 3.1–3.4: a move can strand a seed before its first placement.
Create a --from instance, let reconcile mint its route, and move it before its first wake. Its seed is ready; its database exists only under seeds/<host>/ in the home bucket. No specified seed-state guard prevents the move.
With the moves switch off, the existing legacy move door remains active (apiinstancemove.go:399). Its transition admits an ordinary instance without requiring a database (provision.go:1146). The worker mirrors only the replica prefix and treats a zero-byte gap as ready (movespass.go:815); it skips checkpointing an absent local database and then completes the region flip (movespass.go:919).
The destination consequently receives neither replica nor seed snapshot. Under §3.4, its first wake must fail.
Fix: refuse move admission until a replica seed is placed, and until an import is committed. Apply that predicate under the record CAS and in the move worker before effects. Supporting earlier moves would instead require explicitly transferring seed ownership and, for imports, rollback responsibility.
carlos run: accept.
Seeded instances: revise.