The blue-green deployment decision record: why the schema compatibility contract you chose determines your cutover overlap failure surface and your rollback window

Blue-green deployment decisions are made in three founding sessions that never document the operational consequences — the deploy sequence session that runs a NOT NULL column migration against the shared database while blue is still serving writes (blue inserts fail immediately; 1,100 transaction failures in 8 minutes before the migration is rolled back); the load balancer cutover session that terminates blue 90 seconds after the health check switch (4,200 WebSocket connections are forcibly reset simultaneously; the reconnect storm overwhelms green's connection accept path for 7 minutes); and the drain window session that sets a 2-minute blue termination delay based on maximum HTTP request duration rather than maximum background job duration (5 report generation jobs running in blue are killed mid-execution; their partial S3 outputs are abandoned and user notification emails are never sent). What none of these sessions produce is the schema migration classification that distinguishes additive-safe changes from changes that require an expand-contract sequence across multiple deploys, the connection drainage inventory that enumerates every long-lived connection type and its drainage mechanism before the termination clock starts, or the rollback window specification that keeps blue alive and ready to receive traffic until green's health signal is verified rather than until an automatic cleanup job fires.

A 34-person fintech SaaS company processed payments through a REST API backed by a PostgreSQL database shared between the application and three background job workers. Their deployment process for blue-green was: bring up the green application and worker instances, run the database migrations for the new release against the shared database, flip the load balancer to route new traffic to green, and terminate blue. The process had run successfully for six months and eleven releases. The sequence was written during the initial blue-green design session and documented as a four-step checklist in the deploy runbook. The founding session that produced the checklist recorded the deploy sequence — it did not record which categories of database migration were safe to run at step two, while blue was still serving production traffic at step one.

In the twelfth release, the engineering team shipped a feature that required tracking the payment method type on each transaction. The schema change: add a payment_method_type column to the transactions table with a NOT NULL constraint and no DEFAULT, because every new transaction would have the value set by the new green application code. The migration was written as a single ALTER TABLE statement: ALTER TABLE transactions ADD COLUMN payment_method_type VARCHAR(32) NOT NULL. The migration was tested against the staging environment, where the green application ran alone against the migrated schema with no concurrent blue traffic. Testing passed. The migration was added to the release alongside the green application code that populated the new column on every INSERT.

The deploy ran on a Wednesday afternoon. At 2:44 PM, the green instances started up and passed their health checks. At 2:45 PM, the migration ran against the shared database. At the moment the migration ran, the transactions table required a NOT NULL value for payment_method_type on every INSERT. Blue was still serving production traffic. Blue's INSERT statements for new transactions did not supply a payment_method_type value — blue's code predated the column and had no knowledge of it. PostgreSQL rejected every INSERT from blue with ERROR: null value in column "payment_method_type" of relation "transactions" violates not-null constraint. The payment processing API returned HTTP 500 for every new payment attempt. The errors began at 2:45 PM. The load balancer health check switch to green had not yet happened — it was scheduled for step three, after the migration ran at step two. For the 8 minutes between the migration at 2:45 PM and the load balancer switch at 2:53 PM, 100% of production payment traffic was still on blue. 1,100 payment transactions failed with database errors during that window. The on-call engineer identified the cause at 2:48 PM, spent 5 minutes confirming that the migration was the cause and locating the rollback procedure, and rolled back the migration with an ALTER TABLE DROP COLUMN statement at 2:53 PM — at the same moment the load balancer switch happened. The payment error rate returned to zero. The rollback left the column absent from the schema; the green instances that had started at 2:44 PM immediately began failing their own health checks because green's code expected the column to exist. The team rolled back the load balancer to blue at 2:54 PM and terminated the green instances. The founding session documented "deploy sequence: bring up green, run migrations, switch load balancer, terminate blue" — it did not specify that a migration must be compatible with blue's writes and reads during the overlap window between the migration running and blue being terminated.

A 52-person SaaS company built a collaborative document editing product where users held persistent WebSocket connections to the application for real-time cursor position and edit broadcasting. Each WebSocket connection was maintained by the application server process for the duration of the user's editing session, typically 20 to 90 minutes per session. The application ran on AWS ECS with a Network Load Balancer in front. Their blue-green deployment model used ECS service replacement: bring up the green task set, register green with the load balancer target group, deregister blue from the target group, and configure ECS to terminate blue tasks after the deregistration delay. The deregistration delay — the time ECS waits after deregistering a target before marking it for termination — was set to 90 seconds, which the team had chosen to allow in-flight HTTP requests to complete after the target was deregistered. The founding session that designed the blue-green ECS configuration documented "90-second deregistration delay to drain in-flight requests" — it did not specify that WebSocket connections are not in-flight HTTP requests and are not drained by the deregistration delay mechanism.

The ECS deregistration delay controls how long the NLB waits before closing HTTP keep-alive connections to the deregistered target. For HTTP/1.1 keep-alive connections, the NLB stops sending new requests to the deregistered target after deregistration, waits the deregistration delay, and then closes the connection. For WebSocket connections, the deregistration mechanism is different: the NLB does not route new WebSocket connection upgrades to the deregistered target, but it does not close existing WebSocket connections that were established before deregistration. Existing WebSocket connections remain open through the NLB to the blue tasks for as long as those tasks are running. When the ECS service terminates the blue tasks at the end of the 90-second deregistration delay, every WebSocket connection that was established before deregistration is forcibly reset at the TCP layer — the blue process exits, the OS closes its sockets, and the NLB sees the connection as failed and sends a TCP RST to each client.

At 11:14 AM on a Tuesday, the deploy ran. Blue was deregistered from the target group at 11:14 AM. Green was registered at 11:14 AM. New WebSocket connections from clients opening new editing sessions connected to green. Existing WebSocket connections — 4,200 active editing sessions open at the time of the deploy — remained open to the blue tasks. At 11:15:30 AM (90 seconds after deregistration), ECS terminated the blue tasks. All 4,200 WebSocket connections were forcibly reset simultaneously. Every client received a TCP disconnect event at the same moment. The client's reconnect logic (a 0-millisecond immediate retry with three attempts at 1-second intervals before falling back to a 5-second polling interval) fired for all 4,200 clients at 11:15:30 AM. The reconnect storm hit green's connection accept path with 4,200 new WebSocket connection requests in the span of 800 milliseconds. Green's application server had a configured concurrency limit of 200 WebSocket handshakes per second — above that, the handshake queue backed up. 4,200 simultaneous connection requests took 21 seconds to process at 200/second. During those 21 seconds, clients whose reconnect attempt timed out before being accepted fell back to the 5-second polling interval — disconnecting the real-time editing experience and requiring users to manually reload to recover their session. The collaborative session state (cursor positions, uncommitted edits in the operational transform buffer) was held in blue's application memory. When blue terminated, the state was lost. Clients that reconnected to green received the last committed document state from the database, not the in-memory operational transform buffer accumulated during the session. For 214 users who had uncommitted edits at 11:15:30 AM, those edits were lost. The incident lasted 7 minutes from first WebSocket reset to green processing all reconnect requests at normal edit latency. The founding session documented "90-second ECS deregistration delay to drain in-flight requests" — it did not specify that WebSocket connections require a different drainage mechanism, that the deregistration delay does not drain WebSocket connections, that in-memory session state must be persisted before blue terminates, or that the client reconnect logic must include jitter to prevent reconnect storms.

A 41-person analytics SaaS company allowed users to generate reports from their connected data sources. Report generation was computationally intensive — the application fetched data from the user's database, ran aggregation queries, rendered charts, assembled a PDF, uploaded the PDF to S3, and sent the user a notification email with a download link. Report generation jobs ran in Celery workers deployed in the same container image as the web application. Blue-green deployment used the same container image for both the web tier and the Celery worker tier — when a new release deployed, both the web containers and the Celery worker containers were replaced simultaneously. The drain window for Celery workers was controlled by the same ECS deregistration delay as the web tier: 2 minutes, chosen to allow in-flight HTTP requests to the web tier to complete. The founding session that designed the deployment pipeline documented "Celery workers replaced alongside web containers during blue-green deploy, 2-minute drain window" — it did not specify that the drain window for Celery workers must equal the maximum job duration, not the maximum HTTP request duration.

Report generation jobs were enqueued when a user clicked "Generate Report" in the UI. The job duration depended on the user's connected data source size and the report complexity — fast reports completed in 30 to 90 seconds, complex reports over large datasets took 3 to 6 minutes. At any given time during business hours, 15 to 25 report generation jobs were running across the Celery worker pool. The deploy runbook specified that deploys should run during business hours on weekdays, as the team had less monitoring coverage overnight and preferred to have engineers available to respond to issues. This meant deploys ran while report generation jobs were active.

The deploy on a Thursday at 2:15 PM proceeded normally. Green web containers and green Celery workers came up and passed health checks. The load balancer switched traffic to green. At 2:17 PM — 2 minutes after the traffic switch — ECS terminated the blue Celery worker containers. At 2:15 PM, 23 report generation jobs had been running in the blue Celery worker pool, with completion times between 12 seconds and 5 minutes 47 seconds remaining. 18 of the 23 jobs completed within the 2-minute drain window before blue was terminated. The remaining 5 jobs were in the middle of their execution when the blue Celery worker processes were killed by ECS. Three of the 5 killed jobs were in the S3 upload step: their PDF had been assembled in memory and the upload was in progress when the process was killed. The partial S3 uploads were abandoned — S3 registered the upload as incomplete and the multipart upload parts were eventually cleaned up by S3's lifecycle policy 24 hours later. The PDF data was in the Celery worker's memory and was lost. The other 2 jobs were in the database query step, partway through fetching data. No partial output was written anywhere. For all 5 jobs, the Celery task was not marked as failed in the task queue backend — the process was killed without a clean shutdown, so the task was left in a running state in the Redis queue with no completion or failure record. The users whose jobs were killed saw "Report generation in progress" in the UI indefinitely. The report completion check ran every 30 seconds and looked for a completion record in the task backend — which never appeared because the task was never marked complete or failed. The users did not receive notification emails. Two of the 5 users opened support tickets the next morning asking why their report hadn't arrived. The support team investigated, found the abandoned S3 upload attempts in the access log, recognized the pattern from a previous deploy, and manually re-enqueued the report generation jobs for the affected users. The manual re-enqueue happened 18 hours after the original request. The founding session documented "2-minute drain window after blue-green cutover before terminating blue workers" — it did not specify that the Celery worker drain window must equal the maximum job duration (6 minutes, not 2 minutes), that in-flight jobs must be tracked separately from the task queue state to detect mid-execution kills, or that Celery workers must be shut down with a graceful stop signal rather than a process kill to allow in-flight jobs to complete or re-queue themselves.

Structural properties set by the blue-green deployment decision

Three structural properties are determined when a team designs their blue-green deployment process. None appear explicitly in the session that establishes the deploy sequence, the session that configures the ECS deregistration delay, or the session that sets the drain window for background workers — they are the operational consequences of design choices made under the assumption that blue-green means "bring up green, switch traffic, clean up blue" without specifying the constraints that make each step safe to execute.

Property 1: The database schema compatibility contract and the cutover overlap window. The blue-green model requires the shared database schema to be simultaneously compatible with the code running in both blue and green during the overlap window — the period from when the database migration runs to when blue is terminated. The overlap window is not zero even for instantaneous load balancer cutover: the migration runs before the cutover, and blue runs against the migrated schema from the moment the migration completes until blue terminates at the end of the rollback window. Every migration that runs during this period must be compatible with blue's writes and reads. The compatibility contract classifies every migration into one of three categories. Additive-safe: migrations that add structure without removing or changing existing structure that blue references — adding nullable columns (blue's INSERT statements do not supply the column, PostgreSQL stores NULL, blue's SELECT queries do not reference the column), adding tables (blue is unaware of the table), adding indexes CONCURRENTLY (no table lock, blue's writes continue), and adding NOT VALID foreign key constraints (not validated against existing rows until a separate VALIDATE FOREIGN KEY command runs post-cutover). Expand-contract required: migrations that change existing structure blue references — renaming a column, changing a column's type in a way that rejects current blue writes, adding a NOT NULL constraint without a DEFAULT, and dropping a column or constraint that blue's code references; these require a three-phase sequence across multiple sequential deploy cycles: expand (add the new structure alongside the old, so both blue and green can write to either), migrate (update existing data and application code to write to both, or write only to new and read from both), and contract (remove the old structure, which is now safe because blue — in the release that includes the contract step — no longer references it and the rollback window for that release is closed). Post-cutover-only: migrations that are safe to run after blue is terminated and the rollback window closes — dropping tables blue references in its code, removing constraints blue relies on, changing defaults for columns blue reads. The database migration strategy decision record documents the expand-contract pattern in full — the migration classification framework, the two-table rename sequence (add new column, backfill, dual-write, switch reads, drop old column across five sequential releases), and the automated migration lint gate that blocks single-migration column renames from reaching the deploy pipeline without a preceding expand step. The CI/CD pipeline decision record documents the pipeline gate configuration that enforces the migration classification: a pre-deploy migration check that parses the pending migration SQL, classifies each statement, and blocks the deploy if any statement is classified as non-additive-safe while the previous deploy's rollback window is still open.

Property 2: The long-lived connection drainage window and the in-memory state loss surface. Blue-green deployment terminates the blue environment. Before blue can be safely terminated, every long-lived connection and every in-flight operation blue holds must complete, be migrated to green, or be gracefully closed with the client informed of the disconnection. The drainage window is the time between "stop routing new connections to blue" and "terminate blue." The drainage window specification must enumerate every category of connection and operation that blue serves, state the drainage mechanism for each, and set the minimum drainage window to the maximum drainage time across all categories. HTTP keep-alive connections drain within the request pipeline: the load balancer stops sending new requests to blue after deregistration, existing keep-alive connections complete their in-flight request and then close naturally (the NLB closes the connection after the deregistration delay), so the drainage window for HTTP keep-alive connections equals the maximum in-flight HTTP request duration plus a buffer — typically under 60 seconds. WebSocket connections do not drain through the deregistration delay mechanism. The NLB keeps existing WebSocket connections open to blue after deregistration, because WebSocket is a long-lived stateful connection that cannot be automatically migrated to a new upstream. Blue must drain WebSocket connections by sending a server-initiated WebSocket close frame to each connected client, which triggers the client to close the connection and reconnect to green. This requires the application code to have a graceful shutdown handler that iterates over open WebSocket connections and sends close frames before the process exits — not a feature that is automatically present in most frameworks. The close frames must be sent with enough time before termination for clients to receive them, close their connections, and initiate reconnects before blue's process exits and the OS sends TCP RSTs. The minimum drainage window for WebSocket connections is the round-trip time for the close frame plus a reconnect initiation delay — practically, 10 to 30 seconds. Background job workers require a separate drainage mechanism: the worker process must receive a graceful shutdown signal (SIGTERM for most job frameworks) rather than a kill signal (SIGKILL), the framework must stop accepting new jobs from the queue, and in-flight jobs must be given time to complete before the process exits. The minimum drainage window for background workers is the maximum job duration. In-memory state is the most persistent risk: application state held in process memory — collaborative session contexts, operational transform buffers, in-progress computation results, local caches not backed by Redis — is lost when the process exits, regardless of how gracefully the shutdown proceeds. The deploy session that designs each in-memory stateful feature must specify whether the state is a candidate for pre-cutover persistence flush (acceptable for session state that can be checkpointed to Redis or a database table before the WebSocket close frames are sent) or whether a cold reconnect is architecturally acceptable for that feature (acceptable for features where the persistent data layer contains enough state for the client to reconstruct its context on reconnect). The real-time architecture decision record documents the session state persistence model — whether collaborative session state is held in application memory or in Redis, and the consequence for blue-green cutover: memory-backed session state requires a pre-cutover flush step and a graceful WebSocket close sequence, while Redis-backed session state survives blue termination and clients reconnecting to green pick up where they left off. The background job infrastructure decision record documents the Celery, Sidekiq, or equivalent worker graceful shutdown configuration — the SIGTERM handler, the in-flight job timeout, and the re-queue behavior for jobs that exceed the timeout — and the separate drain window for each job class by maximum job duration, which is the value that must be used for the blue termination delay for the worker tier, not the value used for the web tier.

Property 3: The rollback window and the blue termination trigger. After traffic is cut to green and the drainage window closes, blue enters the rollback window: it is running, idle, and ready to receive traffic if the load balancer cutover is reversed. The rollback window ends when blue is terminated. The value of the rollback window depends entirely on what it is triggered by. A rollback window triggered by a fixed wall-clock timer — "terminate blue 10 minutes after cutover" — is a time-box that closes before the production error signals that would trigger a rollback have had a chance to appear. The class of errors that are only visible under real production load includes: schema-dependent query failures triggered by data green writes in a shape that blue's schema migration modified (a query that worked on the pre-migration schema and on test data may fail on production data that carries pre-migration values alongside post-migration values until the backfill completes), business-logic failures triggered by concurrent state modifications from blue's in-flight jobs and green's new code processing the state those jobs left, and failures in low-traffic paths that are exercised by specific user workflows infrequently enough that 10 minutes of green traffic may not have triggered them. A rollback window triggered by a health signal is substantially more useful: green's HTTP error rate (5xx responses) must be below the pre-deploy baseline for a continuous minimum observation period (10 minutes is the minimum for most services; 30 minutes is appropriate for services with traffic patterns that vary significantly within a 10-minute window), no P0 or P1 incident has been opened in the monitoring system since the cutover, and key business-logic metrics — transaction success rate, report completion rate, data export success rate — are within their normal bounds. The health signal must be verified by a human or by an automated check that queries the observability stack, not by the absence of alerts (the absence of alerts in the first 10 minutes post-cutover does not mean green is healthy — it may mean the alert has not fired yet). The authorization to terminate blue must be an explicit action — a deploy pipeline step that requires human approval after the rollback window health check passes, or a runbook step that the deploying engineer executes after verifying the health signal. The observability strategy decision record documents the metric-based alerting that generates the green health signal — the error rate dashboard, the business-logic metric panels, and the alert suppression policy during the cutover window that prevents false rollback triggers from deployment health check delays while still catching genuine post-cutover degradation. The incident response playbook decision record documents the rollback authorization process — who can authorize a blue-green rollback (the on-call engineer, the service owner), what the rollback procedure is (reverse the load balancer cutover, which blue environment to use if the rollback is triggered hours after cutover and a new blue has not been preserved), and the post-rollback analysis process for understanding what green failed on before the rollback is re-attempted.

What the founding session records and what it omits

The founding blue-green deployment session typically records the deployment topology (two parallel environments behind a shared load balancer), the traffic cut mechanism (load balancer target group switch, DNS record update, feature flag percentage rollout, or weighted routing policy), and the deploy sequence (bring up green, run migrations, switch traffic, terminate blue, or some ordering of those steps). It may record the rationale for blue-green over rolling update — zero-downtime cutover with an instant rollback path, clear environment separation for testing, or the organizational requirement that every release be validated in a green environment before receiving production traffic. What it does not record is the schema migration compatibility requirement: that the migration running at step two of the deploy sequence must be simultaneously compatible with blue at step one and green at step three, and that the category of change (additive-safe, expand-contract, post-cutover-only) determines whether the deploy can complete in a single cycle or requires a multi-deploy sequence. What it also does not record is the connection drainage inventory: the list of every long-lived connection type the application holds, the mechanism by which each is drained before blue terminates, and the drain time that each requires — from which the minimum blue termination delay is derived as the maximum drain time across all connection types. And what it does not record is the rollback window specification: the condition under which blue can be safely terminated, expressed as a health signal from green rather than a wall-clock time after cutover.

The schema migration omission compounds with the team's confidence in the blue-green model. Blue-green is understood as the zero-downtime deployment pattern — the pattern that eliminates deployment-caused downtime. The assumption that migration failures are prevented by the blue-green model is natural but wrong: the blue-green model prevents downtime from application code changes by allowing instant rollback to blue, but it does not prevent downtime from incompatible schema migrations because the migration runs against the shared database before the cutover, and rolling back an incompatible migration requires a new migration that itself must be backward-compatible. The teams that operate blue-green for years without schema migration incidents do so not because blue-green protects them, but because they have developed an intuition for which schema changes are safe to run during the overlap window — an intuition that is not written down and is not transmitted to engineers who join the team after the blue-green model is established. The migration classification — additive-safe, expand-contract, post-cutover-only — makes the implicit rule explicit and creates a gate that catches incompatible migrations in the pipeline before they reach the deploy. The database migration strategy decision record documents the classification taxonomy and the CI gate that enforces it. The database connection pooling decision record documents the connection pool behavior at cutover — how the pool is configured to release connections gracefully during the blue termination sequence, and the pool exhaustion risk when both blue and green have pools open against the same database during the overlap window (the aggregate pool size of blue plus green may exceed the database's maximum connection limit, causing connection refusals during the overlap window if the pool configuration does not account for the double-fleet period).

The connection drainage omission is a structural gap between the abstraction the blue-green model presents and the implementation that executes it. The abstraction — "switch traffic from blue to green, then terminate blue" — treats termination as instantaneous and connection closure as automatic. The implementation — ECS deregistration delay, SIGTERM handler, WebSocket close frame sequence, Celery worker graceful stop — is a set of separate mechanisms, each covering a specific connection type, each requiring explicit configuration in the framework or the infrastructure layer. The gap appears at every new long-lived connection type the application introduces. When the team adds WebSocket support to a service that previously had only HTTP endpoints, the existing deregistration delay configuration does not automatically extend to cover WebSocket connections — a new drainage mechanism must be designed and configured for the WebSocket tier. When the team adds a background job runner, the existing drain window does not automatically accommodate the maximum job duration — the drain window must be updated to reflect the new maximum. The drainage inventory — a living document maintained alongside the application architecture that lists every long-lived connection type, its drain mechanism, and its drain time — is the artifact that prevents the gap from compounding silently. The real-time architecture decision record documents the WebSocket connection count at steady state, the maximum session duration, and the graceful shutdown sequence for the WebSocket tier — the inputs required to calculate the WebSocket-specific drain time and design the pre-cutover close frame broadcast. The container orchestration decision record documents the Kubernetes or ECS lifecycle configuration — the preStop hook, the terminationGracePeriodSeconds, the deregistration delay — and the precedence rules that determine which setting governs the blue termination behavior when multiple settings interact (ECS deregistration delay and ECS task stop timeout both affect when the process receives SIGKILL; if the stop timeout is shorter than the deregistration delay, the process is killed before the drain completes).

The rollback window omission is the most invisible of the three, because rolling back a blue-green deploy is an exceptional event — it happens rarely enough that the rollback window is rarely tested in practice. Most teams discover the rollback window specification is inadequate only when they need to roll back and find that blue was terminated before the issue that triggered the rollback was visible. The wall-clock termination timer — "terminate blue 10 minutes after cutover" — feels adequate because most deploys do not need a rollback and 10 minutes feels like more than enough time to detect a problem. The class of errors that appears after 10 minutes is precisely the class that the rollback window is designed to catch: low-traffic-path failures that require specific user actions to trigger, schema-dependent query failures that appear only when a query hits a data row with a specific combination of old and new-format values, and failures in scheduled jobs that run at a fixed time that may not fall within the first 10 minutes of green traffic. The health-signal-based rollback window — "terminate blue when green's error rate has been below baseline for 15 continuous minutes and no P0/P1 incident is open" — is operationally heavier but produces a rollback window that closes when the evidence supports termination rather than when a fixed timer expires. The observability strategy decision record documents the pre-deploy baseline capture (the error rate and business-logic metric snapshot taken 60 minutes before the deploy begins, used as the comparison baseline for the post-cutover health signal), the alert suppression policy during the cutover window (which alerts are suppressed during the 5-minute health check ramp-up period to avoid false rollback triggers from deployment lag), and the automated health signal check that the deploy pipeline can query to determine whether the rollback window has passed. The WhyChose decision extractor finds the founding deploy sessions in your ChatGPT and Claude export — the "how should we do blue-green on ECS?" infrastructure design session, the "what's our deployment sequence?" runbook writing session, the "how do we handle WebSocket connections during deploys?" feature design session. It extracts the deploy sequence, the drain window, and the termination trigger from the founding session and surfaces the schema compatibility contract, the connection drainage inventory, and the rollback window specification that the session documented versus the ones it omitted.

The five ADR sections for a blue-green deployment decision

Section 1: Deployment topology and traffic shift strategy. Specify the two-environment topology: how blue and green are provisioned (separate ECS services, separate Kubernetes deployments, separate Auto Scaling groups, separate virtual machine sets), what infrastructure they share (the database, the Redis cluster, the S3 bucket, the message queue — shared state is the primary risk surface for overlap-window failures), and what infrastructure is environment-specific (the application containers, the Celery or Sidekiq workers, the in-memory caches, the application configuration). Specify the traffic shift mechanism and its granularity: an instantaneous load balancer switch (all traffic moves from blue to green in one operation — zero overlap for new connections, but existing long-lived connections continue to blue until they drain), a weighted routing policy (10% to green, then 50%, then 100% — creates a longer overlap window during which both blue and green serve production traffic simultaneously, which extends the schema compatibility requirement to the full overlap period and requires both environments to handle concurrent writes to the shared database), or a DNS record update (slower propagation, longer overlap, DNS TTL determines the maximum time any client is still routing to blue after the switch is intended). Specify which environment serves as the authoritative writer during the overlap window for any stateful operations that must have a single authoritative writer to avoid split-brain conflicts — session creation, payment processing, report job enqueuing. The CDN decision record documents the CDN caching and origin switching model — whether the CDN caches responses from the origin and, if so, how the CDN cache is flushed or bypassed during the cutover to prevent stale blue responses from being served by the CDN after the load balancer has switched to green.

Section 2: Database schema migration classification and compatibility contract. Specify the migration classification taxonomy: additive-safe (nullable column additions, new table additions, concurrent index additions, NOT VALID constraint additions), expand-contract required (column renames, type changes that reject current blue write values, NOT NULL additions without DEFAULT, column drops), and post-cutover-only (table drops, constraint drops that blue relies on for correctness). Specify the expand-contract sequence for each expand-contract-required migration type: the number of sequential deploy cycles required (column rename requires at minimum three cycles: add new column, dual-write to both, switch reads to new, drop old column), the data migration step (the backfill that populates the new column for all existing rows during the dual-write phase), and the gate condition for advancing from each phase to the next (the backfill must complete and be verified before the switch-reads phase, the switch-reads phase must be stable in production for a minimum observation period before the drop-old-column phase). Specify the CI pipeline gate: a migration linter that parses each migration SQL statement, classifies it, and blocks the deploy if any statement is classified as non-additive-safe without a preceding expand phase being confirmed in the deploy history. Specify the migration rollback procedure for additive-safe migrations that fail post-deploy (a compensating migration that drops the added column or table, which is itself additive-safe and can be run while green is serving traffic). The database migration strategy decision record documents the migration framework selection, the migration ordering and locking model (advisory locks to prevent concurrent migrations, ordering constraints to ensure the expand phase's migration has committed before the dual-write phase's application code is deployed), and the migration history table that the CI gate queries to confirm that the preceding expand phase's migration has been applied to the production database before the application code that assumes the expand is available is allowed to deploy.

Section 3: Connection drainage window specification and in-memory state audit. Enumerate every long-lived connection type the application holds: HTTP keep-alive connections (specifying the maximum in-flight request duration and the NLB deregistration delay required to drain them), WebSocket connections (specifying the steady-state connection count, the maximum session duration, the graceful shutdown handler that sends close frames, the minimum drain time from first close frame sent to last client reconnected, and whether the client reconnect logic includes exponential backoff with jitter to prevent reconnect storms), background job workers (specifying the job class, the maximum job duration per class, the graceful stop signal, the re-queue behavior for jobs that exceed the graceful stop timeout, and the drain time per job class), and any other stateful long-lived connection (gRPC streaming connections, server-sent event streams, long-poll connections). Specify the minimum drain time for each connection type and the composite minimum blue termination delay as the maximum across all types. Enumerate all in-memory application state and classify it: state that is replicated to green through a durable backing store (Redis, database) and survives blue termination without loss, state that must be flushed to a durable store before the drain begins (session state that can be checkpointed), and state that is inherently ephemeral and is lost when blue terminates (in-progress computation results with no checkpoint). For state that must be flushed before drain begins, specify the flush mechanism and the maximum flush time, which adds to the effective minimum blue termination delay. The database connection pooling decision record documents the pool configuration at the blue-green fleet level — the aggregate pool size of blue plus green during the overlap window and the maximum connections the database accepts, with the constraint that the aggregate pool size must not exceed the database's maximum connection limit during the double-fleet period.

Section 4: Blue termination criteria and rollback window specification. Specify the rollback window duration as a health signal from green, not as a wall-clock time after cutover. The health signal consists of: green's HTTP error rate (5xx responses as a fraction of total responses) must be below the pre-deploy baseline for a continuous minimum observation period (10 minutes minimum; 30 minutes for services with variable traffic patterns; 60 minutes for services with infrequent but high-value transactions), green's key business-logic metrics (transaction success rate, job completion rate, data export success rate) must be within defined normal bounds for the same observation period, and no P0 or P1 incident has been opened in the monitoring system with the deploy's change ID cited as a potential cause. Specify the pre-deploy baseline capture: a snapshot of the error rate and business-logic metrics taken in the 60 minutes before the deploy begins, used as the comparison baseline for the post-cutover health signal. Specify the blue termination authorization: an explicit action by the on-call engineer or the deploying engineer after verifying the health signal, not an automatic pipeline step. Specify the rollback procedure and its authorization: the on-call engineer can initiate rollback without requiring additional approval for a P0 or P1 incident; the rollback procedure is to reverse the load balancer cutover to blue (which must still be running and healthy); and the post-rollback analysis process to determine what green failed on before the next deploy attempt. Specify the maximum rollback window duration: if green has been healthy for the minimum observation period and no rollback trigger has fired, blue must be terminated within a maximum time (commonly 4 to 24 hours after cutover) to avoid the operational complexity of maintaining two live environments indefinitely. The multi-region deployment decision record documents the sequencing of blue-green cutover across regions — the order in which regions receive traffic (typically starting with the lowest-traffic region to validate before the highest-traffic region), the per-region rollback window, and the propagation of a rollback decision across regions when a regional health check fails.

Section 5: Cutover monitoring specification and automatic rollback triggers. Specify the monitoring instrumentation required during the cutover window: a deploy event annotation in the observability platform (marking the exact cutover timestamp in every metric and log view for the post-cutover analysis), environment-tagged metrics that distinguish blue and green traffic during the overlap window (to identify whether errors are originating from blue or green), and a cutover health dashboard that aggregates error rate, latency, business-logic metrics, and the background job completion rate for the 60-minute window around the cutover. Specify automatic rollback triggers: conditions that, if detected during the rollback window, automatically reverse the load balancer cutover without requiring a human decision — an error rate that exceeds three times the pre-deploy baseline for more than 2 continuous minutes, a P0 alert firing for a service that the deploy modified, or a business-logic metric dropping below 80% of its pre-deploy baseline for more than 5 minutes. Specify the alert suppression policy for the cutover window: which alerts are suppressed during the 5-minute ramp-up period after the cutover (health check delays, connection count transitions, cache cold-start latency spikes) to prevent false automatic rollback triggers from the expected transient effects of the cutover itself. Specify the post-cutover analysis process: after blue is terminated and the rollback window closes, a mandatory post-deploy review of the error rate, business-logic metrics, and background job completion rate for the 24 hours following the cutover, with any anomalies documented in the deploy log. The observability strategy decision record documents the metric tagging model that makes environment-tagged metrics possible — the env=blue and env=green label on every metric emitted by the application, and the Grafana or Datadog query that filters by environment label to isolate blue and green error rates independently during the overlap window for diagnoses that require attributing an error to a specific environment during a weighted routing cutover.