<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pradeep Kandepaneni</title>
    <description>The latest articles on DEV Community by Pradeep Kandepaneni (@pradeep_kandepaneni).</description>
    <link>https://dev.to/pradeep_kandepaneni</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4039222%2F9a1dc160-51ad-490a-a15b-a11040122abc.png</url>
      <title>DEV Community: Pradeep Kandepaneni</title>
      <link>https://dev.to/pradeep_kandepaneni</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pradeep_kandepaneni"/>
    <language>en</language>
    <item>
      <title>Blast Radius First: A Trust-Tier Model for Letting AI Agents Touch Production</title>
      <dc:creator>Pradeep Kandepaneni</dc:creator>
      <pubDate>Tue, 04 Aug 2026 06:20:34 +0000</pubDate>
      <link>https://dev.to/pradeep_kandepaneni/blast-radius-first-a-trust-tier-model-for-letting-ai-agents-touch-production-4ceo</link>
      <guid>https://dev.to/pradeep_kandepaneni/blast-radius-first-a-trust-tier-model-for-letting-ai-agents-touch-production-4ceo</guid>
      <description>&lt;p&gt;How to decide what an autonomous agent is allowed to do before you decide how clever it is.&lt;br&gt;
Originally published on AWS Builder Center&lt;br&gt;
[&lt;a href="https://builder.aws.com/content/3HRGyQKfP1sAjbyhm1WkJsBDca8/blast-radius-first-a-trust-tier-model-for-letting-ai-agents-touch-production" rel="noopener noreferrer"&gt;https://builder.aws.com/content/3HRGyQKfP1sAjbyhm1WkJsBDca8/blast-radius-first-a-trust-tier-model-for-letting-ai-agents-touch-production&lt;/a&gt;]&lt;br&gt;
Most conversations about AI in operations start in the wrong place. They start with the model - how good is it, how much can we trust its judgment, will it hallucinate a kubectl delete at 3 a.m. The capability question feels like the important one, so it gets all the attention.&lt;br&gt;
It's the wrong question to lead with.&lt;br&gt;
The question that actually determines whether AI-driven operations is safe or reckless isn't how good is the agent - it's what happens when it's wrong. Not if. When. Every automated actor, human or machine, eventually takes the wrong action against a live system. The engineers who've run production at scale know this in their bones: you don't design for the day everything works, you design for the day it doesn't. AI changes nothing about that principle and everything about its urgency, because an agent can be wrong faster, more confidently, and at higher frequency than any on-call human.&lt;br&gt;
So this piece is about designing from blast radius first. Decide what an agent is allowed to touch based on what breaks when it's wrong - and only then worry about how capable it needs to be. I'll lay out a trust-tier model I've found useful for that, grounded in the same reliability discipline - SLOs, error budgets, progressive delivery - that we already trust to govern human change.&lt;br&gt;
The capability trap&lt;br&gt;
Here's the seductive logic that gets teams into trouble. The model is getting better every quarter. Once it's good enough, we'll let it do more. So autonomy becomes a function of trust in the model's judgment, and trust grows with benchmarks and vibes.&lt;br&gt;
The problem is that model capability and blast radius are completely independent axes, and teams collapse them into one. A highly capable agent restarting a stateless pod is low-risk. A mediocre agent modifying an IAM policy is catastrophic-risk. Capability tells you how often the agent is right. Blast radius tells you how bad it is when the agent is wrong. You cannot buy down the second with the first. A 99.9%-accurate agent acting on something with an irreversible, estate-wide blast radius is still one bad call away from an incident you can't take back - and at machine frequency, 99.9% accuracy produces a wrong action surprisingly often.&lt;br&gt;
This is why "let it do more once it's smarter" quietly inverts the safety model. It ties the size of the blast radius to the thing that varies most (model quality) instead of the thing you actually control (permissions). Reliability engineering solved this for humans decades ago and we forgot to apply it: we don't give a new SRE root on the billing database because they're clever. We give them scoped access that widens as the cost of their mistakes proves survivable. Same principle. Different actor.&lt;br&gt;
Trust tiers: permissions scoped to reversibility&lt;br&gt;
The model I use scopes agent authority to a single question asked of every possible action: how expensive is it to undo this if it's wrong? That gives four tiers.&lt;br&gt;
Tier 0 - Observe&lt;br&gt;
The agent can read everything and act on nothing. It surfaces correlations, drafts a diagnosis, proposes a remediation - and stops. A human executes. Blast radius: zero. This is where every agent starts and where most should live longer than teams want them to. The value here is real and underrated: a good Tier 0 agent that turns forty dashboards into one ranked hypothesis has already paid for itself, with none of the risk.&lt;br&gt;
Tier 1 - Reversible action&lt;br&gt;
The agent can take actions that fully self-heal or roll back with no residual state. Restart a stateless pod. Scale a deployment within pre-set bounds. Drain and cordon a node the cluster will replace. Flush a cache. The defining test: if the agent is wrong, the system returns to its prior state automatically or with a trivial, well-understood undo. Blast radius: bounded and recoverable. This is the sweet spot where autonomy earns its keep on toil.&lt;br&gt;
Tier 2 - Semi-reversible action&lt;br&gt;
Actions that can be undone, but at a cost - a config change that requires a redeploy to revert, a traffic shift, a scale-up that costs real money. Reversible in principle, but the undo has latency, blast radius, or a price tag. Agents operate here only with a guardrail outside the model: a policy engine that bounds the action, a canary that must stay healthy, an error-budget check that halts the action if the service is already burning budget. The agent proposes and initiates; the system, not the model's confidence, decides whether it proceeds.&lt;br&gt;
Tier 3 - Irreversible / high-consequence&lt;br&gt;
Deleting persistent data. Modifying IAM or security groups. Anything touching secrets, billing, or the control plane itself. Anything a human would need a second reviewer for. The agent's authority here is exactly zero, permanently, regardless of how capable it becomes. Not "not yet" - no. These actions get a human in the loop by design, because the cost of being wrong is unbounded and no accuracy figure justifies unbounded downside. The point of naming this tier explicitly is to stop the quiet drift of Tier 3 actions into Tier 2 because the demo looked impressive.&lt;br&gt;
Mapping this onto real platform work makes it concrete. Automated pod restarts and bounded autoscaling sit comfortably at Tier 1 - reversible, well understood, safe to let run. Traffic shifts and configuration changes that need a redeploy to undo belong at Tier 2, gated behind canary health and an error-budget check rather than the agent's own confidence. And the things that warrant the tightest governance in any DevSecOps context - CI/CD pipeline changes, tool-access controls, IAM policy - are unambiguously Tier 3: no autonomous authority, human review by design, regardless of how good the tooling becomes.&lt;br&gt;
Wiring the tiers to reliability primitives you already&amp;nbsp;have&lt;br&gt;
The elegant part - and the part that makes this practical rather than aspirational - is that you don't need new machinery to enforce these tiers. The primitives already exist in any mature SRE practice.&lt;br&gt;
Error budgets become the throttle. A Tier 2 action shouldn't fire when the target service is already burning its error budget - that's precisely when an automated change is most likely to compound an incident. Gate agent actions on burn rate the same way you gate deploys. When the budget is healthy, the agent has room to act; when it's exhausted, autonomy contracts automatically. The error budget stops being just a release-cadence signal and becomes a real-time autonomy governor.&lt;br&gt;
Progressive delivery becomes the safety envelope. Any Tier 2 agent action ships the way a risky deploy ships: to a canary first, watched against SLIs, with automated rollback if the signal degrades. The agent doesn't get a special fast path around the safeguards humans use - it gets the same envelope, which is the whole point. If your rollback automation is good enough to trust with a human's deploy, it's good enough to backstop an agent's action.&lt;br&gt;
Policy-as-code becomes the tier boundary. The line between tiers can't live in a prompt - prompts are suggestions, and an agent under pressure will rationalise past a suggestion. The boundary lives in an external policy engine (OPA, admission control, IAM itself) that the agent physically cannot talk its way around. This is the single most important design commitment in the whole model: the tier boundary must be enforced by something the model cannot reason with. Guardrails the agent can argue with are decoration.&lt;br&gt;
Put together, these give you an agent whose authority expands and contracts with the real-time health of the system, bounded by machinery it can't override - which is a far more honest safety story than "the model is good, trust it."&lt;br&gt;
Why this beats "trust the&amp;nbsp;model"&lt;br&gt;
Three reasons this framing holds up where capability-first thinking doesn't.&lt;br&gt;
It's auditable. "The agent can take Tier 0 and Tier 1 actions on these services, gated on error budget, with everything above requiring a human" is a sentence you can put in front of a security review, an auditor, or a nervous VP and have it mean something. "We trust the model's judgment" is not.&lt;br&gt;
It's stable under model change. Swap the underlying model, upgrade it, downgrade it to save cost - the safety envelope doesn't move, because it was never a function of the model in the first place. Your risk posture doesn't silently drift every time a vendor ships a new version.&lt;br&gt;
It decouples value from danger. Most of the operational value of AIOps lives at Tiers 0 and 1 - faster diagnosis, less toil, quicker recovery on reversible actions. Most of the danger lives at Tier 3. Teams that lead with capability chase the danger to get the value. Teams that lead with blast radius harvest the value and leave the danger on the table where it belongs.&lt;br&gt;
Where to start on&amp;nbsp;Monday&lt;br&gt;
You don't roll this out as a platform program. You start by asking one question of whatever automation or agent you already have, or are about to build: what's the worst irreversible thing this could do, and what physically stops it? If the answer is "the prompt tells it not to," you have a tier boundary enforced by a suggestion, and that's the first thing to fix.&lt;br&gt;
From there: inventory your candidate remediation actions and sort them into the four tiers by reversibility, not by how confident you are in the model. Enforce the Tier 2/3 line in policy-as-code, not prose. Gate Tier 2 on error budget. Keep everything at Tier 0 longer than feels necessary, and promote actions up a tier only when the tier below has proven boring. Boring is the goal. Boring is what safe automation looks like from the outside.&lt;br&gt;
The agents will keep getting better. That's exactly why the discipline has to come from somewhere other than the agent. Blast radius first, capability second - and the reliability practice you already trust to govern human change is more than enough to govern the machine kind too.&lt;/p&gt;




&lt;p&gt;This trust-tier model sits above two companion pieces I've written: pricing agent autonomy against error budgets and dollars, and building a production-safe AI remediation firewall for Amazon EKS.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Autonomy Boundary: Pricing Your AIOps Agent in Both Error Budget and Dollars</title>
      <dc:creator>Pradeep Kandepaneni</dc:creator>
      <pubDate>Wed, 29 Jul 2026 05:23:49 +0000</pubDate>
      <link>https://dev.to/pradeep_kandepaneni/the-autonomy-boundary-pricing-your-aiops-agent-in-both-error-budget-and-dollars-e2a</link>
      <guid>https://dev.to/pradeep_kandepaneni/the-autonomy-boundary-pricing-your-aiops-agent-in-both-error-budget-and-dollars-e2a</guid>
      <description>&lt;p&gt;Autonomous SRE agents like AWS DevOps Agent can already investigate and remediate incidents — the unsolved problem is the boundary: which actions run unsupervised. A first-principles framework for drawing that line by reversibility, evidence-based confidence, and metered cost, with a reproducible lab behind every claim.&lt;/p&gt;

&lt;p&gt;The full lab — the blast-radius router, the Terraform guardrails, the fault-injection scripts, and the capture tooling behind every figure above — is at &lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="github.com/PradeepKandepaneni/autonomy-boundary-lab" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;github.com/PradeepKandepaneni/autonomy-boundary-lab&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;
Originally published on the AWS Builder Center:&lt;br&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://builder.aws.com/content/3HAAh06HXby9dHRSDX0jejEsdDj/the-autonomy-boundary-pricing-your-aiops-agent-in-both-error-budget-and-dollars" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbuilder.aws.com%2Fassets%2Fog-hiXAX-on.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://builder.aws.com/content/3HAAh06HXby9dHRSDX0jejEsdDj/the-autonomy-boundary-pricing-your-aiops-agent-in-both-error-budget-and-dollars" rel="noopener noreferrer" class="c-link"&gt;
            AWS Builder Center
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Connect with builders who understand your journey. Share solutions, influence AWS product development, and access useful content that accelerates your growth. Your community starts here.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbuilder.aws.com%2Fassets%2Fbuilder-favicon-sq0js-4n.svg" width="16" height="16"&gt;
          builder.aws.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Every number in this article traces to a test, a captured log, or the budget model in that repo.&lt;/p&gt;

&lt;p&gt;The claim, up front&lt;/p&gt;

&lt;p&gt;Autonomy is no longer a capability problem. Your agent can already investigate an incident and act on it. AWS DevOps Agent went generally available on March 31, 2026, built on Amazon Bedrock AgentCore, and it correlates telemetry, code, and deployment data to triage issues without a human driving each step. The interesting question moved somewhere else.&lt;/p&gt;

&lt;p&gt;The binding constraint is now a decision boundary: which actions may an agent execute unsupervised, which must it escalate, and how do you encode that line so it survives change-management policy, a budget ceiling, and a 2 a.m. failure? Almost every "look, it self-healed" demo skips this. Industry data for 2026 puts it bluntly — only about one in five organizations has a mature governance model for autonomous agents. That gap, not model capability, is where production incidents and surprise bills come from.&lt;/p&gt;

&lt;p&gt;This article gives you a first-principles framework for drawing that boundary, and it insists on a second axis most treatments ignore: the boundary is simultaneously a reliability decision and a cost decision. An autonomous investigation triggered by a flapping, false-positive alert burns error budget and agent-minutes. If you draw the line using reliability logic alone, you will leak money; if you draw it using cost logic alone, you will suppress investigations you needed. You have to price both.&lt;/p&gt;

&lt;p&gt;First principles: why this is a decision-theory problem, not a tooling problem&lt;/p&gt;

&lt;p&gt;Strip away the vendor framing and every autonomous remediation reduces to one comparison. For a given detected condition, you weigh the expected cost of the agent acting on its own against the expected cost of escalating to a human.&lt;/p&gt;

&lt;p&gt;Acting alone has an expected cost of roughly P(agent is wrong) × (blast radius of a wrong action). Escalating has a cost too, and it is not zero: human response latency, on-call toil, and — the part people forget — the agent-minutes and tokens already spent investigating before the escalation. AI SRE agents make far more model calls than a chatbot because a single incident triggers planning, tool selection, evidence gathering, hypothesis revision, and reporting. That work has a meter running on it.&lt;/p&gt;

&lt;p&gt;So the boundary is defined by three quantities, and you can reason about all three concretely:&lt;/p&gt;

&lt;p&gt;Reversibility and blast radius of the action. Restarting a crash-looping pod is contained and reversible. Scaling a Karpenter node group within a ceiling is reversible. Modifying a production database, deleting a volume, or rolling a schema is neither.&lt;br&gt;
The agent's confidence — defined as evidence completeness, not model self-report. A hypothesis backed by a specific file, line, log record, and a clean before/after correlation is high-confidence. "The model said 87%" is not evidence; agents hallucinate, and a confidently wrong root-cause analysis is the dangerous failure mode.&lt;br&gt;
The economic weight of investigating. Investigation-based pricing punishes noisy alerts: an agent investigating a false positive still costs you. Alert quality is therefore a direct input to agent spend, which couples your SLO hygiene to your FinOps.&lt;/p&gt;

&lt;p&gt;Everything below is just these three quantities, made operational.&lt;/p&gt;

&lt;p&gt;The framework: a blast-radius router, not a self-healing switch&lt;/p&gt;

&lt;p&gt;Do not ship an on/off "autonomy" toggle. Ship a router that classifies each candidate action into one of four dispositions, parameterised by the three quantities above.&lt;/p&gt;

&lt;p&gt;Agent confidence (evidence completeness)    Reversible + contained blast radius Irreversible or wide blast radius&lt;br&gt;
High (specific evidence, clean correlation) Auto-execute, then log an immutable audit record and open a prevention item Execute-with-preview: agent proposes the exact change; human approves before it runs&lt;br&gt;
Low (thin or conflicting evidence)  Auto-investigate under a budget cap, gather evidence, act only if confidence crosses the threshold; otherwise escalate  Escalate immediately. Do not act. Attach evidence and page a human&lt;/p&gt;

&lt;p&gt;Two design rules make this router safe rather than decorative:&lt;/p&gt;

&lt;p&gt;Confidence is a gate, not a suggestion. Below your threshold, the disposition can never be auto-execute regardless of blast radius. The threshold is a policy value you tune from measured calibration, not a vibe.&lt;/p&gt;

&lt;p&gt;The router's ceilings are enforced below the agent, in infrastructure, not inside the agent's own logic. This is the single most important architectural decision in the whole design, and I will justify it next.&lt;/p&gt;

&lt;p&gt;Deep mechanics: guardrails as code, enforced beneath the agent&lt;/p&gt;

&lt;p&gt;An agent that polices its own limits is a single point of failure — the same LLM that might hallucinate the root cause is the thing deciding whether it is allowed to act. Put the hard limits where the agent cannot reason its way past them.&lt;/p&gt;

&lt;p&gt;Scope IAM so the blast radius is physically bounded. The agent's execution role should be able to restart pods, cordon a node, or trigger a rollback of a specific deployment, and should have no path to delete persistent volumes, alter a production database, or touch IAM. If the router mis-classifies, the permission boundary is the backstop.&lt;/p&gt;

&lt;p&gt;Encode budget and scale ceilings in Terraform / policy, not prose. A Karpenter provisioner gets a hard node ceiling. A cost guardrail caps agent-minutes per incident and per day. The failure this prevents is real: a misconfigured AI agent can generate in hours a bill that would take months to accumulate under ordinary provisioning, and there is at least one publicly reported near-half-billion-dollar AI-misconfiguration incident on record. The ceiling is the difference between a bounded experiment and an unbounded liability.&lt;/p&gt;

&lt;p&gt;Encode change-freeze windows as policy. An agent that scales or patches outside an approved change window has produced a governance violation even if the action itself was correct. This is one of the named risks in the 2026 governance-gap data — autonomous actions that conflict with change-management policy — and it is trivially preventable with a deny window the agent honours.&lt;/p&gt;

&lt;p&gt;Keep an immutable audit trail. Every auto-executed action writes an audit record the agent cannot later modify. AWS DevOps Agent produces immutable investigation timelines for exactly this reason; if you are wiring your own remediation layer, replicate the property. Auditability is what lets you widen autonomy later with evidence instead of hope.&lt;/p&gt;

&lt;p&gt;Route the low-severity and known-noisy alerts away from auto-investigation. This is the cost-hygiene mechanism. Deduplicate first, suppress flappers, and only spend agent-minutes on signals that clear a quality bar. Then feed the noise metrics back into tightening your SLOs, closing the loop between reliability and spend.&lt;/p&gt;

&lt;p&gt;The failure modes (this is the part your readers actually need)&lt;/p&gt;

&lt;p&gt;Anyone can show the happy path. Credibility comes from the failure modes, and there are four worth naming.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Auto-resolution that masks the root cause. The most seductive failure. The alarm returns to OK, the graph looks clean, and the underlying defect is untouched and will recur. This is not hypothetical — AWS's own AgentCore observability walkthrough shows an incident that self-resolved in about a minute while the triggering vulnerability remained live. Mitigation: every auto-resolve must still open a prevention-backlog item. Recovery is not resolution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The noisy-alert cost trap. Investigation-based billing means an agent chewing on false positives is a silent budget leak. Mitigation: gate investigations on alert quality and dedupe aggressively before the meter starts. Your alert hygiene is now a line item.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Change-management conflict. A technically correct scale-up during a freeze is still an incident of its own kind. Mitigation: freeze windows as enforced policy, not documentation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Confidence miscalibration. The agent is confidently wrong. Mitigation: require concrete evidence artifacts — the specific file, line, and log record — as a precondition for auto-execute, and treat the model's self-reported confidence as untrusted input.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A note on metrics — read this before you quote anyone&lt;/p&gt;

&lt;p&gt;The market is saturated with unverifiable numbers. You will see claims of 90%-plus alert-noise reduction, 40–60% MTTR improvement across enterprise deployments, and one vendor advertising 94% root-cause accuracy with up to 75% MTTR improvement. These are third-party and vendor-reported figures. Cite them as such or not at all, and never present them as your own results.&lt;/p&gt;

&lt;p&gt;The only numbers you should attach your name to are ones you measured, with a stated baseline, a stated method, and a stated time window. A senior reviewer — or a senior interviewer — will ask you all three, and a borrowed figure collapses under the first follow-up. This is why the rest of this article is a lab you run, not a benchmark I assert.&lt;/p&gt;

&lt;p&gt;Reproduce this: the autonomy-boundary-lab&lt;/p&gt;

&lt;p&gt;Everything above is buildable at low cost. The repo is deliberately named to stand apart from generic "golden path" demos, because its contribution is the policy layer, not the platform.&lt;/p&gt;

&lt;p&gt;What you build:&lt;/p&gt;

&lt;p&gt;A small service on a kind cluster (or a single-node EKS if you want the DevOps Agent integration end to end), instrumented so a CloudWatch alarm fires on a defined failure.&lt;br&gt;
A reproducible fault-injection script — a crash loop, a bad deploy, a dependency timeout — so the same incident is repeatable and your logs are real, not staged.&lt;br&gt;
The blast-radius router as a small policy component: it reads the alarm and the agent's evidence, classifies the action into one of the four dispositions, and enforces the confidence gate.&lt;br&gt;
The guardrails as code: a scoped IAM role, a Karpenter node ceiling, an agent-minute budget cap, and a change-freeze deny window, all in Terraform.&lt;br&gt;
What the lab actually produced (this run)&lt;/p&gt;

&lt;p&gt;The fault-injection script moves the app's listen port to :9999 while the readiness and liveness probes still target :5678. That is a single, locatable configuration change — the high-evidence path the router routes to auto_execute. The captured Kubernetes event stream shows the root cause in plain text:&lt;/p&gt;

&lt;p&gt;Warning  Unhealthy  Liveness probe failed:  dial tcp 10.244.0.7:5678: connect: connection refused&lt;br&gt;
Warning  Unhealthy  Readiness probe failed: dial tcp 10.244.0.7:5678: connect: connection refused&lt;br&gt;
Normal   Killing    Container app failed liveness probe, will be restarted&lt;/p&gt;

&lt;p&gt;The failing pod's restart count climbed on a clean cadence — 1, 2, 3, 4 at roughly 30-second intervals, matching the probe's periodSeconds: 10 × failureThreshold: 3 — before Kubernetes backed it off into CrashLoopBackOff. This is the two halves of high-confidence evidence in one capture: an exact location (probes hitting a port the app no longer serves) and a clean before/after correlation (the failure begins precisely at the config change).&lt;/p&gt;

&lt;p&gt;Equally important is what did not break. The previous ReplicaSet held its two Ready replicas throughout, so the service stayed up while the bad revision failed to roll out. The incident was reversible and contained — exactly the quadrant the router sends to auto_execute. The lab's behaviour and the router's classification agree, on the same run.&lt;/p&gt;

&lt;p&gt;The cost dimension (modeled, not measured)&lt;/p&gt;

&lt;p&gt;Investigation is metered, so the boundary has a price. The rate is AWS-official — $0.0083 per agent-second, i.e. $0.498 per agent-minute, per AWS's DevOps Agent pricing page, billed only for active agent time (idle is free). AWS's own example puts a typical 8-minute investigation at about $3.98. What is modeled below is how many agent-minutes a given incident consumes, since these figures come from the lab's budget.py ceilings rather than a live agent run — read them as a model of the dynamics, not a measurement of this specific fault:&lt;/p&gt;

&lt;p&gt;A per-incident ceiling of 15 agent-minutes caps a single investigation at about $7.47 — a deliberate ceiling set above AWS's ~$3.98 typical, not a prediction of typical spend. A per-day ceiling of 240 agent-minutes caps a runaway day at about $119.52. The ceiling is the difference between a bounded experiment and an unbounded liability.&lt;br&gt;
The router suppresses a known-noisy alert before the meter starts, spending $0.00 on it. An ungated agent investigating the same false positive spends up to the per-incident cap. So each suppressed false positive avoids up to $7.47 — which is why alert hygiene is a FinOps lever, not just a reliability one.&lt;/p&gt;

&lt;p&gt;That is one measured claim (the incident timeline, reproducible from the repo) and a modeled cost claim at an AWS-official rate (clearly labelled, traceable to real code output). Both are smaller and less flashy than the vendor headlines, and that is exactly why they hold up. The measured version — real agent-minutes from a live DevOps Agent investigation of this same fault — is the subject of the follow-up.&lt;/p&gt;

&lt;p&gt;Tradeoffs, stated plainly&lt;/p&gt;

&lt;p&gt;When full autonomy is correct: contained, reversible, well-understood operations where the cost of a wrong action is low and recovery is trivial — pod restarts, in-ceiling scaling, rollbacks of a specific known-bad deploy. Some domains already run closed-loop remediation in production, notably patch management and certain automated security responses.&lt;/p&gt;

&lt;p&gt;When full autonomy is negligent: irreversible or wide-blast-radius actions, anything touching the data plane, low-confidence situations, and anything inside a change freeze. Here the correct disposition is escalate-with-evidence, and "the agent was confident" is not a defence.&lt;/p&gt;

&lt;p&gt;The multi-cloud wrinkle. The GA release of AWS DevOps Agent extended investigations beyond AWS into Azure and on-premises workloads. If your estate is hybrid, your boundary policy has to be cloud-agnostic — the router classifies by blast radius and evidence, which are portable concepts, while the guardrail enforcement is implemented per-environment. Do not hard-wire the policy to one provider's primitives.&lt;/p&gt;

&lt;p&gt;The one-line version&lt;/p&gt;

&lt;p&gt;The agents can act. The engineering that separates a production-grade AIOps posture from a demo is the boundary — drawn from reversibility, evidence-based confidence, and the metered cost of investigation — and enforced in infrastructure the agent cannot override. Draw that line well and the autonomy is an asset. Skip it and you have automated your way into a governance violation with a bill attached.&lt;/p&gt;

&lt;p&gt;The full lab — the blast-radius router, the Terraform guardrails, the fault-injection scripts, and the capture tooling behind every figure above — is at github.com/PradeepKandepaneni/autonomy-boundary-lab. Every number in this article traces to a test, a captured log, or the budget model in that repo.&lt;/p&gt;

</description>
      <category>aiops</category>
      <category>devops</category>
      <category>sre</category>
      <category>aws</category>
    </item>
    <item>
      <title>Building a Production-Safe AI Remediation Firewall for Amazon EKS</title>
      <dc:creator>Pradeep Kandepaneni</dc:creator>
      <pubDate>Wed, 29 Jul 2026 05:10:46 +0000</pubDate>
      <link>https://dev.to/pradeep_kandepaneni/building-a-production-safe-ai-remediation-firewall-for-amazon-eks-2pen</link>
      <guid>https://dev.to/pradeep_kandepaneni/building-a-production-safe-ai-remediation-firewall-for-amazon-eks-2pen</guid>
      <description>&lt;p&gt;A reproducible multi-AZ resilience walkthrough: spread a service across simulated zones, kill one under load, and measure the dropped requests — plus the parts that only show up in real production.&lt;/p&gt;

&lt;p&gt;Originally published on the AWS Builder Center: &lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://builder.aws.com/content/3GnvKe3PBz3fP3m3pFFDFghjIxX/making-a-service-survive-an-availability-zone-outage-and-proving-it-for-dollar0" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbuilder.aws.com%2Fassets%2Fog-hiXAX-on.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://builder.aws.com/content/3GnvKe3PBz3fP3m3pFFDFghjIxX/making-a-service-survive-an-availability-zone-outage-and-proving-it-for-dollar0" rel="noopener noreferrer" class="c-link"&gt;
            AWS Builder Center
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Connect with builders who understand your journey. Share solutions, influence AWS product development, and access useful content that accelerates your growth. Your community starts here.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbuilder.aws.com%2Fassets%2Fbuilder-favicon-sq0js-4n.svg" width="16" height="16"&gt;
          builder.aws.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;
Repo: &lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/PradeepKandepaneni" rel="noopener noreferrer"&gt;
        PradeepKandepaneni
      &lt;/a&gt; / &lt;a href="https://github.com/PradeepKandepaneni/golden-path-resilience" rel="noopener noreferrer"&gt;
        golden-path-resilience
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;golden-path-resilience&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Make a service &lt;strong&gt;survive the loss of an entire availability zone&lt;/strong&gt; — and prove
it, on free infrastructure, with a demo that kills a zone under load and counts
how many requests drop. Spoiler: it should be zero.&lt;/p&gt;
&lt;p&gt;This is a sequel to &lt;a href="https://github.com/PradeepKandepaneni/golden-path" rel="noopener noreferrer"&gt;golden-path&lt;/a&gt;
Same tiny service; now the interesting part is the &lt;strong&gt;topology&lt;/strong&gt;: how it's spread
so that one zone can vanish without taking the service with it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Runs end-to-end on a local multi-node &lt;a href="https://kind.sigs.k8s.io/" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;kind&lt;/code&gt;&lt;/a&gt;
cluster and in CI on GitHub's free runners. &lt;strong&gt;Total cost: $0.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What this proves&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Three worker nodes are labelled as three simulated zones (&lt;code&gt;az-a&lt;/code&gt;, &lt;code&gt;az-b&lt;/code&gt;,
&lt;code&gt;az-c&lt;/code&gt;). Six replicas spread two-per-zone. Then &lt;code&gt;scripts/az-outage-demo.sh&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;starts a continuous stream of requests at the service,&lt;/li&gt;
&lt;li&gt;cordons and drains one zone's node (a stand-in for that AZ going dark),&lt;/li&gt;
&lt;li&gt;watches the evicted pods reschedule onto the surviving zones,&lt;/li&gt;
&lt;li&gt;tallies how many…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/PradeepKandepaneni/golden-path-resilience" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The claim, up front&lt;/p&gt;

&lt;p&gt;Autonomy is no longer a capability problem. Your agent can already investigate an incident and act on it. AWS DevOps Agent went generally available on March 31, 2026, built on Amazon Bedrock AgentCore, and it correlates telemetry, code, and deployment data to triage issues without a human driving each step. The interesting question moved somewhere else.&lt;/p&gt;

&lt;p&gt;The binding constraint is now a decision boundary: which actions may an agent execute unsupervised, which must it escalate, and how do you encode that line so it survives change-management policy, a budget ceiling, and a 2 a.m. failure? Almost every "look, it self-healed" demo skips this. Industry data for 2026 puts it bluntly — only about one in five organizations has a mature governance model for autonomous agents. That gap, not model capability, is where production incidents and surprise bills come from.&lt;/p&gt;

&lt;p&gt;This article gives you a first-principles framework for drawing that boundary, and it insists on a second axis most treatments ignore: the boundary is simultaneously a reliability decision and a cost decision. An autonomous investigation triggered by a flapping, false-positive alert burns error budget and agent-minutes. If you draw the line using reliability logic alone, you will leak money; if you draw it using cost logic alone, you will suppress investigations you needed. You have to price both.&lt;/p&gt;

&lt;p&gt;First principles: why this is a decision-theory problem, not a tooling problem&lt;/p&gt;

&lt;p&gt;Strip away the vendor framing and every autonomous remediation reduces to one comparison. For a given detected condition, you weigh the expected cost of the agent acting on its own against the expected cost of escalating to a human.&lt;/p&gt;

&lt;p&gt;Acting alone has an expected cost of roughly P(agent is wrong) × (blast radius of a wrong action). Escalating has a cost too, and it is not zero: human response latency, on-call toil, and — the part people forget — the agent-minutes and tokens already spent investigating before the escalation. AI SRE agents make far more model calls than a chatbot because a single incident triggers planning, tool selection, evidence gathering, hypothesis revision, and reporting. That work has a meter running on it.&lt;/p&gt;

&lt;p&gt;So the boundary is defined by three quantities, and you can reason about all three concretely:&lt;/p&gt;

&lt;p&gt;Reversibility and blast radius of the action. Restarting a crash-looping pod is contained and reversible. Scaling a Karpenter node group within a ceiling is reversible. Modifying a production database, deleting a volume, or rolling a schema is neither.&lt;br&gt;
The agent's confidence — defined as evidence completeness, not model self-report. A hypothesis backed by a specific file, line, log record, and a clean before/after correlation is high-confidence. "The model said 87%" is not evidence; agents hallucinate, and a confidently wrong root-cause analysis is the dangerous failure mode.&lt;br&gt;
The economic weight of investigating. Investigation-based pricing punishes noisy alerts: an agent investigating a false positive still costs you. Alert quality is therefore a direct input to agent spend, which couples your SLO hygiene to your FinOps.&lt;/p&gt;

&lt;p&gt;Everything below is just these three quantities, made operational.&lt;/p&gt;

&lt;p&gt;The framework: a blast-radius router, not a self-healing switch&lt;/p&gt;

&lt;p&gt;Do not ship an on/off "autonomy" toggle. Ship a router that classifies each candidate action into one of four dispositions, parameterised by the three quantities above.&lt;/p&gt;

&lt;p&gt;High confidence (specific evidence, clean before/after correlation):&lt;/p&gt;

&lt;p&gt;Reversible + contained blast radius → Auto-execute, then log an immutable audit record and open a prevention item.&lt;br&gt;
Irreversible or wide blast radius → Execute-with-preview: the agent proposes the exact change; a human approves before it runs.&lt;/p&gt;

&lt;p&gt;Low confidence (thin or conflicting evidence):&lt;/p&gt;

&lt;p&gt;Reversible + contained blast radius → Auto-investigate under a budget cap; gather evidence and act only if confidence crosses the threshold, otherwise escalate.&lt;br&gt;
Irreversible or wide blast radius → Escalate immediately — do not act; attach evidence and page a human.&lt;/p&gt;

&lt;p&gt;Two design rules make this router safe rather than decorative:&lt;/p&gt;

&lt;p&gt;Confidence is a gate, not a suggestion. Below your threshold, the disposition can never be auto-execute regardless of blast radius. The threshold is a policy value you tune from measured calibration, not a vibe.&lt;/p&gt;

&lt;p&gt;The router's ceilings are enforced below the agent, in infrastructure, not inside the agent's own logic. This is the single most important architectural decision in the whole design, and I will justify it next.&lt;/p&gt;

&lt;p&gt;Deep mechanics: guardrails as code, enforced beneath the agent&lt;/p&gt;

&lt;p&gt;An agent that polices its own limits is a single point of failure — the same LLM that might hallucinate the root cause is the thing deciding whether it is allowed to act. Put the hard limits where the agent cannot reason its way past them.&lt;/p&gt;

&lt;p&gt;Scope IAM so the blast radius is physically bounded. The agent's execution role should be able to restart pods, cordon a node, or trigger a rollback of a specific deployment, and should have no path to delete persistent volumes, alter a production database, or touch IAM. If the router mis-classifies, the permission boundary is the backstop.&lt;/p&gt;

&lt;p&gt;Encode budget and scale ceilings in Terraform / policy, not prose. A Karpenter provisioner gets a hard node ceiling. A cost guardrail caps agent-minutes per incident and per day. The failure this prevents is real: a misconfigured AI agent can generate in hours a bill that would take months to accumulate under ordinary provisioning, and there is at least one publicly reported near-half-billion-dollar AI-misconfiguration incident on record. The ceiling is the difference between a bounded experiment and an unbounded liability.&lt;/p&gt;

&lt;p&gt;Encode change-freeze windows as policy. An agent that scales or patches outside an approved change window has produced a governance violation even if the action itself was correct. This is one of the named risks in the 2026 governance-gap data — autonomous actions that conflict with change-management policy — and it is trivially preventable with a deny window the agent honours.&lt;/p&gt;

&lt;p&gt;Keep an immutable audit trail. Every auto-executed action writes an audit record the agent cannot later modify. AWS DevOps Agent produces immutable investigation timelines for exactly this reason; if you are wiring your own remediation layer, replicate the property. Auditability is what lets you widen autonomy later with evidence instead of hope.&lt;/p&gt;

&lt;p&gt;Route the low-severity and known-noisy alerts away from auto-investigation. This is the cost-hygiene mechanism. Deduplicate first, suppress flappers, and only spend agent-minutes on signals that clear a quality bar. Then feed the noise metrics back into tightening your SLOs, closing the loop between reliability and spend.&lt;/p&gt;

&lt;p&gt;The failure modes (this is the part your readers actually need)&lt;/p&gt;

&lt;p&gt;Anyone can show the happy path. Credibility comes from the failure modes, and there are four worth naming.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Auto-resolution that masks the root cause. The most seductive failure. The alarm returns to OK, the graph looks clean, and the underlying defect is untouched and will recur. This is not hypothetical — AWS's own AgentCore observability walkthrough shows an incident that self-resolved in about a minute while the triggering vulnerability remained live. Mitigation: every auto-resolve must still open a prevention-backlog item. Recovery is not resolution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The noisy-alert cost trap. Investigation-based billing means an agent chewing on false positives is a silent budget leak. Mitigation: gate investigations on alert quality and dedupe aggressively before the meter starts. Your alert hygiene is now a line item.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Change-management conflict. A technically correct scale-up during a freeze is still an incident of its own kind. Mitigation: freeze windows as enforced policy, not documentation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Confidence miscalibration. The agent is confidently wrong. Mitigation: require concrete evidence artifacts — the specific file, line, and log record — as a precondition for auto-execute, and treat the model's self-reported confidence as untrusted input.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A note on metrics — read this before you quote anyone&lt;/p&gt;

&lt;p&gt;The market is saturated with unverifiable numbers. You will see claims of 90%-plus alert-noise reduction, 40–60% MTTR improvement across enterprise deployments, and one vendor advertising 94% root-cause accuracy with up to 75% MTTR improvement. These are third-party and vendor-reported figures. Cite them as such or not at all, and never present them as your own results.&lt;/p&gt;

&lt;p&gt;The only numbers you should attach your name to are ones you measured, with a stated baseline, a stated method, and a stated time window. A senior reviewer — or a senior interviewer — will ask you all three, and a borrowed figure collapses under the first follow-up. This is why the rest of this article is a lab you run, not a benchmark I assert.&lt;/p&gt;

&lt;p&gt;Reproduce this: the autonomy-boundary-lab&lt;/p&gt;

&lt;p&gt;Everything above is buildable at low cost. The repo is deliberately named to stand apart from generic "golden path" demos, because its contribution is the policy layer, not the platform.&lt;/p&gt;

&lt;p&gt;What you build:&lt;/p&gt;

&lt;p&gt;A small service on a kind cluster (or a single-node EKS if you want the DevOps Agent integration end to end), instrumented so a CloudWatch alarm fires on a defined failure.&lt;br&gt;
A reproducible fault-injection script — a crash loop, a bad deploy, a dependency timeout — so the same incident is repeatable and your logs are real, not staged.&lt;br&gt;
The blast-radius router as a small policy component: it reads the alarm and the agent's evidence, classifies the action into one of the four dispositions, and enforces the confidence gate.&lt;br&gt;
The guardrails as code: a scoped IAM role, a Karpenter node ceiling, an agent-minute budget cap, and a change-freeze deny window, all in Terraform.&lt;br&gt;
What the lab actually produced (this run)&lt;/p&gt;

&lt;p&gt;The fault-injection script moves the app's listen port to :9999 while the readiness and liveness probes still target :5678. That is a single, locatable configuration change — the high-evidence path the router routes to auto_execute. The captured Kubernetes event stream shows the root cause in plain text:&lt;/p&gt;

&lt;p&gt;Warning  Unhealthy  Liveness probe failed:  dial tcp 10.244.0.7:5678: connect: connection refused&lt;br&gt;
Warning  Unhealthy  Readiness probe failed: dial tcp 10.244.0.7:5678: connect: connection refused&lt;br&gt;
Normal   Killing    Container app failed liveness probe, will be restarted&lt;/p&gt;

&lt;p&gt;The failing pod's restart count climbed on a clean cadence — 1, 2, 3, 4 at roughly 30-second intervals, matching the probe's periodSeconds: 10 × failureThreshold: 3 — before Kubernetes backed it off into CrashLoopBackOff. This is the two halves of high-confidence evidence in one capture: an exact location (probes hitting a port the app no longer serves) and a clean before/after correlation (the failure begins precisely at the config change).&lt;/p&gt;

&lt;p&gt;Equally important is what did not break. The previous ReplicaSet held its two Ready replicas throughout, so the service stayed up while the bad revision failed to roll out. The incident was reversible and contained — exactly the quadrant the router sends to auto_execute. The lab's behaviour and the router's classification agree, on the same run.&lt;/p&gt;

&lt;p&gt;The cost dimension (modeled, not measured)&lt;/p&gt;

&lt;p&gt;Investigation is metered, so the boundary has a price. The rate is AWS-official — $0.0083 per agent-second, i.e. $0.498 per agent-minute, per AWS's DevOps Agent pricing page, billed only for active agent time (idle is free). AWS's own example puts a typical 8-minute investigation at about $3.98. What is modeled below is how many agent-minutes a given incident consumes, since these figures come from the lab's budget.py ceilings rather than a live agent run — read them as a model of the dynamics, not a measurement of this specific fault:&lt;/p&gt;

&lt;p&gt;A per-incident ceiling of 15 agent-minutes caps a single investigation at about $7.47 — a deliberate ceiling set above AWS's ~$3.98 typical, not a prediction of typical spend. A per-day ceiling of 240 agent-minutes caps a runaway day at about $119.52. The ceiling is the difference between a bounded experiment and an unbounded liability.&lt;br&gt;
The router suppresses a known-noisy alert before the meter starts, spending $0.00 on it. An ungated agent investigating the same false positive spends up to the per-incident cap. So each suppressed false positive avoids up to $7.47 — which is why alert hygiene is a FinOps lever, not just a reliability one.&lt;/p&gt;

&lt;p&gt;That is one measured claim (the incident timeline, reproducible from the repo) and a modeled cost claim at an AWS-official rate (clearly labelled, traceable to real code output). Both are smaller and less flashy than the vendor headlines, and that is exactly why they hold up. The measured version — real agent-minutes from a live DevOps Agent investigation of this same fault — is the subject of the follow-up.&lt;/p&gt;

&lt;p&gt;Tradeoffs, stated plainly&lt;/p&gt;

&lt;p&gt;When full autonomy is correct: contained, reversible, well-understood operations where the cost of a wrong action is low and recovery is trivial — pod restarts, in-ceiling scaling, rollbacks of a specific known-bad deploy. Some domains already run closed-loop remediation in production, notably patch management and certain automated security responses.&lt;/p&gt;

&lt;p&gt;When full autonomy is negligent: irreversible or wide-blast-radius actions, anything touching the data plane, low-confidence situations, and anything inside a change freeze. Here the correct disposition is escalate-with-evidence, and "the agent was confident" is not a defence.&lt;/p&gt;

&lt;p&gt;The multi-cloud wrinkle. The GA release of AWS DevOps Agent extended investigations beyond AWS into Azure and on-premises workloads. If your estate is hybrid, your boundary policy has to be cloud-agnostic — the router classifies by blast radius and evidence, which are portable concepts, while the guardrail enforcement is implemented per-environment. Do not hard-wire the policy to one provider's primitives.&lt;/p&gt;

&lt;p&gt;The one-line version&lt;/p&gt;

&lt;p&gt;The agents can act. The engineering that separates a production-grade AIOps posture from a demo is the boundary — drawn from reversibility, evidence-based confidence, and the metered cost of investigation — and enforced in infrastructure the agent cannot override. Draw that line well and the autonomy is an asset. Skip it and you have automated your way into a governance violation with a bill attached.&lt;/p&gt;

&lt;p&gt;A reproducible multi-AZ resilience walkthrough: spread a service across simulated zones, kill one under load, and measure the dropped requests — plus the parts that only show up in real production.&lt;/p&gt;

&lt;p&gt;Originally published on the AWS Builder Center: &lt;a href="https://builder.aws.com/content/3GnvKe3PBz3fP3m3pFFDFghjIxX/making-a-service-survive-an-availability-zone-outage-and-proving-it-for-dollar0" rel="noopener noreferrer"&gt;https://builder.aws.com/content/3GnvKe3PBz3fP3m3pFFDFghjIxX/making-a-service-survive-an-availability-zone-outage-and-proving-it-for-dollar0&lt;/a&gt;&lt;br&gt;
Repo: &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/PradeepKandepaneni" rel="noopener noreferrer"&gt;
        PradeepKandepaneni
      &lt;/a&gt; / &lt;a href="https://github.com/PradeepKandepaneni/golden-path-resilience" rel="noopener noreferrer"&gt;
        golden-path-resilience
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;golden-path-resilience&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Make a service &lt;strong&gt;survive the loss of an entire availability zone&lt;/strong&gt; — and prove
it, on free infrastructure, with a demo that kills a zone under load and counts
how many requests drop. Spoiler: it should be zero.&lt;/p&gt;
&lt;p&gt;This is a sequel to &lt;a href="https://github.com/PradeepKandepaneni/golden-path" rel="noopener noreferrer"&gt;golden-path&lt;/a&gt;
Same tiny service; now the interesting part is the &lt;strong&gt;topology&lt;/strong&gt;: how it's spread
so that one zone can vanish without taking the service with it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Runs end-to-end on a local multi-node &lt;a href="https://kind.sigs.k8s.io/" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;kind&lt;/code&gt;&lt;/a&gt;
cluster and in CI on GitHub's free runners. &lt;strong&gt;Total cost: $0.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What this proves&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Three worker nodes are labelled as three simulated zones (&lt;code&gt;az-a&lt;/code&gt;, &lt;code&gt;az-b&lt;/code&gt;,
&lt;code&gt;az-c&lt;/code&gt;). Six replicas spread two-per-zone. Then &lt;code&gt;scripts/az-outage-demo.sh&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;starts a continuous stream of requests at the service,&lt;/li&gt;
&lt;li&gt;cordons and drains one zone's node (a stand-in for that AZ going dark),&lt;/li&gt;
&lt;li&gt;watches the evicted pods reschedule onto the surviving zones,&lt;/li&gt;
&lt;li&gt;tallies how many…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/PradeepKandepaneni/golden-path-resilience" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>aiops</category>
      <category>devops</category>
      <category>sre</category>
    </item>
    <item>
      <title>Building a Production-Safe AI Remediation Firewall for Amazon EKS</title>
      <dc:creator>Pradeep Kandepaneni</dc:creator>
      <pubDate>Wed, 29 Jul 2026 03:32:51 +0000</pubDate>
      <link>https://dev.to/pradeep_kandepaneni/building-a-production-safe-ai-remediation-firewall-for-amazon-eks-58cn</link>
      <guid>https://dev.to/pradeep_kandepaneni/building-a-production-safe-ai-remediation-firewall-for-amazon-eks-58cn</guid>
      <description>&lt;p&gt;Originally published on the AWS Builder Center:&lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://builder.aws.com/content/3H9ye70bS5LguAQ93hrnfuKbnyF/building-a-production-safe-ai-remediation-firewall-for-amazon-eks" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbuilder.aws.com%2Fassets%2Fog-hiXAX-on.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://builder.aws.com/content/3H9ye70bS5LguAQ93hrnfuKbnyF/building-a-production-safe-ai-remediation-firewall-for-amazon-eks" rel="noopener noreferrer" class="c-link"&gt;
            AWS Builder Center
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Connect with builders who understand your journey. Share solutions, influence AWS product development, and access useful content that accelerates your growth. Your community starts here.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbuilder.aws.com%2Fassets%2Fbuilder-favicon-sq0js-4n.svg" width="16" height="16"&gt;
          builder.aws.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;AI can reduce the time required to investigate incidents, correlate telemetry, and identify probable root causes. But giving an AI system unrestricted production access creates a new reliability risk: the remediation platform itself can become the cause of the next outage.&lt;/p&gt;

&lt;p&gt;This article presents an &lt;strong&gt;AI Remediation Firewall&lt;/strong&gt; for workloads running on Amazon Elastic Kubernetes Service (Amazon EKS).&lt;/p&gt;

&lt;p&gt;The design follows one principle:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI proposes. Deterministic policy authorises. Controlled automation executes. Independent telemetry verifies.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The architecture uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS DevOps Agent for investigation and root-cause analysis&lt;/li&gt;
&lt;li&gt;A structured remediation proposal as the handoff contract&lt;/li&gt;
&lt;li&gt;AWS Step Functions for workflow control&lt;/li&gt;
&lt;li&gt;Amazon Verified Permissions for deterministic authorisation&lt;/li&gt;
&lt;li&gt;AWS Systems Manager Automation for controlled execution&lt;/li&gt;
&lt;li&gt;Amazon CloudWatch Application Signals and CloudWatch Synthetics for independent verification&lt;/li&gt;
&lt;li&gt;Kubernetes RBAC and IAM to restrict blast radius&lt;/li&gt;
&lt;li&gt;Progressive delivery and rollback to contain failed changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The objective is not unrestricted autonomous operations. It is &lt;strong&gt;bounded autonomy&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The production incident
&lt;/h2&gt;

&lt;p&gt;Consider a digital commerce platform running on Amazon EKS.&lt;/p&gt;

&lt;p&gt;The application contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API gateway&lt;/li&gt;
&lt;li&gt;Checkout service&lt;/li&gt;
&lt;li&gt;Inventory service&lt;/li&gt;
&lt;li&gt;Payment service&lt;/li&gt;
&lt;li&gt;Pricing service&lt;/li&gt;
&lt;li&gt;Amazon Aurora PostgreSQL&lt;/li&gt;
&lt;li&gt;Amazon ElastiCache for Redis&lt;/li&gt;
&lt;li&gt;Amazon SQS&lt;/li&gt;
&lt;li&gt;Application Load Balancer&lt;/li&gt;
&lt;li&gt;CloudWatch Application Signals&lt;/li&gt;
&lt;li&gt;CloudWatch Synthetics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A deployment changes the checkout configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;poolSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
  &lt;span class="na"&gt;connectionTimeoutMilliseconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;

&lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;maximumAttempts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;
  &lt;span class="na"&gt;initialBackoffMilliseconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous configuration was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;poolSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
  &lt;span class="na"&gt;connectionTimeoutMilliseconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2000&lt;/span&gt;

&lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;maximumAttempts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;initialBackoffMilliseconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;250&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within minutes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checkout p99 latency increases from about 220 ms to more than four seconds&lt;/li&gt;
&lt;li&gt;HTTP 5xx errors increase&lt;/li&gt;
&lt;li&gt;Aurora connections approach the configured maximum&lt;/li&gt;
&lt;li&gt;SQS queue depth grows&lt;/li&gt;
&lt;li&gt;HPA activity increases&lt;/li&gt;
&lt;li&gt;CPU usage rises across checkout and payment services&lt;/li&gt;
&lt;li&gt;Pods remain &lt;code&gt;Running&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Liveness probes continue to pass&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a difficult incident because infrastructure health looks acceptable at a superficial level.&lt;/p&gt;

&lt;p&gt;Restarting pods provides only temporary relief. Increasing replicas creates more database connections and makes the problem worse.&lt;/p&gt;

&lt;p&gt;AWS DevOps Agent investigates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CloudWatch metrics and logs&lt;/li&gt;
&lt;li&gt;Application Signals topology&lt;/li&gt;
&lt;li&gt;Kubernetes events&lt;/li&gt;
&lt;li&gt;Deployment history&lt;/li&gt;
&lt;li&gt;CloudTrail configuration changes&lt;/li&gt;
&lt;li&gt;Aurora metrics&lt;/li&gt;
&lt;li&gt;SQS metrics&lt;/li&gt;
&lt;li&gt;Approved runbooks and previous incidents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It identifies the latest configuration change as the probable trigger and proposes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Roll back the checkout service to the previous known-good revision.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That recommendation may be correct, but it is not yet authorised.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why an AI recommendation must be treated as untrusted input
&lt;/h1&gt;

&lt;p&gt;An AI-generated remediation can be technically plausible and still be unsafe because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The root-cause analysis may be incomplete&lt;/li&gt;
&lt;li&gt;Multiple deployments may be active&lt;/li&gt;
&lt;li&gt;The target may have changed after the investigation started&lt;/li&gt;
&lt;li&gt;The rollback revision may contain a security defect&lt;/li&gt;
&lt;li&gt;The proposed blast radius may be too large&lt;/li&gt;
&lt;li&gt;The service may already be recovering&lt;/li&gt;
&lt;li&gt;The action may affect a critical dependency&lt;/li&gt;
&lt;li&gt;The rollback artefact may no longer exist&lt;/li&gt;
&lt;li&gt;The recommendation may be based on stale telemetry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI system must not decide:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Its own permissions&lt;/li&gt;
&lt;li&gt;Whether its evidence is sufficient&lt;/li&gt;
&lt;li&gt;Whether the blast radius is acceptable&lt;/li&gt;
&lt;li&gt;Whether human approval is required&lt;/li&gt;
&lt;li&gt;Whether the remediation succeeded&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Those decisions belong outside the AI reasoning boundary.&lt;/p&gt;




&lt;h1&gt;
  
  
  Reference architecture
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CloudWatch SLO alarm or incident alert
                 |
                 v
          AWS DevOps Agent
                 |
       Investigation and RCA
                 |
                 v
      Remediation Proposal Adapter
                 |
                 v
          Amazon EventBridge
                 |
                 v
          AWS Step Functions
                 |
       +---------+----------+
       |                    |
       v                    v
Live-context collector   Schema validator
       |                    |
       +---------+----------+
                 |
                 v
       Deterministic risk engine
                 |
                 v
    Amazon Verified Permissions
                 |
     +-----------+-----------+
     |           |           |
     v           v           v
Auto-execute  Approval      Deny
     |           |
     +-----+-----+
           |
           v
AWS Systems Manager Automation
           |
           v
Restricted EKS executor
           |
           v
Canary or bounded rollout
           |
           v
Application Signals and Synthetics
           |
     +-----+------+
     |            |
     v            v
 Promote       Roll back
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The trust boundaries are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Investigation boundary&lt;/strong&gt;&lt;br&gt;
AI gathers evidence and proposes an action.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Authorisation boundary&lt;/strong&gt;&lt;br&gt;
Deterministic logic decides whether that action is allowed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Execution boundary&lt;/strong&gt;&lt;br&gt;
A restricted runbook performs one allowlisted operation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Verification boundary&lt;/strong&gt;&lt;br&gt;
Independent telemetry decides whether recovery occurred.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h1&gt;
  
  
  1. Keep diagnostic access read-only
&lt;/h1&gt;

&lt;p&gt;The investigation layer should be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read CloudWatch metrics and logs&lt;/li&gt;
&lt;li&gt;Read Kubernetes events&lt;/li&gt;
&lt;li&gt;Read deployment metadata&lt;/li&gt;
&lt;li&gt;Read CloudTrail changes&lt;/li&gt;
&lt;li&gt;Read service topology&lt;/li&gt;
&lt;li&gt;Read approved incident history&lt;/li&gt;
&lt;li&gt;Invoke narrow diagnostic tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It should not have broad write access to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kubernetes resources&lt;/li&gt;
&lt;li&gt;IAM&lt;/li&gt;
&lt;li&gt;Security groups&lt;/li&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;li&gt;Secrets&lt;/li&gt;
&lt;li&gt;CI/CD pipelines&lt;/li&gt;
&lt;li&gt;DNS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Expose bounded tools such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;get_kubernetes_events(namespace, workload)
get_deployment_revision(namespace, deployment)
collect_eks_node_diagnostics(instance_id)
query_application_errors(service, start_time, end_time)
compare_configuration(current_revision, previous_revision)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not expose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;execute_shell(command)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A generic shell endpoint turns a controlled diagnostic integration into remote code execution.&lt;/p&gt;




&lt;h1&gt;
  
  
  2. Require a structured remediation proposal
&lt;/h1&gt;

&lt;p&gt;Do not send free-form AI text to an executor.&lt;/p&gt;

&lt;p&gt;Use a versioned contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"schemaVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"proposalId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rp-01JZ8A17R2K5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"incidentId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"inc-checkout-0017"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"createdAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-28T20:12:31Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"expiresAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-28T20:17:31Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"environment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"production"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cluster"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"commerce-prod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"namespace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"checkout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"resourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ArgoRollout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"resourceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"checkout-api"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ROLLBACK_DEPLOYMENT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"targetRevision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"requestedBlastRadiusPercent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"evidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"APPLICATION_SIGNALS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LATENCY_INCREASE"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CLOUDTRAIL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RECENT_CHANGE"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"KUBERNETES"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CONFIGURATION_CHANGE"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AURORA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RESOURCE_SATURATION"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rollback"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"available"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"knownGoodRevision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"agentAssessment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"confidencePercent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;92&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Revision 42 introduced retry amplification"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reject proposals containing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unknown actions&lt;/li&gt;
&lt;li&gt;Wildcard targets&lt;/li&gt;
&lt;li&gt;Free-form commands&lt;/li&gt;
&lt;li&gt;Missing rollback data&lt;/li&gt;
&lt;li&gt;Expired timestamps&lt;/li&gt;
&lt;li&gt;Unregistered resources&lt;/li&gt;
&lt;li&gt;Unknown revisions&lt;/li&gt;
&lt;li&gt;Excessive blast radius&lt;/li&gt;
&lt;li&gt;Insufficient evidence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The proposal contains &lt;strong&gt;intent&lt;/strong&gt;, not executable commands.&lt;/p&gt;

&lt;p&gt;Accept:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ROLLBACK_DEPLOYMENT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"targetRevision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reject:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kubectl delete pods --all --all-namespaces"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  3. Separate action risk from incident urgency
&lt;/h1&gt;

&lt;p&gt;A critical incident does not make a dangerous remediation safe.&lt;/p&gt;

&lt;p&gt;Calculate two independent values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Action risk
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Action Risk =
    Action Severity       × 0.25
  + Resource Criticality  × 0.20
  + Blast Radius          × 0.20
  + Evidence Uncertainty  × 0.15
  + Change Collision      × 0.10
  + Rollback Weakness     × 0.10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example action severity:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Restart one stateless pod&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale within approved limits&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Progressive rollback&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modify HPA policy&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change database parameters&lt;/td&gt;
&lt;td&gt;70&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modify routing&lt;/td&gt;
&lt;td&gt;85&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modify IAM&lt;/td&gt;
&lt;td&gt;95&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete data&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Example resource criticality:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resource&lt;/th&gt;
&lt;th&gt;Criticality&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Development service&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internal production service&lt;/td&gt;
&lt;td&gt;35&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customer-facing API&lt;/td&gt;
&lt;td&gt;70&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication service&lt;/td&gt;
&lt;td&gt;90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payment platform&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Incident urgency
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Incident Urgency =
    SLO Burn Rate      × 0.40
  + Customer Impact    × 0.35
  + Incident Duration  × 0.25
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Urgency may shorten approval time or escalate responders. It must not lower the action-risk threshold.&lt;/p&gt;




&lt;h1&gt;
  
  
  4. Do not trust AI confidence directly
&lt;/h1&gt;

&lt;p&gt;The control plane should calculate validated confidence from evidence quality.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;

&lt;span class="n"&gt;ALLOWLISTED_ACTIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RESTART_SINGLE_POD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SCALE_WITHIN_LIMIT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ROLLBACK_DEPLOYMENT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RiskResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;risk_score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;validated_confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validated_confidence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;evidence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;evidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="n"&gt;sources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;evidence&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="n"&gt;types&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;evidence&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;

    &lt;span class="n"&gt;agent_confidence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agentAssessment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confidencePercent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;has_change&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RECENT_CHANGE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;
    &lt;span class="n"&gt;has_telemetry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LATENCY_INCREASE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ERROR_RATE_INCREASE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RESOURCE_SATURATION&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;has_change&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;has_telemetry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;cap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;95&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;has_telemetry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;cap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;75&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;cap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent_confidence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_action_risk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;RiskResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;action&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ALLOWLISTED_ACTIONS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;RiskResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DENY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action is not allowlisted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;expires_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromisoformat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;expiresAt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Z&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+00:00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;expires_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;RiskResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DENY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Proposal expired&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;confidence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validated_confidence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proposal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;uncertainty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;confidence&lt;/span&gt;

    &lt;span class="n"&gt;risk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;actionSeverity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.25&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;resourceCriticality&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.20&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blastRadiusPercent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.20&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uncertainty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.15&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;concurrentChange&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.10&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rollbackAvailable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.10&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;reasons&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rollbackAvailable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;risk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;risk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No verified rollback point&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;concurrentChange&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;risk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;risk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Concurrent change detected&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blastRadiusPercent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;risk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;risk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Blast radius exceeds 25 percent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;confidence&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;risk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;risk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Evidence confidence below threshold&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;risk&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;confidence&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AUTO_EXECUTE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;risk&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REQUIRE_APPROVAL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DENY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;RiskResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;risk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The weights are organisational policy, not universal values.&lt;/p&gt;

&lt;p&gt;The critical properties are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inputs are bounded&lt;/li&gt;
&lt;li&gt;Logic is deterministic&lt;/li&gt;
&lt;li&gt;Algorithms are versioned&lt;/li&gt;
&lt;li&gt;Decisions are reproducible&lt;/li&gt;
&lt;li&gt;Every factor is recorded&lt;/li&gt;
&lt;li&gt;AI cannot change thresholds&lt;/li&gt;
&lt;li&gt;Failure defaults to denial&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  5. Refresh production context before authorisation
&lt;/h1&gt;

&lt;p&gt;Do not authorise using only the data captured during investigation.&lt;/p&gt;

&lt;p&gt;Immediately before execution, verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The incident is still active&lt;/li&gt;
&lt;li&gt;The target revision is still deployed&lt;/li&gt;
&lt;li&gt;No other production change is running&lt;/li&gt;
&lt;li&gt;The previous revision still exists&lt;/li&gt;
&lt;li&gt;The previous revision is security-compliant&lt;/li&gt;
&lt;li&gt;The workload has not already recovered&lt;/li&gt;
&lt;li&gt;The target resource still maps to the same owner and criticality&lt;/li&gt;
&lt;li&gt;The SLO is still burning&lt;/li&gt;
&lt;li&gt;The proposal has not expired&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This prevents time-of-check/time-of-use failures.&lt;/p&gt;

&lt;p&gt;A five-minute proposal expiration is a reasonable starting point for autonomous actions.&lt;/p&gt;




&lt;h1&gt;
  
  
  6. Authorise with Amazon Verified Permissions
&lt;/h1&gt;

&lt;p&gt;Model the remediation controller as an application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Principal:&lt;/strong&gt; remediation orchestrator&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action:&lt;/strong&gt; auto-execute or request-approval&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource:&lt;/strong&gt; production workload&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context:&lt;/strong&gt; risk, confidence, blast radius, rollback status, action type&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Evaluate &lt;code&gt;AutoExecute&lt;/code&gt; first. If denied, evaluate &lt;code&gt;RequestApproval&lt;/code&gt;. If both are denied, block the proposal.&lt;/p&gt;

&lt;p&gt;Automatic execution policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;permit (
    principal == RemediationControl::Service::"orchestrator",
    action == RemediationControl::Action::"AutoExecute",
    resource
)
when {
    context.riskScore &amp;lt;= 25 &amp;amp;&amp;amp;
    context.validatedConfidence &amp;gt;= 90 &amp;amp;&amp;amp;
    context.blastRadiusPercent &amp;lt;= 10 &amp;amp;&amp;amp;
    context.rollbackAvailable &amp;amp;&amp;amp;
    !context.concurrentChange &amp;amp;&amp;amp;
    (
        context.actionType == "RESTART_SINGLE_POD" ||
        context.actionType == "SCALE_WITHIN_LIMIT" ||
        context.actionType == "ROLLBACK_DEPLOYMENT"
    )
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Approval policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;permit (
    principal == RemediationControl::Service::"orchestrator",
    action == RemediationControl::Action::"RequestApproval",
    resource
)
when {
    context.riskScore &amp;lt;= 60 &amp;amp;&amp;amp;
    context.validatedConfidence &amp;gt;= 70 &amp;amp;&amp;amp;
    context.blastRadiusPercent &amp;lt;= 25 &amp;amp;&amp;amp;
    context.rollbackAvailable &amp;amp;&amp;amp;
    !context.concurrentChange
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explicitly forbidden actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forbid (
    principal,
    action,
    resource
)
when {
    context.actionType == "MODIFY_IAM" ||
    context.actionType == "DELETE_DATA" ||
    context.actionType == "DISABLE_AUDIT_LOGGING" ||
    context.actionType == "OPEN_PUBLIC_NETWORK_ACCESS"
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The authorisation request can be submitted from Lambda:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verifiedpermissions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_authorized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;policy_store_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;route_action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;workload_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_authorized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;policyStoreId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;policy_store_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;entityType&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RemediationControl::Service&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;entityId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;orchestrator&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;actionType&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RemediationControl::Action&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;actionId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;route_action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;entityType&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RemediationControl::Workload&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;entityId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;workload_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contextMap&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;riskScore&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;long&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;riskScore&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;validatedConfidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;long&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;validatedConfidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blastRadiusPercent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;long&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blastRadiusPercent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rollbackAvailable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;boolean&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rollbackAvailable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;concurrentChange&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;boolean&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;concurrentChange&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;actionType&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;actionType&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;decision&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ALLOW&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store with every decision:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Risk-engine version&lt;/li&gt;
&lt;li&gt;Policy-store ID&lt;/li&gt;
&lt;li&gt;Policy version&lt;/li&gt;
&lt;li&gt;Risk score&lt;/li&gt;
&lt;li&gt;Validated confidence&lt;/li&gt;
&lt;li&gt;Decision route&lt;/li&gt;
&lt;li&gt;Determining policy IDs&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  7. Orchestrate with AWS Step Functions
&lt;/h1&gt;

&lt;p&gt;The state machine should coordinate:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Proposal validation&lt;/li&gt;
&lt;li&gt;Expiration check&lt;/li&gt;
&lt;li&gt;Live-context collection&lt;/li&gt;
&lt;li&gt;Risk calculation&lt;/li&gt;
&lt;li&gt;Verified Permissions evaluation&lt;/li&gt;
&lt;li&gt;Human approval where required&lt;/li&gt;
&lt;li&gt;Runbook execution&lt;/li&gt;
&lt;li&gt;Canary verification&lt;/li&gt;
&lt;li&gt;Promotion or rollback&lt;/li&gt;
&lt;li&gt;Audit completion&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A simplified workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"StartAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ValidateProposal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"States"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ValidateProposal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:states:::lambda:invoke"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CollectLiveContext"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"CollectLiveContext"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:states:::lambda:invoke"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CalculateRisk"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"CalculateRisk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:states:::lambda:invoke"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AuthoriseRoute"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"AuthoriseRoute"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:states:::lambda:invoke"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RouteDecision"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"RouteDecision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Choice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Choices"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Variable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$.decision.route"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"StringEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AUTO_EXECUTE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ExecuteRunbook"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Variable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$.decision.route"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"StringEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"REQUIRE_APPROVAL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ApprovalRunbook"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Denied"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ExecuteRunbook"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:states:::lambda:invoke.waitForTaskToken"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VerifyCanary"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ApprovalRunbook"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:states:::lambda:invoke.waitForTaskToken"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VerifyCanary"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"VerifyCanary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:states:::lambda:invoke"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VerificationDecision"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"VerificationDecision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Choice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Choices"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Variable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$.verification.passed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"BooleanEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Promote"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Rollback"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Promote"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Succeed"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Rollback"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fail"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Denied"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Succeed"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Production implementations also need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retries with bounded backoff&lt;/li&gt;
&lt;li&gt;Catch handlers&lt;/li&gt;
&lt;li&gt;Idempotency&lt;/li&gt;
&lt;li&gt;Dead-letter handling&lt;/li&gt;
&lt;li&gt;Timeouts&lt;/li&gt;
&lt;li&gt;Duplicate suppression&lt;/li&gt;
&lt;li&gt;Per-workload locking&lt;/li&gt;
&lt;li&gt;Compensating actions&lt;/li&gt;
&lt;li&gt;Audit-write failure handling&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  8. Execute only allowlisted runbooks
&lt;/h1&gt;

&lt;p&gt;Map each action to a versioned Systems Manager runbook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;RUNBOOK_CATALOG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RESTART_SINGLE_POD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;document&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AIOps-RestartSinglePod-v3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maximumBlastRadius&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SCALE_WITHIN_LIMIT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;document&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AIOps-ScaleDeployment-v4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maximumBlastRadius&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ROLLBACK_DEPLOYMENT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;document&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AIOps-RollbackDeployment-v7&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maximumBlastRadius&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI selects intent from the catalogue. It does not generate commands.&lt;/p&gt;

&lt;p&gt;Example runbook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Roll back an approved EKS workload&lt;/span&gt;
&lt;span class="na"&gt;schemaVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0.3'&lt;/span&gt;

&lt;span class="na"&gt;assumeRole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;AutomationAssumeRole&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;

&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;AutomationAssumeRole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::Role::Arn&lt;/span&gt;

  &lt;span class="na"&gt;ExecutorFunctionName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;

  &lt;span class="na"&gt;ClusterName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;

  &lt;span class="na"&gt;Namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;

  &lt;span class="na"&gt;WorkloadName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;

  &lt;span class="na"&gt;TargetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Integer&lt;/span&gt;

  &lt;span class="na"&gt;TrafficPercent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Integer&lt;/span&gt;
    &lt;span class="na"&gt;allowedValues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;

  &lt;span class="na"&gt;ProposalId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;

&lt;span class="na"&gt;mainSteps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ExecuteRestrictedRollback&lt;/span&gt;
    &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws:invokeLambdaFunction&lt;/span&gt;
    &lt;span class="na"&gt;timeoutSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;120&lt;/span&gt;
    &lt;span class="na"&gt;maxAttempts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;onFailure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Abort&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;FunctionName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ExecutorFunctionName&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
      &lt;span class="na"&gt;InvocationType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RequestResponse&lt;/span&gt;
      &lt;span class="na"&gt;Payload&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="s"&gt;{&lt;/span&gt;
          &lt;span class="s"&gt;"operation": "ROLLBACK_DEPLOYMENT",&lt;/span&gt;
          &lt;span class="s"&gt;"cluster": "{{ ClusterName }}",&lt;/span&gt;
          &lt;span class="s"&gt;"namespace": "{{ Namespace }}",&lt;/span&gt;
          &lt;span class="s"&gt;"workload": "{{ WorkloadName }}",&lt;/span&gt;
          &lt;span class="s"&gt;"targetRevision": {{ TargetRevision }},&lt;/span&gt;
          &lt;span class="s"&gt;"trafficPercent": {{ TrafficPercent }},&lt;/span&gt;
          &lt;span class="s"&gt;"proposalId": "{{ ProposalId }}"&lt;/span&gt;
        &lt;span class="s"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For medium-risk actions, add an &lt;code&gt;aws:approve&lt;/code&gt; step before invoking the child runbook.&lt;/p&gt;

&lt;p&gt;High-risk actions such as IAM changes, data deletion, network exposure, or disabling audit controls should remain outside the autonomous remediation catalogue.&lt;/p&gt;




&lt;h1&gt;
  
  
  9. Restrict EKS access
&lt;/h1&gt;

&lt;p&gt;Use a dedicated IAM role and EKS access entry for the executor.&lt;/p&gt;

&lt;p&gt;Do not grant &lt;code&gt;cluster-admin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Map the role to a Kubernetes group:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aiops-remediation-executor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Namespace-scoped Role:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Role&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aiops-remediation-executor&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
&lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiGroups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apps&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;argoproj.io&lt;/span&gt;
    &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deployments&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;rollouts&lt;/span&gt;
    &lt;span class="na"&gt;verbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;get&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;list&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;watch&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;patch&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;update&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiGroups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pods&lt;/span&gt;
    &lt;span class="na"&gt;verbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;get&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;list&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;watch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;RoleBinding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RoleBinding&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aiops-remediation-executor&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
&lt;span class="na"&gt;subjects&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Group&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aiops-remediation-executor&lt;/span&gt;
    &lt;span class="na"&gt;apiGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io&lt;/span&gt;
&lt;span class="na"&gt;roleRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Role&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aiops-remediation-executor&lt;/span&gt;
  &lt;span class="na"&gt;apiGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The executor must not be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read Secrets&lt;/li&gt;
&lt;li&gt;Modify ClusterRoles&lt;/li&gt;
&lt;li&gt;Create privileged pods&lt;/li&gt;
&lt;li&gt;Execute commands in arbitrary containers&lt;/li&gt;
&lt;li&gt;Modify other namespaces&lt;/li&gt;
&lt;li&gt;Delete namespaces&lt;/li&gt;
&lt;li&gt;Change its own IAM access&lt;/li&gt;
&lt;li&gt;Modify EKS access entries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For stronger isolation, use separate executor roles for each action category.&lt;/p&gt;




&lt;h1&gt;
  
  
  10. Limit blast radius with progressive delivery
&lt;/h1&gt;

&lt;p&gt;An approved action should not immediately affect every replica.&lt;/p&gt;

&lt;p&gt;Start with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Initial traffic: 5%
Observation window: 5 minutes
Required successful synthetic runs: 3
Maximum 5xx rate: 1%
Maximum p99 latency: 750 ms
Required business validation success: 100%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stop promotion when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Error rate rises&lt;/li&gt;
&lt;li&gt;Latency exceeds the threshold&lt;/li&gt;
&lt;li&gt;New Kubernetes errors appear&lt;/li&gt;
&lt;li&gt;Database pressure worsens&lt;/li&gt;
&lt;li&gt;SLO burn rate increases&lt;/li&gt;
&lt;li&gt;Business validation fails&lt;/li&gt;
&lt;li&gt;Another production change begins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Promote in stages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5% → 25% → 50% → 100%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each stage requires independent verification.&lt;/p&gt;




&lt;h1&gt;
  
  
  11. Verify business behaviour, not only infrastructure health
&lt;/h1&gt;

&lt;p&gt;A successful rollout does not prove recovery.&lt;/p&gt;

&lt;p&gt;Pods may be healthy and return HTTP 200 while producing an incorrect checkout total.&lt;/p&gt;

&lt;p&gt;CloudWatch Synthetics should validate both technical and business invariants.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SyntheticsLogger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;API_HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_HOST&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;synthetic-customer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SYNTHETIC-SKU-001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/v1/checkout/quote&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Length&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;byteLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;X-Synthetic-Transaction&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;started&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;started&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Unexpected HTTP &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;750&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Latency exceeded threshold: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; ms`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unitPrice&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tax&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shipping&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`Business invariant failed. Expected &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, received &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Unexpected currency: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Synthetic checkout passed in &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; ms`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;durationMilliseconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Synthetic transactions must not create real payments, shipments, inventory consumption, or customer notifications.&lt;/p&gt;

&lt;p&gt;Use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reserved synthetic identities&lt;/li&gt;
&lt;li&gt;Test inventory&lt;/li&gt;
&lt;li&gt;Payment-provider test mode&lt;/li&gt;
&lt;li&gt;Cleanup workflows&lt;/li&gt;
&lt;li&gt;Explicit synthetic headers&lt;/li&gt;
&lt;li&gt;Analytics filters&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  12. Verification contract
&lt;/h1&gt;

&lt;p&gt;The verification layer should query authoritative telemetry directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"proposalId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rp-01JZ8A17R2K5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"observationWindowSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"requirements"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"minimumSuccessfulSyntheticRuns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"maximumErrorRatePercent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"maximumP99LatencyMilliseconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;750&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"maximumDatabaseConnectionUtilisationPercent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"maximumSloBurnRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"minimumHealthyReplicaPercent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"passed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"observations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"successfulSyntheticRuns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"errorRatePercent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"p99LatencyMilliseconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;420&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"databaseConnectionUtilisationPercent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sloBurnRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"healthyReplicaPercent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Promotion requires every mandatory condition to pass.&lt;/p&gt;

&lt;p&gt;Do not average away a critical business failure.&lt;/p&gt;




&lt;h1&gt;
  
  
  End-to-end execution
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 1: Detect
&lt;/h2&gt;

&lt;p&gt;Application Signals detects an elevated SLO burn rate and triggers an investigation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Investigate
&lt;/h2&gt;

&lt;p&gt;AWS DevOps Agent correlates telemetry, configuration history, deployment metadata, and service dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Propose
&lt;/h2&gt;

&lt;p&gt;The proposal adapter creates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Action: ROLLBACK_DEPLOYMENT
Target revision: 41
Initial traffic: 5%
Agent confidence: 92%
Rollback available: Yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Refresh context
&lt;/h2&gt;

&lt;p&gt;The control plane confirms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Revision 42 is still active&lt;/li&gt;
&lt;li&gt;Revision 41 exists&lt;/li&gt;
&lt;li&gt;No concurrent deployment is running&lt;/li&gt;
&lt;li&gt;The incident is still active&lt;/li&gt;
&lt;li&gt;The workload matches the inventory record&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 5: Calculate risk
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Action severity&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resource criticality&lt;/td&gt;
&lt;td&gt;70&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blast radius&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evidence uncertainty&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change collision&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rollback weakness&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;30 × 0.25 = 7.50
70 × 0.20 = 14.00
 5 × 0.20 = 1.00
 8 × 0.15 = 1.20
--------------------
Risk score = 23.70, rounded to 24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Validated confidence is 92%.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Authorise
&lt;/h2&gt;

&lt;p&gt;Verified Permissions allows automatic execution because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Risk is at or below 25&lt;/li&gt;
&lt;li&gt;Confidence is at least 90&lt;/li&gt;
&lt;li&gt;Blast radius is at or below 10%&lt;/li&gt;
&lt;li&gt;Rollback exists&lt;/li&gt;
&lt;li&gt;No concurrent change is active&lt;/li&gt;
&lt;li&gt;The action is allowlisted&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 7: Execute
&lt;/h2&gt;

&lt;p&gt;Systems Manager invokes the restricted rollback executor.&lt;/p&gt;

&lt;p&gt;The executor can modify only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;commerce-prod
└── checkout namespace
    └── checkout-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 8: Verify
&lt;/h2&gt;

&lt;p&gt;Five percent of traffic moves to revision 41.&lt;/p&gt;

&lt;p&gt;CloudWatch Synthetics validates the checkout path. Application Signals validates latency, errors, and SLO burn rate. Database and queue metrics confirm recovery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 9: Promote or roll back
&lt;/h2&gt;

&lt;p&gt;If every gate passes, traffic moves progressively to 100%.&lt;/p&gt;

&lt;p&gt;If any gate fails, the workflow restores the prior state and marks the remediation unsuccessful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 10: Prevent recurrence
&lt;/h2&gt;

&lt;p&gt;The incident generates preventive work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add retry budgets&lt;/li&gt;
&lt;li&gt;Enforce exponential backoff&lt;/li&gt;
&lt;li&gt;Validate connection-pool settings&lt;/li&gt;
&lt;li&gt;Add configuration contract tests&lt;/li&gt;
&lt;li&gt;Add load tests&lt;/li&gt;
&lt;li&gt;Add deployment policies&lt;/li&gt;
&lt;li&gt;Improve SLO coverage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A platform that repeatedly fixes the same incident without creating preventive engineering work is only automating toil.&lt;/p&gt;




&lt;h1&gt;
  
  
  Failure scenarios to test
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Retry amplification
&lt;/h2&gt;

&lt;p&gt;Inject excessive retries, minimal backoff, and aggressive database pool settings.&lt;/p&gt;

&lt;p&gt;Expected result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI correlates deployment and database saturation&lt;/li&gt;
&lt;li&gt;Scaling is not selected as the first response&lt;/li&gt;
&lt;li&gt;Rollback is proposed&lt;/li&gt;
&lt;li&gt;Connection pressure decreases after remediation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Silent network failure
&lt;/h2&gt;

&lt;p&gt;Inject an invalid route or packet-filtering rule.&lt;/p&gt;

&lt;p&gt;Expected result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pods may remain running&lt;/li&gt;
&lt;li&gt;Service-to-service calls fail&lt;/li&gt;
&lt;li&gt;Node diagnostics provide evidence&lt;/li&gt;
&lt;li&gt;The system does not restart every workload blindly&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. HPA thrashing
&lt;/h2&gt;

&lt;p&gt;Configure an aggressive target with insufficient stabilisation.&lt;/p&gt;

&lt;p&gt;Expected result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Oscillation is detected&lt;/li&gt;
&lt;li&gt;Unbounded scaling is denied&lt;/li&gt;
&lt;li&gt;HPA changes require approval&lt;/li&gt;
&lt;li&gt;Verification uses a longer window&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Partial secret rotation
&lt;/h2&gt;

&lt;p&gt;Rotate credentials for only part of the workload.&lt;/p&gt;

&lt;p&gt;Expected result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pod-level error distribution reveals the split&lt;/li&gt;
&lt;li&gt;Secret changes remain outside autonomous execution&lt;/li&gt;
&lt;li&gt;A predefined security runbook is used&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Phantom success
&lt;/h2&gt;

&lt;p&gt;Return HTTP 200 with an incorrect checkout total.&lt;/p&gt;

&lt;p&gt;Expected result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Infrastructure checks pass&lt;/li&gt;
&lt;li&gt;Business synthetic fails&lt;/li&gt;
&lt;li&gt;Promotion stops&lt;/li&gt;
&lt;li&gt;Automatic rollback begins&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Concurrent deployment
&lt;/h2&gt;

&lt;p&gt;Start another deployment after the proposal is generated.&lt;/p&gt;

&lt;p&gt;Expected result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Context refresh detects the collision&lt;/li&gt;
&lt;li&gt;Automatic execution is denied&lt;/li&gt;
&lt;li&gt;The proposal becomes stale&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. Missing rollback artefact
&lt;/h2&gt;

&lt;p&gt;Delete the previous image or revision.&lt;/p&gt;

&lt;p&gt;Expected result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rollback weakness increases&lt;/li&gt;
&lt;li&gt;Risk exceeds the threshold&lt;/li&gt;
&lt;li&gt;The proposal is denied&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Security controls
&lt;/h1&gt;

&lt;h2&gt;
  
  
  IAM separation
&lt;/h2&gt;

&lt;p&gt;Use separate roles for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Investigation&lt;/li&gt;
&lt;li&gt;Proposal ingestion&lt;/li&gt;
&lt;li&gt;Context collection&lt;/li&gt;
&lt;li&gt;Risk evaluation&lt;/li&gt;
&lt;li&gt;Policy evaluation&lt;/li&gt;
&lt;li&gt;Orchestration&lt;/li&gt;
&lt;li&gt;Runbook execution&lt;/li&gt;
&lt;li&gt;EKS modification&lt;/li&gt;
&lt;li&gt;Verification&lt;/li&gt;
&lt;li&gt;Audit writing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not allow one role to modify the proposal, policy, executor, and audit record.&lt;/p&gt;

&lt;h2&gt;
  
  
  Immutable evidence
&lt;/h2&gt;

&lt;p&gt;Store decisions and evidence in encrypted Amazon S3.&lt;/p&gt;

&lt;p&gt;Consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Versioning&lt;/li&gt;
&lt;li&gt;Object Lock where required&lt;/li&gt;
&lt;li&gt;AWS KMS customer-managed keys&lt;/li&gt;
&lt;li&gt;Restricted deletion&lt;/li&gt;
&lt;li&gt;CloudTrail data events&lt;/li&gt;
&lt;li&gt;Payload checksums&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Idempotency
&lt;/h2&gt;

&lt;p&gt;Create an idempotency key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;incidentId + target + actionType + targetRevision
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If an identical action is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Running: reject the duplicate&lt;/li&gt;
&lt;li&gt;Successful: return the previous result&lt;/li&gt;
&lt;li&gt;Failed: require a new proposal&lt;/li&gt;
&lt;li&gt;Rolled back: block automatic retry&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Concurrency locking
&lt;/h2&gt;

&lt;p&gt;Use DynamoDB conditional writes to lock a workload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LOCK#commerce-prod#checkout#checkout-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only one remediation workflow should modify a workload at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Input integrity
&lt;/h2&gt;

&lt;p&gt;Hash the proposal before authorisation.&lt;/p&gt;

&lt;p&gt;Before execution, verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hash(authorised proposal) == hash(execution proposal)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Network controls
&lt;/h2&gt;

&lt;p&gt;Where possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use private subnets&lt;/li&gt;
&lt;li&gt;Use a private EKS endpoint&lt;/li&gt;
&lt;li&gt;Use VPC endpoints&lt;/li&gt;
&lt;li&gt;Restrict outbound access&lt;/li&gt;
&lt;li&gt;Restrict security-group egress&lt;/li&gt;
&lt;li&gt;Avoid general internet access for the executor&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Secrets
&lt;/h2&gt;

&lt;p&gt;The proposal must not contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Passwords&lt;/li&gt;
&lt;li&gt;Tokens&lt;/li&gt;
&lt;li&gt;Private keys&lt;/li&gt;
&lt;li&gt;Database credentials&lt;/li&gt;
&lt;li&gt;Customer data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pass references, not values.&lt;/p&gt;




&lt;h1&gt;
  
  
  Observability for the remediation platform
&lt;/h1&gt;

&lt;p&gt;The remediation control plane needs its own SLOs.&lt;/p&gt;

&lt;p&gt;Recommended metrics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RemediationProposalReceived
RemediationProposalRejected
RemediationProposalExpired
RemediationRiskScore
RemediationAutoExecuted
RemediationApprovalRequested
RemediationDenied
RemediationExecutionSucceeded
RemediationExecutionFailed
RemediationVerificationPassed
RemediationVerificationFailed
RemediationRollbackSucceeded
RemediationRollbackFailed
RemediationDuplicateSuppressed
RemediationConcurrentChangeDetected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recommended dimensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Environment
Cluster
Namespace
Service
ActionType
RiskBand
DecisionRoute
RunbookVersion
PolicyVersion
Outcome
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not use proposal IDs as metric dimensions. Store them in logs.&lt;/p&gt;

&lt;p&gt;Alarm on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Executor failure&lt;/li&gt;
&lt;li&gt;Rollback failure&lt;/li&gt;
&lt;li&gt;Workflow timeout&lt;/li&gt;
&lt;li&gt;Policy-evaluation failure&lt;/li&gt;
&lt;li&gt;Approval timeout&lt;/li&gt;
&lt;li&gt;Audit-write failure&lt;/li&gt;
&lt;li&gt;Unexpected increases in automatic remediation&lt;/li&gt;
&lt;li&gt;Repeated remediation of the same workload&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the control plane fails internally, deny or pause remediation. Do not bypass the control.&lt;/p&gt;




&lt;h1&gt;
  
  
  Metrics that prove value
&lt;/h1&gt;

&lt;p&gt;Do not publish invented performance claims.&lt;/p&gt;

&lt;p&gt;Measure:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Definition&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mean time to detect&lt;/td&gt;
&lt;td&gt;Incident start to alert&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mean time to investigate&lt;/td&gt;
&lt;td&gt;Alert to probable root cause&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mean time to authorise&lt;/td&gt;
&lt;td&gt;Proposal to policy decision&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mean time to remediate&lt;/td&gt;
&lt;td&gt;Authorised action to recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mean time to verify&lt;/td&gt;
&lt;td&gt;Execution to verified recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unsafe-action prevention rate&lt;/td&gt;
&lt;td&gt;Unsafe proposals blocked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automatic-remediation success rate&lt;/td&gt;
&lt;td&gt;Auto actions passing verification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;False-remediation rate&lt;/td&gt;
&lt;td&gt;Executed actions based on incorrect RCA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rollback success rate&lt;/td&gt;
&lt;td&gt;Failed remediations reversed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change-collision prevention rate&lt;/td&gt;
&lt;td&gt;Conflicting changes blocked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost per investigation&lt;/td&gt;
&lt;td&gt;AI, telemetry, workflow, and execution cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repeat-incident rate&lt;/td&gt;
&lt;td&gt;Recurrence of the same failure mode&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Compare:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Manual incident response&lt;/li&gt;
&lt;li&gt;AI-assisted investigation with manual execution&lt;/li&gt;
&lt;li&gt;AI-assisted investigation with risk-gated execution&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The objective is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reduce recovery time without increasing the rate or blast radius of unsafe production changes.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  Limitations
&lt;/h1&gt;

&lt;p&gt;This pattern does not eliminate risk.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Root-cause analysis may be incomplete&lt;/li&gt;
&lt;li&gt;Telemetry may be missing&lt;/li&gt;
&lt;li&gt;Deterministic policies can still be wrong&lt;/li&gt;
&lt;li&gt;Runbooks can contain defects&lt;/li&gt;
&lt;li&gt;Human approval can delay recovery&lt;/li&gt;
&lt;li&gt;Cross-account approval may require additional workflow design&lt;/li&gt;
&lt;li&gt;Business validation may be difficult to automate safely&lt;/li&gt;
&lt;li&gt;Break-glass actions still require human ownership&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not expand autonomous permissions during an outage. Maintain a documented and audited break-glass process.&lt;/p&gt;




&lt;h1&gt;
  
  
  Production-readiness checklist
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Investigation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Diagnostic access is read-only&lt;/li&gt;
&lt;li&gt;MCP tools are narrowly scoped&lt;/li&gt;
&lt;li&gt;Generic shell access is prohibited&lt;/li&gt;
&lt;li&gt;Evidence sources are recorded&lt;/li&gt;
&lt;li&gt;Output uses a versioned schema&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Authorisation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Actions are allowlisted&lt;/li&gt;
&lt;li&gt;Risk and urgency are separated&lt;/li&gt;
&lt;li&gt;Live context is refreshed&lt;/li&gt;
&lt;li&gt;Proposals expire&lt;/li&gt;
&lt;li&gt;Default is deny&lt;/li&gt;
&lt;li&gt;Forbidden actions have explicit deny policies&lt;/li&gt;
&lt;li&gt;Policy changes use CI/CD&lt;/li&gt;
&lt;li&gt;AI cannot change its own permissions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Execution
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Runbooks are versioned&lt;/li&gt;
&lt;li&gt;Parameters are validated&lt;/li&gt;
&lt;li&gt;Free-form commands are rejected&lt;/li&gt;
&lt;li&gt;IAM uses least privilege&lt;/li&gt;
&lt;li&gt;Kubernetes RBAC is namespace-scoped&lt;/li&gt;
&lt;li&gt;Secrets are inaccessible&lt;/li&gt;
&lt;li&gt;Blast radius is bounded&lt;/li&gt;
&lt;li&gt;Actions are idempotent&lt;/li&gt;
&lt;li&gt;Concurrent changes are locked&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Verification
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Verification is independent&lt;/li&gt;
&lt;li&gt;Infrastructure and business checks are included&lt;/li&gt;
&lt;li&gt;Multiple successful observations are required&lt;/li&gt;
&lt;li&gt;Failure triggers rollback&lt;/li&gt;
&lt;li&gt;Rollback is verified&lt;/li&gt;
&lt;li&gt;Success requires evidence&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Audit
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Proposal is immutable&lt;/li&gt;
&lt;li&gt;Risk factors are stored&lt;/li&gt;
&lt;li&gt;Policy and runbook versions are stored&lt;/li&gt;
&lt;li&gt;Approvals are recorded&lt;/li&gt;
&lt;li&gt;Execution logs are retained&lt;/li&gt;
&lt;li&gt;Verification results are retained&lt;/li&gt;
&lt;li&gt;Denied actions are searchable&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;AI can accelerate incident investigation, but investigation and production authority are different capabilities.&lt;/p&gt;

&lt;p&gt;A system that proposes a change, authorises it, executes it, and judges its own success has collapsed too many trust boundaries.&lt;/p&gt;

&lt;p&gt;The safer design separates responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS DevOps Agent investigates&lt;/li&gt;
&lt;li&gt;A structured proposal captures intent&lt;/li&gt;
&lt;li&gt;A deterministic risk engine evaluates danger&lt;/li&gt;
&lt;li&gt;Amazon Verified Permissions authorises&lt;/li&gt;
&lt;li&gt;AWS Step Functions coordinates&lt;/li&gt;
&lt;li&gt;Systems Manager executes allowlisted runbooks&lt;/li&gt;
&lt;li&gt;IAM and Kubernetes RBAC contain access&lt;/li&gt;
&lt;li&gt;Progressive delivery limits blast radius&lt;/li&gt;
&lt;li&gt;Application Signals and Synthetics verify recovery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is not uncontrolled autonomy. It is bounded autonomy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI for investigation&lt;/li&gt;
&lt;li&gt;Policy for authority&lt;/li&gt;
&lt;li&gt;Runbooks for execution&lt;/li&gt;
&lt;li&gt;SLOs and business tests for truth&lt;/li&gt;
&lt;li&gt;Humans for ambiguity and high-risk decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI proposes. Deterministic policy authorises. Controlled automation executes. Independent telemetry verifies.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the difference between an impressive AIOps demo and a production-safe reliability platform.&lt;/p&gt;




&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;The architecture, code samples, scoring weights, thresholds, IAM boundaries, Cedar policies, Kubernetes permissions, approval rules, and verification criteria in this article are reference examples.&lt;/p&gt;

&lt;p&gt;Adapt and test them against your workload characteristics, security policies, compliance requirements, incident processes, service quotas, recovery objectives, and operational maturity.&lt;/p&gt;

&lt;p&gt;Do not enable automatic production remediation until the actions have passed controlled failure injection, rollback testing, security review, and operational readiness exercises.&lt;/p&gt;

</description>
      <category>aiops</category>
      <category>devops</category>
      <category>stepfunctions</category>
      <category>cloudwatch</category>
    </item>
    <item>
      <title>Making a Service Survive an Availability Zone Outage — and Proving It for $0</title>
      <dc:creator>Pradeep Kandepaneni</dc:creator>
      <pubDate>Tue, 21 Jul 2026 08:01:47 +0000</pubDate>
      <link>https://dev.to/pradeep_kandepaneni/making-a-service-survive-an-availability-zone-outage-and-proving-it-for-0-565h</link>
      <guid>https://dev.to/pradeep_kandepaneni/making-a-service-survive-an-availability-zone-outage-and-proving-it-for-0-565h</guid>
      <description>&lt;p&gt;A reproducible multi-AZ resilience walkthrough: spread a service across simulated zones, kill one under load, and measure the dropped requests — plus the parts that only show up in real production.&lt;/p&gt;

&lt;p&gt;Originally published on the AWS Builder Center: &lt;a href="https://builder.aws.com/content/3GnvKe3PBz3fP3m3pFFDFghjIxX/making-a-service-survive-an-availability-zone-outage-and-proving-it-for-dollar0" rel="noopener noreferrer"&gt;https://builder.aws.com/content/3GnvKe3PBz3fP3m3pFFDFghjIxX/making-a-service-survive-an-availability-zone-outage-and-proving-it-for-dollar0&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/PradeepKandepaneni/golden-path-resilience" rel="noopener noreferrer"&gt;https://github.com/PradeepKandepaneni/golden-path-resilience&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>architecture</category>
      <category>devops</category>
      <category>availabilty</category>
    </item>
    <item>
      <title>Preventing Unsafe Regional Failover in Amazon EKS with Policy-Gated Recovery</title>
      <dc:creator>Pradeep Kandepaneni</dc:creator>
      <pubDate>Tue, 21 Jul 2026 07:30:42 +0000</pubDate>
      <link>https://dev.to/pradeep_kandepaneni/preventing-unsafe-regional-failover-in-amazon-eks-with-policy-gated-recovery-3c8l</link>
      <guid>https://dev.to/pradeep_kandepaneni/preventing-unsafe-regional-failover-in-amazon-eks-with-policy-gated-recovery-3c8l</guid>
      <description>&lt;p&gt;This article was originally published on AWS Builder Center.&lt;/p&gt;

&lt;p&gt;A secondary Amazon EKS cluster can appear healthy while still being unsafe to receive production traffic. This article presents a policy-gated recovery model that validates data replication, compute capacity, application health, container images, secrets, certificates, and synthetic business transactions before promoting a recovery Region.&lt;/p&gt;

&lt;p&gt;This article was originally published on [AWS Builder Center]&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://builder.aws.com/content/3GnlrIlqWy7Hel5zlqaIMsg2rPM/preventing-unsafe-regional-failover-in-amazon-eks-with-policy-gated-recovery" rel="noopener noreferrer"&gt;https://builder.aws.com/content/3GnlrIlqWy7Hel5zlqaIMsg2rPM/preventing-unsafe-regional-failover-in-amazon-eks-with-policy-gated-recovery&lt;/a&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Why a Healthy Standby Region Can Still Be Unsafe
&lt;/h2&gt;

&lt;p&gt;Running an application across multiple Availability Zones protects against many infrastructure failures, but it does not provide complete protection from a regional outage. A common recovery design is to maintain a second Amazon Elastic Kubernetes Service (Amazon EKS) cluster in another AWS Region and redirect traffic when the primary Region becomes unavailable.&lt;/p&gt;

&lt;p&gt;The problem is that a reachable cluster is not necessarily ready to operate as the active production Region.&lt;/p&gt;

&lt;p&gt;Kubernetes readiness probes may succeed while the database replica is behind, required container images are missing, regional secrets contain incorrect endpoints, certificates are unavailable, or the recovery cluster lacks enough compute capacity. A DNS or load-balancer health check cannot detect all of these conditions.&lt;/p&gt;

&lt;p&gt;For stateful workloads, premature promotion can be more damaging than a temporary outage. It can introduce data loss, conflicting writes, authentication failures, partial application availability, or a recovery environment that collapses as soon as production traffic arrives.&lt;/p&gt;

&lt;p&gt;A safer approach is to treat regional promotion as a controlled engineering decision rather than a simple routing change.&lt;/p&gt;

&lt;p&gt;This article presents a policy-gated recovery model for Amazon EKS. The model uses mandatory safety gates and a weighted recovery-readiness score to validate infrastructure capacity, application health, data replication, container images, secrets, certificates, GitOps state, writer fencing, and synthetic business transactions before traffic and write authority move to the recovery Region.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reference Architecture
&lt;/h2&gt;

&lt;p&gt;The architecture uses two AWS Regions: a primary Region serving production traffic and a warm-standby recovery Region maintained at reduced capacity.&lt;/p&gt;

&lt;p&gt;Each Region contains an independent Amazon EKS cluster, regional networking, application load balancing, monitoring, secrets, certificates, and container images. Application configuration is synchronized through a GitOps workflow so that the recovery cluster continuously receives approved Kubernetes manifests and deployment changes.&lt;/p&gt;

&lt;p&gt;Stateful data is replicated using Amazon Aurora Global Database. Container images are copied through Amazon Elastic Container Registry (Amazon ECR) cross-Region replication, while AWS Secrets Manager provides regional secret replicas.&lt;/p&gt;

&lt;p&gt;These replication mechanisms must be validated independently. Successful replication configuration does not prove that every required image, secret value, certificate, endpoint, or database change is available and usable in the recovery Region.&lt;/p&gt;

&lt;p&gt;Amazon Application Recovery Controller (ARC) Region switch coordinates the recovery workflow. Region switch uses recovery plans composed of ordered or parallel execution steps. The recovery plan can be initiated manually or through approved automation, depending on the workload's operational requirements.&lt;/p&gt;

&lt;p&gt;A separate recovery-readiness evaluator checks mandatory safety conditions before database promotion, workload scaling, or traffic movement is permitted.&lt;/p&gt;

&lt;p&gt;The design separates four concerns:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure readiness&lt;/strong&gt; — The recovery Region has sufficient networking, compute, quota, and worker-node capacity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application readiness&lt;/strong&gt; — Critical workloads are synchronized, schedulable, healthy, and able to complete synthetic business transactions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data readiness&lt;/strong&gt; — Replication lag is within the approved recovery-point objective, and conflicting writes are prevented.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency readiness&lt;/strong&gt; — Required images, secrets, certificates, identity services, queues, caches, and external integrations are available.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A regional endpoint health check alone cannot prove these conditions. Promotion is allowed only after every mandatory safety gate passes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Endpoint Health Is Not Recovery Readiness
&lt;/h2&gt;

&lt;p&gt;Traditional failover designs often rely on a small number of signals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load balancer endpoint availability&lt;/li&gt;
&lt;li&gt;DNS health-check status&lt;/li&gt;
&lt;li&gt;Kubernetes pod readiness&lt;/li&gt;
&lt;li&gt;Application response codes&lt;/li&gt;
&lt;li&gt;Infrastructure resource availability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These signals are valuable, but they answer only narrow questions.&lt;/p&gt;

&lt;p&gt;A successful readiness probe confirms that a container can respond to a configured health endpoint. It does not prove that the application can authenticate users, perform database writes, retrieve secrets, process queue messages, contact third-party services, or sustain production traffic.&lt;/p&gt;

&lt;p&gt;Consider the following failure conditions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application pods are healthy, but the Aurora secondary cluster has replication lag beyond the accepted recovery-point objective.&lt;/li&gt;
&lt;li&gt;Kubernetes Deployments exist, but worker nodes cannot scale because of service quotas or insufficient subnet address capacity.&lt;/li&gt;
&lt;li&gt;The image tag exists in the recovery Region, but the required immutable image digest does not.&lt;/li&gt;
&lt;li&gt;Secrets were replicated, but a connection string still references a primary-Region endpoint.&lt;/li&gt;
&lt;li&gt;The recovery cluster is synchronized, but the GitOps controller reverses emergency replica changes.&lt;/li&gt;
&lt;li&gt;TLS certificates are missing, expired, or not attached to the recovery load balancer.&lt;/li&gt;
&lt;li&gt;The database is promoted, but the original writer continues accepting requests, creating a split-brain risk.&lt;/li&gt;
&lt;li&gt;The login endpoint responds, but a complete business transaction fails.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regional recovery readiness must therefore be evaluated as a combined system property, not as a single health-check result.&lt;/p&gt;




&lt;h2&gt;
  
  
  Separate Hard Gates from Readiness Scores
&lt;/h2&gt;

&lt;p&gt;The proposed model uses two types of controls:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Hard promotion gates&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Weighted readiness signals&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This separation is critical.&lt;/p&gt;

&lt;p&gt;A weighted score is useful for summarizing operational health, but it must never compensate for a failed data-safety requirement. A recovery Region with excellent application health but unsafe database state should not receive production writes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hard Promotion Gates
&lt;/h3&gt;

&lt;p&gt;Hard gates represent conditions that are non-negotiable. If any hard gate fails, promotion stops.&lt;/p&gt;

&lt;h4&gt;
  
  
  Database Replication
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Replication status must be healthy.&lt;/li&gt;
&lt;li&gt;Replication lag must remain below the approved threshold.&lt;/li&gt;
&lt;li&gt;The target database cluster must be eligible for failover or switchover.&lt;/li&gt;
&lt;li&gt;Database engine versions must be compatible with the selected recovery operation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Writer Fencing
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The previous writer must be unavailable, isolated, or explicitly fenced before the recovery Region accepts writes.&lt;/li&gt;
&lt;li&gt;Applications must not maintain writable connections to both Regions.&lt;/li&gt;
&lt;li&gt;Connection pools and DNS caches must be considered during the transition.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Amazon EKS Capacity
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The required Kubernetes resources must exist in the recovery cluster.&lt;/li&gt;
&lt;li&gt;Sufficient worker-node capacity must be available or capable of scaling.&lt;/li&gt;
&lt;li&gt;Subnets, IP addresses, instance quotas, and Availability Zone distribution must support the desired replica count.&lt;/li&gt;
&lt;li&gt;Critical pods must become schedulable within the recovery timeout.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Application Health
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Required Deployments must have the minimum number of ready replicas.&lt;/li&gt;
&lt;li&gt;Pod disruption budgets, topology constraints, and health probes must be valid.&lt;/li&gt;
&lt;li&gt;Critical services must pass internal and external health validation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Container Image Availability
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Required repositories must exist in the recovery Region.&lt;/li&gt;
&lt;li&gt;The exact image digests referenced by production manifests must be available.&lt;/li&gt;
&lt;li&gt;Image pull permissions and node access must be validated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Amazon ECR replication rules should be configured before images are pushed. Images that existed before replication was configured should not be assumed to appear automatically in the destination Region.&lt;/p&gt;

&lt;h4&gt;
  
  
  Secret and Configuration Readiness
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Required secrets must exist in the recovery Region.&lt;/li&gt;
&lt;li&gt;Secret versions must match the expected deployment version.&lt;/li&gt;
&lt;li&gt;Regional endpoints embedded in secret values must be validated.&lt;/li&gt;
&lt;li&gt;AWS Key Management Service keys and permissions must be available in the recovery Region.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Certificate Readiness
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Certificates must be valid and available in the required Region.&lt;/li&gt;
&lt;li&gt;Load balancer listeners must reference the correct certificate.&lt;/li&gt;
&lt;li&gt;Certificate expiration and domain validation status must be checked.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  GitOps Synchronization
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Critical applications must be synchronized.&lt;/li&gt;
&lt;li&gt;No unresolved high-severity drift should exist.&lt;/li&gt;
&lt;li&gt;GitOps tools must not reverse recovery-time scaling changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Synthetic Business Transactions
&lt;/h4&gt;

&lt;p&gt;A synthetic test should validate more than a basic HTTP response. Depending on the application, it can perform steps such as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Authenticate a test user.&lt;/li&gt;
&lt;li&gt;Create a temporary transaction.&lt;/li&gt;
&lt;li&gt;Read the newly created record.&lt;/li&gt;
&lt;li&gt;Update the record.&lt;/li&gt;
&lt;li&gt;Delete or clean up the test data.&lt;/li&gt;
&lt;li&gt;Verify that logs and metrics were produced.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  ARC Recovery-Plan Evaluation
&lt;/h4&gt;

&lt;p&gt;Before execution, the Region switch plan should pass its available plan-evaluation checks. Custom policy gates should complement—not replace—the validations performed by ARC.&lt;/p&gt;




&lt;h2&gt;
  
  
  Weighted Recovery-Readiness Score
&lt;/h2&gt;

&lt;p&gt;After all hard gates pass, weighted signals can provide a consolidated operational score.&lt;/p&gt;

&lt;p&gt;A reference weighting model could use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;25% application health&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;20% infrastructure capacity&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;20% data health&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;15% dependency health&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;10% observability health&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;10% policy compliance&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The weights must reflect the workload's actual risk profile. A transaction-processing system may assign greater weight to data health, while a stateless content-delivery workload may emphasize capacity and dependency availability.&lt;/p&gt;

&lt;p&gt;The score should not be interpreted as a universal standard. It is an operational decision aid.&lt;/p&gt;

&lt;p&gt;A simple decision policy is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IF any hard gate fails:
    BLOCK PROMOTION

ELSE IF readiness score is below 90:
    REQUIRE OPERATOR REVIEW

ELSE:
    ALLOW THE APPROVED RECOVERY WORKFLOW
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A score of 95 must never override a failed writer-fencing gate, excessive database replication lag, or a missing production image.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example Recovery Policy
&lt;/h2&gt;

&lt;p&gt;The following example represents a simplified policy definition. Production implementations should store thresholds in version-controlled configuration and require peer review for changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;recoveryPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;targetRegion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-west-2&lt;/span&gt;

  &lt;span class="na"&gt;hardGates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;maximumDatabaseLagSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;
    &lt;span class="na"&gt;minimumAvailableReplicasPercent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;95&lt;/span&gt;

    &lt;span class="na"&gt;requiredSyntheticTests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;login&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;create-order&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;read-order&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;update-order&lt;/span&gt;

    &lt;span class="na"&gt;requireDatabasePromotionEligibility&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;requireImageDigestValidation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;requireRegionalSecretValidation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;requireCertificateValidation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;requireGitOpsSynchronization&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;requireWriterFencing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;requireArcPlanEvaluation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="na"&gt;readinessScore&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;minimumAutomaticApprovalScore&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;

    &lt;span class="na"&gt;weights&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;applicationHealth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;
      &lt;span class="na"&gt;infrastructureCapacity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
      &lt;span class="na"&gt;dataHealth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
      &lt;span class="na"&gt;dependencyHealth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;
      &lt;span class="na"&gt;observabilityHealth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
      &lt;span class="na"&gt;policyCompliance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The threshold values above are examples. They must be aligned with the organization's recovery-time objective, recovery-point objective, application behavior, data-loss tolerance, and operational approval model.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example Readiness Evaluation
&lt;/h2&gt;

&lt;p&gt;The following Python example demonstrates the decision logic. It intentionally keeps hard-gate evaluation separate from weighted scoring.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HardGate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WeightedSignal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;evaluate_recovery_readiness&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;hard_gates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HardGate&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;weighted_signals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;WeightedSignal&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;minimum_score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;90.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;failures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;details&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;gate&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;hard_gates&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;gate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;passed&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;decision&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BLOCK&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed_gates&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;signals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weighted_signals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;signals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;decision&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BLOCK&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed_gates&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weighted-signals&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;details&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No weighted readiness signals were provided.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;total_weight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;signals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;total_weight&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Total signal weight must be greater than zero.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;normalized_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;signals&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;total_weight&lt;/span&gt;

    &lt;span class="n"&gt;decision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ALLOW&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;normalized_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;minimum_score&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REVIEW&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;decision&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;normalized_score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed_gates&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a production implementation, each signal should include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Collection timestamp&lt;/li&gt;
&lt;li&gt;Source system&lt;/li&gt;
&lt;li&gt;Region&lt;/li&gt;
&lt;li&gt;Resource identifier&lt;/li&gt;
&lt;li&gt;Evaluation result&lt;/li&gt;
&lt;li&gt;Threshold&lt;/li&gt;
&lt;li&gt;Evidence location&lt;/li&gt;
&lt;li&gt;Expiration period&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stale evidence should fail closed. A database-lag measurement collected 30 minutes earlier should not approve a current regional promotion.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recovery Workflow with AWS ARC Region Switch
&lt;/h2&gt;

&lt;p&gt;A human-approved automated workflow is usually more defensible than fully automatic promotion for business-critical stateful workloads.&lt;/p&gt;

&lt;p&gt;A reference recovery sequence is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An operator declares a regional recovery event or initiates a controlled exercise.&lt;/li&gt;
&lt;li&gt;ARC Region switch evaluates the configured recovery plan.&lt;/li&gt;
&lt;li&gt;The recovery-readiness evaluator collects current evidence from both Regions.&lt;/li&gt;
&lt;li&gt;Hard promotion gates are evaluated.&lt;/li&gt;
&lt;li&gt;The recovery EKS cluster scales critical Kubernetes resources.&lt;/li&gt;
&lt;li&gt;Worker-node autoscaling increases node capacity as required.&lt;/li&gt;
&lt;li&gt;The GitOps controller verifies application synchronization.&lt;/li&gt;
&lt;li&gt;Aurora Global Database performs the appropriate failover operation.&lt;/li&gt;
&lt;li&gt;Applications reconnect to the new database writer.&lt;/li&gt;
&lt;li&gt;Synthetic transactions run against the recovery Region.&lt;/li&gt;
&lt;li&gt;Writer fencing is confirmed.&lt;/li&gt;
&lt;li&gt;ARC routing controls or the approved traffic-management mechanism moves traffic.&lt;/li&gt;
&lt;li&gt;Post-promotion monitoring verifies error rate, latency, saturation, and business transactions.&lt;/li&gt;
&lt;li&gt;The workflow completes, pauses, or rolls back based on validation results.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ARC Region switch can scale supported EKS workload resources as part of a recovery plan. However, increasing Kubernetes replica counts does not independently create worker-node capacity. The cluster still depends on a node-provisioning mechanism such as Karpenter, Cluster Autoscaler, or EKS Auto Mode.&lt;/p&gt;

&lt;p&gt;Recovery testing must therefore validate both layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Desired Kubernetes replica capacity&lt;/li&gt;
&lt;li&gt;Actual schedulable worker-node capacity&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prevent GitOps from Reversing Recovery Changes
&lt;/h2&gt;

&lt;p&gt;GitOps systems continuously reconcile actual cluster state with the state stored in Git. This is normally desirable, but it can conflict with disaster-recovery actions.&lt;/p&gt;

&lt;p&gt;For example, ARC may increase a Deployment from three replicas to twelve replicas during recovery. If the Git repository still specifies three replicas, the GitOps controller may attempt to restore the lower count.&lt;/p&gt;

&lt;p&gt;The same conflict can occur when a recovery workflow modifies Horizontal Pod Autoscaler behavior to prevent immediate scale-down.&lt;/p&gt;

&lt;p&gt;Recovery design should explicitly define which system owns temporary scaling changes.&lt;/p&gt;

&lt;p&gt;Options include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure GitOps to ignore the Deployment replica field.&lt;/li&gt;
&lt;li&gt;Configure GitOps to ignore specific Horizontal Pod Autoscaler fields.&lt;/li&gt;
&lt;li&gt;Commit recovery-state changes to a dedicated Git branch.&lt;/li&gt;
&lt;li&gt;Temporarily suspend reconciliation for selected resources.&lt;/li&gt;
&lt;li&gt;Use environment-specific overlays that represent active and standby capacity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The selected approach must be tested. "GitOps is configured" is not sufficient evidence that GitOps and the recovery workflow will cooperate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Kubernetes Resilience Controls
&lt;/h2&gt;

&lt;p&gt;The recovery Region should enforce the same—or stricter—workload-resilience controls used in the primary Region.&lt;/p&gt;

&lt;p&gt;The following example spreads application replicas across Availability Zones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkout-api&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkout-api&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkout-api&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;topologySpreadConstraints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;maxSkew&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
          &lt;span class="na"&gt;topologyKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;topology.kubernetes.io/zone&lt;/span&gt;
          &lt;span class="na"&gt;whenUnsatisfiable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DoNotSchedule&lt;/span&gt;
          &lt;span class="na"&gt;labelSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkout-api&lt;/span&gt;

      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkout-api&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ACCOUNT_ID.dkr.ecr.REGION.amazonaws.com/checkout-api@sha256:IMAGE_DIGEST&lt;/span&gt;

          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;500m"&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;512Mi"&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1"&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1Gi"&lt;/span&gt;

          &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/health/ready&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
            &lt;span class="na"&gt;initialDelaySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;

          &lt;span class="na"&gt;livenessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/health/live&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
            &lt;span class="na"&gt;initialDelaySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using immutable image digests reduces ambiguity during recovery. The promotion gate can verify that the exact digest referenced by the workload exists in the recovery Region.&lt;/p&gt;




&lt;h2&gt;
  
  
  Database Promotion and Write Safety
&lt;/h2&gt;

&lt;p&gt;Aurora Global Database supports planned switchovers and disaster-recovery failovers. These operations should not be treated as equivalent.&lt;/p&gt;

&lt;p&gt;A planned switchover is used when the current primary and secondary Regions are healthy and the organization intentionally moves the primary role. An unplanned failover is used when the primary Region is impaired or unavailable.&lt;/p&gt;

&lt;p&gt;The recovery workflow must account for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current replication lag&lt;/li&gt;
&lt;li&gt;Engine-version compatibility&lt;/li&gt;
&lt;li&gt;Promotion eligibility&lt;/li&gt;
&lt;li&gt;Application reconnection behavior&lt;/li&gt;
&lt;li&gt;DNS caching&lt;/li&gt;
&lt;li&gt;Connection-pool expiration&lt;/li&gt;
&lt;li&gt;Transaction retries&lt;/li&gt;
&lt;li&gt;Potential data loss during unplanned failure&lt;/li&gt;
&lt;li&gt;Reintroduction of the previous primary as a secondary&lt;/li&gt;
&lt;li&gt;Failback sequencing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Applications should use retry logic that distinguishes transient connectivity failure from permanent transaction rejection. Idempotency controls are especially important for payment, order, provisioning, and messaging workflows.&lt;/p&gt;

&lt;p&gt;Writer fencing must be validated before the recovery Region accepts writes. This can involve isolating the previous writer, revoking application access, disabling routing, applying security controls, or otherwise proving that dual-writer operation cannot occur.&lt;/p&gt;




&lt;h2&gt;
  
  
  Container Image Validation
&lt;/h2&gt;

&lt;p&gt;Amazon ECR supports cross-Region and cross-account private-image replication. However, replication configuration is not equivalent to complete image readiness.&lt;/p&gt;

&lt;p&gt;The recovery workflow should verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Destination repository existence&lt;/li&gt;
&lt;li&gt;Expected image digest&lt;/li&gt;
&lt;li&gt;Multi-architecture manifest availability&lt;/li&gt;
&lt;li&gt;Image-pull permissions&lt;/li&gt;
&lt;li&gt;Encryption configuration&lt;/li&gt;
&lt;li&gt;Vulnerability-scanning status, where required&lt;/li&gt;
&lt;li&gt;Node access to the destination repository&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Images pushed before a replication rule was configured should not be assumed to exist in the destination Region. Validate the exact digests required by active Kubernetes manifests.&lt;/p&gt;

&lt;p&gt;A simple validation process can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extract all image references from production workloads.&lt;/li&gt;
&lt;li&gt;Resolve tags to immutable digests.&lt;/li&gt;
&lt;li&gt;Query the destination ECR registry.&lt;/li&gt;
&lt;li&gt;Compare expected and available digests.&lt;/li&gt;
&lt;li&gt;Block promotion when any required digest is missing.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Secret and Certificate Validation
&lt;/h2&gt;

&lt;p&gt;AWS Secrets Manager can replicate encrypted secret data and metadata across Regions. Replication is useful, but it does not understand the semantic meaning of the values stored inside a secret.&lt;/p&gt;

&lt;p&gt;A replicated secret may still contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A primary-Region database endpoint&lt;/li&gt;
&lt;li&gt;A Region-specific queue URL&lt;/li&gt;
&lt;li&gt;A private service hostname unavailable from the recovery Region&lt;/li&gt;
&lt;li&gt;A certificate identifier valid only in the primary Region&lt;/li&gt;
&lt;li&gt;An external allowlist that excludes recovery egress addresses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The recovery gate must validate both existence and correctness.&lt;/p&gt;

&lt;p&gt;A secret-readiness test should verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expected secret version&lt;/li&gt;
&lt;li&gt;Recovery-Region encryption key&lt;/li&gt;
&lt;li&gt;Resource policy&lt;/li&gt;
&lt;li&gt;Application IAM access&lt;/li&gt;
&lt;li&gt;Regional endpoint values&lt;/li&gt;
&lt;li&gt;Rotation status&lt;/li&gt;
&lt;li&gt;Successful application retrieval&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Certificates should also be validated by Region, expiration date, domain name, listener association, and deployment status.&lt;/p&gt;




&lt;h2&gt;
  
  
  Observability During Recovery
&lt;/h2&gt;

&lt;p&gt;Recovery without observability is guesswork.&lt;/p&gt;

&lt;p&gt;The recovery Region must provide independent visibility into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kubernetes replica availability&lt;/li&gt;
&lt;li&gt;Unschedulable pods&lt;/li&gt;
&lt;li&gt;Worker-node provisioning&lt;/li&gt;
&lt;li&gt;Application error rate&lt;/li&gt;
&lt;li&gt;Request latency&lt;/li&gt;
&lt;li&gt;Database replication lag&lt;/li&gt;
&lt;li&gt;Database connection failures&lt;/li&gt;
&lt;li&gt;Queue depth and consumer lag&lt;/li&gt;
&lt;li&gt;Cache availability&lt;/li&gt;
&lt;li&gt;Synthetic transaction success&lt;/li&gt;
&lt;li&gt;DNS or routing state&lt;/li&gt;
&lt;li&gt;ARC recovery-plan execution&lt;/li&gt;
&lt;li&gt;GitOps synchronization&lt;/li&gt;
&lt;li&gt;Certificate errors&lt;/li&gt;
&lt;li&gt;Secret-access failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not make the recovery workflow dependent solely on a monitoring system hosted in the Region being deactivated.&lt;/p&gt;

&lt;p&gt;Critical dashboards, alarms, logs, and operational evidence should remain available during a regional impairment.&lt;/p&gt;

&lt;p&gt;Post-promotion validation should continue for a defined stabilization period. Passing a single synthetic transaction immediately after traffic movement does not prove sustained recovery.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recovery-Time Budget
&lt;/h2&gt;

&lt;p&gt;A recovery-time objective should be decomposed into measurable stages.&lt;/p&gt;

&lt;p&gt;The following is a worked reference target—not a production benchmark:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Recovery stage&lt;/th&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Event declaration and operator approval&lt;/td&gt;
&lt;td&gt;3 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARC plan evaluation and policy checks&lt;/td&gt;
&lt;td&gt;4 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EKS workload and node-capacity scaling&lt;/td&gt;
&lt;td&gt;8 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database promotion and application reconnection&lt;/td&gt;
&lt;td&gt;6 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Synthetic transaction validation&lt;/td&gt;
&lt;td&gt;4 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Traffic movement and stabilization&lt;/td&gt;
&lt;td&gt;5 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total target recovery budget&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;30 minutes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each stage should produce timestamps and evidence.&lt;/p&gt;

&lt;p&gt;A recovery exercise should record:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start and completion time&lt;/li&gt;
&lt;li&gt;Duration of each execution step&lt;/li&gt;
&lt;li&gt;Manual interventions&lt;/li&gt;
&lt;li&gt;Failed gates&lt;/li&gt;
&lt;li&gt;Overrides&lt;/li&gt;
&lt;li&gt;Database lag&lt;/li&gt;
&lt;li&gt;Replica scaling time&lt;/li&gt;
&lt;li&gt;Node-provisioning time&lt;/li&gt;
&lt;li&gt;Synthetic-test results&lt;/li&gt;
&lt;li&gt;Routing-change time&lt;/li&gt;
&lt;li&gt;Stabilization results&lt;/li&gt;
&lt;li&gt;Corrective actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With a small number of exercises, publish every result along with the minimum, median, and maximum. Avoid statistically weak percentile claims from insufficient samples.&lt;/p&gt;




&lt;h2&gt;
  
  
  Failback Is Part of the Design
&lt;/h2&gt;

&lt;p&gt;Failover is only half of disaster recovery.&lt;/p&gt;

&lt;p&gt;After the original Region becomes healthy, the organization must decide whether and when to return production traffic. Immediate failback can introduce additional risk while teams are still stabilizing the environment.&lt;/p&gt;

&lt;p&gt;A controlled failback process should:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Confirm that the original Region is stable.&lt;/li&gt;
&lt;li&gt;Rebuild or rejoin the original database cluster as required.&lt;/li&gt;
&lt;li&gt;Re-establish replication in the intended direction.&lt;/li&gt;
&lt;li&gt;Validate that no divergent writes exist.&lt;/li&gt;
&lt;li&gt;Synchronize GitOps state.&lt;/li&gt;
&lt;li&gt;Validate images, secrets, certificates, queues, caches, and dependencies.&lt;/li&gt;
&lt;li&gt;Restore sufficient EKS and worker-node capacity.&lt;/li&gt;
&lt;li&gt;Run synthetic business transactions.&lt;/li&gt;
&lt;li&gt;Fence the current writer before changing write authority.&lt;/li&gt;
&lt;li&gt;Perform a planned database switchover when supported.&lt;/li&gt;
&lt;li&gt;Move application traffic.&lt;/li&gt;
&lt;li&gt;Monitor the restored primary Region through a stabilization period.&lt;/li&gt;
&lt;li&gt;Return the other Region to the intended standby capacity.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Failback should use the same policy discipline as failover. "The original Region is back online" is not sufficient evidence that it is safe to become primary again.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security Considerations
&lt;/h2&gt;

&lt;p&gt;A recovery platform has permission to alter critical infrastructure and routing. Its security model deserves the same scrutiny as a production deployment system.&lt;/p&gt;

&lt;p&gt;Recommended controls include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dedicated IAM roles for recovery-plan execution&lt;/li&gt;
&lt;li&gt;Least-privilege EKS access entries&lt;/li&gt;
&lt;li&gt;Namespace-scoped Kubernetes permissions where practical&lt;/li&gt;
&lt;li&gt;Separate permissions for evaluation and execution&lt;/li&gt;
&lt;li&gt;Multi-person approval for high-risk recovery actions&lt;/li&gt;
&lt;li&gt;AWS CloudTrail logging&lt;/li&gt;
&lt;li&gt;Immutable audit records&lt;/li&gt;
&lt;li&gt;Encryption for data and secrets in both Regions&lt;/li&gt;
&lt;li&gt;Restricted emergency-access procedures&lt;/li&gt;
&lt;li&gt;Periodic credential and role review&lt;/li&gt;
&lt;li&gt;Protection against unauthorized policy-threshold changes&lt;/li&gt;
&lt;li&gt;Signed or reviewed recovery configuration&lt;/li&gt;
&lt;li&gt;Separation of duties between application, platform, and security teams&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Manual override capability may be necessary, but overrides should require explicit authorization, justification, timestamped evidence, and post-event review.&lt;/p&gt;

&lt;p&gt;Data-safety gates such as writer fencing should not support routine bypass.&lt;/p&gt;




&lt;h2&gt;
  
  
  Limitations and Trade-Offs
&lt;/h2&gt;

&lt;p&gt;This architecture introduces operational discipline, but it does not eliminate complexity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cost
&lt;/h3&gt;

&lt;p&gt;A warm-standby environment costs more than a pilot-light design because a functional copy of the platform remains active at reduced capacity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recovery Speed
&lt;/h3&gt;

&lt;p&gt;A pilot-light architecture can reduce cost but generally requires more provisioning and scaling during recovery.&lt;/p&gt;

&lt;h3&gt;
  
  
  DNS Behavior
&lt;/h3&gt;

&lt;p&gt;DNS-based traffic movement is affected by resolver and client caching. Configured TTL values do not guarantee that every client immediately honors the new destination.&lt;/p&gt;

&lt;h3&gt;
  
  
  Application Architecture
&lt;/h3&gt;

&lt;p&gt;Applications with hard-coded regional dependencies, non-idempotent workflows, or tightly coupled external services may require significant redesign.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Consistency
&lt;/h3&gt;

&lt;p&gt;Asynchronous cross-Region replication can introduce data-loss exposure during an unplanned failure. The organization must define an acceptable recovery-point objective.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automation Risk
&lt;/h3&gt;

&lt;p&gt;Fully automatic failover may be inappropriate for stateful systems when failure detection is uncertain or write safety cannot be proven automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Service Availability
&lt;/h3&gt;

&lt;p&gt;AWS service features, quotas, instance types, and database-engine support vary by Region and version. Validate the target Regions before implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scoring Limitations
&lt;/h3&gt;

&lt;p&gt;A readiness score is a decision aid. It is not a substitute for hard safety gates, engineering review, or repeated recovery exercises.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recommended Adoption Approach
&lt;/h2&gt;

&lt;p&gt;Do not begin by applying this model to every production workload.&lt;/p&gt;

&lt;p&gt;Start with one representative application that has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear recovery objectives&lt;/li&gt;
&lt;li&gt;Defined business transactions&lt;/li&gt;
&lt;li&gt;Known dependencies&lt;/li&gt;
&lt;li&gt;Testable data-replication behavior&lt;/li&gt;
&lt;li&gt;Manageable compliance constraints&lt;/li&gt;
&lt;li&gt;An engaged application owner&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A practical adoption sequence is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inventory all regional dependencies.&lt;/li&gt;
&lt;li&gt;Define recovery-time and recovery-point objectives.&lt;/li&gt;
&lt;li&gt;Classify hard promotion gates.&lt;/li&gt;
&lt;li&gt;Build the recovery Region with infrastructure as code.&lt;/li&gt;
&lt;li&gt;Configure application and data replication.&lt;/li&gt;
&lt;li&gt;Implement evidence collection.&lt;/li&gt;
&lt;li&gt;Implement synthetic transactions.&lt;/li&gt;
&lt;li&gt;Create the ARC Region switch plan.&lt;/li&gt;
&lt;li&gt;Integrate policy evaluation.&lt;/li&gt;
&lt;li&gt;Run recovery exercises without traffic movement.&lt;/li&gt;
&lt;li&gt;Run controlled failover and failback exercises.&lt;/li&gt;
&lt;li&gt;Correct gaps before expanding to additional applications.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The goal is not to automate every step immediately. The goal is to make every decision explicit, measurable, repeatable, and auditable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A secondary Amazon EKS cluster should not be promoted merely because its API endpoint and pods are reachable.&lt;/p&gt;

&lt;p&gt;Safe regional recovery requires evidence that compute capacity, data, application state, identity, container images, certificates, dependencies, routing, and business transactions are ready together.&lt;/p&gt;

&lt;p&gt;Hard promotion gates protect non-negotiable safety conditions. A weighted readiness score gives operators a consolidated view of the remaining operational signals. Amazon Application Recovery Controller Region switch provides an orchestration layer for executing the recovery workflow, while GitOps, infrastructure as code, replication services, synthetic testing, and observability provide the supporting controls.&lt;/p&gt;

&lt;p&gt;The result is not zero-risk failover. No architecture can honestly promise that.&lt;/p&gt;

&lt;p&gt;The objective is a recovery process in which unsafe conditions block promotion, operational decisions are supported by current evidence, and every recovery exercise improves the next one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;The architecture, code examples, thresholds, and recovery-time budget in this article are provided as a reference scenario. They must be adapted and validated against each organization's workload characteristics, recovery objectives, security requirements, compliance obligations, service quotas, AWS Region availability, and operational procedures.&lt;/p&gt;

&lt;p&gt;This article represents the author's technical perspective. It is not an AWS-supported solution, an official architecture from AWS, or a guarantee of availability, recovery time, or data protection.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/r53recovery/latest/dg/region-switch.html" rel="noopener noreferrer"&gt;Region switch in Amazon Application Recovery Controller&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/r53recovery/latest/dg/eks-resource-scaling-block.html" rel="noopener noreferrer"&gt;Amazon EKS resource scaling execution block&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/r53recovery/latest/dg/aurora-global-database-block.html" rel="noopener noreferrer"&gt;Amazon Aurora Global Database execution block&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/r53recovery/latest/dg/arc-routing-controls-block.html" rel="noopener noreferrer"&gt;ARC routing control execution block&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-global-database-disaster-recovery.html" rel="noopener noreferrer"&gt;Using switchover or failover in Amazon Aurora Global Database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECR/latest/userguide/replication.html" rel="noopener noreferrer"&gt;Private image replication in Amazon ECR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/secretsmanager/latest/userguide/replicate-secrets.html" rel="noopener noreferrer"&gt;Replicate AWS Secrets Manager secrets across Regions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/rel_planning_for_recovery_disaster_recovery.html" rel="noopener noreferrer"&gt;AWS Well-Architected Reliability Pillar: disaster-recovery strategies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>sre</category>
      <category>aws</category>
    </item>
    <item>
      <title>I Built a Platform Engineering Golden Path That Runs for $0 — Every Decision, and Everything That Broke</title>
      <dc:creator>Pradeep Kandepaneni</dc:creator>
      <pubDate>Tue, 21 Jul 2026 05:33:22 +0000</pubDate>
      <link>https://dev.to/pradeep_kandepaneni/i-built-a-platform-engineering-golden-path-that-runs-for-0-every-decision-and-everything-that-114p</link>
      <guid>https://dev.to/pradeep_kandepaneni/i-built-a-platform-engineering-golden-path-that-runs-for-0-every-decision-and-everything-that-114p</guid>
      <description>&lt;p&gt;Originally published on the AWS Builder Center: &lt;a href="https://builder.aws.com/content/3GnbxJrdbgQ5sXNJTRXvHIB5OaV/i-built-a-platform-engineering-golden-path-that-runs-for-dollar0-every-decision-and-everything-that-broke" rel="noopener noreferrer"&gt;https://builder.aws.com/content/3GnbxJrdbgQ5sXNJTRXvHIB5OaV/i-built-a-platform-engineering-golden-path-that-runs-for-dollar0-every-decision-and-everything-that-broke&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/PradeepKandepaneni/golden-path" rel="noopener noreferrer"&gt;https://github.com/PradeepKandepaneni/golden-path&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most "platform engineering" articles show you a diagram. A tidy box labeled Internal Developer Platform, some arrows pointing at happy little developer icons, a paragraph about reducing cognitive load. Then the article ends, and you're holding a concept you can't run, can't fork, and can't check.&lt;/p&gt;

&lt;p&gt;I wanted the opposite. The smallest thing a developer could actually use — push code, get back a tested, hardened, deployed workload, no tickets, no clicking — and I wanted it to cost nothing to run, so anyone reading this could clone it and watch it work instead of trusting me. No AWS bill to reproduce it. No "works on my cluster, promise."&lt;/p&gt;

&lt;p&gt;So that's what I built, and this is the honest write-up. The repo is public and green on every push, so none of what follows requires taking my word for it: github.com/PradeepKandepaneni/golden-path. Every design decision, why I threw out the alternatives, and — the part actually worth your time — the one bug that took the whole thing down and what it taught me about hardened containers.&lt;/p&gt;

&lt;p&gt;What a "golden path" actually is&lt;/p&gt;

&lt;p&gt;The term gets thrown around, so let me pin it down. A golden path is the paved road a platform team hands its developers: one opinionated, well-lit route from "I have code" to "it's running," with the boring-but-critical parts already handled. Tests. Immutable image tags. Health checks. A pod that doesn't run as root. The developer doesn't wire those up per service, and doesn't get to forget them either. They're in the road.&lt;/p&gt;

&lt;p&gt;Platform engineering, stripped of the conference gloss, is mostly the work of building and maintaining those roads so product teams stop rebuilding CI pipelines and Kubernetes manifests from scratch every time they ship something. Pave the road once; every team that drives on it inherits consistency, security, and speed for free. That's the whole pitch.&lt;/p&gt;

&lt;p&gt;The trap — and I nearly walked straight into it — is believing you need a giant portal to deliver any of that. You don't. You need one road that works.&lt;/p&gt;

&lt;p&gt;Decision 1: A template repo, not Backstage&lt;/p&gt;

&lt;p&gt;The flashy way to demo an Internal Developer Platform is Backstage. It's the name everyone knows, it has a slick UI, and "built an IDP with Backstage" looks great on a repo.&lt;/p&gt;

&lt;p&gt;I skipped it, and I'd tell you to skip it too, at least at the start. Backstage is a full-stack app you have to run, host, and babysit. For a solo project meant to show a pattern, that's weeks of wrestling with the portal before you've paved a single road — and a half-finished portal is worse than nothing, because it advertises that you started something big and quit.&lt;/p&gt;

&lt;p&gt;A template repository plus GitHub Actions gets you the same idea — one automated path that scaffolds, tests, scans, and deploys a service — with zero portal code. It's also honestly closer to what a lot of real teams run day to day. Golden paths don't need a portal. They need an opinionated, automated pipeline. That's the thing I built, and it's a thing I could finish.&lt;/p&gt;

&lt;p&gt;If I had to compress the lesson to four words: ship what you can finish.&lt;/p&gt;

&lt;p&gt;Decision 2: kind in CI, not a cloud cluster&lt;/p&gt;

&lt;p&gt;Here's the constraint that shaped everything else: the project had to run for free, in CI and on my laptop.&lt;/p&gt;

&lt;p&gt;That killed running a real EKS cluster as the default. EKS is the right answer in production — it's on the roadmap as the documented production path — but the control plane alone runs about $0.10 an hour before you add a single node, load balancer, or NAT gateway. Leave one up while you iterate and it quietly turns into a $150–300/month surprise. Worse than the money: nobody can cheaply reproduce your work, which defeats the entire point of a demo repo.&lt;/p&gt;

&lt;p&gt;So the default cluster is kind — Kubernetes running inside Docker. Locally, make up creates a cluster, builds the image, loads it, deploys, and smoke-tests it. In CI, the pipeline spins a kind cluster up inside the GitHub Actions runner, deploys to it, checks it, and throws it away when the job ends. My real run created the cluster and had the control plane Ready in 19 seconds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ready after 19s 💚
Set kubectl context to "kind-golden-path"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The economics are the quiet superpower. On a public repo, Actions minutes are unlimited and free, and the cluster lives and dies inside that free runner. The entire pipeline — a live Kubernetes deploy plus a real HTTP smoke test — costs nothing. Every push. Forever.&lt;/p&gt;

&lt;p&gt;yaml&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;name: Create kind cluster
uses: helm/kind-action@v1
with:
cluster_name: golden-path
config: kind/kind-config.yaml&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the whole "provision Kubernetes" step, and it runs on GitHub's dime.&lt;/p&gt;

&lt;p&gt;Decision 3: The image tag is the git SHA. Never :latest&lt;/p&gt;

&lt;p&gt;Small, and non-negotiable. The image is tagged with the short git SHA of the commit that built it, and the manifest is pinned to that exact tag before the deploy.&lt;/p&gt;

&lt;p&gt;yaml&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;name: Compute image tag from git SHA&lt;br&gt;
id: vars&lt;br&gt;
run: echo "sha=${GITHUB_SHA::7}" &amp;gt;&amp;gt; "$GITHUB_OUTPUT"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;name: Build image&lt;br&gt;
run: |&lt;br&gt;
docker build \&lt;br&gt;
  -t golden-path:${{ steps.vars.outputs.sha }} \&lt;br&gt;
  --build-arg VERSION=${{ steps.vars.outputs.sha }} .&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;:latest is a lie. It's a mutable label pointing at different bytes over time, so "what's running" and "what I think is running" drift apart the second someone pushes again. A content-addressable tag means a running pod can tell you exactly which commit it came from — and this service does, because I bake the SHA into the binary at build time with an ldflags override. You'll see it pay off at the end of the war story below, in the actual smoke-test output.&lt;/p&gt;

&lt;p&gt;Tiny discipline. Enormous payoff the first time you're staring at a production incident at 2 a.m. wondering what's actually deployed.&lt;/p&gt;

&lt;p&gt;Decision 4: Distroless and non-root, by default&lt;/p&gt;

&lt;p&gt;A golden path only earns its name if good practice is the default, not a thing you remember to bolt on. So the service runs on a distroless base — no shell, no package manager, almost nothing to pivot into — and the pod is hardened right in the manifest:&lt;/p&gt;

&lt;p&gt;yaml&lt;br&gt;
securityContext:&lt;br&gt;
  runAsNonRoot: true&lt;br&gt;
  allowPrivilegeEscalation: false&lt;br&gt;
  readOnlyRootFilesystem: true&lt;br&gt;
  capabilities:&lt;br&gt;
    drop: ["ALL"]&lt;/p&gt;

&lt;p&gt;Non-root. No privilege escalation. Read-only root filesystem. Every Linux capability dropped. It's the posture you'd eventually want a cluster-wide policy engine to enforce (Kyverno or OPA, on the roadmap), but here it starts as the baked-in default. The distroless choice also just produces a tiny image — the final artifact came out at 10.4MB, which the pipeline confirmed after loading it onto the node:&lt;/p&gt;

&lt;p&gt;docker.io/library/golden-path   fbab3d2   ae676b1d9427   10.4MB&lt;/p&gt;

&lt;p&gt;And this decision is exactly where the project bit me. Which is the part I actually want to talk about.&lt;/p&gt;

&lt;p&gt;The bug: CreateContainerConfigError&lt;/p&gt;

&lt;p&gt;I pushed the first real version, opened the Actions tab, and watched it fail. Not at build. Not at cluster creation. At the deploy:&lt;/p&gt;

&lt;p&gt;Waiting for deployment "golden-path" rollout to finish: 0 of 2 updated replicas are available...&lt;br&gt;
error: timed out waiting for the condition&lt;br&gt;
Error: Process completed with exit code 1&lt;/p&gt;

&lt;p&gt;Zero of two replicas. A three-minute hang, then a red X.&lt;/p&gt;

&lt;p&gt;Here's the first trap, and it's worth internalizing: that error is useless. "Timed out waiting for the condition" tells you the rollout didn't finish. It says nothing about why. The pods could be failing to pull an image, crashing on boot, flunking a health check, any of a dozen things. kubectl rollout status flattens all of them into the same timeout.&lt;/p&gt;

&lt;p&gt;My honest first guess was an image problem — the tag hadn't matched, the load had failed, something like that. Wrong, as it turned out. But I couldn't even tell I was wrong, because the pipeline wasn't telling me anything.&lt;/p&gt;

&lt;p&gt;So my first change wasn't a fix. It was making the pipeline talk. I added a diagnostics step that only fires when the deploy fails and dumps everything about the broken pods:&lt;/p&gt;

&lt;p&gt;yaml&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;name: Diagnostics (only if the deploy failed)
if: failure()
run: |
kubectl get pods -o wide
kubectl describe pods -l app=golden-path
kubectl get events --sort-by=.lastTimestamp | tail -40
kubectl logs -l app=golden-path --all-containers --tail=100 || true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pushed again. Same timeout — but this time the log told the truth right underneath it:&lt;/p&gt;

&lt;p&gt;NAME                           READY   STATUS                       RESTARTS   AGE&lt;br&gt;
golden-path-6445746597-2czz8   0/1     CreateContainerConfigError   0          3m&lt;br&gt;
golden-path-6445746597-svdct   0/1     CreateContainerConfigError   0          3m&lt;/p&gt;

&lt;p&gt;CreateContainerConfigError. Not an image problem at all — the image had loaded fine (so much for my first guess). Not a crash — the container never even started. Kubernetes was refusing to create it from its config.&lt;/p&gt;

&lt;p&gt;The cause is a genuinely sharp edge. I'd set runAsNonRoot: true, which tells the kubelet to refuse to start a container that would run as UID 0. To enforce that at create time, the kubelet needs to know the numeric user ID the container will run as. My distroless image runs as a non-root user — but it doesn't declare a numeric UID the kubelet can read at that moment. No number to check against, so the kubelet can't prove the container is non-root, and rather than risk running something as root, it refuses. Config error. Pods parked. Rollout hangs. Generic timeout.&lt;/p&gt;

&lt;p&gt;One line fixes it: pin the UID so the check has a number. The distroless nonroot variant runs as UID 65532:&lt;/p&gt;

&lt;p&gt;yaml&lt;br&gt;
securityContext:&lt;br&gt;
  runAsNonRoot: true&lt;br&gt;
  runAsUser: 65532        # &amp;lt;- the fix&lt;br&gt;
  allowPrivilegeEscalation: false&lt;br&gt;
  readOnlyRootFilesystem: true&lt;br&gt;
  capabilities:&lt;br&gt;
    drop: ["ALL"]&lt;/p&gt;

&lt;p&gt;Pushed. Green. And this time the rollout log shows the recovery happening in real time — two replicas coming up over about eight seconds:&lt;/p&gt;

&lt;p&gt;Waiting for deployment "golden-path" rollout to finish: 0 of 2 updated replicas are available...&lt;br&gt;
Waiting for deployment "golden-path" rollout to finish: 1 of 2 updated replicas are available...&lt;br&gt;
deployment "golden-path" successfully rolled out&lt;/p&gt;

&lt;p&gt;Then the in-cluster smoke test hit the service and got a real response back:&lt;/p&gt;

&lt;p&gt;{"message":"hello from the golden path","version":"fbab3d2"}&lt;/p&gt;

&lt;p&gt;Look at that version field: fbab3d2. That's the git SHA from Decision 3, baked into the binary, reported by the running pod. The immutable-tag discipline isn't theory in that line — the workload is telling me exactly which commit it came from.&lt;/p&gt;

&lt;p&gt;Why give a whole section to one missing line of YAML? Because it's the shape of nearly every hardening bug you'll meet. Doing the secure thing — refusing to run as root — is what caused the failure. Had I left the container running as root like a lazy default, it would've started instantly, and I'd have shipped something worse. Security correctness cost me an explicit config I didn't know I owed, and the failure mode (CreateContainerConfigError, hiding behind a generic rollout timeout) pointed nowhere near the actual cause. That gap — between where it breaks and why it breaks — is where most of the real work in this field lives.&lt;/p&gt;

&lt;p&gt;Why "free" is a feature, not a shortcut&lt;/p&gt;

&lt;p&gt;It'd be easy to read the zero-cost constraint as me being cheap. It's the reverse. Free-to-run is what makes the work verifiable, and verifiable is the whole point.&lt;/p&gt;

&lt;p&gt;Piece   Cost&lt;br&gt;
GitHub Actions (public repo)    Free, unlimited&lt;br&gt;
Local kind cluster  Free (your CPU)&lt;br&gt;
All tooling — Go, Terraform, Argo CD, Syft, Trivy, Kyverno    Free / open source&lt;br&gt;
EKS (roadmap, optional) Paid — destroy when done&lt;/p&gt;

&lt;p&gt;Because the pipeline deploys to a throwaway cluster and fails the build unless the app actually serves traffic, a green check here doesn't mean "the code compiled." It means "the golden path works, end to end, and here's the run that proves it." Anyone can open the workflow, click into a run, and see the deploy happen — and clone it to reproduce the whole thing locally without spending a cent. That's a different kind of credibility than a screenshot.&lt;/p&gt;

&lt;p&gt;What's deliberately not done yet&lt;/p&gt;

&lt;p&gt;I want to be straight about scope, because the temptation with a piece like this is to pretend the toy is a platform. It isn't. This is the thin slice: one service, end to end, green. The value is that it's finished and runs, not that it's complete.&lt;/p&gt;

&lt;p&gt;Here's what bolts on next, each a self-contained addition to a spine that already works:&lt;/p&gt;

&lt;p&gt;Supply-chain security. Generate an SBOM with Syft and scan the image with Trivy in CI, failing the build on critical CVEs. One of the loudest DevOps themes of 2026, and it drops straight into the existing pipeline.&lt;br&gt;
Policy as code. Enforce that hardening posture cluster-wide with Kyverno or OPA Gatekeeper, so the golden path is guaranteed rather than merely suggested. (Which, satisfyingly, would have caught my non-root bug at admission time with a far clearer message than CreateContainerConfigError.)&lt;br&gt;
GitOps delivery. Hand deploys to Argo CD so a commit becomes the source of truth instead of an imperative kubectl apply.&lt;br&gt;
Real infrastructure. A Terraform/OpenTofu module for an EKS cluster as the documented production path — spun up to capture evidence, then terraform destroy'd, because it isn't free and nobody should leave it running.&lt;/p&gt;

&lt;p&gt;Building them one at a time, on top of something that already works, is the entire method. A finished thin slice beats a half-built everything, every single time.&lt;/p&gt;

&lt;p&gt;Three things I'd hand to anyone building their own&lt;/p&gt;

&lt;p&gt;Ship the thin slice first. The failure mode of ambitious platform projects isn't bad architecture — it's never finishing. Get one service deploying end to end with a single green check, then add layers. Everything I built hangs off that spine.&lt;/p&gt;

&lt;p&gt;Make your pipeline talk before you make it work. The hours I'd have burned guessing at 0 of 2 replicas available collapsed to minutes the moment I added a diagnostics step. Instrument the failure path early. You'll lean on it constantly.&lt;/p&gt;

&lt;p&gt;Hardening forces explicitness, and that's the job. runAsNonRoot without a runAsUser is the small, sharp, real edge between "I read a tutorial" and "I ran this and hit the wall." Secure defaults make you spell things out; learning where they make you spell things out is most of the craft.&lt;/p&gt;

&lt;p&gt;The repo is here, green and free to run: github.com/PradeepKandepaneni/golden-path. Clone it, run make up, break it, and tell me what you'd pave next.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
