Technical Migration Plan Template
Every rollback closes on a nameable event. This plan puts that window in hours beside each check's detection time, then reports which checks still fit.
Free download · No account needed
Every migration plan has a rollback section. Almost none of them says when the rollback stops working, and it always stops working. The moment the new cluster takes its first write, the moment the old version's artifact is garbage collected, the moment a retention boundary passes. So on day three, when the problem surfaces, nobody has worked out whether going back is still possible. It usually is not, and the moment it stopped being possible had a name.
The reference tooling is blunt about this. Postgres' upgrade documentation ships a six-branch revert tree keyed on which mode ran and whether the new cluster was started, and two branches end in restoring from backup. Kubernetes says that once an old ReplicaSet is deleted you lose the ability to roll back to that revision, keeping ten by default. A stock blue-green rollout scales the previous version down after thirty seconds. None of that is unusual, and none of it appears in a migration plan.
So a rollback is a window, and every window is a number. This pack derives it from the ending event, then joins it to each validation check's detection time. Harlow Grid's worked plan has nine phases and fourteen checks. Seven checks can trigger their own rollback. The daily billing reconciliation needs a billing cycle, so it answers twenty-six hours after a cutover whose rollback lapses in eight. It was filed under cutover validation, where it had sat unexamined for a month.
What comes in the pack
Sequencing register with the ending event beside the window
One row per phase. Rollback Ends When names the event: the reverse slot falling outside write-ahead log retention, the old ReplicaSet being garbage collected past the revision limit, the promotion delay expiring, the backup ageing out. The hours follow from the event rather than the other way round, because the event can be changed and a guessed number cannot. Unbounded is a real value and four of the nine worked phases carry it, which is what lets attention go to the five that do not.
A rehearsed column, because an unrehearsed rollback is a paragraph
Rehearsing tells you two things nothing else will: whether the rollback works and how long it takes. The second is the number the window has to accommodate, and a six-hour rollback inside an eight-hour window is two hours of decision time rather than eight. Four of the nine worked rollbacks have a rehearsal date, one is recorded as not needed, and four have never been run. They are the last four, which is the ordinary pattern and runs exactly opposite to where the stakes are.
Validation Checks that are comparisons, not a checklist
Every row carries a baseline measured on the old system on real traffic before anything moved, with its source and date, beside the threshold and the reading. Eleven of fourteen worked checks have one. The three that do not read "the system is stable," "performance is acceptable under load" and "nothing depends on the old cluster," and none of them can fail. That outcome has a name in the reference tooling rather than being a rhetorical point.
The join, which is the whole reason detection time is a field
Detection time is hours from the phase landing to the check producing a verdict that means anything, not how long the query runs. Set it beside the phase's window and one column falls out: can this check trigger the rollback it exists to trigger. Seven of fourteen can. The monthly invoice comparison answers 736 hours after its rollback ended, which is thirty days and sixteen hours, and it is still a good check. It was never a gate.
Risk Register that inherits the join
Every risk names one check and one rollback by identifier, and the sheet reports whether detection lands while the rollback still exists. Five of twelve worked risks do. Four are detected only after it expired. Three have no detection at all, because their check has no baseline. Four risks are critical and three of those four are in the second or third group, which is a sentence nobody would sign off if it were on the front page, so it is on the front page.
A runbook, a per-phase rollback procedure and a comms plan keyed on the phase
The cutover runbook names one person who calls the rollback and decides the no-go readings in advance, because at 02:40 with a graph moving the wrong way nobody invents a threshold well. The rollback procedure has nine sections rather than one, since there is no such thing as the rollback for a migration. Every notice states the window in hours, which is the line that gets replies from integration partners. The decision to migrate at all belongs upstream, in an architecture decision record.
How it works
- 1
Send the architecture and the config
Current and target state, the dependency map, traffic data, a runbook draft. River also goes looking for the two things that set every window and nobody sends: retention settings, and the revision-history and scale-down configuration.
- 2
Phases are cut by their rollback
A phase is a change that can be undone as a unit, so the test is whether reverting half of it leaves a state nobody thought about. Then they are ordered with the unbounded rollbacks first and the one-way phases as late as the dependencies allow.
- 3
Every window is derived from its ending event
River reads the effective configuration rather than the documented default, names the event, and computes the hours. It also names the single change that would most extend the tightest window, which is usually one setting on a system being decommissioned anyway.
- 4
Then the join tells you what you have
Each check gets a baseline, a threshold and a detection time, and the coverage columns compute. You get the count of real gates, the risks nobody could catch in time, and the checks that cannot fail. Reconstruct an undocumented system first if you need to, with inherited architecture reconstruction.
Frequently asked questions
Why does a rollback need an expiry date?
Because it has one whether you write it down or not. Postgres' revert instructions branch on whether the new cluster was ever started, and if it was in link mode the old cluster is unsafe and has to come back from backup. Naming the event is what turns that from a surprise into a number.
How do you get the window in hours?
From the ending event, by reading the effective configuration rather than a default. Write-ahead log retention gives a reverse-replication window. Backup retention gives a restore window. A promotion delay gives a traffic-shift window, and the stock default is thirty seconds, which is worth knowing before you rely on it.
What if a rollback genuinely never expires?
Record it as unbounded, which is a real value, and never put a false clock on it. Four of the nine worked phases are unbounded: a cluster nobody has written to, an expand-only schema change with nothing reading the new columns, a deployment behind a preview service. Knowing which four is what lets you spend attention on the rest.
Why can't a check without a baseline fail?
Because there is nothing for the reading to contradict. "Performance is acceptable" admits no measurement that disproves it. Argo Rollouts evaluates against a success condition and a failure limit declared before the rollout, and names the outcome when neither resolves: Inconclusive. Three worked checks sit there before the migration has started.
What do I do about a check that answers too late?
Three honest responses. Extend the window, which is usually one retention setting on a system being decommissioned anyway. Shorten the detection by running the check as a shadow against both systems before cutover. Or accept in writing on the row that the recovery is a forward fix. What is not honest is leaving it under cutover validation.
Is a rollback window the same as an outage budget?
No, and conflating them is why the number goes missing. A window is how long the option to go back exists. How long you will tolerate being broken before using it is a separate and usually much shorter number. The rollback's own duration is a third. All three go on the row and they answer different questions.
Does this replace the design document for the migration?
No. Proposing the change belongs in an RFC register, and the target architecture belongs in a solution architecture document. This pack starts once the destination is agreed and the only remaining question is whether you can get back.
Find out which rollback you no longer have
Send the architecture and the config. River derives every window from its ending event, then reports which checks still fit.
Install the migration plan pack