A Release With No Rollback Plan
Corvus Manufacturing ships to production three times a year from a UAT sandbox refreshed from production after each release. The coming release contains 8 new custom fields on Case, 3 validation rules that reference two of those fields, 5 updated permission sets, a new Lightning app with 4 tabs, 12 flows to deactivate, 2 modified Apex classes and one new trigger, and a renamed custom object label. Last release, a change set failed in production because a validation rule arrived before the field it referenced, and the team hotfixed during business hours. Org-wide Apex coverage is 68%; the two modified classes sit at 81% and 74% in UAT. The nightly Case integration writes 5,000 records.
1. Sequence the deployment and name the dependency failures that will bite if you do not.
Read the worked answer
Order, driven by dependencies and by the two things change sets cannot undo.
- Custom fields first. Validation rules, permission set field permissions, and any flow referencing the fields all depend on them existing. The rule-before-field failure from last release is exactly this mistake.
- The object label change - cosmetic, no API impact. Confirm the API name is untouched; if someone renamed the API name, stop and re-plan, because every integration and report breaks.
- Validation rules. Before you deploy, run the nightly integration's payload against them in UAT. Three new rules on Case plus 5,000 nightly inserts is a data-quality incident waiting to happen, and a validation rule firing on an integration user looks to the business like the integration is broken.
- Permission sets after fields exist, so FLS references resolve.
- App, tabs - tabs must exist before the app that lists them.
- Apex - deploy with the test level that actually proves it, and be ready for the coverage gate (next task).
- Flows last, and deactivation is the trap: a change set cannot delete or 'deactivate' a component. You deploy an inactive version, or deactivate manually in production afterwards. That manual step must be scripted, assigned to a named person, and logged, or 12 flows keep running and nobody notices for a month.
Validate against production first, then quick-deploy the validated set - never re-upload a fresh change set and call it validated.
2. The coverage numbers look fine locally. Why might production still reject the deployment?
Read the worked answer
Because the gate is not per-class.
- Production requires at least 75% coverage across the org's Apex, and separately that no trigger is left with zero coverage. A class at 81% and another at 74% tell you nothing about whether the deployment passes; the org total here is 68%, which fails outright.
- The fix is not to pad the two modified classes. It is to raise the org total before the release: identify the largest uncovered classes, write or repair tests for the ones that matter, and treat coverage debt as release work rather than a deployment-day surprise.
- The new trigger must have real coverage, not a test that merely inserts and asserts nothing. A trigger that fires only in a test with
seeAllData=trueor with permissions assumed is a latent production failure. - Run the tests in a production-like sandbox at production API version - a UAT sandbox refreshed months ago can have a different test suite passing for different reasons.
- Assume the deployment will fail the first time. Have the failure log triage plan ready: it is almost always coverage, a missing dependency, or a test that depends on org data.
3. The business asks what happens if the release goes wrong on day one. Give an honest answer and a plan.
Read the worked answer
The honest answer: change sets have no rollback. You cannot 'undo' a deployment; you can only deploy something else.
Plan:
- Retrieve and archive the current production metadata for every component in the release before deploying (the new fields, rules, permission sets, app, flows, Apex). Rolling back means redeploying that archive, which only works if you have it.
- Destructive changes cannot ride in a change set. Deleting components requires a destructiveChanges manifest through a migration tool, or manual removal. Decide now which components are 'deactivate and leave' versus 'delete', and schedule deletion for a later release.
- Deactivated flows are the easiest rollback in the release: reactivating a version is a status change. That is an argument for deactivating rather than deleting on day one.
- Data cannot be rolled back by metadata. If a new flow or validation rule touches the 5,000 nightly records, take an export of the affected Cases before the release window and know the restore path.
- Release during a quiet window with the integration paused, and hold a named rollback owner who is not the person doing the deploy.
- Longer term, move toward source-tracked deployments (unlocked packages or a CI pipeline) so a release is reproducible and a revert is a commit rather than an archaeology project.