@@ -956,7 +956,7 @@ The normal automatic sequence is quality/deployment-contract, Django with Postgr
956956one tested image, exact active-pair capture, immutable publication, migration exit ` 0 ` , stable and
957957healthy web with exact SHA, singleton worker, read-only HTTP/browser smoke (including safe 404),
958958terminal exact-pair verification, and artifact finalization. The deployer session is fixed at 3600
959- seconds. The general stage, public-health, and compensation wait remains 180 seconds. A forward
959+ seconds. The general stage and public-health budgets remain 180 seconds. A forward
960960promotion or rollback that intentionally starts/replaces web receives the explicit, code-owned
961961240-second web-stabilization budget; 240 seconds is also its hard maximum. Only a forward promotion
962962or rollback that starts/replaces the singleton worker receives the separate explicit, code-owned
@@ -965,7 +965,10 @@ workflow-dispatch input or an arbitrary operator override. A mutating `UpdateSer
965965only while time remains. Read-only polling makes exactly one final ECS service observation at the
966966monotonic deadline and never sleeps or polls again afterward. Exact completion in that observation
967967succeeds; an incomplete or invalid observation fails. Any response returned after the deadline is
968- discarded.
968+ discarded. Recovery has separate fixed code-owned bounds: 240 seconds for web, 420 seconds for the
969+ singleton worker, and 720 seconds for the complete recovery phase. Those values are fixed workflow
970+ arguments with matching hard maxima; they are not dispatch inputs, repository variables,
971+ environment overrides, or permission for a larger operator value.
969972
970973Web completion still requires its expected task-definition ARN and desired count, exactly one
971974` PRIMARY ` deployment with that definition and count, exact service and primary running/pending
@@ -1002,7 +1005,7 @@ ARN. The immutable receipt target remains the requested tuple. For a positive re
10021005may initially return that exact new PRIMARY at deployment-level desired/running/pending/failed
10031006` 0/0/0/0 ` and ` IN_PROGRESS ` , while the service-level tuple already has the requested count. That
10041007AWS initialization shape binds identity but is poll-only. It does not rewrite ` B/1 ` to ` B/0 ` , prove
1005- stabilization, start public health, or permit the worker mutation.
1008+ stabilization, start public health, or, during forward rollout, permit the worker mutation.
10061009
10071010A structurally partial acknowledgement is reconciled with an immediate ` DescribeServices ` call;
10081011there is no preliminary sleep. Every present member must be correctly typed, and the complete set
@@ -1068,14 +1071,54 @@ remained the untouched exact prior singleton. This run remains failed; ultimate
10681071not a release success and does not substitute for a bound restorative receipt, terminal proof,
10691072public health, smoke, or a successful-release record.
10701073
1074+ Run ` 31289994036 ` on 2026-08-09 failed at the deployed HTTP smoke because the smoke assertion for
1075+ the intentional ` /courses/ ` production canonical was stale. The new web task was healthy and
1076+ served the exact candidate SHA; this was not an ECS rollout failure. Automatic compensation began
1077+ after that failure, spent about 160 seconds restoring and serially waiting for web, then issued the
1078+ worker restore under the unrelated 180-second general-stage budget. The controller timed out about
1079+ 183 seconds into that worker wait. ECS later converged to the exact captured worker about 280
1080+ seconds after its restore began, inside the accepted 420-second singleton-worker behavior. The run
1081+ and its compensation remain failed: later convergence supplied neither a timely worker receipt
1082+ proof nor the required terminal pair and public-health proof.
1083+
10711084If an attempted ` UpdateService ` response is lost or invalid, recovery uses the same absolute
1072- 180-second per-service deadline for candidate reconciliation and the restorative receipt wait.
1085+ per-workload deadline for candidate reconciliation, restorative receipt acquisition, and
1086+ stabilization: web uses exactly 240 seconds and worker exactly 420 seconds. One absolute 720-second
1087+ phase deadline starts before the first attempted-predecessor observation or recovery mutation. A
1088+ workload deadline is ` min(workload recovery start + workload budget, phase deadline) ` and is never
1089+ reset by acknowledgement, reconciliation, polling, error handling, terminal proof, health proof,
1090+ or evidence handling.
10731091It polls only the captured terminal identity under the same bounded retirement rules and the
10741092actually attempted target until that target is observed as the unique PRIMARY and its deployment ID
1075- can be bound while time remains. The deadline is finite, cannot exceed the general-stage maximum,
1076- and is never restarted between capture and restore. A capture that returns exactly at the deadline
1093+ can be bound while time remains. Both ambiguous attempted identities are reconciled in fixed
1094+ ` web -> worker ` order before restorative mutation, so a reconciliation wait cannot split the two
1095+ restorative updates. The controller then issues and binds the exact web restore followed immediately
1096+ by the exact worker restore. It performs no stabilization wait, public-health check, terminal
1097+ proof, evidence write/upload, or deliberate sleep between those two successfully bound restores;
1098+ only receipt acknowledgement and its immediate exact reconciliation belong to binding. A capture
1099+ that returns exactly at its workload deadline
10771100cannot start the restorative mutation. A speculative workload that was never invoked is absent from
10781101the recovery allowlist.
1102+
1103+ After all eligible restore bindings have been attempted, the controller observes the retained
1104+ receipts cooperatively in single-threaded ` web -> worker ` rounds. There are no threads, processes,
1105+ async calls, concurrent SDK mutations, or blind retries. Each pending workload receives one
1106+ observation per round against its own receipt, predecessor set, and absolute deadline. The
1107+ controller sleeps at most once after a round, bounded by the poll interval, the earliest pending
1108+ workload deadline, and the phase deadline. Completion or failure removes only that workload from
1109+ later rounds; it cannot consume, reset, or suppress the other workload's observation. Equality is
1110+ inclusive: an exact terminal response on the workload deadline passes. An incomplete response on
1111+ that final read expires, no later sleep/read is allowed, and any provider response returned after
1112+ the workload or phase deadline is rejected.
1113+
1114+ An isolated workload binding or observation error is retained while the other already-authorized
1115+ restore proceeds within its own deadline. The failed mutation is never retried and identity is
1116+ never inferred from later convergence. Invalid prior context, workload allowlist, budget, or a
1117+ global attribution contradiction stops further mutation. Any retained error makes total recovery
1118+ fail even if later read-only state appears converged. A contradiction or unknown error has
1119+ precedence over deadline expiry; ` receipt_deadline_expired ` is retained only when every recovery
1120+ error is that allowlisted reason.
1121+
10791122An attempted candidate may be failed while its restorative receipt replaces it, but the recovery
10801123receipt itself may not fail. Every restorative call must return a new receipt, including an
10811124` A -> A ` force-new recovery; the old ` A ` deployment is always a predecessor, never recovery success.
@@ -1091,16 +1134,43 @@ part of the final pair proof. Once worker mutation was actually attempted, its r
10911134receipt-bound. Artifact-finalization recovery intentionally restores both workloads because both
10921135belong to the failed release that had already reached terminal proof.
10931136
1137+ Only after all receipt observations finish does the controller perform one exact terminal pair
1138+ proof and, for a non-bootstrap prior release, exact prior-SHA public readiness/liveness. Success
1139+ requires one newly bound receipt for every mutated workload, each receipt as the unique exact
1140+ ` PRIMARY ` with ` COMPLETED ` , exact task definition and desired/running/pending counts, zero failed
1141+ tasks, and only absent or exact recognized zero-work predecessors. The terminal pair must bind both
1142+ exact captured task definitions/counts/receipt IDs, active task definitions, image digest, source
1143+ identity, and the singleton worker. Bootstrap ` 0/0 ` skips public health but still proves exact zero
1144+ terminal state. Missing or duplicate receipts/PRIMARYs, third or cross-paired identities, unsafe
1145+ predecessors, failed tasks/rollouts, inexact counts, SHA/readiness mismatch, phase expiry, or any
1146+ unclassified error fails closed. Ultimate ECS convergence is not a substitute.
1147+
1148+ Compensation never creates or preserves a rollback-eligible success record. An exact restored pair
1149+ does not change the original promotion or rollback failure: that release still ends red.
1150+ Artifact-finalization recovery removes the local failed-release record only after this complete
1151+ exact recovery passes and also ends red.
1152+
1153+ At worker capture, acknowledgement, every cooperative observation, and terminal proof, service
1154+ ` running + pending ` and the sum across all recognized deployments must each remain at most one.
1155+ Final active-task proof requires exactly the captured worker task when desired count is one and no
1156+ task for bootstrap. Any transient or final overlap is an immediate contradiction and cannot be
1157+ masked by a later singleton read.
1158+
10941159For triage, compare redacted service/PRIMARY tuples and deployment IDs against the recorded receipt
10951160and phase predecessors. Forward, rollback, compensation, and artifact-finalization recovery expose
1096- each bound receipt using only its workload, deployment ID, allowlisted binding reason, and whether
1161+ the fixed plan (` 240/420/720 ` , restore order, eligible and intentionally untouched workloads), each
1162+ bound receipt using only its workload, deployment ID, allowlisted binding reason, and whether
10971163an exact terminal reconciliation observation was carried. The summary is recorded before waiting,
1098- so it remains available after a post-binding failure. Evidence uses only allowlisted reason codes
1164+ but after every eligible binding has been attempted, so it remains available after a post-binding
1165+ failure without splitting the web/worker restore sequence. Per-workload evidence reports only
1166+ ` passed ` , ` receipt_deadline_expired ` , or ` contract_contradiction ` plus the intentionally-untouched
1167+ boolean. Terminal-pair, public-health, worker-singleton, and total results are separate safe facts.
1168+ Evidence uses only allowlisted reason codes
10991169for complete binding, zero-count initialization, partial acknowledgement reconciliation,
11001170contradiction, and receipt deadline expiry; it never stores the raw provider payload. Do not retry
11011171the mutation, add an unrecognized identity, pre-sleep before
11021172the first observation, or infer adoption from a running task, target health, logs, or an old
1103- completed deployment. A candidate that never becomes the unique PRIMARY by the shared recovery
1173+ completed deployment. A candidate that never becomes the unique PRIMARY by its workload recovery
11041174deadline, or any third/cross-paired identity, leaves recovery failed closed for operator review.
11051175
11061176Restorative failure classification retains ` receipt_deadline_expired ` only when every observed
@@ -1109,15 +1179,22 @@ restorative error is that allowlisted deadline reason. If any workload, terminal
11091179reason is also collapsed to ` contract_contradiction ` ; raw exception messages and provider payloads
11101180are never propagated into evidence or CLI output.
11111181
1182+ Recovery evidence, CLI output, exception text, and artifacts never contain raw AWS responses,
1183+ provider exception messages, request/response bodies, URLs with query strings, headers, cookies,
1184+ credentials, tokens, environment values, task logs, or recovery-context contents. Exact
1185+ task-definition ARNs, deployment IDs, desired/count tuples, booleans, and the documented reason
1186+ codes are the complete safe operator allowlist.
1187+
11121188The conservative critical-stage recovery envelope is
11131189` 180 + 120 + 240 + 180 + 420 + 180 + 360 + 720 = 2400 ` seconds: migration observation,
11141190stopped-migration terminal proof, web stabilization, public readiness/liveness, worker
11151191stabilization, deployed browser smoke, three critical two-minute artifact uploads, and the
1116119212-minute finalization-recovery cap. This deliberately conservative sum includes mutually
11171193exclusive migration-stop and later recovery work. It leaves ` 3600 - 2400 = 1200 ` seconds (20
11181194minutes) of the fixed deployer session for recovery. Automatic compensation and finalization
1119- recovery inherit neither forward stabilization budget: their exact-pair service waits stay at 180
1120- seconds and remain inside the separate 12-minute recovery cap. Migration observation, public
1195+ recovery use the same mutually exclusive 720-second phase cap, with the separate fixed 240-second
1196+ web and 420-second singleton-worker recovery deadlines inside it. They do not inherit or alter the
1197+ forward stabilization waits. Migration observation, public
11211198health, browser smoke, and artifact finalization likewise retain their existing independent
11221199bounds. Do not raise any timeout in workflow inputs or code. If either reviewed stabilization
11231200value is insufficient, disable automatic deployment and file/groom another issue with new
0 commit comments