

Engineering teams rarely fail migrations because they lack technical skill. They fail because they measure movement when they should be measuring meaning.
Record counts match. New deployments are up. The target control plane is serving traffic. The rollback switch still exists. None of that proves the platform is preserving meaning. It only proves the system is moving. On our multi-cloud team, that distinction was the difference between a migration that ‘looked’ successful and one that actually was.
Control planes are where this matters most. A control plane decides what a resource means: Which downstream infrastructure it owns, which tenant it belongs to, what life cycle state it’s in and which operations are safe to perform. If that meaning shifts during migration, the failure is rarely obvious at first. It shows up later as an incorrect cleanup, a broken lookup path, a missing telemetry flow, a downstream workflow acting on stale assumptions. By the time you notice the symptom, the dashboards have been green for days.
Migration observability has to be part of the migration design. Not bolted on after the switch-over plan is approved. It’s the mechanism that tells you whether the plan is actually preserving correctness.
Record Counts are Progress Signals, not Correctness Signals
Most migration dashboards start with the same familiar metrics: Records copied, requests served by the target, backlog depth, queue lag, and workflow completion counts. They tell you the migration is moving.
They don’t tell you it’s right.
In a control-plane migration, correctness lives in semantics. A resource record is only meaningful if the target control plane interprets it the same way the legacy one did. A lookup API is only compatible if the downstream system gets the same operational answer, not just a response with a similar shape, but one that means the same thing. A cleanup workflow is only safe if it reaches the same decision about shared infrastructure that the pre-migration system would have reached.
‘All records copied’ is rarely enough. In one of our migrations, old resources stayed in a legacy metadata store while new resources went to the target until a reconciliation workflow caught up. During that phase, record counts looked completely healthy while the operational truth was still split across both stores. We only realized the gap when a cleanup workflow made the wrong decision for a compartment that was ‘empty’ in one store but not the other. The record count metric had nothing to say about it.
We were measuring movement. We should have been measuring meaning.
Migrations Need a Defined Idea of Drift
Traditional operational observability focuses on latency, errors, throughput and saturation. Migration observability needs a different category: Semantic drift.
Drift is the distance between what the legacy system means and what the target system currently means for the same logical resource or workflow decision. Ordinary service monitoring usually misses it. Requests still return 200. Workflows complete. Consumers get answers. The answers may no longer mean the same thing.
In a live control-plane migration, drift shows up in several forms: A resource exists in one store but not the other; the same resource is in both stores but one copy is newer; both copies have the same timestamp but different content; the target can answer a read but not with the semantics the legacy path used; shared infrastructure cleanup decisions differ depending on which store is consulted; a downstream component falls back to the legacy path more often than expected because parity hasn’t converged.
These are the signals that tell you whether the migration is still controlled or has started drifting.
We started treating drift as a first-class metric after a cleanup workflow made the wrong decision based on an incomplete view of active resources. Before that, we tracked progress. After, we tracked the meaning. I’m still not sure we have the right drift metrics for every scenario. It’s an evolving practice. But the shift in mindset was worth it on its own.
Drift Budgets Make Cutover Decisions Defensible
In SRE, error budgets turn a subjective question (Does this feel stable enough?) into an operational contract. The same logic works for migration drift. A drift budget says how much semantic divergence the platform is willing to tolerate at each phase.
Early in a migration, the budget may allow some controlled mismatch. Dual reads are still enabled. The reconciliation workflow is expected to copy records for a while. Fallback reads may be normal. Later, tolerated drift should shrink. By the time the target control plane is primary for provisioning and rollback risk is being reduced, the budget should be tight enough that unresolved differences are blockers, not background noise.
This changes how cutover conversations go. Instead of ‘the dashboards look good’ or ‘the sync job seems caught up’, the team can say: Fallback read rate is below threshold, reconciliation updates have converged, no cleanup-invariant violations observed, parity checks show no unresolved mismatches in the active resource set. On our team, adopting this checklist moved cutover decisions from ‘I think we’re ready’ to something we could actually defend in a review.
Without a drift budget, migrations are governed by intuition. Intuition has a place in distributed systems, but it’s a poor substitute for measured convergence, especially at 3 a.m., when someone is asking whether to proceed or roll back.
Parity has to be Shaped to the Domain
‘Parity’ gets used often in migrations. It’s only useful when tied to what matters in the specific system.
A multi-cloud observability control plane doesn’t need generic record parity. It needs operational parity.
Can the unified control plane resolve the same monitored resource to the same provider-visible target that the legacy one would have resolved? Does a lookup that now requires compartment context still preserve the meaning downstream components depend on? When a cleanup workflow evaluates whether shared service connectors or managed rules can be removed, does it reason over the full active set or just the locally visible one? When a resource exists in both stores, does reconciliation keep the one that preserves the correct life cycle state?
Behavior checks. Not formatting checks.
A useful parity model breaks into three areas: Behavioral parity (the system takes the same action or returns the same effective result for the same logical resource), life cycle parity (create, active and delete meaning is preserved, especially where cleanup safety or rollback depends on it) and authority parity (the system respects the current migration phase, so if a record is supposed to remain readable through fallback until reconciliation completes, parity isn’t just ‘record exists in target’ but ‘the platform still gives the intended answer at this phase’).
Our first parity definition was too loose. We checked record existence and field equality but not operational equivalence. The day we added behavioral parity checks was the day our migration dashboard started telling us things we could actually act on. Before that, it was mostly reassuring. Reassuring isn’t the same as informative.
Dual Reads Need to be Observable, Not Hidden
Dual reads are common in migrations because they let the target path serve traffic while falling back to the legacy path when necessary. Useful. Dangerous when invisible.
A migration should know, at all times: How often the primary read succeeds on the target; how often fallback to the legacy path is still required; which resource categories still rely on fallback; whether fallback behavior is shrinking as expected; whether fallback is happening because parity hasn’t converged or because an API contract changed in a way the target path doesn’t yet satisfy.
This matters because dual reads can create a false sense of readiness. Traffic flows, so the migration looks successful. But the target may still depend heavily on the old system for correctness. If observability doesn’t surface that dependency, the team can disable rollback support or turn off legacy reads too early.
Dual-read telemetry should be a top-level migration metric.
In practice, it becomes one of the clearest convergence indicators. A healthy migration shows fallback trending down as reconciliation catches up. If fallback stays flat or spikes after switch-over, the migration has moved traffic faster than it has moved meaning. We saw exactly that pattern once. Fallback plateaued at about 15% for a specific resource class. The target lookup path was returning a subtly different answer for resources with compartment-level dependencies. The dual-read metric told us. The rest of our monitoring didn’t. We would have disabled legacy reads and broken those lookups without it.
Reconciliation Workflows Need Their Own Telemetry Contract
A periodic sync job isn’t enough. A migration needs to know what the job is actually doing.
For a reconciliation workflow that copies records from a legacy store to a target store, useful signals include: Source records scanned; missing target records created; target records replaced because source was newer; target records preserved because target was newer; equal-timestamp records that matched exactly; equal-timestamp records that did not match, which is an invariant failure; cycles with no new effective changes.
These tell you whether the sync path is converging or churning.
This matters even more when only one sync direction should run at a time. If forward sync and rollback sync are both possible but only one is supposed to be active, telemetry needs to make that visible. Otherwise, the platform can end up with two sides rewriting each other under the banner of ‘reconciliation’. We almost hit this during a rollback test. The metric that caught it was the ‘records replaced’ counter going up on both sides in the same time window.
Phase-aware monitoring matters too. Early on, frequent new-record additions may be normal. Later, the expected pattern shifts toward no-op cycles and exact matches. The meaning of the metric changes with the migration stage. Good observability reflects that shift instead of flattening all activity into a single ‘records processed’ number.
Cleanup Safety Needs Dedicated Visibility
If service connectors, managed rules or similar shared resources are provisioned per compartment and reused across multiple logical resources, cleanup isn’t a per-record operation. It’s a decision scoped to the active set in that compartment. During migration, that active set may be split across stores.
The system has to answer: Did the cleanup workflow check both legacy and target sources? How many active dependents were found in each? Was the cleanup skipped because a dependent remained? How often would a single-store decision have produced the wrong outcome? Were any cleanup actions taken during periods when dual-store reasoning was still required?
On our team, this was where a superficially successful cutover nearly became a customer-facing incident. Shared infrastructure was about to be removed because the target store looked empty, while the legacy store still had active resources. We caught it because we had added cross-store dependency checks to the cleanup path.
Cleanup-safety signals now live in our top-level migration dashboard. The lesson: Any shared-infrastructure cleanup during migration needs its own telemetry, separate from general workflow monitoring. If the observability layer can’t distinguish between ‘compartment is genuinely empty’ and ‘compartment looks empty from one store’s perspective’, the most important life cycle guarantee isn’t being measured.
Cloud-Specific Visibility Matters in a Unified Control Plane
One of the promises of convergence: Fewer deployments, less duplicated code, real value. But once one control plane serves multiple CSP integrations, telemetry has to preserve cloud-specific visibility.
If request traffic, errors, fallback rates, reconciliation events and cleanup decisions are all emitted without cloud context, a unified deployment blurs the signals operators need. One provider path may be fully converged while another still depends heavily on fallback. One cloud-specific lookup flow may be stable while another has unresolved parity issues.
Migration observability in a unified control plane needs enough dimensionality to answer: Which cloud path is healthy, which feature flags are active, which resource class is still reconciling and which signals belong to which provider context.
We learned this the hard way. An issue specific to one provider’s lookup path was masked by healthy aggregate metrics from the other two. Everything looked fine in aggregate. One provider was broken. We started tagging every migration metric with cloud type after that.
Tracing Matters Because Cutovers Fail on Explanation Time
When a migration issue surfaces, the worst outcome isn’t always the bug itself. Often it’s how long it takes to explain the bug.
Which endpoint served the request? Which feature-flag state was active? Did the lookup hit the target first and then fall back? Which store supplied the resource? Which converter path ran? Did reconciliation update the target record before or after the workflow decision? Did cleanup evaluate one source or both?
Without structured traces or strongly correlated logs, these questions become an incident review project instead of an operational response.
A good migration trace reconstructs the full decision path: Request enters through the target control plane, dual read is enabled, target lookup misses, fallback succeeds from the legacy source, response returns, reconciliation later copies the record, subsequent reads resolve natively, and cleanup stays blocked because a dependent still exists in the alternate store. When the system can show that path quickly, rollback or mitigation becomes operationally realistic.
During migration, time to explanation is often as important as time to recovery.
A Cutover is a Measured Progression, not a Moment
The cleanest migration diagrams show cutover as a switch: Before and after, old and new. Real cutovers are messier.
Provisioning traffic may switch before all historical metadata is copied. Lookup consumers may move to a new API shape while keeping fallback to the old path. Reverse sync may stay disabled until rollback is needed. Legacy workflows may need to complete work they have already accepted. Some regions may migrate before others. Preproduction may show healthy parity while a production slice still requires whitelisted tenant validation.
A strong migration observability model follows that sequence: Dual-read enablement becomes visible; target-read success rate rises; provisioning traffic shifts; reconciliation reduces active divergence; cleanup safety stays enforced across both stores; rollback readiness stays intact until convergence criteria are met. Only then do dual reads or reverse paths get reduced.
Mapping this sequence and building a dashboard that tracked where we were in it was one of the most useful things we did. It took the mystery out of cutover readiness. It also made it clear when we weren’t ready.
Migration Observability Makes No-Downtime Claims Credible
Many migrations aspire to be no-downtime. Reasonable goal. Easy to overstate if the only evidence is service availability.
A no-downtime control-plane migration isn’t just one where the API stayed up. It’s one where the platform preserved the meaning of its operations throughout the transition: Resources remained discoverable, shared infrastructure wasn’t cleaned up prematurely, downstream systems continued receiving the correct mappings and rollback stayed possible until convergence was real rather than assumed.
None of that can be established through generic service health. It takes drift-aware metrics, domain-shaped parity checks, dual-read telemetry, reconciliation metrics, cloud-specific dimensions, cleanup-safety monitoring and traces that explain decision paths.
After three migrations with this approach, I can say: The telemetry work was always the part we underestimated, and always the part that mattered most. Measure meaning, not movement. The dashboards that track whether your system is doing the right thing are harder to build than the ones that track whether it’s doing anything at all. They’re also the ones that let you sleep.
Key Takeaways
- Record counts and service availability are progress signals, not correctness signals. A migration can look healthy on every standard dashboard while silently drifting on semantics.
- Semantic drift (the distance between what the legacy system means and what the target currently means for the same resource) deserves to be treated as a first-class telemetry entity, not a debug afterthought.
- Drift budgets, borrowed from SRE error-budget thinking, turn vague cutover intuition into a measurable contract: How much divergence is tolerable at each phase, and when it must reach zero.
- Dual-read telemetry, reconciliation metrics and cleanup-safety signals belong at the top of your migration dashboard, not buried in logs nobody reads until something breaks.
- In unified control planes serving multiple cloud integrations, observability has to preserve cloud-specific dimensions, or one broken provider path disappears into healthy aggregate numbers.