Hands-On Labs · The Capstone · Part 4 of 5

Capstone Part 4 — The Data Move & the Cutover Runbook

Parts 1 to 3 were decisions on paper. This is the part where something actually has to happen on a specific Sunday at a specific hour, and 22 clinics open on Monday whether you finished or not. You’ll do the arithmetic that decides how 50.2 terabytes physically travel — in the open, with every unit conversion shown — then write the minute-by-minute runbook for the single hardest cutover in the estate, and finally the rollback plan that answers the only question that matters at four in the morning: what happens to the clinical notes that were written twelve minutes ago and exist in exactly one place?

☺ Explain it like I’m 10

You’re moving house on Sunday night, and the family has to be able to live normally on Monday morning. Two questions decide everything. First: forty-one thousand boxes won’t fit through the letterbox, so do you post them one at a time for a month, or hire a lorry? Second: once you’ve handed the old keys back, what exactly do you do if the new house’s lights don’t come on — and what about the homework someone already did on the new kitchen table, which exists nowhere else in the world?

🐘🐢Your hosts for this part: Ellie the Elephant & Timmy the Turtle — Ellie never drops a box, so she owns the 50.2 TB and every check that proves it arrived intact; Timmy doesn’t trust a cutover until something has actually verified it, so he owns the go/no-go gates and the way back. 🐦 Pip the Hummingbird flies in for the link arithmetic, and 👺 Gizmo is on the bridge call at 03:55 whispering “we’re nearly there.”
⚠ Where you’re starting, and what you’ll have when you’re done

Starting: a disposition matrix from Part 1, a landing-zone design from Part 2, and a wave plan from Part 3 that puts ImageVault’s bulk seed in month 2 and PIMS-Core’s cutover in Wave 4. Leaving this page: three finished documents — a data-movement plan covering every dataset in the estate with a named validation step and a named signer; a cutover runbook for PIMS-Core, minute by minute, that fits inside a four-hour Sunday window with an hour of slack; and a rollback plan with an explicit point of no return, a wall-clock deadline, and a named person allowed to call it. Part 5 picks up the morning after and asks what all of this costs.

You need a spreadsheet and a text editor. Nothing else. No cloud account, no card, no infrastructure. Real tools are named throughout as “this is what you’d reach for” — none of them is required to finish this page.

What this part assumes, and what it produces

☺ Like you’re 10: Three earlier pages made the decisions. This page turns three of those decisions into things you could hand to someone on a Sunday night and they’d know what to do.

This part is written to follow Part 3, but it is deliberately self-contained: every fact about the estate that this page needs is restated below, so you can work it cold. If you have done the earlier parts, use your own answers where they differ from the ones here — the method is what’s being practised, not the specific R you chose.

The three things Parts 1–3 were supposed to leave behind

FromThe decision this part depends onIf you skipped it, assume this
Part 1Which datasets travel at all — because the cheapest terabyte to move is the one you already decided to retire.FileShare’s cold 40% and 31 of BI-Reports’ 40 reports are Retire. Everything else in the table below travels.
Part 2A destination that exists, with non-overlapping CIDRs, hybrid connectivity, identity, and a static egress address for LabBridge.Landing zone live from month 1; site-to-site VPN up; DNS for brambleside.internal served from the cloud with on-prem forwarders.
Part 3When each thing moves — and specifically that ImageVault seeds in month 2 even though PIMS-Core doesn’t cut over until Wave 4, month 8.Wave 0 = foundation (month 1). Wave 4 = PIMS-Core + ImageVault path flip, a Sunday in month 8 (February).

What you will produce

◆ Key idea

These three artifacts are one document in three parts, and they are written in this order for a reason. The data-movement plan decides how long the bulk takes, which decides what is already in place on the night, which decides how short the cutover can be, which decides how much you might have to hand-carry back. Reverse the order and you end up designing a four-hour window around a copy job that needs thirty-four days.

The estate, restated — only the parts that move bytes

☺ Like you’re 10: Here’s the full list of boxes, how big each one is, and the rules about when you’re allowed to be carrying them.

Brambleside Veterinary Group runs 22 small-animal clinics plus one 24-hour emergency hospital, around 600 staff, all in one country. Everything currently lives at Fort Rusty: VMware vSphere 7 across a converted server room at the flagship clinic and eight racks in a colo 40 km away. The colo contract ends 31 March — month 9 of a nine-month programme, and there is no renewal beyond a three-month extension at 2.4× the rate.

The stated data footprint — 50.2 TB

SystemDataShapeThe fact that decides how it travels
ImageVault — X-ray/ultrasound archive since 200441 TB
1,502,384 studies (~28 MB each)
+900 GB/month
Aging NAS in the colo, SMBPIMS-Core references every study by UNC path. 78% of studies untouched in 24 months. Reads must never break.
FileShare — staff file server6.2 TB
1,100,000 files across ~140,000 folders
mean 5.6 MB, median 340 KB
Windows file server, NTFS ACLs40% of the bytes untouched in 5 years. A full enumeration pass with ACLs takes 3.5 hours — file count, not size, is the constraint.
PIMS-Core — appointments, clinical notes, billing1.9 TB4 × Win Server 2016 + SQL Server 2016 Enterprise clusterUsed every minute in every clinic. Downtime tolerance ≤ 4 h, Sunday 02:00–06:00 only, never a Monday.
BI-Reports — SSRS, 40 scheduled reports400 GB1 VMThe audit log proves 31 of the 40 haven’t been opened in 18 months. Only the 9 survivors’ history needs to travel — roughly 60 GB.
ClaimsFeed — nightly insurance claims via SFTP280 GBOracle Database 12c SEMay miss one night. Licence renewal due month 7 — which is the whole reason it replatforms rather than rehosts.
VetLearn — internal CPD portal220 GB1 VMRepurchased to the vendor’s SaaS. The export goes to the vendor’s importer, not into your landing zone — but it still crosses the same link.
StockCtrl — consumables + controlled-drug register140 GBVendor app on SQL ServerControlled-drug register carries a 7-year retention obligation that survives the migration.
BramblesideOnline — site, booking, repeat scripts90 GB2 VMs + MySQL 5.7MySQL 5.7 is out of support — the version jump is the work, not the bytes. Downtime tolerance ≤ 2 h.
RotaMaster — staff rota~15 GB export
(not part of the 50.2 TB)
Classic ASP, Win Server 2012 R2Repurchased. Only a CSV bundle travels; the application is retired in place.
LabBridge · AD-DC01/02 · PrintSrv · BackupVault · DevTestno material data of their ownVMs, tape libraryLabBridge needs a fixed public egress IP. PrintSrv and AD are Retained on-prem for now. The tape library holds the 7-year finance retention.

The four constraints that decide this whole part

ConstraintThe numberWhat it forbids
The linkColo circuit is 500 Mbps but contractually shared. Brambleside can sustain at most 150 Mbps without burst charges.Any plan that assumes 500 Mbps. Any plan that saturates 150 Mbps for weeks while 22 clinics are also using it.
The windowPIMS-Core: ≤ 4 hours, Sunday 02:00–06:00 only, never a Monday. BramblesideOnline ≤ 2 h. ClaimsFeed may miss one night. ImageVault reads must never break.Any cutover whose happy path uses more than about three hours. You need slack, and slack has to be designed in, not hoped for.
The blackoutsNo cutovers during the two-week spring vaccination campaign (mid-March) or 20 Dec – 3 Jan emergency-cover period.December and March. Which is why Wave 4 lands in February — month 8: after Christmas, before the campaign, six weeks clear of the 31 March hard stop.
The clockColo contract ends 31 March. Extension only at 2.4× the rate.Any bulk transfer that isn’t finished with months to spare. A 34-day copy that starts late has no second attempt.
⚠ On the numbers

Every figure on this page — sizes, transfer rates, shipping durations, row counts — is invented for the exercise, and Brambleside Veterinary Group is a fictional company. Real link goodput, real appliance logistics and real cloud pricing all change constantly. The skill being practised is the method: convert units explicitly, compare paths on both wall-clock and link cost, and write the answer down where someone else can check it. Never carry a number from this page into a real business case.

Artifact A — the data-movement plan

☺ Like you’re 10: Sort every box into “goes on the lorry”, “goes through the letterbox”, and “doesn’t go at all” — and write down how you’ll know it arrived.

Start with the arithmetic, because the arithmetic is the only part of a migration that gives an unambiguous answer. Everything else is judgement; this is a division problem, and a division problem that nobody does in the open is a division problem that gets guessed.

Step 1 — do the 41 TB sum, showing every conversion

The single question this part exists to answer: can ImageVault go over the wire? Do not reach for a rule of thumb. Do it properly, one line at a time, so that anyone reading your plan can find the step they disagree with.

ImageVault over the wire — the full working

  1.  41 TB                                   the archive, as it stands today
  2.  41 × 1,000            =    41,000 GB    TB → GB   (decimal, as storage is sold)
  3.  41,000 × 1,000        = 41,000,000 MB   GB → MB
  4.  41,000,000 × 8        = 328,000,000 Mb  BYTES → BITS  ← this is the ×8 everyone forgets
  5.  328,000,000 ÷ 150     =  2,186,667 s    at the 150 Mbps we are allowed to sustain
  6.  2,186,667 ÷ 3,600     =      607.4 h
  7.  607.4 ÷ 24            =       25.3 days at a PERFECT, uninterrupted 150 Mbps
  8.  25.3 ÷ 0.75           =       33.7 days at 75% goodput (TCP overhead, retries,
                                             the sync tool's own chatter, checksums)

  ANSWER: ~34 days of continuously saturating a link that 22 clinics also need,
          during which the archive grows by another ~1 TB.

Line 4 is where most people’s estimate silently breaks. Storage is sold in bytes; links are sold in bits per second. If your answer is eight times too optimistic, that is the line you skipped. Line 8 is the second trap: nobody ever gets the sticker rate. Pick a goodput assumption, write it down as an assumption, and be ready to defend it — 75% is a reasonable planning figure for a WAN sync with verification enabled, and if your organisation has measured its own, use that instead.

⚠ Watch out

Thirty-four days is not the problem. Thirty-four days of a shared circuit is the problem. Brambleside is allowed 150 Mbps of a 500 Mbps contractually shared link; above that, burst charges land every month. So the honest reading of line 8 is not “the copy takes five weeks” — it is “for five weeks, nothing else can move, and clinic traffic competes with a bulk job the whole time.” Wall-clock is only half the cost of a transfer. Link occupancy is the other half, and it is the half that gets people shouted at.

Step 2 — cost the appliance round trip honestly

An offline appliance — AWS Snowball, Azure Data Box, Google Transfer Appliance, and each cloud’s equivalents — is a rugged encrypted box the provider ships you. You copy onto it over your own LAN, ship it back, and they ingest it. Its wall clock is dominated by logistics, not by data size, which is exactly why it wins at scale. But it is not free of time, and a plan that says “ship an appliance” without a day count is not a plan.

StageDaysUses the colo link?Needs Brambleside staff?
Order placed → appliance delivered to the colo7NoNo
On-site copy — ImageVault 41 TB at ~200 MB/s over 10 GbE2.4NoYes
On-site copy — FileShare hot 3.7 TB at ~40 MB/s (small files, ACLs preserved)1.1NoYes
Return shipping2NoNo
Provider ingest + checksum verification5NoNo
Total, door to door~18 daysZero4 days

Look hard at rows two and three. FileShare’s hot subset is eleven times smaller than ImageVault and takes 45% as long to copy. That is the file-count trap appearing for the first time — and it appears on your own LAN, before a single byte has gone anywhere near the WAN. If you sized the appliance window on total terabytes, you just under-booked it by a day.

Step 3 — find the crossover, and then distrust it slightly

The crossover is the dataset size at which the appliance stops being slower and starts being faster. It is worth deriving once, for your own link, because after that you can answer the question in your head for every dataset in the estate.

Where does the appliance start winning on wall-clock?

  Over the wire, per TB:   8,000,000 Mb ÷ (150 Mbps × 0.75) ÷ 86,400 s/day
                         = 0.823 days per TB

  By appliance:            14 days fixed (ship out, ship back, ingest)
                         + 0.058 days per TB of local copy (at 200 MB/s)

  Set them equal:          0.823 × S = 14 + 0.058 × S
                           0.765 × S = 14
                                   S = 18.3 TB

  CROSSOVER: just over 18 TB on THIS link with THIS logistics chain.

Now distrust it slightly, in two directions. Downward: at 10 TB the wire technically “wins” at 8.2 days — but that is 8.2 days of a circuit the clinics are sharing, and the appliance would have cost zero of it. Upward: the crossover collapses if you can buy more bandwidth, and it climbs if delivery is slow or your country’s customs are involved. 18.3 TB is a property of Brambleside’s situation, not a fact about the universe. The transferable skill is the derivation, not the number — that is precisely what the Size the Data Move drill exists to give you reps on.

Step 4 — the number that makes the whole plan work

Here is the part people miss. Once the bulk seed has landed, keeping the cloud copy current until Wave 4 does not need 150 Mbps. It needs almost nothing:

The standing sync, month 2 → month 8

  Archive growth:      900 GB/month
  900,000 MB × 8   =   7,200,000 Mb per month
  30 days × 86,400 =   2,592,000 seconds per month
  7,200,000 ÷ 2,592,000 = 2.78 Mbps average
  ÷ 0.75 goodput        = 3.7 Mbps of budget

  ANSWER: under 4 Mbps of your 150 keeps the cloud copy current
          for the six months between the seed landing and the flip.

That is the argument in one line: the appliance converts a 34-day link-saturating problem into an 18-day logistics problem plus a permanent 4 Mbps trickle. And it explains why Part 3 insists the seed happens in month 2 even though the cutover is in month 8. Seed early and you buy six months of cheap, boring, unattended sync. Seed late and either PIMS-Core reads 41 TB back over the VPN for months, or your entire nine-month schedule is hostage to one copy job with no second attempt before 31 March.

◆ Key idea

Seed-then-sync is the shape of almost every large data move: one enormous one-off transfer by whatever means is fastest, then a small continuous one that keeps the copy warm until you’re ready to switch. The on-prem NAS stays authoritative the whole time — a strictly one-way sync, never bidirectional — and only at cutover does the path flip. Two-way sync between an old and a new home is not a safety net; it is two sources of truth, which is one more than you can afford.

Step 5 — the FileShare problem, which bandwidth math will lie to you about

FileShare’s hot subset is 3.7 TB. By line 8 of the arithmetic above that is 3.0 days over the wire — comfortably under the crossover, so the wire should win. It doesn’t, and the reason has nothing to do with bandwidth.

So FileShare gets three answers, not one: the hot 3.7 TB rides the same appliance as ImageVault (it is already going, and the box has room); the final delta uses a change-journal-based mechanism — the NTFS USN journal, or a DFS-R-style replication group — so the last sync reads a list of changes rather than re-deriving one; and the cold 2.5 TB never travels at all, because Part 1 marked it Retire.

🦫 Benny’s workshop · 10 min

Before you read the model ledger, fill in three rows yourself on paper. For ClaimsFeed (280 GB), BramblesideOnline (90 GB) and PIMS-Core (1.9 TB), write: how it travels, how many hours or nights that takes at 40 Mbps (a third of your budget — leaving room for everything else), and one validation check that would catch a silent failure. Then check yourself: does any of those three justify a second appliance? (It doesn’t — and knowing why is the point.)

Step 6 — write the ledger

Now put it all in one table. This is Artifact A. Every dataset in the estate appears exactly once, including the ones that don’t travel, because “we consciously decided not to move this” is a line a steering committee will ask you for and you will not want to reconstruct it from memory.

Artifact A — data-movement plan. One row per dataset. Columns:

  Dataset | Size | File count | Travels? | Path | Why this path
          | Scheduled | Validation on arrival | Signed off by

Rules for filling it in:
  • Every row's "Why this path" must cite a number, not an adjective.
  • Every row that travels must name a validation step that would
    catch a SILENT failure — not just "the job said success".
  • Every row must name a human who signs the reconciliation report.
  • Rows that don't travel still need a "Signed off by" — someone
    has to own the decision not to move something.
Reveal the worked data-movement plan (Artifact A)

Two paths carry everything: one appliance takes 44.7 TB, and the wire takes 2.7 TB spread across seven months. That is 94% of everything that travels going by road and 6% going by wire — and the 6% is what people instinctively worry about.

DatasetSize / countPathWhy — with the numberValidation on arrivalSigned by
ImageVault — bulk, frozen at seed41 TB
1,502,384 studies
Appliance, month 234 days over the wire at 75% goodput vs 18 days door-to-door using zero link. Above the 18.3 TB crossover by a factor of two.Study count matched to the DICOM index; SHA-256 manifest generated at freeze, re-verified after ingest; byte-for-byte compare of 500 randomly sampled studies; 20 named studies opened in the PIMS-Core viewer by a clinician.Migration lead + Head of Diagnostic Imaging
ImageVault — delta, seed → cutover~30 GB/day
~32,000 studies/month
One-way sync over the link, months 2–83.7 Mbps of a 150 Mbps budget. NAS stays authoritative until the path flips.Daily automated reconciliation: studies written on-prem vs studies present in cloud, difference must be zero at 06:00 each day. Three consecutive non-zero days escalates.Migration lead
FileShare — hot 60%3.7 TB
660,000 files
Same appliance, then change-journal sync3.0 days by bandwidth — but 3.5 h per enumeration pass makes a timestamp walk impossible inside any window. USN journal for the delta.File count and total bytes per top-level share; ACL comparison on 50 sampled paths including three known-restricted folders; a list-only (robocopy /L) pass returning zero differences.IT manager
FileShare — cold 40%2.5 TB
440,000 files
Does not travelUntouched in 5 years. Retired per Part 1 — one verified offline archive copy retained, restore-tested once, then the live share is deleted.Archive copy restore-tested end to end before the source is deleted. Deletion evidence captured (file list + hashes) before wipe.IT manager + Finance Director
PIMS-Core SQL1.9 TB
→ ~550 GB compressed
Wire. Compressed full backup seed at T-14d, then log shipping to cutoverUncompressed, 1.9 TB at 40 Mbps is 5.9 days. With SQL Server backup compression at ~3.5×, the seed is 550 GB ≈ 41 hours — under two nights.LSN match source vs target; DBCC CHECKDB clean; the 12 reconciliation queries (below), each against a value recorded at 02:00 from the frozen source.Database engineer + Practice Systems Manager
ClaimsFeed Oracle 12c → managed PostgreSQL280 GBWire. Schema conversion, then CDC21 hours at 40 Mbps — one night. Heterogeneous, so the schema is the work, not the bytes. A managed migration service (AWS DMS / Azure DMS / Database Migration Service) does the conversion assessment first.Row counts per table; SUM() of every money column matched to source; a parallel run — one night’s claims batch generated on both systems and the two output files diffed byte for byte.Database engineer + Finance Director
VetLearn export220 GBWire, to the SaaS vendor’s importer17 hours at 40 Mbps. Repurchased — it never enters your landing zone, but it does cross your link, so it gets a scheduled slot like everything else.Course count and learner-record count reported by the vendor’s import log; 25 sampled learner records checked for completion dates and certificates.L&D Manager
StockCtrl140 GBWire. Backup/restore9 hours at 40 Mbps. Vendor supports cloud hosting, so a straight rehost.Row counts; controlled-drug register reconciled row for row against the 7-year retention requirement — this one is a legal record, so a sampled check is not enough.Head of Clinical Operations
BramblesideOnline MySQL 5.7 → managed MySQL 890 GBWire. Dump + CDC6 hours at 40 Mbps. The 5.7 → 8 version jump is the work; ≤ 2 h downtime tolerance means CDC, not a dump-and-restore on the night.Row counts and a per-table checksum comparison; functional tests of the booking and repeat-prescription flows against a known client record.Application engineer
BI-Reports — 9 surviving reports60 GBWire. Export4 hours at 40 Mbps. Only the survivors’ snapshot history travels.Each of the 9 reports executed on both old and new, outputs diffed. Any report that can’t be diffed clean is not a survivor — it is a rebuild.Finance Director
BI-Reports — 31 dead reports340 GBDoes not travel18 months with no opens, proven by the audit log. Retired per Part 1.Audit-log evidence exported and retained as the justification before anything is deleted.Finance Director
RotaMaster export~15 GB CSVWire, into the SaaS rota productUnder an hour. The ASP application itself is retired in place — no source control, no tests, nothing worth carrying.Staff count matched; the next 8 weeks of published rota compared line by line by the HR manager before the old system is switched off.HR Manager
BackupVault + tape librarytapesDoes not travel — Retained, then re-homed in Part 5Holds the 7-year finance retention. The obligation outlives the data centre, so it needs a new home before 31 March, not a migration.Retention inventory produced and matched against the 7-year obligation; a restore tested from the oldest tape still in scope.Finance Director

Totals. Appliance: 41 + 3.7 = 44.7 TB. Wire: 1.9 + 0.28 + 0.22 + 0.14 + 0.09 + 0.06 TB + a 15 GB rota export ≈ 2.7 TB, which is 2.2 days of continuous link at 150 Mbps — spread across seven months, it is close to invisible. Does not travel: 2.5 + 0.34 = 2.84 TB. Sum: 50.2 TB, which is the whole estate, accounted for.

The one-sentence version for the steering committee: “We ship 94% of the data on one appliance in month 2, keep it current on under 4 Mbps for six months, and move the remaining 2.7 TB over the existing link in scheduled overnight slots — so the colo circuit is never the thing standing between us and 31 March.”

Step 7 — validation, and the difference between “the job said success” and “it arrived”

☺ Like you’re 10: The lorry driver saying “all delivered” is not the same as you counting the boxes and opening a few.

A copy tool reporting success means the tool did not crash. It does not mean the data is right. Every dataset in Artifact A therefore names a check that would catch a silent failure — the kind that reports green and is wrong. Four techniques cover almost everything, and Data Migration & Data Gravity covers the theory behind each:

TechniqueCatchesMissesUse it for
Row / file / object countsMissing or duplicated records — a truncated copy, a re-run that double-loadedCorruption. A row that arrived with the wrong contents still counts as one row.Every dataset, every time. It is cheap and it is the first thing that ever goes wrong.
Checksums / hash manifestsSilent corruption — a flipped bit, a truncated file, a character-set manglingStructural problems. A perfectly-hashed file in the wrong folder still hashes fine.ImageVault’s 1.5 million studies; anything that goes on physical media and travels by road.
Aggregate reconciliationSUM(), MAX(), per-day totalsOff-by-a-day loads, timezone shifts, decimal precision loss, encoding damage in money columnsCompensating errors — two mistakes that happen to cancel outAnything financial. ClaimsFeed, InvoiceLine, the controlled-drug register.
Parallel run — do the real work on both, diff the outputEverything the other three miss, because it exercises the actual business process end to endNothing much — but it is the most expensive check, so reserve it for the highest-stakes datasetClaimsFeed’s nightly batch. Run one night on both, diff the two output files.

And then the step that is not technical at all: somebody signs. Each reconciliation report gets a named human who has read it and accepts the data is correct. Not the person who ran the copy — the person who owns the consequence if it is wrong. That is why the ledger’s last column pairs a technical signer with a business one for anything with a legal or financial obligation attached.

Artifact B — the PIMS-Core cutover runbook

☺ Like you’re 10: The exact list of what happens, minute by minute, on the one night that matters — written weeks earlier, in daylight, by people who slept the night before.

PIMS-Core is the hardest single cutover in the estate, and it is worth being precise about why: it is used every minute in every clinic; it has a four-hour window that can only ever be a Sunday and never a Monday; it depends on Active Directory, which is Retained on-prem; it depends on StockCtrl and on PrintSrv, which is also Retained on-prem and latency-sensitive; and it reads 1.5 million imaging studies by UNC path, which means the imaging archive and the practice system have to flip in the same hour or not at all.

A note on which R you chose

◆ Key idea

This runbook is written for Rehost — the four-node SQL Server cluster and the application tier lifted onto cloud VMs inside your own landing zone, because the vendor supports this product on IaaS only and their hosted SaaS edition is a clinical-data conversion plus a 22-clinic retraining programme that will not fit before 31 March. Repurchasing to that hosted edition is deliberately deferred to year two, which is exactly the kind of two-step a hard deadline forces and Part 5 picks up as a modernization candidate. If Part 1 got the vendor to confirm an in-country hosted tenant with a slot before month 7 and you chose Repurchase, that is the better answer and you do not need to redo this page: every row of the runbook still applies. Three things change and nothing else. The restore is run by the vendor’s DBA rather than yours, so a third party sits on your bridge call and owns a step in your critical path. The go/no-go deadline gets earlier, because the vendor’s change window is theirs and not yours. And the UNC-path answer below becomes something you negotiate rather than engineer — which turns it into a lead-time item, and lead-time items get asked about in week 1, not month 7. Note those three deltas at the top of your runbook and carry on.

The UNC path — the one design decision that makes this cutover short

PIMS-Core stores every study as a path like \\NAS-COLO-01\imaging\2019\04\1145882.dcm, in a table with 1,502,384 rows. When PIMS-Core moves, that string has to keep resolving. There are three ways to arrange that, and only one of them is a four-hour cutover:

OptionWhat you changeCutover costRollback costVerdict
Rewrite the stored paths1.5 million rows in the clinical databaseA large, slow, transactional data change in the middle of your window — and a schema you now have to keep consistent with the vendor’s next upgradeAnother 1.5 million-row update, under pressure, at 04:12No. You are changing clinical data to solve a naming problem.
Leave PIMS-Core reading the on-prem NASNothingZero on the night — and every imaging read afterwards crosses the VPN, and Fort Rusty stays alive past 31 MarchN/ANo. It defeats the entire programme to save one hour.
Keep the string, move what it points atOne DNS record: NAS-COLO-01 resolves to the cloud SMB endpoint instead of the colo NASSeconds. TTL lowered to 60 s at T-24h.Seconds. Change the record back.Yes. The flip is a name resolution change, and so is the way back.

This is worth internalising well beyond this exercise: the cheapest thing to move on the night is a pointer; the most expensive thing to move on the night is data. Every hour you spend in the weeks beforehand converting a data change into a pointer change buys you back ten minutes of the window and an entire rollback path. Read Architecture Patterns on what actually flips the traffic — DNS, load balancer, feature flag — and notice that every mechanism it lists is a pointer.

The prep block — everything that happens in daylight

A runbook that starts at 02:00 is a runbook that will fail at 02:40. Most of the work is before the night, done by people who are awake:

WhenWhatWhoWhy it can’t wait until the night
T-14dFull dress rehearsal against the DevTest copy: restore, catch up to zero lag, flip a test DNS zone, run every validation query, run the smoke test, then roll the whole thing back. Record the actual minutes for every step.Whole teamIf the rehearsal doesn’t fit in three hours, your plan is wrong — and you have two weeks to fix a plan, or forty minutes to fix a night.
T-14dCompressed full backup seed of the 1.9 TB SQL cluster shipped over the link (550 GB compressed, ~41 h at 40 Mbps), then log shipping enabled and left running.Database engineerThe whole point of the four-hour window is that only the tail log moves on the night.
T-7dChange freeze on PIMS-Core: no vendor patches, no schema changes, no new scheduled reports, no new integrations.Practice Systems ManagerEvery change after the rehearsal is a change you did not rehearse.
T-7dImageVault read verification: 500 sampled studies opened from the cloud SMB endpoint; sync lag confirmed under 15 minutes; study-count difference confirmed zero.Migration leadDiscovering the archive doesn’t read at 02:50 is discovering it four hours too late.
T-5dComms wave 1 to all 22 clinic managers, the emergency hospital, and the out-of-hours triage provider: date, window, what will be unavailable, what the fallback is, the number to call.Comms leadPeople plan their Sunday around this. Five days is the minimum notice that gets read.
T-3dThe paper fallback pack, couriered to every site: blank consult forms, blank dispensing labels, a printed list of Sunday and Monday appointments per clinic, and — for the emergency hospital — a printed 72-hour medication schedule for every in-patient.Practice Systems ManagerThis is the actual disaster plan. A veterinary practice can run on paper for a day; it cannot run on a promise that the system will be back shortly.
T-2dGo/no-go pre-check. Nine entry criteria, all must be green in writing: rehearsal passed, seed complete, log shipping healthy, ImageVault read test passed, comms sent, paper packs delivered, on-call roster confirmed, rollback rehearsed, decision owner available.Decision ownerCancelling two days out costs a rescheduled Sunday. Cancelling at 02:00 costs the team’s confidence.
T-24hDNS TTL lowered to 60 seconds on pims.brambleside.internal and NAS-COLO-01. Verified from a clinic workstation, not just from the server room.Network engineerA 24-hour TTL turns a 60-second rollback into a day-long one. This single step is the difference between a revert and an outage.
T-12hFinal full backup of the source cluster, verified restorable — actually restored somewhere, not merely taken.Database engineerAn untested backup is a rumour.
T-12hOn-call roster published: seven named people, mobile numbers, escalation tree, bridge details.Cutover leadAt 03:40 you need a name, not a rota.

The seven people, and why one of them isn’t from IT

RoleOwnsFrom
Cutover leadThe runbook and the clock. Calls the clean revert. Declares done.Migration team
Database engineerThe tail-log ship, the LSN gate, the restore, the delta export if it comes to that.Migration team
Network / platform engineerDNS, the VPN, the SMB endpoint, LabBridge’s static egress address.Migration team
Application engineerThe app tier; keeps the vendor’s support line open on a second bridge.Migration team
Comms leadThe comms plan. The only person who talks to clinics.Migration team
Clinical validatorRuns the smoke test on a real clinic workstation. The only person who can fail it.A senior veterinary nurse
Decision ownerGo/no-go #1 and #2, and the mitigate-forward call. On the bridge from 03:30.Head of Clinical Operations

Two of those seven are not from IT, and that is deliberate. The clinical validator exists because “the service returned HTTP 200” and “a vet can do a consultation” are different claims, and only one of them matters on Monday. The decision owner exists because the person who spent nine months building this is the worst possible person to ask whether to abandon it at 03:55 — you want the decision owned by whoever carries the consequence, not whoever carries the sunk cost.

Note also what this costs: five of the seven come from a migration team that Part 3 established is six people, and one of them left at month 3. The entire remaining migration team is on this bridge. Nothing else happens that weekend, and your wave plan has to say so.

The night — minute by minute

This is the table. Every row has a clock time, an owner, an expected result, and a failure branch — because a runbook that only describes the happy path is a description, not a runbook.

ClockStepWhoExpected resultIf it fails
01:30Bridge opens. Roll call of all seven roles. Rollback runbook open on a second screen.Cutover leadSeven voices.Any role absent → no-go. Stand down, reschedule. Nothing has been touched.
01:45Pre-flight: log-shipping lag < 60 s; target instance healthy; ImageVault sync lag < 15 min; DNS TTLs confirmed at 60 s from a clinic workstation.DBA + NetworkFour greens, read aloud.Any red → no-go.
02:00GO/NO-GO #1. Proceed, or stand down with nothing changed.Decision ownerA spoken “go”, logged with the time.Stand down. Reschedule to the next non-Monday Sunday outside the blackouts.
02:00Freeze. Stop the application service on all 4 nodes; set the database READ_ONLY; disable the ClaimsFeed and LabBridge scheduled jobs; publish the maintenance page and login banner.App + DBAZero active sessions within 3 minutes.Kill lingering sessions; log which clinic each came from — you will want that for next time.
02:05Verify zero sessions and zero open transactions.DBAOnly the DBA’s own session remains.An open transaction means someone is still writing. Do not proceed until it is gone.
02:10Final log ship. Tail-log backup → transfer → restore on target → bring target online.DBABudget 15 min. Rehearsed at 11.Over 25 min → clean revert. Do not “just wait a bit longer”; that is how windows are eaten.
02:25Zero-lag gate. Compare last LSN, source vs target.DBAExact match. Hard gate.No match → clean revert immediately. There is no version of this where you proceed with a gap.
02:30Validation A — data. Run all 12 reconciliation queries against the values recorded from the frozen source at 02:00.DBA + Practice Systems Manager12 of 12 exact.Any mismatch → clean revert. A count that is “nearly right” is a count that is wrong.
02:50Validation B — the ImageVault path. From the new app tier, open five named studies by their stored UNC path: one from 2004, one from 2011, one from 2019, one from last month, one from yesterday.App + Clinical validatorAll five render.Clean revert — and find out why the T-7d read test passed when this doesn’t. This is the step everyone forgets and it is the one that ends careers.
03:00The flip. Change the DNS record for pims.brambleside.internal to the new app tier. Stored UNC strings are not touched.NetworkPropagated within 60 s, verified from three clinics.Revert the record. It is one record.
03:05Bring the application tier up.AppAll 4 nodes healthy within 4 min.One node down → continue on three, note it. Two or more → clean revert.
03:10Smoke test A — the clinic script (nine steps, below), on a real workstation at the flagship clinic.Clinical validatorNine of nine pass. 20 min.Any step fails → clean revert. The validator’s call is final and is not overruled by the migration lead.
03:30Smoke test B — the same nine steps, from a clinic on the far side of the country over the clinic VPN.Clinical validatorNine of nine. 10 min.Passing A but failing B means it works when you’re in the building — which is not a pass.
03:40GO/NO-GO #2 — the point-of-no-return gate. Everything so far is reversible; everything after 04:00 is not.Decision ownerA decision, logged.Decision must be made by 03:55. If it is not made by 03:55, the answer is automatically no-go and the clean revert runs. The default is safe.
03:45Re-enable the ClaimsFeed and LabBridge jobs. Confirm LabBridge egresses from the allow-listed static IP — check with the reference lab’s connection log, not with your own.NetworkThe lab’s log shows the expected source address.Leave the jobs disabled. ClaimsFeed may miss one night; that is a stated tolerance. Do not revert the whole cutover for it.
04:00⛔ POINT OF NO RETURN — writes open. Database set READ_WRITE. From this minute, new clinical notes exist only in the new system.DBA, on the decision owner’s instructionTimestamped in the bridge log, out loud, by name.See Artifact C. There is no “fail” branch here — only a different plan.
04:05Comms wave 2 — live. To 22 clinic managers, the emergency hospital, the out-of-hours triage provider, the reference lab, and the claims processor.Comms leadSent, with the “report anything odd to this number” line.
04:10–05:00Hypercare watch. Session count against a normal Sunday, error rate, ImageVault read latency (95th percentile), dispensing-label print success, and DR replication of the new system started and healthy.AllNothing anomalous for 50 minutes.Anything anomalous → Artifact C’s mitigate-forward table.
05:00Declared done — with a full hour of the four-hour window unspent.Cutover leadAnnounced on the bridge.
05:00–08:00Bridge stays open, unattended but reachable. Everyone sleeps with a phone on.AllSilence.
08:00 SunFirst live consult of the day at the emergency hospital is watched end to end by the clinical validator.Clinical validatorUneventful.
07:00 MonHypercare peak. All seven back on the bridge before the busiest day of the week begins.AllThe real test. Sunday was the rehearsal that happened to be live.
The PIMS-Core window — where the way back stops REVERSIBLE — clean revert, 12 min source is read-only · nothing new exists anywhere IRREVERSIBLE — mitigate forward only new clinical notes exist only in the new system 02:00 freeze · go/no-go #1 03:00 the flip (DNS) ⛔ 04:00 POINT OF NO RETURN 06:00 window closes 02:25 zero-lag gate 03:40–03:55 go/no-go #2 05:00 declared done revert: DNS back, source read-write. Nobody outside the room ever knows. 04:12 ≈ 40 clinical notes capture the delta first, then choose: fix forward, or paper

The twelve reconciliation queries

Every one of these has an expected value recorded at 02:00 from the frozen source — that is the entire trick. A query that returns a number nobody can compare against has told you nothing.

-- Three of the twelve, written out in full. Run against the frozen SOURCE at
-- 02:02, record the results on the bridge; run against the TARGET at 02:30
-- and compare. Every one is an exact match or the cutover does not proceed.

-- (3) Total clinical notes — the record that matters most and is never deleted.
SELECT COUNT_BIG(*) AS note_rows, MAX(NoteId) AS max_id, MAX(CreatedUtc) AS newest
FROM   dbo.ClinicalNote;
-- expected: 4,912,663 | 4,912,663 | (the freeze instant, to the second)

-- (6) Money. Row count AND sum, because a count alone misses a mangled decimal.
SELECT COUNT_BIG(*) AS line_rows, SUM(AmountGross) AS gross
FROM   dbo.InvoiceLine
WHERE  FinancialYear = @currentFY;
-- expected: 1,204,559 | 18,442,915.60

-- (11) The ImageVault join. This number IS the archive's study count --
--      if these two ever disagree, a study exists that nothing can find.
SELECT COUNT_BIG(*) AS linked_studies
FROM   dbo.StudyLink
WHERE  UncPath IS NOT NULL;
-- expected: 1,502,384  -- matches the DICOM index exactly
#CheckWhat a mismatch would mean
1–2Row counts: Client (61,418) and Patient (88,204)A truncated or partially-restored load. The cheapest check there is.
3ClinicalNote count, max id, max timestamp (4,912,663)Lost clinical records. This is a legal document set; there is no acceptable variance.
4ClinicalNote written in the last 24 h (3,180)A timezone or watermark bug that silently drops the most recent day — the classic one.
5Max NoteId and max CreatedUtc match source exactlyReplication stopped before the freeze. Should be impossible after the LSN gate; check anyway.
6InvoiceLine count + SUM(AmountGross) for the current FY (1,204,559 / 18,442,915.60)Decimal precision loss or an encoding problem in a money column.
7Open (unpaid) invoices (9,341)A state column that didn’t survive a type conversion.
8ControlledDrugRegister count + max entry timestamp (214,880)A 7-year statutory retention obligation with a hole in it.
9Appointments booked for the next 14 days (27,905)Monday morning arrives and 22 waiting rooms have no schedule.
10Distinct active user accounts (611)Staff who cannot log in on Monday — the most visible possible failure.
11StudyLink rows with a non-null UNC path (1,502,384)Imaging history that exists on disk but that nothing can find.
12DBCC CHECKDB — 0 allocation errors, 0 consistency errorsCorruption you would otherwise discover in three weeks, after the source is gone.

The nine-step clinic script

☺ Like you’re 10: Don’t ask “is the computer on?” Ask a real vet nurse to do a real appointment, start to finish, and watch.

A smoke test that checks endpoints tests the thing you built. A smoke test that walks a working day tests the thing they need. The clinical validator runs all nine, in order, on a real clinic workstation — twice, once at the flagship and once from a remote clinic over the VPN:

  1. Log in with a normal clinic account — proving the on-prem Active Directory that is Retained at Fort Rusty still authenticates against a system that now lives in the cloud.
  2. Find a client by surname, with a deliberately awkward one — an apostrophe, an accent, a hyphen. Character-set damage in a migration hides in exactly these names.
  3. Open the pet’s history and read a note written more than five years ago.
  4. View an X-ray from ImageVault — the UNC path, the SMB endpoint, the DNS change and the appliance seed, all proven in one click.
  5. Add a clinical note and save it. (During the smoke test the database is still read-only, so this step is run against a designated test patient after 04:00, and rerun if the revert is called.)
  6. Dispense an item from StockCtrl, including a controlled drug, and confirm the register entry appears.
  7. Print a dispensing label on the clinic’s own printer — PrintSrv is Retained on-prem and latency-sensitive, so this is the step that proves the hybrid path actually works rather than merely existing on a diagram.
  8. Take a payment via the processor’s hosted redirect, confirming no cardholder data touches Brambleside systems — the arrangement that keeps the compliance scope small stays intact after the move.
  9. Book a follow-up appointment and confirm it appears in the clinic diary.
⚠ Watch out

Steps 1, 6, 7 and 8 all cross a boundary — to on-prem AD, to StockCtrl, to a Retained print server, to an external payment processor. Those four are where migrated systems break, and they are precisely the steps a technical smoke test skips because they are “not part of PIMS-Core.” They are part of the working day, which is the only unit of testing that matters at 03:10 on a Sunday.

The comms plan

WhenWho is toldChannelThe messageSent by
T-14dAll staffEmailPIMS-Core is moving on Sunday DD. Here is what changes for you (nothing) and what to expect.Comms lead
T-5d22 clinic managers · emergency hospital · out-of-hours triage providerEmail + the practice group chatThe window, what will be unavailable, the fallback, the number to call.Comms lead
T-3dEvery sitePhysical courierThe paper fallback pack.Practice Systems Manager
T-12hThe seven on-callBridge invite + SMSJoin link, roles, escalation tree, the rollback runbook.Cutover lead
02:00All staffStatus page + login bannerPIMS-Core is unavailable until 06:00.Automated
04:0522 clinics · emergency hospital · out-of-hours · the reference lab · the claims processorEmail, plus SMS to the 22 managersLive. Report anything odd to this number.Comms lead
Within 10 min of a revertThe same full listEmail + SMSThe move did not go ahead. Nothing has changed for you. Monday is normal.Comms lead
07:00 Mon22 clinic managersSMSWe are on the bridge all day. Here is the number.Cutover lead

The two rows that separate an experienced plan from a first one are the reference lab and the claims processor. They are external organisations with their own on-call, their own change freezes and their own opinions about a partner’s system going quiet at 02:00 on a Sunday. Telling them is not courtesy; it is how you avoid an automated integration being disabled at the other end because it looked like a fault.

Reveal the runbook’s time budget, checked against the window (Artifact B)
BlockBudgetRehearsed at T-14dRunning total from 02:00
Freeze and confirm zero sessions10 min6 min02:10
Final log ship and restore15 min11 min02:25
Zero-lag gate5 min2 min02:30
Validation A — 12 queries20 min14 min02:50
Validation B — ImageVault paths10 min4 min03:00
DNS flip + app tier up10 min7 min03:10
Smoke test A (flagship)20 min18 min03:30
Smoke test B (remote clinic)10 min9 min03:40
Go/no-go #2 — decide by 03:5515 min03:55
Re-enable ClaimsFeed + LabBridge5 min3 min04:00
Writes open04:00
Hypercare watch before declaring60 min05:00 — done
Window closes 06:00 — slack remaining60 minutes

Read the rehearsed column, not the budget column. Every block came in under budget at rehearsal, which is how you know the budget is honest rather than optimistic. The 74 minutes of accumulated headroom between budget and rehearsal is what absorbs the one thing that always goes differently on the night — and the 60 minutes at the end is what absorbs the second one. A plan whose happy path lands at 05:55 is a plan with no plan.

Two design choices did most of the work. The seed and log shipping ran for fourteen days beforehand, so only a tail log moves on the night — the 1.9 TB copy happened in October, quietly. And the ImageVault flip is a DNS record rather than 1.5 million row updates, which is the difference between a 60-second step and a step that does not fit in the window at all. Almost all cutover time is won in the weeks before the cutover.

Artifact C — the rollback plan

☺ Like you’re 10: Decide now, in daylight, the exact moment after which “let’s just put it back” stops being a thing you’re allowed to say — and write down what you do instead.

Everything above was preparation for this. A rollback plan is not a paragraph saying “we will roll back if necessary”; that is a wish. A rollback plan names a moment, names a person, names a deadline, and describes two completely different procedures either side of that moment.

Define the point of no return, precisely

◆ The whole idea

The point of no return is the first moment at which data exists in the new system and nowhere else. For PIMS-Core that is not the DNS flip, not the app tier coming up, and not the go/no-go — it is 04:00, the minute the database is set READ_WRITE and the first clinical note is written. Before that instant the source has been frozen read-only since 02:00 and the target has taken no user traffic, so there is literally nothing to reconcile. After it, “roll back” stops meaning “undo” and starts meaning “decide what happens to real records.”

This is why the freeze at 02:00 is not an inconvenience to be minimised — it is the mechanism that keeps the whole night reversible. Every minute the source is read-only is a minute in which a mistake costs nothing but time. That is a trade worth making deliberately: you are buying reversibility with downtime, and four hours of Sunday downtime buys you two full hours of it.

Before 04:00 — the clean revert

Rehearsed at T-14d, timed at 12 minutes. Who may call it: the cutover lead, and only the cutover lead. Latest permitted minute: 03:55 — and if go/no-go #2 has not produced a decision by 03:55, the revert runs automatically. The default is safe.

CLEAN REVERT — before 04:00. Rehearsed: 12 minutes.

  1. Cutover lead calls it, out loud, on the bridge, with the time. Logged.
  2. DNS: pims.brambleside.internal  -> on-prem VIP        (TTL 60s)
  3. DNS: NAS-COLO-01                -> colo NAS           (TTL 60s)
  4. Source database: READ_ONLY -> READ_WRITE
  5. Restart the application service on all 4 on-prem nodes
  6. Re-enable ClaimsFeed and LabBridge jobs against the on-prem instance
  7. Clinical validator reruns all NINE smoke-test steps -- against the OLD system.
     A revert is a change too, and an unverified revert is just a second outage.
  8. Comms wave 3-A within 10 minutes, to the full list:
     "The move did not go ahead. Nothing has changed for you. Monday is normal."
  9. Take down the maintenance page.

  DATA STATE AT THIS MOMENT: zero new writes exist anywhere.
  The source has been read-only since 02:00; the target took no user traffic.
  Nothing to reconcile. This is the entire reason the freeze exists.

Step 7 is the one people leave out. A revert puts you back on a system that has been read-only for two hours, with services restarted and DNS changed — three things that can each fail. Verify it with the same nine steps you would have used to accept the new system. Anything less and you have swapped a suspected problem for an unmeasured one.

After 04:00 — there is no rollback, only mitigate-forward

At 04:12 — twelve minutes past the point of no return — the new system holds roughly 40 clinical notes, 6 dispensing records including one controlled drug, and 3 card payments. They came from the emergency hospital, which never closes, and from the out-of-hours triage line. Every one of those clinical notes is a legal record with a seven-year retention obligation attached, and none of them exists anywhere else in the world.

So the plan changes shape entirely:

AFTER THE POINT OF NO RETURN — the order is fixed. Do not improvise it.

  STEP 1 — CAPTURE, ALWAYS, BEFORE ANYTHING ELSE.
      Run the pre-written delta export. Written and tested at the T-14d
      rehearsal -- NOT composed at 04:12 by someone who has been awake
      for twenty-two hours. Output to a file, checksummed, held by the DBA.

  STEP 2 — CHOOSE, and the choice is the decision owner's, not IT's:
      (a) FIX FORWARD -- stay live, vendor on the bridge. Default for
          anything that is merely slow or ugly.
      (b) DEGRADED MODE -- set the new system READ_ONLY, clinics fall
          back to the paper pack delivered at T-3d. Buys unlimited time
          with NO new writes accumulating. Default for anything that is
          wrong rather than slow.
      (c) REVERSE MIGRATION -- only if (a) and (b) have both failed.
          This is a project, not a night: transform the delta file,
          load it into the old system, and have a clinician verify
          every record with a second clinician countersigning.

  NEVER: flip DNS back before STEP 1 has completed. Ever. Not once.
-- The delta export. Written at the T-14d rehearsal. Tested at the rehearsal.
-- Its existence is a milestone, not an afterthought.

DECLARE @cutover datetime2 = '<< the exact UTC instant writes were opened >>';

SELECT * INTO dbo.delta_ClinicalNote
FROM dbo.ClinicalNote            WHERE CreatedUtc >= @cutover;

SELECT * INTO dbo.delta_ControlledDrug
FROM dbo.ControlledDrugRegister  WHERE EntryUtc   >= @cutover;

SELECT * INTO dbo.delta_InvoiceLine
FROM dbo.InvoiceLine             WHERE CreatedUtc >= @cutover;

SELECT * INTO dbo.delta_Appointment
FROM dbo.Appointment             WHERE BookedUtc  >= @cutover;

-- Then, immediately, the count that tells the decision owner how big
-- the problem is -- BEFORE they are asked to choose (a), (b) or (c):
SELECT 'notes'  AS t, COUNT_BIG(*) FROM dbo.delta_ClinicalNote
UNION ALL SELECT 'drugs',    COUNT_BIG(*) FROM dbo.delta_ControlledDrug
UNION ALL SELECT 'invoices', COUNT_BIG(*) FROM dbo.delta_InvoiceLine
UNION ALL SELECT 'appts',    COUNT_BIG(*) FROM dbo.delta_Appointment;

That last query is the most important thing on this page. The decision owner cannot choose between fix-forward and a reverse migration without knowing the size of the delta, and at 04:12 nobody has time to write a query. Forty records is an evening’s careful work for two clinicians. Four thousand is not recoverable by hand at all, and knowing which of those two you are in changes the answer.

The trigger table — what each failure actually means, on each side of 04:00

What has gone wrongBefore 04:00After 04:00
Replication lag won’t reach zeroClean revert. This is exactly why the LSN gate sits at 02:25 and not at 03:40.Cannot happen — you never opened writes without passing a zero-lag gate. If it somehow has, you have a bug in the gate, not in the cutover.
The app tier won’t come up healthyClean revert.Fix forward on the vendor bridge. If not resolved within 30 minutes, degrade to paper.
ImageVault studies won’t renderClean revert — then go and find out why the T-7d read test passed.Degrade imaging only. Clinics can consult; they just can’t view history. PIMS-Core itself stays live. Do not take down a working practice system to fix a viewer.
A reconciliation query is off by rowsHard stop. Do not proceed under any circumstances.Correctness fault. Read-only immediately, paper pack, delta export, DBA and vendor on the bridge. This is the one that goes straight to (b).
It works, but it’s slowClean revert if you are not confident by 03:55.Fix forward. Slow is survivable for a day and you have a week of hypercare; abandoning a correct system because it is sluggish costs more than it saves.
The dispensing-label printers won’t printClean revert — a clinic that cannot label a controlled drug cannot dispense one.Local problem, local fallback: hand-written labels per the paper pack, per the practice’s existing procedure. Do not roll back an entire practice management system for a print queue.
A clinician reports a note filed against the wrong patientHard stop, clean revert, and the cutover does not get rescheduled until the cause is found.Immediate degraded mode. A slow system is an inconvenience; a system that mis-files clinical records is a patient-safety incident, and the two are not on the same scale.
⚠ Watch out

Notice the pattern down the right-hand column: speed problems get fixed forward; correctness problems go to paper immediately. That single distinction is the whole of after-hours decision-making, and it is worth writing at the top of your rollback plan in one line, because at 04:12 nobody is going to read a table. Gizmo’s entire pitch — “we’re nearly there, just push through” — is only ever correct on the speed side of that line, and he will offer it just as loudly on the other side.

Reveal the worked rollback plan (Artifact C)
FieldThe answer
Point of no return04:00 — the minute the PIMS-Core database is set READ_WRITE and the first clinical note can be written. Timestamped out loud, by name, in the bridge log.
Who may call the clean revertThe cutover lead. One person. Not a committee, not the migration lead, not whoever is loudest at 03:50.
Latest minute it may be called03:55. With a rehearsed 12-minute revert, the old system is verified and live by 04:07 — inside the window with 113 minutes to spare.
What happens if nobody decides by 03:55The revert runs. Indecision resolves to the safe option, by design, so that “we didn’t want to be the one to say it” cannot become a decision.
Who owns the mitigate-forward callThe Head of Clinical Operations, on the bridge from 03:30. Deliberately not from IT: the choice between fix-forward and paper is a clinical-risk judgement wearing a technical costume.
Data state before 04:00Zero new writes exist anywhere. Source read-only since 02:00, target has taken no user traffic. Nothing to reconcile — this is what the freeze bought.
Data state at 04:12~40 clinical notes, 6 dispensing records (one controlled drug), 3 card payments — from the emergency hospital and the out-of-hours line. All legal records. All existing in exactly one place.
What happens to those 40 notesStep 1 is always capture — the pre-written delta export runs before any other action, output checksummed and held by the DBA. Then the decision owner chooses fix-forward, degraded mode, or reverse migration, having been shown the row counts first. If it comes to a reverse migration, each record is re-keyed by a clinician and countersigned by a second one.
The forbidden actionFlipping DNS back before the delta export has completed. There is no scenario in which that is the right first move, and it is the move a tired team will reach for.
Why 02:00, and not 22:00 on SaturdayBecause the size of the delta you might have to hand-carry is a function of the hour you chose. 04:00 on a Sunday is the quietest hour Brambleside has — an emergency hospital and a triage line, and nothing else. The same cutover finishing at 08:00 would leave hundreds of records on the wrong side of the line instead of forty.

The one line to put at the top of the plan: “Before 04:00 we go back and nobody outside this room ever knows. After 04:00 we capture first, then choose — and correctness problems go to paper immediately, speed problems get fixed forward.”

🦫 Benny’s workshop · 10 min

Take the second-hardest cutover in the estate — BramblesideOnline, with a ≤ 2 hour tolerance, 90 GB of MySQL, and a version jump from 5.7 to 8 — and write just three lines: its point of no return, who may call the revert, and the latest wall-clock minute. Then notice how different the answer is. A public booking site has no freeze that stops the world; customers arrive whenever they like, so the point of no return arrives the moment the first booking is taken on the new stack. Which means the entire rollback strategy has to be something else — a parallel run, or a dual-write, or an accepted tolerance for reconciling a handful of bookings by hand. The point of no return is a property of the system, not of the runbook.

🎬 At the Migration Academy
🦊

Foxy: Forty-one terabytes and nine months. Why can’t we just start the upload tonight and forget about it?

🐦

Pip: I did the sums. Thirty-four days at the fastest we’re allowed to push — and only if the link is ours alone, which it never is. Every one of those days, twenty-two clinics are sharing it with us.

👺

Gizmo: So push harder! It’s a five-hundred megabit circuit, isn’t it? Use the circuit.

🦥

Sol: It’s five hundred we’re allowed to be billed for. Above one-fifty it’s burst charges — every month, for a month nobody budgeted. Slowly, now: that’s not more bandwidth, that’s a bigger invoice.

🐘

Ellie: So the archive goes by road. One appliance, eighteen days door to door, and not one bit of it touches the link. Then I keep a one-way sync running at under four megabits until the night we flip. The old NAS stays the truth the whole time.

🐢

Timmy: And on the night, nothing goes live until five named studies open, twelve queries return the exact numbers I wrote down at two a.m., and a vet nurse has printed a real label on a real printer in a real clinic. Not one of those is optional.

🦊

Foxy: And if it’s still not right at four?

🐢

Timmy: At three fifty-five we go back and nobody outside the room ever knows. At four twelve it’s a completely different question — forty clinical notes exist in one place on earth, and what you do about them is something you write down in October, not something you invent at four twelve.

👺

Gizmo: …we’re nearly there though. Just push through?

🐘

Ellie: That’s the sentence, Foxy. That exact sentence is why we wrote the deadline down two weeks ago and gave it to somebody who isn’t us.

Milestones

☺ Like you’re 10: Tick a box only when the thing actually exists on your page — not because you’ve read about it and it sounds sensible.

Work these in order; each builds on the one before. Progress saves in this browser.

0 / 12 milestones complete
1Restate the four constraints in your own words
The link budget, the window, the two blackouts, the 31 March stop. One sentence each, saying what the constraint forbids — not what it is.
Done when: each sentence names a plan you are no longer allowed to propose.
2Build the dataset ledger — every dataset, travels or not
One row per dataset from the estate table, including the ones that don’t move. Columns: size, file count, travels?, path, why, scheduled when, validation, signed by.
Done when: your sizes total 50.2 TB and every row has a “travels?” answer, including the Retire rows.
3Do the 41 TB arithmetic, showing every unit conversion
TB → GB → MB → Mb → seconds → hours → days, then apply a goodput assumption and write the assumption down.
Done when: you land within a day of ~34 days, and you can point at the line where the ×8 happens.
4Compute the standing sync rate after the seed lands
900 GB/month, converted to a sustained Mbps and then divided by your goodput figure.
Done when: you get under 4 Mbps and can say in one sentence why that number is the argument for seeding in month 2.
5Cost the appliance round trip and derive the crossover
Order, deliver, copy (both datasets, at different rates), ship back, ingest. Then solve for the dataset size where appliance and wire tie.
Done when: you have ~18 days door to door and a crossover near 18 TB — and you have written one sentence on why that number is not portable to another organisation.
6Write the file-count answer for FileShare
Explain in three sentences why 3.7 TB across 660,000 files is not a 3-day bandwidth problem, and name the mechanism you would use for the final delta.
Done when: your answer mentions enumeration cost per pass, not just per-file transfer overhead.
7Give every travelling dataset a validation step and a signer
For each, name a check that would catch a silent failure, and a named human who signs the reconciliation report. Financial and clinical data get two signatures.
Done when: no row’s validation is “the job reported success”, and no row’s signer is “IT”.
8Write the T-14d → T-12h prep block
Rehearsal, seed and log shipping, change freeze, ImageVault read test, three comms waves, the paper pack, the pre-check, the TTL drop, the verified backup, the roster.
Done when: every row answers “why can’t this wait until the night?” — and the TTL drop is in there.
9Write the minute-by-minute table with both go/no-go gates
Clock · step · owner · expected result · if it fails. Include the LSN gate, both validation blocks, the DNS flip, and a stated wall-clock deadline on gate #2.
Done when: your happy path finishes with at least 45 minutes of the window unspent, and every row has a failure branch.
10Write the nine-step clinic smoke test
A real working day, in order, run by a named non-IT person on a real workstation. Then mark which steps cross a boundary to something Retained on-prem or external.
Done when: at least four of your steps cross a boundary, and one of them physically prints something.
11Write the comms plan, including the external parties
When · who · channel · message · sender. Include the revert message, pre-written, and the two external organisations.
Done when: the reference lab and the claims processor both appear, and the “it didn’t go ahead” message is already written.
12Write the rollback plan — and answer the 04:12 question
Point of no return, who calls it, the latest wall-clock minute, what happens if nobody decides, the clean-revert steps, and the after-04:00 order: capture, then choose.
Done when: you can say out loud what happens to the clinical notes written at 04:12, in under thirty seconds, without reading.

What “done” looks like for Part 4

☺ Like you’re 10: Four things you can check yourself, without anyone marking it.

If any of those four is a paragraph of intent rather than a table of specifics, it isn’t done yet. The test is simple and unforgiving: could someone who was not in any of these conversations run this night from your document alone?

Where this goes next

PageWhat it does with Part 4’s artifacts
Part 5 — Operate, Optimize & ModernizePicks up the morning after and asks what all of this costs — including the two things you must refuse to optimize, one of which is the parallel-run capacity that made this cutover survivable.
Drill — Size the Data MoveThree harder scenarios of the same arithmetic, including one rigged so an online transfer never converges at all.
Drill — Write a Rollback PlanThree cutovers that have already gone wrong, at three different moments — including one where the rollback itself is what breaks.
Move Brambleside — Start HereThe hub: the full estate fact sheet, the five parts, and the afternoon fast path.
🐢 Timmy’s checkpoint

1. Walk the 41 TB conversion out loud — which step is the one people skip, and how wrong does skipping it make you? 2. The appliance takes 18 days and the wire takes 34. Name the second reason the appliance wins, the one that has nothing to do with wall-clock. 3. FileShare’s hot subset is 3.7 TB — three days by bandwidth. Why isn’t bandwidth the constraint, and what does that change about the final sync? 4. What exactly is the point of no return for PIMS-Core, and why is it 04:00 rather than the 03:00 DNS flip? 5. Something goes wrong at 04:12. What is the first action, in every case, before anyone decides anything?

Check your answers
  1. 41 TB → 41,000 GB → 41,000,000 MB → ×8 = 328,000,000 megabits → ÷150 Mbps = 2,186,667 s → 607.4 h → 25.3 days at a perfect link, or ~34 days at 75% goodput. The skipped step is the ×8: storage is sold in bytes, links in bits per second. Skip it and your estimate is eight times too optimistic — you plan a four-day copy and get a month.
  2. Link occupancy. The appliance uses zero of the colo circuit; the wire would saturate Brambleside’s entire 150 Mbps allowance for five weeks, competing with 22 clinics the whole time and risking burst charges above the contracted rate. Even below the 18.3 TB crossover, where the wire wins on days, it still spends days of a circuit somebody else needs. Wall-clock is only half the cost of a transfer.
  3. Because the binding constraint is enumeration, not transfer: a full walk of 1.1 million files with NTFS ACLs takes 3.5 hours, and a timestamp-based sync pays that cost on every pass, just to discover the handful of files that changed. Four hours of window cannot contain a 3.5-hour scan. So the final delta must come from a change journal (the NTFS USN journal, or a DFS-R-style replication group) that reads a list of changes rather than re-deriving one — and the bulk rides the appliance regardless of what the bandwidth math says.
  4. The point of no return is 04:00, the minute the database goes READ_WRITE and the first clinical note can be written — it is the first moment data exists in the new system and nowhere else. The 03:00 DNS flip is not it, because DNS is a pointer: changing it back takes 60 seconds and nothing has been written in the meantime. The source has been frozen read-only since 02:00 precisely so that everything up to 04:00 stays reversible with nothing to reconcile. You are buying reversibility with downtime, deliberately.
  5. Capture. Run the pre-written, pre-tested delta export — every row created since 04:00, to a checksummed file held by the DBA — and produce the row counts, before the decision owner is asked to choose between fixing forward, degrading to paper, or a reverse migration. Nobody can weigh those options without knowing whether the delta is 40 records or 4,000. And under no circumstances does DNS get flipped back before that export has completed.

Part 4 turned three decisions into three documents: an arithmetic-backed plan for moving 50.2 terabytes, a runbook a stranger could execute on a Sunday night, and a rollback plan that names the minute after which “put it back” stops being a sentence anyone is allowed to say. Continue to Capstone Part 5 — Operate, Optimize & Modernize, where the bill arrives and you find out what the lift-and-shift instinct really costs. Step back to Part 3 — The Wave Plan if the month-2 seed still feels arbitrary, or to Move Brambleside — Start Here for the whole track. And for the theory behind everything on this page, revisit Data Migration & Data Gravity, Architecture Patterns, Best Practices and Security, Cost & Resilience.