<?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: Igor Eduardo</title>
    <description>The latest articles on DEV Community by Igor Eduardo (@igoreduardoai).</description>
    <link>https://dev.to/igoreduardoai</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%2F3929927%2F8c3a1bbb-7afd-475e-baad-ed984b036b51.png</url>
      <title>DEV Community: Igor Eduardo</title>
      <link>https://dev.to/igoreduardoai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/igoreduardoai"/>
    <language>en</language>
    <item>
      <title>Your Agent's Failure Predictor Is Grading the Task, Not the Run</title>
      <dc:creator>Igor Eduardo</dc:creator>
      <pubDate>Mon, 09 Nov 2026 08:23:21 +0000</pubDate>
      <link>https://dev.to/igoreduardoai/your-agents-failure-predictor-is-grading-the-task-not-the-run-2ak1</link>
      <guid>https://dev.to/igoreduardoai/your-agents-failure-predictor-is-grading-the-task-not-the-run-2ak1</guid>
      <description>&lt;h1&gt;
  
  
  Your Agent's Failure Predictor Is Grading the Task, Not the Run
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;By Igor Eduardo · Austin, TX · &lt;a href="https://igoreduardo.com" rel="noopener noreferrer"&gt;https://igoreduardo.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A short new paper, &lt;a href="https://arxiv.org/abs/2611.08285" rel="noopener noreferrer"&gt;Hard Issue, Weak Model, or Bad Run? Rethinking Failure Prediction for Coding Agents&lt;/a&gt; (arXiv 2611.08285, posted 2026-11-05), asks a question most agent monitoring skips: when a predictor flags a run as "going wrong", has it learned anything about &lt;strong&gt;that run&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;The setup is familiar. A coding agent works on a repository issue for many steps. A predictor reads the partial trajectory (reasoning, commands, tool output) and raises an alarm. On an alarm you stop the run, retry it, or hand the issue to another model.&lt;/p&gt;

&lt;p&gt;The authors point out that a run can fail for three different reasons, and each one calls for a different action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hard issue:&lt;/strong&gt; most models fail it. Stopping or asking a human is the better move.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weak model:&lt;/strong&gt; this model fails many issues. Switching to a stronger one is the better move.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bad run:&lt;/strong&gt; the same model solves the same issue on other attempts. Only here does a retry help.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Their finding is that current trajectory-based predictors mostly can't tell these apart.&lt;/p&gt;

&lt;h2&gt;
  
  
  What they report
&lt;/h2&gt;

&lt;p&gt;They used public trajectories on a widely used benchmark of &lt;strong&gt;500&lt;/strong&gt; real repository issues, where each model attempts each issue &lt;strong&gt;once&lt;/strong&gt;: &lt;strong&gt;3,492&lt;/strong&gt; runs from &lt;strong&gt;seven&lt;/strong&gt; models, &lt;strong&gt;994&lt;/strong&gt; of them failures, plus outcomes for &lt;strong&gt;23&lt;/strong&gt; models and a separate public corpus with repeated runs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A score that never sees the run wins.&lt;/strong&gt; A reference that only knows how hard an issue is for &lt;em&gt;other&lt;/em&gt; models reaches &lt;strong&gt;0.92 pooled AUROC&lt;/strong&gt;. The trajectory predictors reach &lt;strong&gt;0.62–0.63&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pooled AUROC is mostly a between-task number.&lt;/strong&gt; Of &lt;strong&gt;494,109&lt;/strong&gt; failed/successful pairs in the test folds, &lt;strong&gt;99.66%&lt;/strong&gt; compare &lt;em&gt;different issues&lt;/em&gt;. A score that recognizes hard issues can look excellent without reading a single step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Within an issue, knowing the model beats reading the run.&lt;/strong&gt; Model identity alone reaches &lt;strong&gt;0.72&lt;/strong&gt; within-issue AUROC, against &lt;strong&gt;0.60–0.61&lt;/strong&gt; for the predictors. On "upset" pairs, where the overall weaker model won, the predictors score &lt;strong&gt;0.42&lt;/strong&gt;, below chance. They are reproducing the model ranking, not watching the run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What the trajectory adds is statistically zero.&lt;/strong&gt; Adding a predictor's score on top of issue difficulty and model identity changes AUROC by an amount equivalent to zero in all &lt;strong&gt;18&lt;/strong&gt; configurations they tested.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The "switch models" story mostly dissolves.&lt;/strong&gt; The best single model solves &lt;strong&gt;76.8%&lt;/strong&gt; of issues and &lt;em&gt;some&lt;/em&gt; model solves &lt;strong&gt;86.8%&lt;/strong&gt;, a &lt;strong&gt;10.0-point&lt;/strong&gt; "oracle gap". That gap sits inside the range chance alone produces. &lt;strong&gt;45%&lt;/strong&gt; of failures (&lt;strong&gt;448 of 994&lt;/strong&gt;) happen on &lt;strong&gt;64&lt;/strong&gt; issues no model solves, so there is nothing to switch to. Picking a model per issue from its past runs gains &lt;strong&gt;+0.09&lt;/strong&gt; points on new runs; a router for new issues gains &lt;strong&gt;+0.41&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The gain people attribute to routing comes from a second attempt.&lt;/strong&gt; Escalating every failure to one fixed second model gains &lt;strong&gt;+6.91&lt;/strong&gt; points, and that assumes a perfect failure detector. The win is the extra try, not a better-suited model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bad runs are real.&lt;/strong&gt; In the repeated-run pilot (&lt;strong&gt;522&lt;/strong&gt; issues, at least four runs per model), outcome variation splits into &lt;strong&gt;53%&lt;/strong&gt; issue difficulty, &lt;strong&gt;42%&lt;/strong&gt; run-to-run variation, and only &lt;strong&gt;4.6%&lt;/strong&gt; model-issue specialization. So retries have real room to help, but &lt;strong&gt;64–82%&lt;/strong&gt; of predictor score variance lies &lt;em&gt;between&lt;/em&gt; issues, which means the alarm mostly fires on the cases where a retry is less likely to work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scope, in their words: mainly one benchmark and one scaffold, trajectory-based predictors only, a repeated-run pilot with older models, and a router with shallow issue features. Not detecting specialization is not proof it is absent. Those are their numbers, not mine. I have not re-run the experiments, and I am deliberately not naming the models, the benchmark, or the prior systems the paper discusses.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stake
&lt;/h2&gt;

&lt;p&gt;Teams will read "our failure predictor has a good AUROC" as "our agent knows when a run is going wrong".&lt;/p&gt;

&lt;p&gt;That is the same mistake as reading a leaderboard as a forecast. A pooled score mixes three things into one number: how hard the tasks were, how strong the model is, and what happened in this attempt. Only the third is something a run-time monitor can act on. If the number is carried by the first two, you have built an expensive difficulty estimate and wired it to a retry button.&lt;/p&gt;

&lt;p&gt;The cost shows up in the action layer. A predictor that fires on hard issues triggers retries on exactly the failures a retry rarely fixes, and stays quiet on the bad runs a retry would rescue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opinion (one sentence)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Any claim that a monitor, router or retry rule makes an agent more reliable should be backed by repeated runs and run-blind baselines at equal budget, because a single-attempt leaderboard can't tell a hard task from a weak model from a bad run.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is a preference with a limiter, not a benchmark result. If your agent runs short, cheap, deterministic tasks, single runs may be enough. Once runs are long, stochastic, and you act on an alarm mid-run, the cause of failure decides whether the action helps.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a cause-aware agent eval reports (menu, not recipe)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Column&lt;/th&gt;
&lt;th&gt;Question it answers&lt;/th&gt;
&lt;th&gt;Failure if skipped&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Run-blind baselines&lt;/td&gt;
&lt;td&gt;Does the monitor beat "how hard is this task" and "which model ran"?&lt;/td&gt;
&lt;td&gt;A difficulty estimate sold as run monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Within-task score&lt;/td&gt;
&lt;td&gt;Can it rank two attempts at the &lt;em&gt;same&lt;/em&gt; task?&lt;/td&gt;
&lt;td&gt;Pooled score carried by task mix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repeated runs&lt;/td&gt;
&lt;td&gt;How often does the same model pass and fail the same task?&lt;/td&gt;
&lt;td&gt;Bad runs invisible, luck read as skill&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chance reference for gaps&lt;/td&gt;
&lt;td&gt;Is the "best of several models" gap bigger than noise?&lt;/td&gt;
&lt;td&gt;Routing built on a coin-flip artifact&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Equal-budget comparison&lt;/td&gt;
&lt;td&gt;Does the strategy beat simply trying again with the same model?&lt;/td&gt;
&lt;td&gt;A second attempt credited to cleverness&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Action outcome&lt;/td&gt;
&lt;td&gt;Did the triggered stop, switch or retry actually fix the failure?&lt;/td&gt;
&lt;td&gt;An alarm graded on itself, not on what it changed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;None of that requires a private harness or new model. It needs repeated runs, two baselines that never look at the trajectory, and the discipline to grade the &lt;em&gt;decision&lt;/em&gt;, not the alarm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "the alarm was right" is not a pass
&lt;/h2&gt;

&lt;p&gt;The detail I would steal first is the toy example the authors open with. If a model succeeds 90% of the time on easy issues and 10% on hard ones, a score that only knows which issues are hard reaches &lt;strong&gt;0.90&lt;/strong&gt; pooled AUROC, yet it ranks two runs of the same issue at &lt;strong&gt;0.50&lt;/strong&gt;, a coin flip. A great-looking metric with zero information about the run.&lt;/p&gt;

&lt;p&gt;That is the eval-as-contract problem in miniature. The metric was computed correctly. It was just answering a different question from the one the product needs answered at run time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this connects to habits I already keep public
&lt;/h2&gt;

&lt;p&gt;My public work is mostly retrieve-first and evaluation-as-contract systems, and the habit is the same: before a component gets credit, compare it against the dumbest baseline that could have produced the same number. In retrieval, that means checking whether a gain survives query-class slices. For agents, this paper names the baselines for run-time monitoring: task difficulty, model identity, and "just try again". A monitor that can't beat them isn't monitoring the run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steal this check
&lt;/h2&gt;

&lt;p&gt;Pick one agent with a stop, retry or routing rule and add four things before your next release:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Run each task more than once.&lt;/strong&gt; Even a small repeated slice tells you how much of failure is the run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Score two run-blind baselines.&lt;/strong&gt; Task difficulty and model identity, next to your monitor, on the same cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Report within-task ranking.&lt;/strong&gt; Can the monitor tell a good attempt from a bad one on the same task?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compare at equal attempts.&lt;/strong&gt; Does your clever strategy beat a plain second try with the same model?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then ask whether the monitor is still worth its cost once the baselines are on the same chart.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am not claiming
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I am not reporting this paper's results as my own, and I have not reproduced them.&lt;/li&gt;
&lt;li&gt;I am not ranking models, agents or vendors.&lt;/li&gt;
&lt;li&gt;I am not saying failure prediction is useless. The authors call for predictors that explain &lt;em&gt;why&lt;/em&gt; a run fails, evaluated on repeated runs, in closed-loop, equal-budget settings.&lt;/li&gt;
&lt;li&gt;I am not publishing alarm thresholds or retry rules. Those depend on what a wasted run and a missed failure cost you.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The point
&lt;/h2&gt;

&lt;p&gt;A failure alarm that mostly knows the task is hard is not watching the run. Run tasks more than once, put run-blind baselines on the same chart, and grade the action the alarm triggers, not the alarm itself.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Igor Eduardo builds retrieve-first and evaluation-as-contract systems. More at &lt;a href="https://igoreduardo.com" rel="noopener noreferrer"&gt;igoreduardo.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>testing</category>
      <category>llm</category>
    </item>
    <item>
      <title>Your Agent Used 6% of Its Context Window and Still Lost a Third of Its Tool Output</title>
      <dc:creator>Igor Eduardo</dc:creator>
      <pubDate>Mon, 02 Nov 2026 08:20:24 +0000</pubDate>
      <link>https://dev.to/igoreduardoai/your-agent-used-6-of-its-context-window-and-still-lost-a-third-of-its-tool-output-3ce1</link>
      <guid>https://dev.to/igoreduardoai/your-agent-used-6-of-its-context-window-and-still-lost-a-third-of-its-tool-output-3ce1</guid>
      <description>&lt;h1&gt;
  
  
  Your Agent Used 6% of Its Context Window and Still Lost a Third of Its Tool Output
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;By Igor Eduardo · Austin, TX · &lt;a href="https://igoreduardo.com" rel="noopener noreferrer"&gt;https://igoreduardo.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A short new paper, &lt;a href="https://arxiv.org/abs/2610.36114" rel="noopener noreferrer"&gt;Context Is a Pipeline, Not a Window: Information Attrition in LLM Agent Harnesses&lt;/a&gt; (arXiv 2610.36114, posted 2026-10-26), measures something most agent dashboards never show: how much of a tool's output is lost &lt;strong&gt;before the model ever sees it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The authors instrumented a real tool-using agent that diagnoses injected faults by reading Linux kernel traces. Their point is simple. An agent never reads its context window directly. It reads whatever the harness, the code wrapped around the model, decided to put there. Between "the tool produced a result" and "the model saw it", the harness serializes, cuts to a budget, keeps or drops history, and passes findings between workers. Each of those steps can lose information.&lt;/p&gt;

&lt;p&gt;What they report:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The window was nearly empty.&lt;/strong&gt; Across &lt;strong&gt;720 runs&lt;/strong&gt;, the single largest prompt used &lt;strong&gt;5.75%&lt;/strong&gt; of the window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A third of tool results were cut anyway.&lt;/strong&gt; &lt;strong&gt;3,827 of 11,189&lt;/strong&gt; tool results were truncated before reaching the model, and &lt;strong&gt;every cut result became broken JSON&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The loss followed position, not importance.&lt;/strong&gt; The harness sliced each result's text at a fixed length, so whatever sat near the end disappeared. One list of containers reached the model in &lt;strong&gt;4.7%&lt;/strong&gt; of calls; a second list, in the very same payloads, reached it in &lt;strong&gt;99.3%&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accuracy split along the same line.&lt;/strong&gt; Faults that showed up in the surviving list scored &lt;strong&gt;40–55 out of 60&lt;/strong&gt;; faults that showed up only in the deleted list scored &lt;strong&gt;0–24 out of 60&lt;/strong&gt;. The authors are explicit that this field split is correlation, not proven cause.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On a production-scale trace, a whole evidence class vanished.&lt;/strong&gt; Replaying the shipped cut on one real trace delivered &lt;strong&gt;0 of 128&lt;/strong&gt; records of the fault's evidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The first cost was extra work, not wrong answers.&lt;/strong&gt; In a controlled experiment, when the agent had another route to the answer it still found it, but tool calls rose from &lt;strong&gt;53 to 76&lt;/strong&gt; (the paper's "43% more"), computations roughly doubled (&lt;strong&gt;18 to 36&lt;/strong&gt;), and yield, findings per computation, fell from &lt;strong&gt;0.61 to 0.31&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It hides well.&lt;/strong&gt; Only &lt;strong&gt;2.5%&lt;/strong&gt; of calls were affected in their replay of &lt;strong&gt;864&lt;/strong&gt; recorded results, and in traces from two production coding agents, waiting on the model took a median &lt;strong&gt;84%&lt;/strong&gt; of wall-clock time, so latency dashboards barely move.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The authors also surveyed seven agent frameworks and found two that cut tool output by position in the same way. I am not naming them here; the paper does, and the point is the pattern, not a scoreboard.&lt;/p&gt;

&lt;p&gt;Scope, in their words: one harness, one domain, one model, small samples, and the causal link to the accuracy drop is still an open question. Those are their numbers, not mine. I have not re-run the experiments.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stake
&lt;/h2&gt;

&lt;p&gt;Teams will read "context window: mostly empty" as "the model saw everything".&lt;/p&gt;

&lt;p&gt;Context size and final accuracy are the two numbers agents are usually judged on. Neither tells you whether the evidence the model needed was delivered intact. A log that records what the harness &lt;em&gt;sent&lt;/em&gt; cannot show what the tool &lt;em&gt;produced&lt;/em&gt;, so this class of loss is invisible in the place people look for it.&lt;/p&gt;

&lt;p&gt;And it fails quietly. When the agent has a second route to the answer, the loss shows up as more calls and more tokens. When it does not, as with a quiet fault that lives in exactly one field, the evidence is simply gone and the agent answers anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opinion (one sentence)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;For any agent that acts on tool output, "what reached the model" should be a measured, reported number next to accuracy, because a harness can delete the evidence that matters while every capacity and latency metric looks healthy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is a preference with a limiter, not a benchmark result. If your tools return small, flat outputs that never approach a budget, this may cost you nothing. Once tools return lists, logs or traces that can grow, the delivery step becomes part of the system under test.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a delivery-aware agent eval looks like (menu, not recipe)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Column&lt;/th&gt;
&lt;th&gt;Question it answers&lt;/th&gt;
&lt;th&gt;Failure if skipped&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Produced vs. delivered&lt;/td&gt;
&lt;td&gt;Did each field of the tool result reach the model?&lt;/td&gt;
&lt;td&gt;Evidence lost upstream looks like model error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payload validity&lt;/td&gt;
&lt;td&gt;Did the delivered result still parse?&lt;/td&gt;
&lt;td&gt;Broken structure passed off as "the data"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loss by position&lt;/td&gt;
&lt;td&gt;Do late fields disappear more than early ones?&lt;/td&gt;
&lt;td&gt;Importance decided by key order&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Work per finding&lt;/td&gt;
&lt;td&gt;How many calls and computations per useful finding?&lt;/td&gt;
&lt;td&gt;A silent cost rise read as "harder task"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hand-off between workers&lt;/td&gt;
&lt;td&gt;Did computed findings reach whatever decides?&lt;/td&gt;
&lt;td&gt;Silence read as "nothing found"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quiet-case accuracy&lt;/td&gt;
&lt;td&gt;Accuracy on cases with only one route to the evidence&lt;/td&gt;
&lt;td&gt;Redundant routes masking the loss&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;None of that requires a private harness or a new model. It requires logging the tool's full result next to what was actually sent, and refusing a release that only reports window size and final accuracy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "the answer was still right" is not a pass
&lt;/h2&gt;

&lt;p&gt;The finding I would steal first is the compensation tax. In the controlled runs, accuracy on the easy, loud cases stayed flat while the agent did far more work to get there. That is exactly the kind of result that passes a pass-rate gate and then fails in production on the one case where the second route does not exist.&lt;/p&gt;

&lt;p&gt;The authors' own prediction was wrong in an instructive way: they expected that deleting the culprit's list would drop accuracy, and the agent recovered the name from another table. Their sharper rule is that the cut hurts only where there is no second route, and that its cost appears as extra work before it appears as errors. If your eval set is full of loud cases, you will measure the work and miss the risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this connects to habits I already keep public
&lt;/h2&gt;

&lt;p&gt;My public work is mostly retrieve-first and evaluation-as-contract systems, and the habit is the same: grade each stage on its own before letting the final answer vouch for the pipeline. In retrieval, that means checking that the right evidence came back before grading the answer. For agents, this paper isolates the next stage: whether the evidence that came back actually reached the model. A system can retrieve correctly and still never show the model what it retrieved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steal this check
&lt;/h2&gt;

&lt;p&gt;Pick one agent that reads tool output and add four things before your next release:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Log produced and delivered side by side.&lt;/strong&gt; Keep the full tool result and the text the model actually received, per call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Count what didn't arrive.&lt;/strong&gt; Per field, per run: how often was it cut, and did the payload still parse?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Track work per finding.&lt;/strong&gt; Calls and computations per useful result, next to accuracy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep a quiet-case slice.&lt;/strong&gt; Cases where the evidence lives in exactly one place. Grade accuracy there separately.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then ask whether the release is still an upgrade once delivery is visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am not claiming
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I am not reporting this paper's results as my own, and I have not reproduced them.&lt;/li&gt;
&lt;li&gt;I am not ranking frameworks, models or vendors.&lt;/li&gt;
&lt;li&gt;I am not claiming truncation caused the accuracy split. The authors say that is still open.&lt;/li&gt;
&lt;li&gt;I am not publishing budgets or cut rules to use. Those depend on your tools and what a missed field costs you.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The point
&lt;/h2&gt;

&lt;p&gt;A mostly empty context window tells you there was room. It does not tell you what arrived. Measure the path from tool to model, report loss next to accuracy, and keep a slice of cases where the agent has only one way to find the truth.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Igor Eduardo builds retrieve-first and evaluation-as-contract systems. More at &lt;a href="https://igoreduardo.com" rel="noopener noreferrer"&gt;igoreduardo.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
      <category>observability</category>
    </item>
    <item>
      <title>Your Agent's Pass Rate Doesn't Tell You Whether It Can Notice Its Own Mistake</title>
      <dc:creator>Igor Eduardo</dc:creator>
      <pubDate>Mon, 26 Oct 2026 07:18:30 +0000</pubDate>
      <link>https://dev.to/igoreduardoai/your-agents-pass-rate-doesnt-tell-you-whether-it-can-notice-its-own-mistake-471m</link>
      <guid>https://dev.to/igoreduardoai/your-agents-pass-rate-doesnt-tell-you-whether-it-can-notice-its-own-mistake-471m</guid>
      <description>&lt;p&gt;&lt;em&gt;By Igor Eduardo · Austin, TX · &lt;a href="https://igoreduardo.com" rel="noopener noreferrer"&gt;https://igoreduardo.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A new benchmark paper, &lt;a href="https://arxiv.org/abs/2610.27645" rel="noopener noreferrer"&gt;CUA-Recovery: Benchmarking Error Recovery in Long-Horizon Computer-Use Agents&lt;/a&gt; (arXiv 2610.27645, posted 2026-10-20), asks a question most agent scoreboards skip: when an agent inherits a workflow that already went wrong, does it notice, and can it fix it?&lt;/p&gt;

&lt;p&gt;The setup is careful. The authors compose long, multi-application desktop workflows with an executable "gold lineage", the correct value at every step. They run six agents, collect the failures those agents actually produce, locate the root-cause step of each failure, and replay the run to a point 0 to 25 steps after that root cause. Then an agent takes over from that state &lt;strong&gt;without being told anything went wrong&lt;/strong&gt;. The test suite has &lt;strong&gt;2,250 human-verified erroneous states over 100 tasks&lt;/strong&gt;, drawn from &lt;strong&gt;619 failed rollouts&lt;/strong&gt;. They score three things separately: whether the agent says something is wrong (Error-Awareness Rate, EAR), how much of the task it completes (Rubric Score), and whether it fully completes the task in any of three runs (Pass@3).&lt;/p&gt;

&lt;p&gt;What they report:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Recovery is rare.&lt;/strong&gt; Across six agents and six takeover depths, EAR reaches at most &lt;strong&gt;44.0%&lt;/strong&gt; and Pass@3 at most &lt;strong&gt;25.5%&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clean-start skill does not predict noticing.&lt;/strong&gt; One agent solves &lt;strong&gt;66.9%&lt;/strong&gt; of the source tasks from a clean start but notices at most &lt;strong&gt;18.5%&lt;/strong&gt; of the errors in its own failures. Another solves &lt;strong&gt;5.1%&lt;/strong&gt; from a clean start but notices &lt;strong&gt;14.1–26.1%&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Noticing is not fixing.&lt;/strong&gt; Macro-averaged across the six agents, runs that recognized the inherited error passed the verifier &lt;strong&gt;15.6%&lt;/strong&gt; of the time, versus &lt;strong&gt;12.2%&lt;/strong&gt; for runs that did not. Agents often name the problem and then leave the affected state unchanged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Errors surface late.&lt;/strong&gt; In their annotated failures, &lt;strong&gt;78.1%&lt;/strong&gt; of errors became explicit three or more steps after the root cause, with a median delay of &lt;strong&gt;17 steps&lt;/strong&gt;. In &lt;strong&gt;361 of 602&lt;/strong&gt; failures where the error became explicit, the first evidence appeared only at the final step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Most root causes are decisions, not clicks.&lt;/strong&gt; Planning and perception account for &lt;strong&gt;57.3%&lt;/strong&gt; of root causes; termination errors, including reporting success while requirements remain unmet, account for &lt;strong&gt;23.5%&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The authors are explicit about scope: one desktop environment, agents run with their own scaffolds, and an LLM judge that they checked against human labels and found slightly strict. They also show that fine-tuning on their recovery trajectories raises one open model's average EAR from &lt;strong&gt;19.9%&lt;/strong&gt; to &lt;strong&gt;35.2%&lt;/strong&gt;. Code is public at &lt;a href="https://github.com/xu-hu-2002/CUA-Recovery" rel="noopener noreferrer"&gt;CUA-Recovery&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Those are their numbers, not mine. I have not re-run the benchmark, and I am not using it to rank anyone. What I want to formalize is the eval habit it exposes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stake
&lt;/h2&gt;

&lt;p&gt;Teams will ship agents that are good at starting and bad at noticing.&lt;/p&gt;

&lt;p&gt;A clean-start pass rate measures one thing: given a correct initial state, does the agent reach the goal? Production does not hand agents correct states. A previous step, a previous run, a human, or a flaky tool has often already written something wrong into a file, a spreadsheet or a record. If the eval never starts from a broken state, the agent's ability to notice is never measured, and the number you ship on is silent about the failure that hurts most.&lt;/p&gt;

&lt;p&gt;AI failures rarely fail loud. An agent that builds 17 confident steps on top of a wrong record looks, on a completion dashboard, a lot like one that did the job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opinion (one sentence)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Any agent that writes to persistent state should be graded on takeovers from broken states, with "noticed" and "repaired" scored as separate columns, because a clean-start pass rate cannot tell you whether the agent will catch its own inherited mistake.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is a preference with a limiter, not a benchmark result. For read-only agents that only answer questions, clean-start evals may be enough. Once an agent writes, sends or orders, the inherited-error case is the one that compounds.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a recovery-aware agent eval looks like (menu, not recipe)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Column&lt;/th&gt;
&lt;th&gt;Question it answers&lt;/th&gt;
&lt;th&gt;Failure if skipped&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Clean-start completion&lt;/td&gt;
&lt;td&gt;Can it do the task from a correct state?&lt;/td&gt;
&lt;td&gt;No baseline at all&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Takeover completion&lt;/td&gt;
&lt;td&gt;Can it finish from a state that is already wrong?&lt;/td&gt;
&lt;td&gt;Shipping a system that only works when nothing went wrong before&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error awareness&lt;/td&gt;
&lt;td&gt;Did it say something earlier is wrong?&lt;/td&gt;
&lt;td&gt;Silent agents look identical to careful ones&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repair, scored apart from awareness&lt;/td&gt;
&lt;td&gt;Did it actually fix the affected state?&lt;/td&gt;
&lt;td&gt;Crediting "I see a problem" as a fix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Depth since root cause&lt;/td&gt;
&lt;td&gt;How far back was the mistake?&lt;/td&gt;
&lt;td&gt;Missing that late takeovers behave differently&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Completion claim vs. state&lt;/td&gt;
&lt;td&gt;Does the final state match what the agent reported?&lt;/td&gt;
&lt;td&gt;Premature "done" passing as success&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;None of that needs a private harness. It needs someone to refuse an agent release that only reports the first column.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "noticed" and "repaired" must be different columns
&lt;/h2&gt;

&lt;p&gt;The finding I would steal first is the gap between awareness and recovery. A system that says "it looks like the earlier step used the wrong year" and then carries on with the wrong year has produced a better transcript, not a better outcome. If one metric lumps the two together, it will reward agents that narrate problems over agents that fix them.&lt;/p&gt;

&lt;p&gt;The paper also shows the two can move in opposite directions. As the takeover point moves further from the root cause, some agents became more likely to notice something was off while becoming less likely to complete the task, because the step that caused the problem had left their context window. Later is not simply harder or easier. It is different, so it needs its own row.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this connects to habits I already keep public
&lt;/h2&gt;

&lt;p&gt;My public work is mostly retrieve-first and evaluation-as-contract systems, and the habit is the same: grade each part on its own before letting the final answer vouch for it. For agents, the "part" this paper isolates is the moment the agent receives state it did not create. I would treat that moment as a first-class test case, next to the clean start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steal this check
&lt;/h2&gt;

&lt;p&gt;Pick one agent workflow that writes to persistent state and add four things before your next release:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Collect real failures.&lt;/strong&gt; Keep the runs where your agent actually went wrong, not just synthetic faults.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replay to a broken state and hand over.&lt;/strong&gt; Start a fresh run from a point after the mistake, without warning it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Score awareness and repair separately.&lt;/strong&gt; "Said something is wrong" and "fixed what was wrong" go in different columns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the claim against the state.&lt;/strong&gt; If the agent says done, verify the final state, not the final message.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then ask whether the release is still an upgrade once the takeover columns are visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am not claiming
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I am not reporting CUA-Recovery results as my own, and I have not reproduced the benchmark.&lt;/li&gt;
&lt;li&gt;I am not ranking models or vendors. The paper's per-agent tables exist; this post deliberately does not use them as a leaderboard.&lt;/li&gt;
&lt;li&gt;I am not publishing thresholds for acceptable awareness or recovery rates. Those depend on what a wrong write costs in your product.&lt;/li&gt;
&lt;li&gt;One desktop environment is not every environment. The authors scope their claims the same way.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The point
&lt;/h2&gt;

&lt;p&gt;A pass rate from a clean start tells you the agent can begin well. It does not tell you whether the agent will catch a mistake already sitting in the state it inherits. Start some evals from broken states, score noticing and repairing separately, and check every "done" against the state it claims to have produced.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Igor Eduardo builds retrieve-first and evaluation-as-contract systems. More at &lt;a href="https://igoreduardo.com" rel="noopener noreferrer"&gt;igoreduardo.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>evaluation</category>
      <category>llm</category>
    </item>
    <item>
      <title>Extra Retrieval Rounds Can Make RAG Worse at Saying "I Don't Know"</title>
      <dc:creator>Igor Eduardo</dc:creator>
      <pubDate>Fri, 23 Oct 2026 07:24:51 +0000</pubDate>
      <link>https://dev.to/igoreduardoai/extra-retrieval-rounds-can-make-rag-worse-at-saying-i-dont-know-4elo</link>
      <guid>https://dev.to/igoreduardoai/extra-retrieval-rounds-can-make-rag-worse-at-saying-i-dont-know-4elo</guid>
      <description>&lt;p&gt;A new benchmark paper, &lt;a href="https://arxiv.org/abs/2610.28340" rel="noopener noreferrer"&gt;DeclineCraft: A RAG Abstention Benchmark for Jointly Measuring Combined Retrieval and Parametric Knowledge&lt;/a&gt; (arXiv 2610.28340, posted 2026-10-20), measures something most RAG scoreboards skip: how often a system admits that neither its documents nor its weights can answer the question.&lt;/p&gt;

&lt;p&gt;The setup is clever. The authors build a retrieval corpus from Minecraft Wiki pages as they stood at a 31 March 2025 cut-off, then write unanswerable questions about game features documented only after that date. The benchmark has 700 answerable and 300 unanswerable questions, and they evaluate 27 LLMs. Their headline metric is Correct Abstention Rate (CAR): the share of unanswerable questions where the model acknowledges it lacks the answer. They score "premise denial", where the model asserts without support that the item does not exist, separately from an honest "I don't know".&lt;/p&gt;

&lt;p&gt;What they report:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single-shot retrieval helps.&lt;/strong&gt; Compared with no retrieval, it raises CAR significantly in &lt;strong&gt;38 of 40&lt;/strong&gt; model/thinking configurations. Mean CAR goes from about &lt;strong&gt;17.1%&lt;/strong&gt; to &lt;strong&gt;56.4%&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterative retrieval gives part of that back.&lt;/strong&gt; When the model can request up to two more retrieval rounds, CAR drops significantly in &lt;strong&gt;30 of 40&lt;/strong&gt; configurations, to a mean of about &lt;strong&gt;46.4%&lt;/strong&gt;. Answer Accuracy on the answerable questions barely moves (about &lt;strong&gt;68.5% â†’ 69.3%&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adding query rewriting plus reranking to hybrid retrieval lowered CAR for all 12 models tested&lt;/strong&gt;, from a mean of about 54.7% to 49.8%. The authors note that only 3 of the 60 per-model paired comparisons against plain hybrid are individually significant, so the direction is consistent but each per-model gap is small.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieving more chunks also lowered it.&lt;/strong&gt; On an 11-model subset, going from 5 to 10 chunks dropped mean CAR from about 56.8% to 51.7%.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The authors are careful about what this does and does not show. Their aggregate comparison does not isolate which part of iterative RAG causes the drop: chunk count, context length, follow-up queries and self-reflection all change together. Their corpus is one domain with one chunking scheme. Code and data are public at &lt;a href="https://github.com/Thakur-Atharva/declinecraft-benchmark" rel="noopener noreferrer"&gt;declinecraft-benchmark&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Those are their numbers, not mine. I have not re-run the benchmark. What I want to formalize is the eval habit the paper forces into the open.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stake
&lt;/h2&gt;

&lt;p&gt;Teams will ship the wrong upgrade.&lt;/p&gt;

&lt;p&gt;The usual path for improving a RAG system is to add things: more chunks, a reranker, query rewriting, a second retrieval round. Each one is justified by an accuracy chart on answerable questions. In this paper, accuracy on answerable questions stays roughly flat while the system gets measurably worse at declining the questions it cannot answer. If your eval set has no unanswerable questions, that regression is invisible. You will ship it as an improvement.&lt;/p&gt;

&lt;p&gt;AI failures rarely fail loud. A confident answer to a question your corpus cannot support looks exactly like a correct one on a dashboard that only grades answerable items.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opinion (one sentence)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Every change to a retrieval pipeline should be graded on unanswerable questions too, because "more context" can buy a little accuracy while quietly spending the system's ability to say "I don't know."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is a preference with a limiter, not a benchmark result. I am not saying iterative retrieval, reranking or query rewriting are mistakes. I am saying the contract for adding them must include the column that can go down.&lt;/p&gt;

&lt;h2&gt;
  
  
  What an abstention-aware eval contract looks like (menu, not recipe)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Question it answers&lt;/th&gt;
&lt;th&gt;Failure if skipped&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Answerable accuracy&lt;/td&gt;
&lt;td&gt;Did we answer the questions the corpus supports?&lt;/td&gt;
&lt;td&gt;Shipping on vibes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Correct abstention rate&lt;/td&gt;
&lt;td&gt;Did we decline the questions nothing supports?&lt;/td&gt;
&lt;td&gt;Confident answers with no evidence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Premise denial, counted separately&lt;/td&gt;
&lt;td&gt;Did we claim something does not exist without being able to verify it?&lt;/td&gt;
&lt;td&gt;"No such thing" passing as caution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Attempt rate on answerable items&lt;/td&gt;
&lt;td&gt;Did we refuse questions we could have answered?&lt;/td&gt;
&lt;td&gt;A system that looks safe because it answers nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-change deltas&lt;/td&gt;
&lt;td&gt;Which single change moved each column?&lt;/td&gt;
&lt;td&gt;Crediting the whole pipeline for one component's regression&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;None of that needs a private harness. It needs someone to refuse a pipeline change that only reports the accuracy column.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "I don't know" is not the same as "no such thing"
&lt;/h2&gt;

&lt;p&gt;The distinction I would steal first is premise denial.&lt;/p&gt;

&lt;p&gt;When a corpus is older than the question, "I can't find this" and "this doesn't exist" are different claims. The first is honest. The second is a statement about the world that the system cannot back. A metric that lumps both into "declined" will reward the second. The paper's own example is a model that, asked about an item added after the cut-off, says the item is not recognized and then answers about a different item instead.&lt;/p&gt;

&lt;p&gt;If you run retrieval over documentation that changes, such as product docs, internal wikis or release notes, this is the failure to watch. The question can be newer than your index.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this connects to habits I already keep public
&lt;/h2&gt;

&lt;p&gt;My public work is mostly retrieve-first systems, and the same habit applies there: measure the retrieval half on its own before letting the answer vouch for it. My hybrid retrieval work is built around that habit. This week's paper adds a column I would put next to it: what the system does when the right evidence is not in the index at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steal this check
&lt;/h2&gt;

&lt;p&gt;Pick one RAG pipeline you are about to "improve" and add four things before you merge:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Write a small unanswerable slice.&lt;/strong&gt; Questions about things newer than, or missing from, your corpus. Even a few dozen is better than none.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grade abstention next to accuracy.&lt;/strong&gt; Report both columns for the before and after versions of the pipeline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split premise denial from abstention.&lt;/strong&gt; "I can't find it" and "it doesn't exist" go in different buckets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Change one thing at a time.&lt;/strong&gt; Extra chunks, reranking, rewriting and extra rounds each get their own before/after row.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then ask whether the change is still an upgrade once the abstention column is visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am not claiming
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I am not reporting DeclineCraft results as my own, and I have not reproduced the benchmark.&lt;/li&gt;
&lt;li&gt;I am not saying iterative RAG, reranking or query rewriting should be removed. The paper's own caveat is that it cannot isolate which component drives the drop.&lt;/li&gt;
&lt;li&gt;I am not publishing thresholds. What counts as an acceptable abstention rate depends on the product and on what a wrong answer costs.&lt;/li&gt;
&lt;li&gt;One domain (a game wiki) is not every domain. The authors say so too.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The point
&lt;/h2&gt;

&lt;p&gt;An accuracy chart on answerable questions cannot tell you whether your upgrade made the system more willing to bluff. Put unanswerable questions in the eval, grade "I don't know" as a real outcome, and make every pipeline change earn its place on both columns.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Igor Eduardo builds retrieve-first and evaluation-as-contract systems. More at &lt;a href="https://igoreduardo.com" rel="noopener noreferrer"&gt;igoreduardo.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>evaluation</category>
      <category>llm</category>
    </item>
    <item>
      <title>An 8-Point nDCG Bump That Costs Two Minutes Is Not Free</title>
      <dc:creator>Igor Eduardo</dc:creator>
      <pubDate>Mon, 12 Oct 2026 16:12:42 +0000</pubDate>
      <link>https://dev.to/igoreduardoai/an-8-point-ndcg-bump-that-costs-two-minutes-is-not-free-206h</link>
      <guid>https://dev.to/igoreduardoai/an-8-point-ndcg-bump-that-costs-two-minutes-is-not-free-206h</guid>
      <description>&lt;p&gt;A new NVIDIA NeMo Retriever paper, &lt;a href="https://arxiv.org/abs/2610.05750" rel="noopener noreferrer"&gt;Beyond Semantic Similarity: Performance and Costs of Agentic Retrieval for Complex Tasks&lt;/a&gt; (arXiv 2610.05750, posted around 2026-10-05), puts numbers on a trade everyone arguing about agentic RAG already feels. With the same embedding model, their agentic retrieval setup lifts nDCG@10 by about &lt;strong&gt;8.7 points&lt;/strong&gt; over standard dense retrieval. It also averages roughly &lt;strong&gt;107.4 seconds&lt;/strong&gt; of latency against about &lt;strong&gt;0.67 seconds&lt;/strong&gt; for the standard path, and burns on the order of &lt;strong&gt;764.1K input tokens&lt;/strong&gt; plus &lt;strong&gt;5.8K output tokens&lt;/strong&gt; per query. They also report competitive results on ViDoRe v3 and BRIGHT without task-specific specialization. Their retrieval-bench notes live in the public &lt;a href="https://github.com/NVIDIA/NeMo-Retriever/tree/main/retrieval-bench" rel="noopener noreferrer"&gt;NeMo-Retriever&lt;/a&gt; tree.&lt;/p&gt;

&lt;p&gt;Those are their numbers, not mine. I have not re-run the bench. What I want to formalize is the eval shape the paper forces into the open.&lt;/p&gt;

&lt;p&gt;Here is what I would require before I trusted an "agentic retrieval win," and what I would not claim yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stake
&lt;/h2&gt;

&lt;p&gt;Teams will ship the wrong default.&lt;/p&gt;

&lt;p&gt;Most retrieval scoreboards still answer one question: "did we find better documents?" That question is real. It is incomplete. An 8-point nDCG bump that costs two minutes and three-quarters of a million input tokens is a different product than a sub-second dense call. If your dashboard only shows the quality column, the expensive path looks like a free upgrade. In production it is a budget, a timeout policy, and a fallback story.&lt;/p&gt;

&lt;p&gt;AI failures rarely fail loud. They fail as bills that looked like wins on the eval sheet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opinion (one sentence)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;An eval contract that reports only retrieval quality without latency, token cost, and failure/fallback rate is grading a different product than the one you will ship.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is a preference with a limiter, not a benchmark result. The NeMo numbers stay theirs. What I am formalizing is the contract: quality, cost, and reliability sit in the same report, or you are not evaluating the system you will actually run.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a cost-aware retrieval contract looks like (menu, not recipe)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Question it answers&lt;/th&gt;
&lt;th&gt;Failure if skipped&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Retrieval quality&lt;/td&gt;
&lt;td&gt;Did we find the right evidence under the stated metric?&lt;/td&gt;
&lt;td&gt;Shipping on vibes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency distribution&lt;/td&gt;
&lt;td&gt;How long did the path take, including agent loops?&lt;/td&gt;
&lt;td&gt;A "win" that times out in UX or SLA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token / dollar cost&lt;/td&gt;
&lt;td&gt;What did one query cost on average and at the tail?&lt;/td&gt;
&lt;td&gt;Quality gains that bankrupt the budget&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure / fallback rate&lt;/td&gt;
&lt;td&gt;How often did the agentic path abort, stall, or hand off?&lt;/td&gt;
&lt;td&gt;A green mean that hides a red path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same-model / same-corpus controls&lt;/td&gt;
&lt;td&gt;Did we change one variable at a time?&lt;/td&gt;
&lt;td&gt;Crediting the agent loop for an embedding upgrade&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;None of that needs a private harness. It needs someone to refuse a scoreboard that only prints nDCG.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the latency column belongs next to nDCG
&lt;/h2&gt;

&lt;p&gt;The paper's latency gap is the part I would steal first as a reporting habit.&lt;/p&gt;

&lt;p&gt;A sub-second dense path and a ~two-minute agentic path are not two settings of the same product. They are different products with different failure modes. One fails by missing evidence. The other can also fail by being too slow to use, too expensive to run at volume, or too brittle when a tool call hangs. If you only publish the quality delta, you are arguing about a system your users will never wait for.&lt;/p&gt;

&lt;p&gt;I would report latency and token cost next to the quality metric, not bury them in an appendix. The same goes for failure and fallback rate: every run that aborted or handed back to a cheaper path belongs in its own column.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this connects to retrieval habits I already keep public
&lt;/h2&gt;

&lt;p&gt;My public work is mostly retrieve-first systems, and the same split shows up there. A fluent answer can look like a retrieval win the same way a slow agent loop can look like a quality win. In both cases the fix is the same move: measure the retrieval half on its own, and refuse to let one number vouch for the whole product.&lt;/p&gt;

&lt;p&gt;The hybrid retrieval pipeline I keep public (&lt;a href="https://github.com/nomad-link-id/hybrid-rag-pipeline" rel="noopener noreferrer"&gt;hybrid-rag-pipeline&lt;/a&gt;) is built around that habit: measure retrieval separately before letting generation, or orchestration, speak for it. This week's paper is a cost-shaped version of the same lesson.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steal this check
&lt;/h2&gt;

&lt;p&gt;Pick one retrieval path you already call "agentic" or "multi-hop" and add four things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Keep the quality metric.&lt;/strong&gt; Report nDCG (or your usual ranking metric) with the same embedding model and corpus controls you already trust.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add latency next to it.&lt;/strong&gt; Mean is not enough; look at the tail your users will feel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add token cost next to it.&lt;/strong&gt; Input and output, average and heavy queries, in the same table as quality.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Count failure / fallback separately.&lt;/strong&gt; Every abort, timeout, or handoff to a cheaper path goes in its own column. That column is the one that becomes an incident or a surprise bill.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then ask whether the quality bump is still the headline once those columns are visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am not claiming
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I am not reporting NeMo Retriever results as my own, and I have not reproduced their bench.&lt;/li&gt;
&lt;li&gt;I am not saying agentic retrieval is a mistake. The paper shows a real quality gain on hard tasks. Cost is part of the grade, not a reason to ignore the gain.&lt;/li&gt;
&lt;li&gt;I am not publishing thresholds. What counts as acceptable latency or token spend depends on the product and the query class.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The point
&lt;/h2&gt;

&lt;p&gt;An 8-point nDCG bump that costs two minutes is not free. Grade the product you will ship: quality, cost, and the rate at which the expensive path fails closed.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Igor Eduardo builds retrieve-first and evaluation-as-contract systems. More at &lt;a href="https://igoreduardo.com" rel="noopener noreferrer"&gt;igoreduardo.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>evaluation</category>
      <category>retrieval</category>
    </item>
    <item>
      <title>Done Is Testimony. Terminal State Is the Grade.</title>
      <dc:creator>Igor Eduardo</dc:creator>
      <pubDate>Mon, 05 Oct 2026 15:54:00 +0000</pubDate>
      <link>https://dev.to/igoreduardoai/done-is-testimony-terminal-state-is-the-grade-og8</link>
      <guid>https://dev.to/igoreduardoai/done-is-testimony-terminal-state-is-the-grade-og8</guid>
      <description>&lt;p&gt;Two things landed in the same week and they are the same argument.&lt;/p&gt;

&lt;p&gt;Microsoft and Hugging Face published &lt;a href="https://huggingface.co/blog/microsoft/thinkingbox" rel="noopener noreferrer"&gt;ThinkingBox&lt;/a&gt;, a benchmark that grades agents on the backend state and side effects they leave behind instead of the sentences they generate, and then asks whether they can do it twenty times in a row. Their opening example is an agent that makes nine clean tool calls, closes a ticket as resolved, and is wrong: the carrier exception was still open, so the required end state was "on hold." A grader reading tool calls sees nine well-formed calls. The database disagrees.&lt;/p&gt;

&lt;p&gt;On Dev.to, &lt;a href="https://dev.to/james_anderson_h/the-witness-was-the-suspect-why-ai-audit-logs-cant-be-trusted-2190"&gt;The Witness Was the Suspect&lt;/a&gt; made the same point from the incident side: when the agent writes its own success log, the record of the incident was authored by the cause of the incident.&lt;/p&gt;

&lt;p&gt;Here is what I would require before I trusted an agent's "done," and what I would not claim yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stake
&lt;/h2&gt;

&lt;p&gt;Teams will ship the wrong default.&lt;/p&gt;

&lt;p&gt;Most agent dashboards still answer "did it say it succeeded?" Status strings, tool-call traces, and a tidy final message are all produced by the same run that took the action. They are useful for debugging. They are not a grade. When the eval and the agent share a witness, a confident wrong action scores the same as a correct one, and the failure shows up later as a customer, a ledger, or an auditor.&lt;/p&gt;

&lt;p&gt;AI failures rarely fail loud. They fail plausible. That is exactly why the grade has to come from somewhere the agent cannot write.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opinion (one sentence)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;An agent's "done" is testimony, not evidence. The eval contract should grade the terminal state through a read path the agent does not control, and it should grade it more than once.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is a preference with a limiter, not a benchmark result. I have not run ThinkingBox, and its numbers (507 stateful workflows, 20 runs each) are theirs. What I am formalizing is the shape: separate the actor from the grader, and treat "said done while the state is red" as a named failure, not as noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  What separating the witness looks like (menu, not recipe)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Question it answers&lt;/th&gt;
&lt;th&gt;Failure if skipped&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Required end state&lt;/td&gt;
&lt;td&gt;What should the record look like when the task is truly finished?&lt;/td&gt;
&lt;td&gt;"Resolved" accepted when "on hold" was correct&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Independent read path&lt;/td&gt;
&lt;td&gt;Who reads the final state, and can the agent influence that read?&lt;/td&gt;
&lt;td&gt;The agent's own log grades the agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Side-effect ledger&lt;/td&gt;
&lt;td&gt;What else changed (tickets, refunds, emails, rows)?&lt;/td&gt;
&lt;td&gt;Correct primary record, wrong collateral writes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Done-while-red&lt;/td&gt;
&lt;td&gt;Did the run claim success while the state check failed?&lt;/td&gt;
&lt;td&gt;Confident wrong actions blend into the pass rate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repeat consistency&lt;/td&gt;
&lt;td&gt;Does the same task reach the same end state across N runs?&lt;/td&gt;
&lt;td&gt;One lucky green run treated as a capability&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;None of that needs a private harness. It needs someone to write down the required end state before the run, and a grader that reads the system of record after the run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why repeats belong in the contract
&lt;/h2&gt;

&lt;p&gt;ThinkingBox's "twenty times in a row" framing is the part I would steal first.&lt;/p&gt;

&lt;p&gt;A single green run tells you the agent &lt;em&gt;can&lt;/em&gt; reach the right state. Production needs to know whether it &lt;em&gt;will&lt;/em&gt;. If the same ticket ends "resolved" on some runs and "on hold" on others, you do not have a capability with a small error rate. You have a coin with a nice transcript. I would report consistency next to the pass rate, not bury it in an appendix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this connects to retrieval
&lt;/h2&gt;

&lt;p&gt;My public work is mostly retrieve-first systems, and the same split shows up there. A RAG answer can cite cleanly and still be wrong about the source, the same way an agent can log cleanly and still leave the wrong record. In both cases the fix is the same move: grade against something the generator did not produce. For retrieval that is a gold source set; for agents it is the terminal state.&lt;/p&gt;

&lt;p&gt;The hybrid retrieval pipeline I keep public (&lt;a href="https://github.com/nomad-link-id/hybrid-rag-pipeline" rel="noopener noreferrer"&gt;hybrid-rag-pipeline&lt;/a&gt;) is built around that habit: measure the retrieval half on its own before letting a fluent answer vouch for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steal this check
&lt;/h2&gt;

&lt;p&gt;Pick one agent workflow you already run and add three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Write the required end state first.&lt;/strong&gt; Not "the agent responds," but "the ticket is on hold, no refund issued, customer told why."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grade from the system of record.&lt;/strong&gt; Read the final state with a query the agent never touches, and ignore the agent's own status message for scoring.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Count done-while-red separately.&lt;/strong&gt; Every run where the agent claimed success but the state check failed goes in its own column. That column is the one that becomes an incident.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then run it more than once and report how often it lands in the same place.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am not claiming
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I am not reporting ThinkingBox results or reproducing their benchmark.&lt;/li&gt;
&lt;li&gt;I am not saying traces and logs are useless. They are how you debug. They are just the wrong thing to score.&lt;/li&gt;
&lt;li&gt;I am not publishing thresholds. What counts as acceptable consistency depends on what the action costs when it is wrong.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The point
&lt;/h2&gt;

&lt;p&gt;The process that acted should not be the only witness that it worked. Grade the record, not the report.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Igor Eduardo builds retrieve-first and evaluation-as-contract systems. More at &lt;a href="https://igoreduardo.com" rel="noopener noreferrer"&gt;igoreduardo.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>evaluation</category>
      <category>testing</category>
    </item>
    <item>
      <title>Green Scores Without a Pinned Harness Are Screenshots</title>
      <dc:creator>Igor Eduardo</dc:creator>
      <pubDate>Mon, 28 Sep 2026 16:09:46 +0000</pubDate>
      <link>https://dev.to/igoreduardoai/green-scores-without-a-pinned-harness-are-screenshots-3666</link>
      <guid>https://dev.to/igoreduardoai/green-scores-without-a-pinned-harness-are-screenshots-3666</guid>
      <description>&lt;p&gt;Everyone is talking about Evaluation Cards and reproducible eval benches — the EvalEval × UK AISI write-up on Hugging Face, plus a week of discourse where green numbers still hide the wrong harness (and DeepEval-style “which half is broken?” chatter keeps landing). That heat is a live market object, not a niche footnote.&lt;/p&gt;

&lt;p&gt;Here is what I would require before I trusted a green eval score for high-stakes retrieval or generation — and what I would not claim yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stake
&lt;/h2&gt;

&lt;p&gt;Teams will ship the wrong default.&lt;/p&gt;

&lt;p&gt;A dashboard can show a comforting pass rate while the report never pins &lt;em&gt;how&lt;/em&gt; the score was earned: which protocol, which compute budget, which dataset slice, and whether the number measured retrieval, generation, or a blended soup. Celebrate that number and you optimize a screenshot. The next engineer cannot reproduce the gate, and the next incident cannot tell which half failed.&lt;/p&gt;

&lt;p&gt;If your domain is identifier-heavy, multi-hop, or regulated-adjacent, a fluent answer after an unpinned harness is not a win. It is a silent miss with a pretty badge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opinion (one sentence)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A green score without a pinned harness — protocol, compute, dataset slice, and which half of the pipeline it measures — is not an eval contract; it is a screenshot.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is a preference with a limiter, not a SOTA claim. I have not run EvalEval in production. AISI card fields and anyone else’s leaderboard numbers stay theirs. What I am formalizing is the &lt;em&gt;harness pin&lt;/em&gt; as a first-class part of eval-as-contract, from the same reliable-systems lane I already publish on.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a pinned harness looks like (menu, not recipe)
&lt;/h2&gt;

&lt;p&gt;Evaluation Cards earned attention because they make the boring fields visible: protocol, compute, data cut, scoring rules. You do not need their exact schema to steal the &lt;em&gt;shape&lt;/em&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Question it answers&lt;/th&gt;
&lt;th&gt;Failure if skipped&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;What procedure produced this number?&lt;/td&gt;
&lt;td&gt;“We eval’d it” with no replay path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compute&lt;/td&gt;
&lt;td&gt;What budget / hardware / call limits?&lt;/td&gt;
&lt;td&gt;Incomparable scores across teams&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dataset slice&lt;/td&gt;
&lt;td&gt;Which queries / docs / holdouts?&lt;/td&gt;
&lt;td&gt;Student-subset vibes framed as prod&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipeline half&lt;/td&gt;
&lt;td&gt;Retrieval, generation, or joint?&lt;/td&gt;
&lt;td&gt;Green faithfulness while recall is broken (or the reverse)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The DeepEval-style lesson that keeps circulating is the same shape: a single RAG score can hide &lt;em&gt;which half&lt;/em&gt; failed. Pin the half. Prefer two honest columns over one blended crown.&lt;/p&gt;

&lt;h2&gt;
  
  
  The check you can run without my internals
&lt;/h2&gt;

&lt;p&gt;You do not need my private stacks (and I will not publish them). Steal this menu-only check:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pin the harness block before the score.&lt;/strong&gt; Same report header every time: protocol name/version, compute class, dataset slice id, and pipeline half (retrieval / generation / joint). If any field is missing, the number is not ready to celebrate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split halves when you report.&lt;/strong&gt; For the same query set, publish retrieval quality and generation/faithfulness as separate columns. One green blended score is not enough — “which half is broken?” should be answerable from the table alone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Freeze the evaluator before you chase labels.&lt;/strong&gt; If the judge, metric, or prompt changed mid-board, say so. Moving the goalposts mid-week and claiming progress is theater.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep a missing-evidence arm.&lt;/strong&gt; Same task with the gold document removed (or retrieval forced empty). If generation still narrates a confident answer, the eval contract is incomplete — regardless of how green the happy-path column looks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No thresholds copied from anyone’s blog as “our production numbers.” No paste recipe. Calibrate cutoffs on &lt;em&gt;your&lt;/em&gt; corpus; where missing evidence is costly, treat empty retrieval as a failure in the harness, not as a soft success.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why query-class honesty transfers
&lt;/h2&gt;

&lt;p&gt;On Portuguese clinical text, BM25 and dense retrieval solved different query classes; fusing them beat either alone on a public 500-query study. Exact terms and conceptual phrasing fail in different ways. That finding is checkable: open code at &lt;a href="https://github.com/nomad-link-id/hybrid-rag-pipeline" rel="noopener noreferrer"&gt;&lt;code&gt;nomad-link-id/hybrid-rag-pipeline&lt;/code&gt;&lt;/a&gt;, companion write-up on Dev.to.&lt;/p&gt;

&lt;p&gt;The lesson that transfers to Evaluation Cards is not “clone our fusion.” It is &lt;strong&gt;eval honesty on query classes and pipeline halves&lt;/strong&gt;. If your harness cannot say &lt;em&gt;which class&lt;/em&gt; and &lt;em&gt;which half&lt;/em&gt; produced the green cell, you are not ready to ship the number into a decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I will not claim
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;That EvalEval, UK AISI cards, or any one vendor harness is universally correct for every workload. Workload-honest eval first.&lt;/li&gt;
&lt;li&gt;That we “ran EvalEval inside Cortexa/DocMinds.” We did not. Trend-jacking with fake usage is spam.&lt;/li&gt;
&lt;li&gt;That a pinned harness alone proves end-to-end answer quality. Downstream faithfulness and missing-doc policy remain separate gates.&lt;/li&gt;
&lt;li&gt;Internal thresholds, prompts, or clone guides for private products. Menu only: pin the fields, split the halves — not the spice blend.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why this formalizes who we are
&lt;/h2&gt;

&lt;p&gt;The market is amplifying Evaluation Cards and green eval dashboards. The thesis I want indexed next to that heat:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Eval as contract&lt;/strong&gt; — protocol, compute, slice, and pipeline half are gates, not vibes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliable systems&lt;/strong&gt; — production AI fails on harness mismatch and wrong-half celebration — not only on model choice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieve-first&lt;/strong&gt; — when the retrieval half is unpinned, generation fluency is not evidence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a sharp reader walks away believing &lt;em&gt;this engineer will not celebrate a green score without a pinned harness&lt;/em&gt;, the post did its job. Follows that come from that are the point — not volume.&lt;/p&gt;

&lt;h2&gt;
  
  
  Soft pointers (contribution first)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Public hybrid pipeline (BM25 + dense + RRF): &lt;a href="https://github.com/nomad-link-id/hybrid-rag-pipeline" rel="noopener noreferrer"&gt;https://github.com/nomad-link-id/hybrid-rag-pipeline&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Empirical companion (500 clinical queries, open methodology): &lt;a href="https://dev.to/nomad-link-id/two-retrieval-methods-are-better-than-one-evidence-from-500-clinical-queries-4g41"&gt;Dev.to — Two Retrieval Methods Are Better Than One&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Site / builder trail: &lt;a href="https://igoreduardo.com" rel="noopener noreferrer"&gt;https://igoreduardo.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Market object that sparked this note: &lt;a href="https://huggingface.co/blog/evaleval-aisi" rel="noopener noreferrer"&gt;EvalEval × UK AISI Evaluation Cards (HF)&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stop here. No recipe. No “we proved SOTA.” Preference + limiter + public trail.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;By Igor Eduardo · Austin, TX · Engineer of reliable search and AI systems for high-stakes science · &lt;a href="https://igoreduardo.com" rel="noopener noreferrer"&gt;https://igoreduardo.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>evaluation</category>
      <category>rag</category>
      <category>ai</category>
      <category>llm</category>
    </item>
    <item>
      <title>Ranking Isn't Judging: What the Jev Wave Still Owes Retrieval</title>
      <dc:creator>Igor Eduardo</dc:creator>
      <pubDate>Thu, 24 Sep 2026 17:58:50 +0000</pubDate>
      <link>https://dev.to/igoreduardoai/ranking-isnt-judging-what-the-jev-wave-still-owes-retrieval-301m</link>
      <guid>https://dev.to/igoreduardoai/ranking-isnt-judging-what-the-jev-wave-still-owes-retrieval-301m</guid>
      <description>&lt;h1&gt;
  
  
  Ranking Isn't Judging: What the Jev Wave Still Owes Retrieval
&lt;/h1&gt;

&lt;p&gt;Everyone is talking about typed judgment models for RAG — Jev-class scorers that keep or drop passages, not only reorder them. Hugging Face just got a clean write-up of &lt;code&gt;jev-reranker&lt;/code&gt;: hybrid pool in, relevance filter out, fewer documents reaching the generator. That is a live market object, not a niche blog.&lt;/p&gt;

&lt;p&gt;Here is what I would require before I trusted “we upgraded ranking to judging” for high-stakes retrieval — and what I would not claim yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stake
&lt;/h2&gt;

&lt;p&gt;Teams will ship the wrong default.&lt;/p&gt;

&lt;p&gt;A hybrid lexical + dense pool can look fine on ranking metrics while still shipping distracting neighbors into the prompt. Rerank asks &lt;em&gt;in what order?&lt;/em&gt; Relevance filtering asks &lt;em&gt;should this context reach the generator at all?&lt;/em&gt; Those are different contracts. Collapsing them into one score hides the broken half.&lt;/p&gt;

&lt;p&gt;If your domain is identifier-heavy, multi-hop, or regulated-adjacent, a fluent answer after a weak retained set is not a win. It is a silent miss.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opinion (one sentence)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Ranking answers closeness; judging needs an explicit leave-out policy plus a faithfulness gate that is scored separately — never a single blended “quality” number.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is a preference with a limiter, not a SOTA claim. I have not run Jev in production. Their NanoHotpotQA numbers stay theirs. What I am formalizing is the &lt;em&gt;judgment type&lt;/em&gt; split, from the same retrieve-first / eval-as-contract lane I already publish on.&lt;/p&gt;

&lt;h2&gt;
  
  
  What ranking gets right — and where it stops
&lt;/h2&gt;

&lt;p&gt;Hybrid retrieval earned its keep for a reason. On Portuguese clinical text, BM25 and dense retrieval solved different query classes; fusing them beat either alone on a public 500-query study. Exact terms (scores, drug names, identifiers) and conceptual phrasing fail in different ways. That finding is checkable: open code at &lt;a href="https://github.com/nomad-link-id/hybrid-rag-pipeline" rel="noopener noreferrer"&gt;&lt;code&gt;nomad-link-id/hybrid-rag-pipeline&lt;/code&gt;&lt;/a&gt;, companion write-up on Dev.to, Zenodo preprint under CC BY.&lt;/p&gt;

&lt;p&gt;Reranking on top of that pool is a natural next step. Cross-encoders and decision models both try to push the useful passages up. Fine — as a &lt;em&gt;ranking&lt;/em&gt; layer.&lt;/p&gt;

&lt;p&gt;Judging is different work:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Judgment&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Failure if skipped&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rank&lt;/td&gt;
&lt;td&gt;Which of these hits is closer?&lt;/td&gt;
&lt;td&gt;Wrong order; still often has &lt;em&gt;something&lt;/em&gt; in context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filter / leave-out&lt;/td&gt;
&lt;td&gt;Should this hit reach the generator?&lt;/td&gt;
&lt;td&gt;Distractors in the prompt; token waste&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Faithfulness&lt;/td&gt;
&lt;td&gt;Does the final answer’s claim live in the cited source?&lt;/td&gt;
&lt;td&gt;Fluent invention with a real cite list&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A leave-out policy is not “sort harder.” When the filter clears the deck, the system needs a first-class &lt;strong&gt;missing-evidence&lt;/strong&gt; outcome — not a silent fallback into guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The check you can run without my internals
&lt;/h2&gt;

&lt;p&gt;You do not need my private stacks (and I will not publish them). Steal this menu-only check:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Split the report.&lt;/strong&gt; For the same query set, publish (a) ranking quality on the candidate pool and (b) retained-set size / leave-out rate after the filter. One number is not enough — the HF &lt;code&gt;jev-reranker&lt;/code&gt; table that pairs nDCG with documents retained is the right &lt;em&gt;shape&lt;/em&gt; of honesty, independent of their thresholds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pin a missing-evidence arm.&lt;/strong&gt; Same task with the filter forced to retain nothing (or with the gold document removed from the pool). If the generator still narrates a confident answer, the eval contract is incomplete.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep faithfulness separate.&lt;/strong&gt; For every quoted span, verify membership against the &lt;em&gt;cited&lt;/em&gt; source id. Fail closed on miss. Ranking/relevance can still look fine while the quote-span check fails — I have seen that failure mode in public discourse this week, and it matches retrieve-first practice.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No thresholds copied from anyone’s blog as “our production numbers.” No paste recipe. Calibrate cutoffs on &lt;em&gt;your&lt;/em&gt; corpus; where missing evidence is costly, treat empty retained sets as failures in the harness, not as soft successes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hybrid pools make the split sharper
&lt;/h2&gt;

&lt;p&gt;Once you run BM25 and dense in parallel, the candidate set is &lt;em&gt;intentionally&lt;/em&gt; broad. That is a feature: complementary methods catch different query classes. It is also why a leave-out layer matters more, not less.&lt;/p&gt;

&lt;p&gt;A wide hybrid pool without a filter ships more distractors. A filter without a missing-evidence policy ships fluent guesses when nothing survived. Rerank alone does not fix either failure — it only reorders the same set.&lt;/p&gt;

&lt;p&gt;So when the market says “just add a judgment model,” I hear two separate jobs: upgrade the &lt;em&gt;order&lt;/em&gt; when you still want generation, and upgrade the &lt;em&gt;admit/deny&lt;/em&gt; policy when generation should be allowed to refuse. Publish both outcomes in the eval report. Prefer workload-honest tables over a universal crown for any one store, model, or scorer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I will not claim
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;That Jev (or any typed decision model) is universally better than a cross-encoder or a lexical filter. Workload-honest eval first.&lt;/li&gt;
&lt;li&gt;That filter quality alone proves end-to-end answer quality. Downstream faithfulness and missing-doc policy are separate gates.&lt;/li&gt;
&lt;li&gt;That we “shipped Jev inside Cortexa/DocMinds.” We did not. Trend-jacking with fake usage is spam.&lt;/li&gt;
&lt;li&gt;Internal thresholds, prompts, or clone guides for private products. Menu only: what we serve is the judgment split and the eval shape — not the spice blend.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why this formalizes who we are
&lt;/h2&gt;

&lt;p&gt;The market is amplifying judgment models. The thesis I want indexed next to that heat:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Retrieve-first&lt;/strong&gt; — evidence path before orchestration theater.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid / complementary search&lt;/strong&gt; — lexical and dense cover different query classes; fusion needs honest eval, not a universal crown.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eval as contract&lt;/strong&gt; — exact-match, faithfulness, context precision/recall, paired leave-out tests — gates, not vibes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a sharp reader walks away believing &lt;em&gt;this engineer will not collapse ranking into judging, and will fail closed when evidence is missing&lt;/em&gt;, the post did its job. Follows that come from that are the point — not volume.&lt;/p&gt;

&lt;h2&gt;
  
  
  Soft pointers (contribution first)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Public hybrid pipeline (BM25 + dense + RRF): &lt;a href="https://github.com/nomad-link-id/hybrid-rag-pipeline" rel="noopener noreferrer"&gt;https://github.com/nomad-link-id/hybrid-rag-pipeline&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Empirical companion (500 clinical queries, open methodology): &lt;a href="https://dev.to/nomad-link-id/two-retrieval-methods-are-better-than-one-evidence-from-500-clinical-queries-4g41"&gt;Dev.to — Two Retrieval Methods Are Better Than One&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Preprint (CC BY): &lt;a href="https://doi.org/10.5281/zenodo.19686739" rel="noopener noreferrer"&gt;https://doi.org/10.5281/zenodo.19686739&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Market object that sparked this note: &lt;a href="https://huggingface.co/blog/hotchpotch/introducing-jev-reranker" rel="noopener noreferrer"&gt;Introducing jev-reranker (HF)&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stop here. No recipe. No “we proved SOTA.” Preference + limiter + public trail.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;By Igor Eduardo · Austin, TX · Engineer of reliable search and AI systems for high-stakes science · &lt;a href="https://igoreduardo.com" rel="noopener noreferrer"&gt;https://igoreduardo.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rag</category>
      <category>evaluation</category>
      <category>ai</category>
    </item>
    <item>
      <title>Two Retrieval Methods Are Better Than One: Evidence from 500 Clinical Queries</title>
      <dc:creator>Igor Eduardo</dc:creator>
      <pubDate>Wed, 13 May 2026 19:14:30 +0000</pubDate>
      <link>https://dev.to/igoreduardoai/two-retrieval-methods-are-better-than-one-evidence-from-500-clinical-queries-4g41</link>
      <guid>https://dev.to/igoreduardoai/two-retrieval-methods-are-better-than-one-evidence-from-500-clinical-queries-4g41</guid>
      <description>&lt;p&gt;When I set out to evaluate retrieval configurations for Portuguese clinical text, I expected one method to dominate. Instead, I found something more interesting: BM25 and dense retrieval solve &lt;em&gt;different&lt;/em&gt; questions. Neither is a substitute for the other.&lt;/p&gt;

&lt;p&gt;This post summarizes the methodology and results from a 500-query empirical study of hybrid retrieval for clinical question answering. All code is open source: &lt;a href="https://github.com/nomad-link-id/hybrid-rag-pipeline" rel="noopener noreferrer"&gt;https://github.com/nomad-link-id/hybrid-rag-pipeline&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;500 clinical queries across 6 medical specialties (cardiology, endocrinology, infectology, nephrology, neurology, oncology). Each query has a single reference answer grounded in a specific passage from clinical documentation.&lt;/p&gt;

&lt;p&gt;Four retrieval configurations were evaluated:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Config&lt;/th&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;BM25-only&lt;/td&gt;
&lt;td&gt;BM25 with Portuguese stopword removal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dense-only&lt;/td&gt;
&lt;td&gt;BioBERTpt embeddings, cosine similarity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hybrid-RRF&lt;/td&gt;
&lt;td&gt;BM25 + dense via Reciprocal Rank Fusion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hybrid-Rerank&lt;/td&gt;
&lt;td&gt;RRF candidates re-ranked with cross-encoder&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What Is Reciprocal Rank Fusion?
&lt;/h2&gt;

&lt;p&gt;RRF combines ranked lists from multiple retrievers without requiring score normalization:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rrf_score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rankings&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;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="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&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="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;scores&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="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;ranking&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rankings&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;rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doc_id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ranking&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;doc_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scores&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="n"&gt;doc_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.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;1.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;rank&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;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;reverse&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Config&lt;/th&gt;
&lt;th&gt;Recall@5&lt;/th&gt;
&lt;th&gt;MRR&lt;/th&gt;
&lt;th&gt;Citation F1&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;BM25-only&lt;/td&gt;
&lt;td&gt;0.71&lt;/td&gt;
&lt;td&gt;0.64&lt;/td&gt;
&lt;td&gt;0.82&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dense-only&lt;/td&gt;
&lt;td&gt;0.68&lt;/td&gt;
&lt;td&gt;0.61&lt;/td&gt;
&lt;td&gt;0.78&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hybrid-RRF&lt;/td&gt;
&lt;td&gt;0.84&lt;/td&gt;
&lt;td&gt;0.77&lt;/td&gt;
&lt;td&gt;0.91&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hybrid-Rerank&lt;/td&gt;
&lt;td&gt;0.86&lt;/td&gt;
&lt;td&gt;0.79&lt;/td&gt;
&lt;td&gt;0.93&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Complementarity Finding
&lt;/h2&gt;

&lt;p&gt;McNemar's test on BM25-only versus dense-only:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BM25 correct, dense incorrect: 89 queries&lt;/li&gt;
&lt;li&gt;Dense correct, BM25 incorrect: 57 queries&lt;/li&gt;
&lt;li&gt;McNemar chi2 = 39.55, p &amp;lt; 0.001&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The asymmetry is statistically significant. Dense-only missed 22.2% of queries that BM25 solved. You need both.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Deterministic approach&lt;/strong&gt; (BM25 score threshold + exact n-gram overlap): 461/500 citations verified.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt-based LLM approach&lt;/strong&gt; (same passages, ask LLM "does this support the answer?"): 1/500.&lt;/p&gt;

&lt;p&gt;The difference is task design, not model quality. A deterministic check measures actual textual overlap; a prompt check measures the model's opinion of the overlap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inter-Annotator Agreement
&lt;/h2&gt;

&lt;p&gt;100 query-response pairs independently annotated by two reviewers. Cohen's kappa = 0.954 — near-perfect agreement on what constitutes correct retrieval for clinical text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Takeaway
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run both BM25 and dense retrieval&lt;/li&gt;
&lt;li&gt;Use RRF to merge results&lt;/li&gt;
&lt;li&gt;Implement deterministic citation verification&lt;/li&gt;
&lt;li&gt;Measure complementarity with McNemar's test on your domain&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Code and Data
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/nomad-link-id/hybrid-rag-pipeline" rel="noopener noreferrer"&gt;https://github.com/nomad-link-id/hybrid-rag-pipeline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nomad-link-id/citation-guard" rel="noopener noreferrer"&gt;https://github.com/nomad-link-id/citation-guard&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Preprint: &lt;a href="https://doi.org/10.5281/zenodo.19686739" rel="noopener noreferrer"&gt;https://doi.org/10.5281/zenodo.19686739&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Igor Eduardo | igoreduardo.com | ORCID: 0009-0005-6288-1135&lt;/p&gt;

</description>
      <category>python</category>
      <category>rag</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
