All notes

Release Risk Depends on Recovery, Not Just Lines Changed

Evaluate rollout, rollback, forward repair, and persistent side effects around user outcomes.

English edition, edited for length. Read the complete Chinese original.

Changing a default price value that only appears in a single line could affect all new orders. Restructuring thousands of lines of internal code, provided that the behavior remains the same, thorough testing is performed, and immediate rollback is possible, could actually pose a lower risk. The number of code lines is not a reliable indicator of release risk.

The evaluation should focus on the scope of impact, the nature of the change, the speed of detection, and the ability to recover. Products, engineering, and operations need to understand who will be affected by the failure, and whether recovery is truly feasible.

Breaking Down Risks into Discussable Dimensions

The scope of impact includes the number of users and the criticality of their actions, while the nature of the changes includes data writing, permissions, billing, and user habits. The speed of detection depends on whether the monitoring system can identify the problem, and the recovery capability depends on whether the side effects can be reversed.

For example, the copy for the subscription entry can be quickly reverted, while incorrect billing requires refunds and communication. Deleting a database requires either a backup or reconstruction. None of these processes should use the same “rollback if deployment fails” plan.

A risk register does not require complex scoring formulas. If the numbers cause people to overlook the most serious scenarios, they become ineffective. It’s better to first list the main failure scenarios, their potential impact, and the recovery actions, and then decide on the appropriate level of verification.

A Canary Rollout Must Be Representative and Isolated

The risk can be assessed by examining a specific failure scenario. Suppose the default price is incorrectly entered, but a new order is still successfully created, and all HTTP indicators are green. If there is no reconciliation of the amounts, the error could persist for a long time. Even if the order is rolled back within a minute, the already paid order still needs to be processed. The risk is not only from the probability of failure, but also from how long it takes for the error to accumulate and become apparent, and which side effects cannot be reversed.

It’s crucial to recognize that detection speed cannot rely solely on user complaints as a signal. Changes in billing should be checked to ensure they align with the rules, and changes in permissions should be monitored for unusual denials and cross-tenant testing. Content publishing should be verified to ensure that draft paths do not exist. These signals directly correspond to business consequences and are closer to this type of risk than “service error rate.” The metrics should also avoid recording unnecessary sensitive content.

Risk discussions do not necessarily require a precise overall score. Low-frequency but irreversible data corruption may be more important than frequent, automatically recoverable page retries. By clearly stating the most severe and reasonable failure scenarios, current controls, and remaining risks, the team can choose appropriate verification methods. Numbers can assist in prioritization, but should not obscure situations that require human judgment.

Releasing the new version to a small group of users can help limit the impact, but this group must represent real-world key scenarios. Selecting only internal employees may not provide the necessary scale of production data, legacy clients, or special permissions.

Groups should remain stable so users do not switch repeatedly between versions. When the feature writes data, both old and new versions must handle the same format. A canary rollout does not reduce every risk proportionally; changes to a shared database can affect every user immediately.

Before the canary rollout, define:

  • Which metrics to monitor
  • How long to monitor them
  • The conditions under which the canary will end.

Without an end condition, a canary rollout merely delays the announcement of a full release.

Distinguishing between Rollback and Forward Repair

The canary design must account for shared resources. If the new version changes a database field from optional to required, the old application may fail to write immediately even when the feature is enabled for only a few users. The data model and protocol determine the blast radius, not the percentage of users shown a new page. Use a compatible migration for shared changes first, then use the canary to verify business behavior instead of hiding global risk behind a limited rollout.

This includes representative data and edge cases. The selection should cover controlled accounts that involve refunds, cancellations, cross-time zone transactions, and different permission levels, rather than just newly registered accounts. Internal employees often know how to avoid issues, while external users may rely on older clients or specific historical states. While a small sample cannot prove all possible paths, it can prioritize covering the most important risk scenarios.

Canary observation must leave enough time for results to mature. Delayed email delivery, payment callbacks, and end-of-day reconciliation do not finish immediately after deployment. Specify how long each result needs and whether the rollout may expand while those outcomes remain immature. One successful page click cannot replace a complete business cycle.

Problems with the interface code might be resolved by reverting the application, but data written incorrectly will not automatically disappear. This requires fixing the script, reconciling data, and communicating with users. After removing old fields and reverting the application, there is a risk of causing a second failure.

Therefore, the release plan clearly defines the rollback window and irreversible steps. Data migration uses a phased approach, first expanding and then switching, and finally deleting the old structure. Irreversible actions are kept separate from regular feature releases to minimize the risk of both being affected simultaneously during recovery.

Forward repair is suitable for certain changes that cannot be rolled back, but it requires pre-existing capabilities, not simply saying “let’s release a new version” after a failure occurs. Verify the responsible person, the testing path, and the user impact control method.

Switches also have maintenance costs

Compatibility migration can be illustrated using user preference fields as an example: First, add the new field, deploy code that can read both the old and new formats, and gradually populate the new field, confirming that the read operation has been switched over. Then, delete the old field. The process of populating the new field should record progress and any exceptions, preventing some user states from being silently defaulted. Each step should retain a working window for the old version, and only deleting the old field should be the clear and irreversible checkpoint.

Forward fixes must distinguish between code and data. Code patches prevent further errors, while script fixes correct existing records, and reconciliation checks identify omissions. Users should be notified about the impact. Scripts should first be validated on a copy or controlled sample, supporting idempotency and range limits, and reviewed by authorized personnel. Temporary scripts are also high-risk code and should not be skipped due to being in a maintenance window.

Having a backup does not automatically mean it is recoverable. The time required for recovery, the window of data loss, the external payment details, and the need to re-run tasks after recovery all need to be verified. Restoring the database to yesterday could undo today’s normal orders, but external charges would not disappear automatically. The recovery strategy should be chosen based on real-world business needs, rather than simply stating “we have a backup” as a universal fallback.

The functionality switches can quickly disable new capabilities, but both sides of the switch must remain in a usable state, and the permissions and data semantics must remain synchronized. If switches are not cleared regularly, they can accumulate a large number of untested states.

Specify the conditions for each temporary switch to be enabled and disabled. After an emergency shutdown, it’s necessary to verify whether background tasks, caches, and external side effects have also been stopped. Hiding a button on the front-end does not necessarily mean that the functionality has been disabled.

Switching permissions and auditing should also be managed. A configuration that allows disabling all payments is not a standard preference and should be restricted to authorized users, with changes being logged to prevent unauthorized actions from becoming a new risk.

Communication is a part of recovery

The functionality switches must cover the complete execution surface. After disabling the subscription entry, queued emails may still be sent; after disabling the proxy write, background tasks may still hold old capabilities. The stop conditions should propagate to the execution layer, and unexecuted tasks should check the current policy. The switches should only prevent future actions, without pretending that past actions have been undone.

The combination of switches can limit the number and lifespan. Each release uses a clearly defined control entry, and temporary switches are cleared after verification. Permanent policies are kept separate from experimental switches. The system supports combinations in testing, but does not guarantee that any combination is valid. The owner is responsible for monitoring, reverting, and deleting switches, to avoid the situation where no one knows which switch is still protecting critical processes after several years.

Whether users need to be informed about the changes, whether they affect existing workflows, and whether the support team has provided instructions are all essential aspects of a successful release. Providing clear and timely notifications about important changes can help users avoid misinterpreting new behaviors as errors.

When reporting an issue, clearly state the scope of the impact, the actions being taken, and the estimated time for the next update. Avoid making unverified promises about complete data security, and don’t simply say “system error” without providing users with clear guidance on whether or not they should retry.

Internal communication should also clearly define the release window, responsible parties, and decision-making authority. Multiple individuals attempting to restore the system simultaneously could interfere with each other; therefore, key actions should be documented for coordination.

Verify User Goals

The ability to grant permissions itself represents a risk boundary. Tasks such as deploying, toggling switches, fixing running data, and notifying users about releases may require different levels of authorization. While allowing rapid coordination during an incident does not mean that everyone should have full access. It’s important to record the actors, targets, and results of each operation, and to review and revoke temporary permissions after the incident, to prevent a single emergency response from creating long-term vulnerabilities.

Changes to external dependencies also require a separate plan. Upgrades to vendor interfaces, DNS switches, or certificate updates may not be resolved by simply rolling back the application. List the retention period for old paths, the effective window for caching, and the verification location to confirm that the restored dependencies are still available. The rollback button is only meaningful when the subsequent resources still support the old version.

Clear communication can directly explain to users how they should proceed: whether repeated submissions will result in repeated charges, whether confirmation is required, and which information cannot be temporarily modified. When investigating, clearly state that information is being verified, and avoid making assumptions or guarantees. Even if a complete fix is not possible, the next update time should still be adhered to. Users need predictable information, not just technical completion announcements.

The support team needs to be in sync with the technical status. They should not prematurely announce “Everything has been fully restored” during reconciliation, but only confirm that the page has been restored without guaranteeing that historical data has been fixed. They should maintain a shared record of events, including the scope, known facts, and current actions, to prevent different teams from independently disseminating versions. They should provide external communication that reduces technical details while retaining information useful for user decision-making.

The health checks pass, which only confirms that the service is running. To verify the publish and subscribe functionality, we need to confirm that the confirmation email and unsubscribe functionality are working correctly. For the publish and billing functionality, we need to verify that the amount, currency, and duplicate requests are being handled correctly. Finally, for the publish article system, we need to verify that drafts are not being leaked and that published content is visible.

You can maintain a short checklist for each type of change, and perform specific tests based on the level of risk. The checklist is not simply a matter of checking boxes; any failure should be associated with a clear action to stop or resume the process.

Online verification uses controlled test accounts to avoid sending unnecessary messages to real users or generating incorrect invoices. Data cleanup and auditing are also part of the acceptance process.

Rehearse Full Recovery from an Incorrect Price Release

The new version incorrectly defaulted one package’s currency to another, and both the order creation and payment interfaces returned successfully. This did not result in a decrease in system availability. Identifying the issue should rely on verifying order amounts against pricing rules, controlled testing, and user feedback, rather than solely relying on HTTP errors. The scope of the problem should be determined based on actual error logs and supplier verification, and it should not be assumed that all new orders are incorrect, nor should normal operation be used to ignore the feedback from a small number of affected users.

First, stop creating further errors by disabling related charges or reverting to verified configurations. Second, retain order and payment transaction details to confirm which charges have been made and which are pending. Third, process refunds, discrepancies, and notifications based on business and contract requirements.

Rolling back code only addresses future behavior. Historical data and external funds require separate recovery procedures. Each step has a designated person, a precise scope, and documented results to prevent multiple people from running different scripts simultaneously.

The repair script first reads the candidates and outputs the plan. Using version or status conditions prevents overwriting records that are being changed. Repeated execution does not allow for repeated refunds, and payments that cannot be confirmed are not automatically marked as unexecuted. The script’s isolation transactions are used to verify success, rejection, and unknown paths. The script does not require real customers to prove its effectiveness. Script review and deployment review are equally important, and emergency situations cannot be avoided without confirming the target.

The user manual clearly states which functions are paused, whether reordering is possible, what is currently being verified, and the next update time. When the result is unknown, it requests the user to wait for confirmation instead of being prompted to retry. When the page is restored, and there are still refunds pending, the current situation should be truthfully explained. Restoring is not a green light; instead, all affected aspects are appropriately addressed.

Introducing Rollback-Enabled Checkpoints for Releases

The data migration process involves several stages: expansion, compatibility read, rollback, switch, and contraction. Each stage lists the conditions under which the old version can still run. If the rollback fails midway, it can continue. The old write operation will not overwrite new fields with empty values, and the read-switch stage involves verifying against the actual sample. Finally, deleting the old columns is a new, irreversible checkpoint that cannot be performed simultaneously with a regular interface release.

A canary rollout controls only behavior that can actually be split between cohorts. Shared table schemas, global configuration, and indexes may affect every user immediately; showing a new button to only some users does not isolate those changes. The release plan should separate global foundation changes from feature-flagged behavior, verify compatibility first, and then expand the business rollout gradually. The observation window must include the maturation time for asynchronous callbacks, email, and reconciliation rather than relying on one successful page click.

Maintaining old paths also incurs costs and has a time limit. Old vendor interfaces, keys, DNS, and data formats must be genuinely available for the rollback button to be meaningful. It’s important to conduct small-scale rollback rehearsals in advance to confirm that caches, certificates, and external configurations do not prevent the recovery. Simply ensuring that Git can revert is not enough; you must also verify that the environment can still support the old program.

Handle Background Work Separately After Disabling a Feature

After closing the entry point, tasks that were already in progress may still be executed. The timer may continue to create new tasks, and the cache may still display its capabilities. The execution layer checks the current policy to distinguish between tasks that have not been executed, tasks that are currently executing, and tasks that have been completed. Unexecuted work is stopped, and the results are checked first. Side effects of completed tasks are not disguised as undo operations. The hidden button on the front end can only reduce the entry point, but does not provide a complete stop semantics.

The permissions for operating switches, auditing, and recovery are clearly defined. A switch that affects all-site charges is not a simple preference; it restricts the operator and preserves non-sensitive change identities. Temporary emergency permissions have expiration dates and can be revoked, preventing the creation of long-term accounts with high privileges. The ability to release switches is based on pre-prepared, controlled capabilities, not on granting all users administrator privileges during an emergency.

Permanent policies, experiments, and temporary release switches are managed separately. The temporary switch is removed once the results are stable. Testing only covers combinations that are actually supported, preventing unknown states from arising due to years of overlapping switches. Cleanup also checks background tasks and data compatibility, ensuring that the protected branch no longer performs critical stopping functions before it is removed. Removing a single line of code does not automatically reduce risk.

Design Production Acceptance Around User Outcomes

Subscription acceptance covers confirmation, repeated clicks, unsubscribe, and a controlled inbox. Article-system acceptance covers published content being visible, draft paths being inaccessible, and old secrets being absent from caches. Billing acceptance covers amount, currency, retries of the same intent, and disconnects after submission. Every failure maps to a stop or recovery action so the rollout does not expand after a problem is found.

The online testing utilizes approved independent accounts and resources, with precise targeting and no deletion of real user data. External charging and notifications are implemented using permitted methods, and deployment into production does not imply the ability to test any user. Technical health, business closure, and historical impact management are all marked as complete before the release is announced.

The release record should primarily document the key assumptions, the scope of validation, any conditions not covered, and the parties accepting the risks. After deployment, if actual issues arise in the unvalidated paths, review and update the next check. If the planned rollback is not feasible, focus on restoring functionality rather than simply adding extra testing. The risk model should be updated based on real failures and effective controls, not solely on the number of lines of code modified to determine the validation intensity.

Data repair and reverting to the original program will have an impact on each other. The old program continues to write data in the old format, while the new script simultaneously corrects this, which can lead to repeated overwriting. The recovery plan specifies which writes to pause, which reads to retain, and which version of the script to use, as well as the steps for gradual recovery after completion. The order of operations is a practical protocol that relies on a shared understanding, rather than on implicit assumptions that everyone knows.

Before restoring from backup, verify the lost window and external facts. Restoring a local database cannot undo payments, and re-sending messages may again trigger notifications. Deleting a list may require re-execution. The recovery process should begin with reconciliation of business data after recovery, checking the new and old operational identities against the unknown results, and not just focusing on the database process startup. The existence of a backup proves that a copy exists, but it does not guarantee that it can be restored within the user’s tolerance range.

After deployment, a clear list of temporary testing resources should be maintained, and audit and legally required records should be retained according to policy. Do not treat the entire object bucket or database as the final testing goal. The recovery tools should also retain version information and responsible parties, and should be re-verified before each change to ensure they are still functional, preventing a successful test from becoming a permanent, unverified recovery guarantee.

Update the Risk Model During the Retrospective

The checklist should include specific actions to be taken for each failure. Immediately stop publishing and clear the cache if there is a draft leak. Pause new charges and begin reconciliation if the amounts are inconsistent. Instead of requiring users to retry indefinitely, check the email delay queue. This ensures that the checklist not only describes the successful state but also provides guidance for handling exceptions. Successful deployment and business release should be two distinct states.

After deployment, compare expected and actual issues, check whether the canary provided useful information, and verify that rollback actually worked. Instead of merely celebrating a successful deployment, incorporate unforeseen failure paths into the next assessment.

A mature release process does not guarantee the absence of failures. Instead, it makes the scope of changes visible, facilitates earlier detection of issues, and maintains sufficient recovery options. The speed of the product comes from controlled risk, not from ignoring risk.

A retrospective review can compare the expected and actual discovery times, as well as the planned recovery paths with the actual available paths. If a warning remains unaddressed, the issue may be due to unclear shift responsibilities. If the rollback fails, it may be because the compatibility window was closed too early. Instead of simply adding a general “strengthen testing” action, incorporate these specific gaps into the next release.

References