<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Chaos-Engineering on Mauro Medda</title><link>https://mauro.medda.xyz/tags/chaos-engineering/</link><description>Recent content in Chaos-Engineering on Mauro Medda</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><managingEditor>mauro@medda.xyz (Mauro Medda)</managingEditor><webMaster>mauro@medda.xyz (Mauro Medda)</webMaster><copyright>Mauro Medda</copyright><lastBuildDate>Sat, 29 Aug 2026 17:00:00 +0200</lastBuildDate><atom:link href="https://mauro.medda.xyz/tags/chaos-engineering/index.xml" rel="self" type="application/rss+xml"/><item><title>Adding Chaos Engineering to our harness</title><link>https://mauro.medda.xyz/posts/adding-chaos-engineering/</link><pubDate>Sat, 29 Aug 2026 17:00:00 +0200</pubDate><author>mauro@medda.xyz (Mauro Medda)</author><guid>https://mauro.medda.xyz/posts/adding-chaos-engineering/</guid><description>&lt;p>&lt;img src="https://mauro.medda.xyz/images/posts/adding-chaos-engineering.jpeg" alt="Adding Chaos Engineering to our harness">&lt;/p>
&lt;p>Ciao, over the past month, while Italy was deep into the holiday season, things at HikmaAI and in our learning process went quite the opposite way.&lt;/p>
&lt;p>We started iterating faster on the platform because we got some very good feedback from design partners and pilot users. We also ran our first installations based on the new deployment model.&lt;/p>
&lt;p>Yes, we moved from SaaS to on-premise. That&amp;rsquo;s what the market had been screaming for.&lt;/p></description><content:encoded><![CDATA[<p><img src="/images/posts/adding-chaos-engineering.jpeg" alt="Adding Chaos Engineering to our harness"></p>
<p>Ciao, over the past month, while Italy was deep into the holiday season, things at HikmaAI and in our learning process went quite the opposite way.</p>
<p>We started iterating faster on the platform because we got some very good feedback from design partners and pilot users. We also ran our first installations based on the new deployment model.</p>
<p>Yes, we moved from SaaS to on-premise. That&rsquo;s what the market had been screaming for.</p>
<p>Of course, none of the above came for free.</p>
<p>We started finding edge cases and the usual distributed systems problems. Because, agents or not, at the end you still got a bunch of containers competing for resources, sharing information, processing data, interacting with external services and, last but not least, dealing with failures.</p>
<p>As with every &ldquo;cloud native&rdquo; distributed system, you have a lot of points that can fail and generate a waterfall of failures across the synchronous and asynchronous parts of the system.</p>
<p>Some of you may already be asking:</p>
<blockquote>
<p>Why am I reading about this basic stuff in a series about coding agent harnesses?</p>
</blockquote>
<p>And here is the thing.</p>
<p>As mentioned in the first article, we believe, like many others, that to get the most out of agentic or automated programming you need strong feed-forward and feedback loops, with deterministic computation and LLM gates working together.</p>
<p>The coding agent is not the software factory. The complete loop is.</p>
<p>One of the first additions I made to our harness was the ability to spawn on-demand environments on k3d, perform end-to-end tests, and collect, measure and address errors coming from both the application and the infrastructure.</p>
<p>As always happens, the tendency is to leave reliability tests for later. Or, as modern naming conventions like to call it: technical debt.</p>
<p>But the faster you go, and the faster you want to go, the longer product qualification can take. This time also increases as soon as you start engaging with customers, for two simple reasons:</p>
<ol>
<li>No one likes building and shipping shit code.</li>
<li>No user likes wasting time and feeling like they are your tester.</li>
</ol>
<p>With those two criteria in mind, and given that we now have AI helping us, the question got an immediate answer in my head:</p>
<blockquote>
<p>Why should we keep those tickets in the backlog? Let&rsquo;s start addressing them now.</p>
</blockquote>
<p>We had already automated the end-to-end qualification tests against real target environments, thanks to <a href="https://xference.ai">Xference.ai</a> for providing model access.</p>
<p>We also had a proper improvement loop in our harness:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">commit
</span></span><span class="line"><span class="ln">2</span><span class="cl">run the CI tests
</span></span><span class="line"><span class="ln">3</span><span class="cl">deploy into an ephemeral environment
</span></span><span class="line"><span class="ln">4</span><span class="cl">run the end-to-end tests
</span></span><span class="line"><span class="ln">5</span><span class="cl">send me an update on Telegram every ten minutes
</span></span><span class="line"><span class="ln">6</span><span class="cl">identify and fix errors
</span></span><span class="line"><span class="ln">7</span><span class="cl">repeat</span></span></code></pre></div><p>At that point, it was time to add Chaos Engineering to the pipeline.</p>
<p>Agentic coding allows the team to focus on establishing solid practices and foundations without waiting for a technical debt reduction sprint.</p>
<p>This does not mean asking the coding agent to &ldquo;make the system resilient&rdquo;. That kind of prompt is too vague and will probably produce a lot of plausible code without giving you any proof that the system is actually more resilient.</p>
<p>The real value comes from giving the agent an executable hypothesis, a controlled environment, clear safety boundaries and a measurable expected result.</p>
<h2 id="avoiding-failures-is-not-an-option">Avoiding failures is not an option</h2>
<p>Equipped with memories from my SRE days, I started looking at what was available in the open-source space.</p>
<p>The goal was to generate and inject failures as part of our qualification process, then have <code>pi</code>, my coding agent, investigate those failures and add or fix the resiliency mechanisms exposed by the tests, just as it already did for our normal CI and end-to-end tests.</p>
<p>Chaos Engineering means introducing failures deliberately to test the system&rsquo;s resilience inside a controlled environment. In my case, that controlled environment is an ephemeral k3d qualification environment.</p>
<p>The idea was to take some of those annoying &ldquo;edge case&rdquo; and &ldquo;what if?&rdquo; questions and transform them into rehearsed responses.</p>
<p>It is not about generating chaos for the pleasure of breaking things. It is about:</p>
<ol>
<li>Making the system more resilient to failures.</li>
<li>Reacting with calm and confidence in production, which only happens after you have already dealt with a similar failure.</li>
<li>Creating operational runbooks. Yes, this one is closely related to number two.</li>
</ol>
<p>I am not going to write another post explaining the principles and history of Chaos Engineering. Google has already made a great effort there:</p>
<ol>
<li><a href="https://sre.google/books/">Google SRE books</a></li>
<li><a href="https://cloud.google.com/blog/products/devops-sre/getting-started-with-chaos-engineering">Getting Started with Chaos Engineering</a></li>
</ol>
<p>What I want to focus on is how Chaos Engineering fits into an agentic coding workflow.</p>
<h2 id="choosing-the-framework">Choosing the framework</h2>
<p>AI makes it easier to describe a steady state, generate a hypothesis, parse outputs and create automation scripts.</p>
<p>Still, the human needs to decide what success means and how much of the system the experiment is allowed to touch.</p>
<p>My first task was to evaluate frameworks that could help us:</p>
<ul>
<li>inject failures into the messaging layer;</li>
<li>generate memory pressure and OOM conditions;</li>
<li>add latency and connection problems between workers and dependencies;</li>
<li>interrupt callbacks and external calls;</li>
<li>validate readiness and liveness behaviour;</li>
<li>collect evidence that an agent could inspect.</li>
</ul>
<p>The framework I opted for is <a href="https://chaostoolkit.org/">Chaos Toolkit</a>, an open-source framework written in Python.</p>
<p>Chaos Toolkit gives us a modular architecture where we can plug in extensions and custom drivers to execute experiments against the parts of the system we want to test.</p>
<p>As the first extension, we added <a href="https://github.com/Shopify/toxiproxy">Toxiproxy</a>.</p>
<p>Toxiproxy sits between a worker and a dependency, allowing us to introduce network problems without modifying either side. We use it to introduce latency, timeouts, bandwidth limits, interrupted responses and connection problems across the messaging layer, databases, callbacks and controlled external targets.</p>
<p>For Kubernetes failures, we can terminate workers or temporarily remove a dependency. For memory failures, we can apply bounded pressure inside a worker and observe how its admission logic reacts.</p>
<p>The important part is that all of this happens only inside the dedicated k3d environment.</p>
<h2 id="start-from-the-steady-state">Start from the steady state</h2>
<p>Before introducing a failure, you need to define what the system should look like when it is healthy.</p>
<p>&ldquo;Everything is green&rdquo; is not a steady state.</p>
<p>&ldquo;HTTP returned 200&rdquo; is not a steady state either.</p>
<p>For a long-running asynchronous operation, our steady-state checks look more like this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  <span class="nt">&#34;terminal_status&#34;</span><span class="p">:</span> <span class="s2">&#34;completed&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  <span class="nt">&#34;expected_outputs&#34;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="nt">&#34;physical_external_calls&#34;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">  <span class="nt">&#34;successful_external_calls&#34;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">  <span class="nt">&#34;ambiguous_external_calls&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  <span class="nt">&#34;worker_restarts&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">  <span class="nt">&#34;oom_events&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">  <span class="nt">&#34;failure_codes&#34;</span><span class="p">:</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>The exact fields are not important. The important part is that the expected result is machine-verifiable.</p>
<p>A worker did not recover simply because it started answering health checks again. The operation must resume, persist its outputs, avoid duplicate external calls and eventually reach a stable terminal state.</p>
<p>We require repeated identical terminal observations before accepting convergence. This prevents the harness from mistaking a stale or intermediate response for a recovered system.</p>
<p>This is one of the most useful ways to work with a coding agent:</p>
<blockquote>
<p>Do not ask the agent to make the system &ldquo;reliable&rdquo;. Give it invariants that can fail.</p>
</blockquote>
<h2 id="turning-what-if-into-experiments">Turning &ldquo;what if?&rdquo; into experiments</h2>
<p>Once we had the steady-state contract, we started converting failure hypotheses into experiments.</p>
<p>Some examples:</p>
<ul>
<li>What happens if a worker disappears halfway through a task?</li>
<li>What happens if the messaging layer becomes slow?</li>
<li>What happens if the database resets a connection?</li>
<li>What happens if an internal callback times out?</li>
<li>What happens if a target accepts a request but its response never reaches us?</li>
<li>What happens when there is no memory headroom for another job?</li>
<li>What happens when two workers disagree about the active execution configuration?</li>
<li>What happens when an old message is delivered after a newer generation has started?</li>
</ul>
<p>These scenarios cover different failure classes.</p>
<h3 id="worker-failures">Worker failures</h3>
<p>We terminate workers while an operation is active, then verify that another worker can safely continue the work.</p>
<p>The experiment does not pass because Kubernetes accepted a delete command. We record the original worker identity, prove that it disappeared, wait for its replacement, and then verify that the operation continues.</p>
<h3 id="dependency-failures">Dependency failures</h3>
<p>We temporarily make the messaging or persistence layer unavailable.</p>
<p>We also inject latency and timeouts because a slow dependency is often more interesting than a dead one. A hard failure is usually visible. A dependency that responds after several seconds can consume worker slots, trigger retries and create backlogs before anyone notices.</p>
<h3 id="memory-pressure">Memory pressure</h3>
<p>Containers compete for finite memory. This sounds obvious, but concurrency settings are often based on a number someone picked months ago on a laptop.</p>
<p>We created experiments where a worker sees progressively less memory headroom.</p>
<p>The expected behaviour is not always &ldquo;keep processing&rdquo;. Sometimes the correct behaviour is to stop accepting new work, let the active work finish, and resume only when there is enough headroom again.</p>
<p>Zero admission capacity is valid. An OOM is not a better answer.</p>
<p>We also keep an isolated legacy configuration that intentionally reproduces the old OOM behaviour. This lets us prove both sides:</p>
<ul>
<li>the failure is real and reproducible;</li>
<li>the protected worker reacts differently under the same pressure.</li>
</ul>
<h3 id="external-call-ambiguity">External call ambiguity</h3>
<p>One of the most interesting cases happens when an external target accepts a request but the response gets interrupted.</p>
<p>At that point, the worker does not know whether the target executed the operation.</p>
<p>Automatically retrying can produce a duplicate action. Not retrying means accepting that the result is uncertain.</p>
<p>Without target-side idempotency, you cannot honestly claim exactly-once execution.</p>
<p>Our response is conservative:</p>
<ol>
<li>Persist the call intention before touching the target.</li>
<li>Bind it to a stable operation and case identity.</li>
<li>Persist the result when completion is known.</li>
<li>Mark the call as ambiguous when completion cannot be established.</li>
<li>Never replay the ambiguous call automatically under a different identity.</li>
</ol>
<p>The corresponding experiment verifies both the expected number of physical calls and their outcomes.</p>
<p>This is the kind of detail that normal happy-path tests rarely cover.</p>
<h2 id="injecting-a-fault-is-the-easy-part">Injecting a fault is the easy part</h2>
<p>Creating latency with Toxiproxy takes a few lines of configuration.</p>
<p>For example:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;latency&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nt">&#34;stream&#34;</span><span class="p">:</span> <span class="s2">&#34;downstream&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="nt">&#34;toxicity&#34;</span><span class="p">:</span> <span class="mf">1.0</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">  <span class="nt">&#34;attributes&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="nt">&#34;latency&#34;</span><span class="p">:</span> <span class="mi">750</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="nt">&#34;jitter&#34;</span><span class="p">:</span> <span class="mi">50</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>The hard part is making sure that:</p>
<ul>
<li>the fault targets the correct environment;</li>
<li>the fault is actually active;</li>
<li>the experiment cannot affect shared resources;</li>
<li>rollback happens after both success and failure;</li>
<li>the agent cannot call a partial run successful;</li>
<li>the evidence does not contain credentials or customer data.</li>
</ul>
<p>This is where most of our implementation work went.</p>
<h2 id="safety-first-especially-with-an-agent">Safety first, especially with an agent</h2>
<p>Every chaos run happens inside a new, dedicated k3d namespace.</p>
<p>Before introducing a fault, the harness verifies the cluster, namespace, worker identities, candidate images and experiment configuration.</p>
<p>Names are not enough. The harness works with exact runtime identities and refuses to proceed if something changed after the configuration was reviewed.</p>
<p>Each mutation is also revalidated immediately before execution. If the target changed between preflight and mutation, the experiment stops.</p>
<p>This may sound paranoid. It should.</p>
<p>A coding agent that can delete a worker or interrupt a dependency needs stronger boundaries than an agent that can run a unit test.</p>
<p>The rule is simple:</p>
<blockquote>
<p>If the harness cannot prove that the target belongs to the current experiment, it does nothing.</p>
</blockquote>
<h2 id="prove-that-the-fault-happened">Prove that the fault happened</h2>
<p>Another easy mistake is to assume that the fault is active because the mutation command succeeded.</p>
<p>We do not start the observation window after sending the mutation. We start it after proving activation.</p>
<p>Depending on the experiment, this means verifying that:</p>
<ul>
<li>the original worker disappeared;</li>
<li>the dependency reached the expected unavailable state;</li>
<li>the network fault exists with the requested attributes;</li>
<li>traffic crossed the faulted connection;</li>
<li>the worker observed the expected memory pressure.</li>
</ul>
<p>Without activation proof, a passing experiment may simply mean that the fault never happened.</p>
<p>And yes, an LLM can happily summarize that as a successful resilience test if you only give it the command output.</p>
<h2 id="rollback-is-part-of-the-experiment">Rollback is part of the experiment</h2>
<p>Rollback is not cleanup added at the end. It is part of the experiment contract.</p>
<p>Before starting, the harness writes a restricted rollback journal containing the original state and the exact resource owned by the run.</p>
<p>The journal follows explicit transitions:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">prepared
</span></span><span class="line"><span class="ln">2</span><span class="cl">revalidated
</span></span><span class="line"><span class="ln">3</span><span class="cl">mutation attempted
</span></span><span class="line"><span class="ln">4</span><span class="cl">mutation confirmed
</span></span><span class="line"><span class="ln">5</span><span class="cl">restoration attempted
</span></span><span class="line"><span class="ln">6</span><span class="cl">restored</span></span></code></pre></div><p>If the process crashes, recovery uses that exact journal. It does not look for the most recent file and hope it belongs to the same run.</p>
<p>We also avoid broad cleanup operations. If the experiment creates one named network fault, rollback removes that specific fault. It does not reset the complete proxy configuration.</p>
<p>If rollback fails, the harness keeps the state and evidence for diagnosis. It does not remove everything and return green.</p>
<h2 id="evidence-instead-of-vibes">Evidence instead of vibes</h2>
<p>The coding agent needs structured evidence, not ten thousand lines of logs.</p>
<p>For each experiment, we collect a bounded snapshot containing:</p>
<ul>
<li>the current operation status;</li>
<li>stable output identifiers;</li>
<li>external call counts and outcomes;</li>
<li>worker restart and OOM observations;</li>
<li>recovery transitions;</li>
<li>failure codes;</li>
<li>proof that the injected fault carried traffic;</li>
<li>proof that rollback completed.</li>
</ul>
<p>The retained result is signed and redacted.</p>
<p>We exclude credentials, raw prompts, responses, payloads, endpoints and unfiltered logs.</p>
<p>This gives the agent enough information to investigate a failure without giving it unnecessary access to sensitive data.</p>
<p>It also prevents a common problem in automated qualification: accepting a plausible summary without being able to reproduce how that summary was produced.</p>
<h2 id="fixtures-are-not-runtime-evidence">Fixtures are not runtime evidence</h2>
<p>We built deterministic fixtures for every experiment.</p>
<p>They help us validate the harness itself:</p>
<ul>
<li>configuration parsing;</li>
<li>scenario generation;</li>
<li>expected-result matching;</li>
<li>rollback transitions;</li>
<li>evidence generation;</li>
<li>signature and tamper detection.</li>
</ul>
<p>But fixture evidence is always marked as non-qualifying.</p>
<p>A mocked worker that survives a simulated network timeout does not prove that the real worker survived it inside Kubernetes.</p>
<p>This distinction becomes even more important with coding agents because they are very good at making local tests pass. If the boundary is not explicit, a green fixture can slowly become a &ldquo;qualified&rdquo; feature in the conversation history.</p>
<p>We do not allow that.</p>
<h2 id="the-improvement-loop">The improvement loop</h2>
<p>Once the safety controls were in place, <code>pi</code> could work inside the loop.</p>
<p>A task for the agent looks more like this:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">Run one reviewed scenario inside the dedicated k3d environment.
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">Do not touch shared environments.
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">Do not broaden selectors or resource ownership.
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">Stop if preflight, fault activation, rollback or evidence verification fails.
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">Inspect only the redacted evidence.
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">Identify the smallest defect that violates the steady-state contract.
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">Fix it.
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">Run the unit and contract tests.
</span></span><span class="line"><span class="ln">10</span><span class="cl">Build a new immutable candidate.
</span></span><span class="line"><span class="ln">11</span><span class="cl">Repeat the same scenario.
</span></span><span class="line"><span class="ln">12</span><span class="cl">Do not weaken the experiment to make it pass.</span></span></code></pre></div><p>This is very different from:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Make the workers resilient.</span></span></code></pre></div><p>The agent can generate experiment definitions, write probes, run tests, inspect failures, implement fixes and update runbooks.</p>
<p>The human still decides:</p>
<ul>
<li>which environment can be touched;</li>
<li>which failure is safe to introduce;</li>
<li>what the expected behaviour should be;</li>
<li>whether the collected evidence is enough.</li>
</ul>
<p>Agentic coding does not remove engineering responsibility. It increases the speed at which engineering decisions become running code, including bad decisions.</p>
<h2 id="how-to-start-applying-this">How to start applying this</h2>
<p>If you want to introduce Chaos Engineering into your agentic coding process, start with one important workflow.</p>
<p>Do not start by randomly killing workers.</p>
<h3 id="1-pick-one-business-operation">1. Pick one business operation</h3>
<p>Choose something with a clear start and end, such as:</p>
<ul>
<li>processing a job;</li>
<li>generating a report;</li>
<li>importing a file;</li>
<li>executing an external action.</li>
</ul>
<h3 id="2-describe-the-steady-state">2. Describe the steady state</h3>
<p>Write down:</p>
<ul>
<li>the expected terminal state;</li>
<li>the expected persisted outputs;</li>
<li>the allowed number of retries;</li>
<li>the number of external calls;</li>
<li>the accepted failure codes;</li>
<li>the convergence deadline;</li>
<li>the allowed worker restarts and OOMs.</li>
</ul>
<p>Turn those expectations into code.</p>
<h3 id="3-build-an-isolated-environment">3. Build an isolated environment</h3>
<p>Create a disposable local cluster or namespace.</p>
<p>Use separate credentials and make ownership explicit. The experiment should fail closed if the environment does not match what was reviewed.</p>
<h3 id="4-introduce-one-reversible-failure">4. Introduce one reversible failure</h3>
<p>Start with something simple:</p>
<ul>
<li>terminate one worker;</li>
<li>add latency to the messaging layer;</li>
<li>interrupt one callback;</li>
<li>temporarily remove memory headroom.</li>
</ul>
<p>Do not combine faults until you understand the recovery path for each one.</p>
<h3 id="5-prove-activation-and-rollback">5. Prove activation and rollback</h3>
<p>Do not trust the mutation command.</p>
<p>Measure that the fault became active and that the original state was restored afterwards.</p>
<h3 id="6-produce-structured-evidence">6. Produce structured evidence</h3>
<p>Give the coding agent IDs, counts, outcomes and failure codes.</p>
<p>Do not ask it to infer success from raw logs.</p>
<h3 id="7-keep-the-agent-inside-the-contract">7. Keep the agent inside the contract</h3>
<p>The agent can change the implementation, but it should not silently change:</p>
<ul>
<li>the steady state;</li>
<li>the fault intensity;</li>
<li>the allowed failure codes;</li>
<li>the qualification boundary.</li>
</ul>
<p>Those changes require human review.</p>
<h3 id="8-repeat-until-the-same-experiment-passes">8. Repeat until the same experiment passes</h3>
<p>The final loop is simple:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">reproduce
</span></span><span class="line"><span class="ln">2</span><span class="cl">inspect
</span></span><span class="line"><span class="ln">3</span><span class="cl">fix
</span></span><span class="line"><span class="ln">4</span><span class="cl">validate
</span></span><span class="line"><span class="ln">5</span><span class="cl">rebuild
</span></span><span class="line"><span class="ln">6</span><span class="cl">repeat</span></span></code></pre></div><p>Simple does not mean easy, but it gives the agent a concrete job and the team a reproducible result.</p>
<h2 id="where-we-are">Where we are</h2>
<p>At the time of writing, the experiment definitions, deterministic fixtures and syntax checks are in place. We have also completed a real baseline run against the ephemeral environment.</p>
<p>The full runtime Chaos Engineering qualification remains a separate gate. We are not treating fixture results or a healthy baseline as proof that every recovery scenario works.</p>
<p>This distinction is part of the engineering practice.</p>
<p>AI makes generating code and automation faster. It does not make partial evidence complete, and it does not turn a simulated failure into a production result.</p>
<p>For me, this has been the most useful part of bringing Chaos Engineering into an agentic coding loop.</p>
<p>The interesting question is no longer:</p>
<blockquote>
<p>Can the agent write a chaos experiment?</p>
</blockquote>
<p>Of course it can.</p>
<p>The real question is:</p>
<blockquote>
<p>Can your harness stop the agent from running it against the wrong environment, accepting the wrong result or hiding a failed recovery?</p>
</blockquote>
<p>That is the part worth engineering.</p>
]]></content:encoded></item></channel></rss>