<?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: Monarch</title>
    <description>The latest articles on DEV Community by Monarch (@animaregem).</description>
    <link>https://dev.to/animaregem</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%2F674858%2Ff81d21da-632d-4dc8-a05e-8530c8df5399.jpeg</url>
      <title>DEV Community: Monarch</title>
      <link>https://dev.to/animaregem</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/animaregem"/>
    <language>en</language>
    <item>
      <title>My AI Agent Refunded a Customer Twice, and Every Status Code Was 200</title>
      <dc:creator>Monarch</dc:creator>
      <pubDate>Sat, 25 Jul 2026 19:43:54 +0000</pubDate>
      <link>https://dev.to/animaregem/my-ai-agent-refunded-a-customer-twice-and-every-status-code-was-200-2d2k</link>
      <guid>https://dev.to/animaregem/my-ai-agent-refunded-a-customer-twice-and-every-status-code-was-200-2d2k</guid>
      <description>&lt;p&gt;Last weekend, during the Agents of SigNoz hackathon, I wanted to avoid building yet another self-healing agent or a demo that simply detected an error and retried the same workflow.&lt;/p&gt;

&lt;p&gt;I was more interested in a harder class of failure: cases where an AI agent behaves incorrectly even though every service involved works exactly as expected.&lt;/p&gt;

&lt;p&gt;So I built a deliberately flawed support agent that could refund ₹4,998 against a ₹2,499 duplicate charge. Nothing crashed. There was no exception, no 500, and no retry storm. Every service returned 200, and the agent confidently told the customer their problem had been solved.&lt;/p&gt;

&lt;p&gt;On a traditional health dashboard, the entire system looked green while its behaviour was financially wrong.&lt;/p&gt;

&lt;p&gt;This post is about what I built to catch that class of failure: &lt;strong&gt;Trace2Test&lt;/strong&gt;, a control plane that compiles failed agent traces from SigNoz into deterministic, replayable regression tests.&lt;/p&gt;

&lt;p&gt;It is also about the debugging detour that consumed three hours of a six-hour sprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: agents fail semantically, not operationally
&lt;/h2&gt;

&lt;p&gt;Some of the worst failures in an LLM agent do not look like errors.&lt;/p&gt;

&lt;p&gt;The model may call the correct tool with the wrong arguments. It may call the right tool twice. It may correctly interpret the API schema while misunderstanding the business rule behind it.&lt;/p&gt;

&lt;p&gt;HTTP-level observability says everything worked because, operationally, everything did work. The payments API successfully executed the refund it was asked to execute. The problem was that the agent should never have requested that refund in the first place.&lt;/p&gt;

&lt;p&gt;My assumption going into the hackathon was that the trace is the most complete record of what the agent actually did.&lt;/p&gt;

&lt;p&gt;A trace should therefore be more than evidence for a post-mortem. It should be something we can compile into a test.&lt;/p&gt;

&lt;p&gt;The loop I wanted looked like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SigNoz detects a semantic failure → an incident opens automatically → the failed trace becomes a frozen recorded world → the same agent binary replays inside it deterministically for $0 → a candidate fix runs against that world with a real LLM before any customer sees it.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The demo system
&lt;/h2&gt;

&lt;p&gt;The demo consists of three FastAPI services, all instrumented with the OpenTelemetry Python SDK and exporting OTLP telemetry to SigNoz.&lt;/p&gt;

&lt;p&gt;I used Foundry to stand up the environment through a &lt;code&gt;casting.yaml&lt;/code&gt; file. One command launched SigNoz and its MCP server locally.&lt;/p&gt;

&lt;p&gt;The services were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;agent-gateway&lt;/code&gt; — the RefundBot agent, using &lt;code&gt;gpt-4o-mini&lt;/code&gt; with tool calling&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;payments-svc&lt;/code&gt; — charge and refund operations, with refunds forced into &lt;code&gt;dry_run&lt;/code&gt; mode&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;crm-svc&lt;/code&gt; — customer lookup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The telemetry contract is the heart of the system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6fq1kfvcp50hj6srirjp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6fq1kfvcp50hj6srirjp.png" alt=" " width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every agent run emits spans with a predictable structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  agent.run                    root span: agent.id, prompt version, request JSON
  llm.exchange                 one per model call: request/response, tokens
  tool.payments.refund_charge  tool spans: tool.mode = live | dry_run | simulated
  eval.outcome                 verdict span: agent.outcome, attempted vs expected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The evaluator is deliberately boring.&lt;/p&gt;

&lt;p&gt;It sums the refunds attempted by the agent and compares the result with the correct refund amount for the support ticket.&lt;/p&gt;

&lt;p&gt;The buggy v1 prompt tells the agent to refund every charge involved in a duplicate-charge incident. As a result, the &lt;code&gt;eval.outcome&lt;/code&gt; span contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;agent.outcome        = semantic_failure
agent.eval.attempted = 499800
agent.eval.expected  = 249900
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The values are stored in minor currency units.&lt;/p&gt;

&lt;p&gt;That span becomes the ground truth for the rest of the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detection: the alert that refused to fire
&lt;/h2&gt;

&lt;p&gt;My first attempt used a metric-based alert.&lt;/p&gt;

&lt;p&gt;I created a counter called &lt;code&gt;agent.eval.failures&lt;/code&gt;, incremented it whenever an evaluation produced a semantic failure, and configured a threshold rule over its per-second rate.&lt;/p&gt;

&lt;p&gt;Textbook observability.&lt;/p&gt;

&lt;p&gt;It fired once during early testing and then went permanently silent.&lt;/p&gt;

&lt;p&gt;The frustrating part was that every layer I inspected appeared to be working.&lt;/p&gt;

&lt;p&gt;The metric existed in ClickHouse. A request to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /api/v5/query_range
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;using the exact query from the alert rule returned a clean, non-zero spike.&lt;/p&gt;

&lt;p&gt;The aggregation matched. The window matched. The data was there.&lt;/p&gt;

&lt;p&gt;But SigNoz's alert evaluator continued printing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alert.count=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;on every evaluation cycle.&lt;/p&gt;

&lt;p&gt;I eventually inspected the &lt;code&gt;time_series_v4&lt;/code&gt; table and found the real problem.&lt;/p&gt;

&lt;p&gt;The metric had &lt;strong&gt;29 cumulative series and 6 delta series under the same metric name&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Partway through the sprint, I had changed the OTLP exporter to use delta temporality. The intention was to make rate alerts more resilient to service restarts.&lt;/p&gt;

&lt;p&gt;Ironically, those restarts helped create the failure.&lt;/p&gt;

&lt;p&gt;The services had restarted around a dozen times, and each restart created new series. My manual queries could still resolve the data, but the rule evaluator struggled with the mixed temporality under the same metric name.&lt;/p&gt;

&lt;p&gt;At that point, I time-boxed the ClickHouse investigation and switched to something structurally simpler: alerting directly on the evaluation span.&lt;/p&gt;

&lt;p&gt;SigNoz v5 threshold rules can query traces, so the rule became a count over matching spans:&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;signal&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;traces&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;aggregations&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;expression&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;count()&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;filter&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;expression&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;name = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;eval.outcome&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AND agent.outcome = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;semantic_failure&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AND trace2test.mode NOT EXISTS&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No temporality. No series lifecycle. No counter resets. No metric-cardinality problem.&lt;/p&gt;

&lt;p&gt;Just one question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Did a semantic-failure span exist during the last five minutes?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The rule fired roughly 3.5 minutes after the next seeded failure and remained reliable after that.&lt;/p&gt;

&lt;p&gt;I also learned two smaller provisioning lessons in the same debugging session.&lt;/p&gt;

&lt;p&gt;First, the SigNoz v0.134 &lt;code&gt;v2alpha1&lt;/code&gt; rule API silently requires a &lt;code&gt;notificationSettings&lt;/code&gt; block. Rules without it are rejected.&lt;/p&gt;

&lt;p&gt;Second, provisioning scripts should upsert rules with &lt;code&gt;PUT&lt;/code&gt;. My first implementation searched for a rule by name and happily returned the stale version instead of updating it.&lt;/p&gt;

&lt;p&gt;The following clause also turned out to be essential:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;trace2test.mode NOT EXISTS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replay runs emit real telemetry.&lt;/p&gt;

&lt;p&gt;My first successful end-to-end replay generated another &lt;code&gt;semantic_failure&lt;/code&gt; span, triggered the alert again, and opened a second incident for the replay itself.&lt;/p&gt;

&lt;p&gt;The system had successfully begun debugging its own debugging process.&lt;/p&gt;

&lt;p&gt;I closed that feedback loop by propagating replay context through W3C baggage and excluding replay spans from the production detection rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  The replay trick: swap the world, not the agent
&lt;/h2&gt;

&lt;p&gt;When the alert fires, SigNoz sends a webhook to the Trace2Test control plane.&lt;/p&gt;

&lt;p&gt;The control plane retrieves the full failed trace through the Trace API and compiles it into a case bundle containing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the original agent request&lt;/li&gt;
&lt;li&gt;every LLM request and response&lt;/li&gt;
&lt;li&gt;every tool call and tool response&lt;/li&gt;
&lt;li&gt;the expected evaluation verdict&lt;/li&gt;
&lt;li&gt;a hash of the generated fixture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key idea behind replay is to run the same agent binary while replacing the environment around it.&lt;/p&gt;

&lt;p&gt;I used two seams.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Replay the recorded LLM exchanges
&lt;/h3&gt;

&lt;p&gt;During deterministic replay, &lt;code&gt;OPENAI_BASE_URL&lt;/code&gt; points to a local simulator.&lt;/p&gt;

&lt;p&gt;The simulator serves the recorded model responses from the failed trace, in order.&lt;/p&gt;

&lt;p&gt;The agent still believes it is communicating with an OpenAI-compatible API. Its application logic does not change, but no real model request is made.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpksjywrnhva1p082weia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpksjywrnhva1p082weia.png" alt=" " width="800" height="625"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fby206yfmkqpe1rd2y73l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fby206yfmkqpe1rd2y73l.png" alt=" " width="800" height="625"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Replay the recorded tool world
&lt;/h3&gt;

&lt;p&gt;W3C baggage carries the following values through every service hop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;trace2test.case_id
trace2test.variant
trace2test.mode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The payments and CRM services inspect that baggage.&lt;/p&gt;

&lt;p&gt;When the request belongs to a replay, they return the recorded responses instead of accessing real payment or customer systems.&lt;/p&gt;

&lt;p&gt;A span processor copies the &lt;code&gt;trace2test.*&lt;/code&gt; baggage values onto every generated span.&lt;/p&gt;

&lt;p&gt;This means the replay is not hidden from observability. It appears in SigNoz as a first-class trace that can be compared directly with the original failure.&lt;/p&gt;

&lt;p&gt;The waterfall structure remains visible, but the replay is tagged with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;variant = baseline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and every tool span records:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tool.mode = simulated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The baseline replay reproduced the double-refund failure in &lt;strong&gt;591 ms for $0.00&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verifying the fix
&lt;/h2&gt;

&lt;p&gt;Reproducing the failure deterministically proves that the fixture is faithful.&lt;/p&gt;

&lt;p&gt;The next step is verifying a candidate fix.&lt;/p&gt;

&lt;p&gt;For verification, I replaced the buggy v1 prompt with a corrected v2 prompt.&lt;/p&gt;

&lt;p&gt;The environment stayed frozen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;same support request&lt;/li&gt;
&lt;li&gt;same customer&lt;/li&gt;
&lt;li&gt;same charges&lt;/li&gt;
&lt;li&gt;same tool responses&lt;/li&gt;
&lt;li&gt;same expected refund amount&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The only meaningful change was the prompt version.&lt;/p&gt;

&lt;p&gt;The simulator switched into proxy mode, allowing the fixed agent to call a real &lt;code&gt;gpt-4o-mini&lt;/code&gt; model while keeping the tool world deterministic.&lt;/p&gt;

&lt;p&gt;I ran the candidate fix three times.&lt;/p&gt;

&lt;p&gt;All three runs passed.&lt;/p&gt;

&lt;p&gt;The total model cost was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$0.001245
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxywogv94kt7dskewztxs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxywogv94kt7dskewztxs.png" alt=" " width="800" height="596"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9m03nkr7kq9rqbvtdjkz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9m03nkr7kq9rqbvtdjkz.png" alt=" " width="800" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The complete golden path—&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;seed failure → detect alert → open incident → compile trace → reproduce failure → verify fix&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;—completed in &lt;strong&gt;235 seconds&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The repository includes a &lt;code&gt;make golden&lt;/code&gt; target that executes the entire sequence.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would tell my past self
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Alert on spans for discrete semantic events
&lt;/h3&gt;

&lt;p&gt;Metrics are useful for rates, saturation, resource usage, and long-running trends.&lt;/p&gt;

&lt;p&gt;But when the thing you care about is an individual event such as “an agent evaluation failed,” the span already is that event.&lt;/p&gt;

&lt;p&gt;Counting matching spans avoids the entire temporality and counter-lifecycle problem.&lt;/p&gt;

&lt;p&gt;That is what worked for this system, and it is what I would reach for first when detecting semantic agent failures again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exclude replays from detection immediately
&lt;/h3&gt;

&lt;p&gt;Do not wait until your replay system raises an incident against itself.&lt;/p&gt;

&lt;p&gt;Replay traffic should be identifiable from the first version of the telemetry contract.&lt;/p&gt;

&lt;p&gt;Propagate replay metadata through baggage, copy it onto spans, and exclude those spans from production alerts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Query results and alert evaluation are different code paths
&lt;/h3&gt;

&lt;p&gt;A query returning data does not prove that the alert evaluator sees the same result.&lt;/p&gt;

&lt;p&gt;My manual query worked while the rule evaluator continued reporting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alert.count=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The evaluator logs were the actual source of truth.&lt;/p&gt;

&lt;p&gt;I should have checked them much earlier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deterministic replay is a boundary decision
&lt;/h3&gt;

&lt;p&gt;I achieved deterministic replay by recording at the network boundaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the LLM API&lt;/li&gt;
&lt;li&gt;the tool HTTP APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That allowed the same agent implementation to run in production, baseline replay, and candidate verification.&lt;/p&gt;

&lt;p&gt;The agent logic did not need separate test-only branches.&lt;/p&gt;

&lt;p&gt;Recording at a finer level would have required mocking internal functions and likely allowed more nondeterminism to leak into the replay.&lt;/p&gt;

&lt;p&gt;The useful abstraction was not “mock the agent.”&lt;/p&gt;

&lt;p&gt;It was “replace the world around the agent.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;A production agent failure should happen exactly once.&lt;/p&gt;

&lt;p&gt;After that, it should become a regression test: compiled from its trace, replayable deterministically, cheap to execute, and ready to guard against the next prompt or model change.&lt;/p&gt;

&lt;p&gt;Trace2Test was my attempt to build that loop.&lt;/p&gt;

&lt;p&gt;SigNoz's existing pieces—OpenTelemetry-native traces, trace-based alerting, webhooks, and the Trace API—were enough to build the full workflow during a hackathon, despite the metric alert detour.&lt;/p&gt;

&lt;p&gt;The result is a control plane that turns an observability artifact into an executable test case.&lt;/p&gt;

&lt;p&gt;Code, telemetry contract, and the one-command golden path:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/anima-regem/trace2test" rel="noopener noreferrer"&gt;github.com/anima-regem/trace2test&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>debugging</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>3 : Procrastination slowing taking over me!</title>
      <dc:creator>Monarch</dc:creator>
      <pubDate>Mon, 08 Aug 2022 19:39:55 +0000</pubDate>
      <link>https://dev.to/animaregem/3-procrastination-slowing-taking-over-me-4010</link>
      <guid>https://dev.to/animaregem/3-procrastination-slowing-taking-over-me-4010</guid>
      <description>&lt;p&gt;Sheesh! Procrastination is getting the better of me. I have been lazy and barely do a CodeChef problem a day! I need to work on that. It might be because of the exams but I doubt that is it. I've been a ton more productive when I was alone, both here and at home. I'm doing simple CodeChef problems and at least a simple GoLang project a day. The hope is still strong #30DaysofCode. &lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>productivity</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>Day 2 (06/08/2022) - The Procrastination</title>
      <dc:creator>Monarch</dc:creator>
      <pubDate>Fri, 05 Aug 2022 19:37:00 +0000</pubDate>
      <link>https://dev.to/animaregem/day-2-06082022-the-procrastination-4oon</link>
      <guid>https://dev.to/animaregem/day-2-06082022-the-procrastination-4oon</guid>
      <description>&lt;p&gt;Aah! Today procrastination got the good outta me! Still I'm fired up to make up for all the time I wasted. Did a simple code-chef problem and completed a one shot Go video. Will be doing some simple Go projects from tomorrow. And since university exams are coming up, time's getting a bit crammed, along with that, my flask skills pleading me to spare it at  least a glance and the backend integration of college admin page. PS: A friend did almost all the UI work, who am I to complain :')&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>productivity</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>Here goes a new series, Code rant. 05/08/2022</title>
      <dc:creator>Monarch</dc:creator>
      <pubDate>Thu, 04 Aug 2022 19:08:32 +0000</pubDate>
      <link>https://dev.to/animaregem/here-goes-a-new-series-code-rant-05082022-3h3l</link>
      <guid>https://dev.to/animaregem/here-goes-a-new-series-code-rant-05082022-3h3l</guid>
      <description>&lt;h1&gt;
  
  
  About Me
&lt;/h1&gt;

&lt;p&gt;Honestly, I am one of the greatest procrastinators out there. I have had great ideas and plans that were ruined solely due to procrastination. This series is to document or record my journey. Currently I'm working on my basic coding skills with Go, learning a bit of devops and working on my Flask, React, Node and Svelte skills.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>productivity</category>
      <category>todayilearned</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
