<?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: 陈瀚</title>
    <description>The latest articles on DEV Community by 陈瀚 (@gpgkd906).</description>
    <link>https://dev.to/gpgkd906</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3789263%2Fb49c13d9-51a8-4536-93a7-d69b58d7b165.jpeg</url>
      <title>DEV Community: 陈瀚</title>
      <link>https://dev.to/gpgkd906</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gpgkd906"/>
    <language>en</language>
    <item>
      <title>A Postmortem on Autonomous LLM-as-Judge: How My Eval Agent Got Two Verdicts Wrong Before I Found a Sandbox Bug</title>
      <dc:creator>陈瀚</dc:creator>
      <pubDate>Wed, 08 Apr 2026 13:26:20 +0000</pubDate>
      <link>https://dev.to/gpgkd906/a-postmortem-on-autonomous-llm-as-judge-how-my-eval-agent-got-two-verdicts-wrong-before-i-found-a-a3j</link>
      <guid>https://dev.to/gpgkd906/a-postmortem-on-autonomous-llm-as-judge-how-my-eval-agent-got-two-verdicts-wrong-before-i-found-a-a3j</guid>
      <description>&lt;p&gt;I run an autonomous eval agent against new coding-agent stacks before trusting their numbers. The setup is standard: same task, same workflow, swap the shell × model combo, score the resulting diff on six dimensions. Last week the eval gave me a verdict that turned out to be wrong — twice — for the same root cause. The agent generating the verdict never flagged any uncertainty.&lt;/p&gt;

&lt;p&gt;I'm sharing the postmortem because the failure mode is the kind of thing that quietly poisons any LLM-as-judge pipeline running in production, and mine only got caught because I happened to ask the right follow-up question.&lt;/p&gt;

&lt;p&gt;Three combos, identical task, scored autonomously by Claude Code (Opus 4.6) running headless in a fresh session each retest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exhibit A: the eval agent's verdicts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Run 1.&lt;/strong&gt; C1 (OpenCode + MiniMax-M2.7) scored &lt;strong&gt;15/60&lt;/strong&gt;. Verdict in the auto-generated report:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Consistent with previous results: fast execution but no meaningful code output."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Run 2.&lt;/strong&gt; Fresh session, no memory of run 1. C1 scored &lt;strong&gt;16/60&lt;/strong&gt;. New verdict, written confidently:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Consistent: MiniMax cannot implement the task. The model may lack the capability to read external files and produce code changes in this Rust codebase."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Read that quote again. The agent identified the &lt;em&gt;exact&lt;/em&gt; symptom — "may lack the capability to read external files" — and immediately blamed the model. It never asked the next question: &lt;em&gt;is something in my pipeline preventing the agent from reading external files in the first place?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Two independent autonomous reports, both confidently ranking MiniMax dead last. If I'd shipped this leaderboard at this point, no one downstream would have questioned it — the wording was airtight.&lt;/p&gt;

&lt;h2&gt;
  
  
  The investigation that should have happened on run 1
&lt;/h2&gt;

&lt;p&gt;I sent one instruction to a fresh session: &lt;em&gt;"go deeper, check the daemon logs before retrying."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's all. No hint about where to look, no hypothesis.&lt;/p&gt;

&lt;p&gt;The new session traced the plan step's output to a spill file at &lt;code&gt;~/.orchestratord/logs/&amp;lt;task_id&amp;gt;.txt&lt;/code&gt;. The plan step itself was working fine — producing 50KB of useful context. But the OpenCode shell runs its agent inside a sandbox that, by default, only allows reads inside the workspace directory. The spill file was outside the workspace. So &lt;code&gt;implement&lt;/code&gt; was getting an empty string, not the plan output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plan step:      ✅ success (50KB output spilled to disk)
implement step: receives empty string, produces nothing
eval step:      "MiniMax cannot implement the task."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two confident wrong verdicts, one config bug.&lt;/p&gt;

&lt;p&gt;The session filed a one-line config fix (spill path goes inside the workspace), then re-ran the whole benchmark. C1 produced real code this time: 219 lines added, a &lt;code&gt;RetryConfig&lt;/code&gt; struct, an actual &lt;code&gt;connect_with_retry&lt;/code&gt; helper. Score: 18/60 — still mediocre, because the model's unit tests had four type-mismatch compile errors. But that's a &lt;em&gt;real&lt;/em&gt; model weakness, not an infrastructure mirage.&lt;/p&gt;

&lt;p&gt;Same numerical score range as before (15→16→18). Completely different story underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for production LLM-as-judge
&lt;/h2&gt;

&lt;p&gt;The piece that should make anyone running autonomous eval uncomfortable: &lt;strong&gt;the agent never decided on its own to check the daemon logs&lt;/strong&gt;. The first two sessions ran the exact prompt that production eval pipelines use ("execute the benchmark, collect artifacts, write a report") and produced confident, well-structured, plausible failure analysis. Neither session paused on the line &lt;em&gt;"may lack the capability to read external files"&lt;/em&gt; to ask whether the pipeline was the cause.&lt;/p&gt;

&lt;p&gt;The bug was discoverable. The third session found it in a single investigation pass with no hint — it just had to be told to look. So the fix isn't "use a smarter model"; the fix is structural.&lt;/p&gt;

&lt;p&gt;What I changed in the pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Spill paths now default to a workspace-relative location&lt;/strong&gt; that is sandbox-readable from every agent sandbox in the harness. (Previously this was an undocumented assumption.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The eval prompt now includes a mandatory "sanity-check the harness" step&lt;/strong&gt; that runs before the agent is allowed to attribute failure to the model. The step looks for specific symptoms (empty stdin/stdout, missing context blocks, sandbox denials in logs) and surfaces them as harness candidates rather than letting them silently shape the verdict.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Any verdict containing absolute language like "cannot" or "incapable"&lt;/strong&gt; is flagged for human review against quantitative artifacts (event logs, exit codes) before it lands in the leaderboard. Two of the three retests above produced exactly such language; both were wrong.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these are clever. They're the kind of thing you put in &lt;em&gt;after&lt;/em&gt; something like this has happened, not before. Which is the actual point of the postmortem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus oddity for the eval-pipeline obsessives
&lt;/h2&gt;

&lt;p&gt;Same retest, separate finding: in the post-fix run, the &lt;em&gt;winning&lt;/em&gt; combo (Codex + GPT-5.4, 50/60, 12 passing tests, clippy-clean) had a &lt;code&gt;step_finished&lt;/code&gt; success rate of &lt;strong&gt;25%&lt;/strong&gt; — three of its four orchestrator steps reported failure. Meanwhile the &lt;em&gt;worst&lt;/em&gt; combo (the one that almost got blamed for not knowing how to read files, 18/60) had a &lt;strong&gt;50%&lt;/strong&gt; step success rate.&lt;/p&gt;

&lt;p&gt;The "step success rate" dimension turned out to be inversely correlated with code quality in this run, because the failing steps were &lt;code&gt;self_test&lt;/code&gt; and &lt;code&gt;benchmark_eval&lt;/code&gt; — both downstream of &lt;code&gt;implement&lt;/code&gt;, both apparently buggy themselves. Another reminder: agent eval metrics are mostly noise unless someone has personally verified each one means what you think it means.&lt;/p&gt;

&lt;p&gt;(And yes, my eval agent — also Claude Code — gave Codex + GPT-5.4 the highest score but not a perfect one. It insists this is purely on the merits.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this all happened
&lt;/h2&gt;

&lt;p&gt;The orchestrator and workflow definitions are open-sourced at &lt;a href="https://github.com/c9r-io/orchestrator" rel="noopener noreferrer"&gt;github.com/c9r-io/orchestrator&lt;/a&gt;. The fix is FR-092. The agent manifests, the benchmark workflow, and the exact prompts used for both the eval agent and the target agents are in &lt;code&gt;fixtures/benchmarks/&lt;/code&gt;. If you're running an autonomous eval pipeline of your own and want to sanity-check it against this failure mode, the spill-path/sandbox interaction is the specific thing to look for.&lt;/p&gt;

&lt;p&gt;The orchestrator isn't the interesting part of this post. The interesting part is that an autonomous evaluator confidently produced two wrong reports, never flagged uncertainty, and the only reason I caught it is one human follow-up question.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>postmortem</category>
      <category>debugging</category>
    </item>
    <item>
      <title>From Auth9 to Agent Orchestrator: how an AI-native development method evolved into a Harness Engineering control plane</title>
      <dc:creator>陈瀚</dc:creator>
      <pubDate>Sun, 29 Mar 2026 12:21:46 +0000</pubDate>
      <link>https://dev.to/gpgkd906/from-auth9-to-agent-orchestrator-how-an-ai-native-development-method-evolved-into-a-harness-2mhd</link>
      <guid>https://dev.to/gpgkd906/from-auth9-to-agent-orchestrator-how-an-ai-native-development-method-evolved-into-a-harness-2mhd</guid>
      <description>&lt;p&gt;I have spent years practicing extreme programming and TDD. So when AI coding tools became good enough to handle a meaningful share of day-to-day work, I adopted them quickly and enthusiastically.&lt;/p&gt;

&lt;p&gt;Then I hit a very predictable wall.&lt;/p&gt;

&lt;p&gt;I became the bottleneck.&lt;/p&gt;

&lt;p&gt;AI could write code quickly. It could write tests quickly too. But the final question, "is this actually correct?", still landed on me. I had to review the implementation, run the environment, click through flows in the browser, inspect application logs, check database state, and decide whether the output was real or just superficially plausible.&lt;/p&gt;

&lt;p&gt;In other words, AI had accelerated generation, but I was still manually carrying too much of the verification burden. The faster the model became, the more manual review and QA work accumulated around me.&lt;/p&gt;

&lt;p&gt;That was the moment I started pushing testing even further left, but this time not just in the classic TDD sense. I started pushing the entire validation loop left.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shifting the validation loop left
&lt;/h2&gt;

&lt;p&gt;I stopped waiting until after implementation to think seriously about testing.&lt;/p&gt;

&lt;p&gt;Before writing code, I started requiring AI to produce explicit test plans. After implementation, AI was not allowed to stop at "done". It had to execute the validation plan: drive the browser, inspect logs, check database state, compare outcomes against expectations, create structured tickets for failures, fix them, and rerun the relevant checks until the results converged.&lt;/p&gt;

&lt;p&gt;Over time, this stopped feeling like a set of prompting tricks and started feeling like a method. The method included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;test plans before implementation&lt;/li&gt;
&lt;li&gt;structured docs for QA, security, and UI/UX verification&lt;/li&gt;
&lt;li&gt;ticket-driven repair loops&lt;/li&gt;
&lt;li&gt;doc governance to keep the verification layer from rotting&lt;/li&gt;
&lt;li&gt;reusable Skills that encode repeatable development and validation behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At that point I needed a real proving ground.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Auth9 mattered
&lt;/h2&gt;

&lt;p&gt;I chose &lt;a href="https://github.com/c9r-io/auth9" rel="noopener noreferrer"&gt;Auth9&lt;/a&gt;, a full identity platform, because I wanted something difficult enough to make the method fail if it was weak.&lt;/p&gt;

&lt;p&gt;Identity systems are full of dangerous edges: protocol semantics, state transitions, interoperability, security constraints, permission models, and long tails of compatibility work. If a method can help govern that kind of system, it is probably doing something real.&lt;/p&gt;

&lt;p&gt;Auth9 was where this approach became concrete. While building it, I kept refining the method itself: how docs should be governed, which checks needed to become standard, how to turn recurring behavior into Skills, and how to keep the ticket/fix/retest loop honest.&lt;/p&gt;

&lt;p&gt;As the project evolved through real iterations, I became convinced that this was not just a convenient way to ship features faster. It was becoming a viable way to govern complex software over time.&lt;/p&gt;

&lt;p&gt;That was when Agent Orchestrator began.&lt;/p&gt;

&lt;p&gt;I did not begin with a plan to build a platform. I began with a method that was proving useful, and I no longer wanted to supervise every step manually. If the method was real, it should be able to keep running after I stepped away from the keyboard. That requirement naturally pulled me toward a control plane.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mid-March test
&lt;/h2&gt;

&lt;p&gt;By mid-February, I was already using early Orchestrator-style automation inside Auth9. In mid-March, I decided to run a high-risk experiment: I wanted to see whether Orchestrator and this method could actually carry a complex low-level refactor.&lt;/p&gt;

&lt;p&gt;I replaced the headless Keycloak setup under Auth9 with a native &lt;code&gt;auth9-oidc&lt;/code&gt; engine.&lt;/p&gt;

&lt;p&gt;For an identity platform, replacing the underlying OIDC engine is not a cosmetic change. It touches protocol behavior, state flow, interoperability assumptions, and a long list of edge cases that often surface only after the "main" work seems complete.&lt;/p&gt;

&lt;p&gt;By then, I was already using the early Orchestrator to help govern the process. It did not magically remove the difficulty, but it did provide a structure around the work: execution flow, task state, logs, tickets, and repeatable validation.&lt;/p&gt;

&lt;p&gt;The core replacement landed over three days. OIDC conformance and Keycloak legacy cleanup followed within the same week.&lt;/p&gt;

&lt;p&gt;More importantly, the story did not end there. The same method and Orchestrator-assisted workflow helped converge the technical debt that surfaced after the change, and eventually completed the community OIDC Certification tests on the native engine.&lt;/p&gt;

&lt;p&gt;That sequence mattered more to me than the initial three-day number. It showed that the method and the tool were not only useful for greenfield development. They could also help govern a high-risk system through long-running, uncomfortable change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the project is called Orchestrator
&lt;/h2&gt;

&lt;p&gt;At the time, the word I cared most about was orchestration.&lt;/p&gt;

&lt;p&gt;What I wanted most was a reliable way to orchestrate this method: execute the next step, keep state, record logs, preserve intermediate outputs, stop safely, and resume later. So the project became Agent Orchestrator.&lt;/p&gt;

&lt;p&gt;The broader conceptual framing came later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Later, I found a better name for the category
&lt;/h2&gt;

&lt;p&gt;When OpenAI later used the term Harness Engineering, I immediately recognized the shape of the work. Not because I thought I had coined the idea first, but because the term described something I had already been converging on through practice.&lt;/p&gt;

&lt;p&gt;The point was larger than orchestration alone. What mattered was the full harness around the agent: workflow, constraints, observability, recovery, and feedback loops.&lt;/p&gt;

&lt;p&gt;That is why I now describe Agent Orchestrator as a Harness Engineering control plane. The project name came first; the clearer positioning came later.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Agent Orchestrator actually is
&lt;/h2&gt;

&lt;p&gt;It is a local-first control plane for shell-based coding agents. Agents, workflows, and step templates are declared in YAML. A daemon (&lt;code&gt;orchestratord&lt;/code&gt;) schedules steps, routes work by capability, keeps task state in SQLite, streams logs, and enforces guardrails such as sandboxing and output redaction. The CLI is machine-parseable so agents can drive it too.&lt;/p&gt;

&lt;p&gt;Some design choices matter a lot here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;local-first runtime&lt;/strong&gt; so the control plane stays close to the repository&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQLite-backed task state&lt;/strong&gt; so long-running work remains inspectable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;machine-readable CLI output&lt;/strong&gt; so agents can participate directly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;declarative YAML resources&lt;/strong&gt; so the workflow logic lives outside one model session&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;support for heterogeneous shell agents&lt;/strong&gt; so the method does not depend on one vendor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To me, Orchestrator is not another code-generation plugin. It is the control surface that lets this method keep running.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I trust most
&lt;/h2&gt;

&lt;p&gt;One reason I trust this framing is that the project has also been used on itself.&lt;/p&gt;

&lt;p&gt;Self-bootstrap and self-evolution were important validation paths from early on. If the method is real, it should not only work on downstream projects. It should also survive contact with the control plane itself.&lt;/p&gt;

&lt;p&gt;If you are also trying to turn repeated AI-assisted engineering work into something more systematic and more durable, that is exactly the gap I built Orchestrator to address.&lt;/p&gt;

&lt;p&gt;You can try it here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;c9r-io/tap/orchestrator
&lt;span class="c"&gt;# or&lt;/span&gt;
cargo &lt;span class="nb"&gt;install &lt;/span&gt;orchestrator-cli orchestratord
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;orchestratord &lt;span class="nt"&gt;--foreground&lt;/span&gt; &lt;span class="nt"&gt;--workers&lt;/span&gt; 2 &amp;amp;
orchestrator init
orchestrator apply &lt;span class="nt"&gt;-f&lt;/span&gt; manifest.yaml
orchestrator task create &lt;span class="nt"&gt;--goal&lt;/span&gt; &lt;span class="s2"&gt;"My first task"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Docs&lt;/strong&gt;: &lt;a href="https://docs.c9r.io" rel="noopener noreferrer"&gt;docs.c9r.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/c9r-io/orchestrator" rel="noopener noreferrer"&gt;github.com/c9r-io/orchestrator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth9&lt;/strong&gt;: &lt;a href="https://github.com/c9r-io/auth9" rel="noopener noreferrer"&gt;github.com/c9r-io/auth9&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License&lt;/strong&gt;: MIT&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;It is open source, still evolving, and I would genuinely like to hear how other people are turning repeated AI-assisted engineering work into something that can survive real software delivery.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ai</category>
      <category>automation</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
