Where the crash lands decides what recovery does
idle
staged
handing-over
running-experiment
readback
promote intent
the point of no return
promoted
rolled-back
Before promote intent: restore stableStop any candidate, start stable again, resume parked work, record rolled-back. Exit 1, and the stable bytes were never touched.
After promote intent: replay the commitFinish the rename of experiment to stable, resume work, record promoted. Idempotent, so a crash during recovery is handled the same way next time.
Recovery never starts a new upgrade. It takes the same lock, checks the operation id, fences the previous controller, then follows the journal.