<?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: Aming</title>
    <description>The latest articles on DEV Community by Aming (@amingin_ai).</description>
    <link>https://dev.to/amingin_ai</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%2F3935251%2Fe38632bc-051d-45df-8c07-d7232255591c.jpg</url>
      <title>DEV Community: Aming</title>
      <link>https://dev.to/amingin_ai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amingin_ai"/>
    <language>en</language>
    <item>
      <title>The agent industry made stack overflow billable—but who owns the return?</title>
      <dc:creator>Aming</dc:creator>
      <pubDate>Thu, 23 Jul 2026 15:25:01 +0000</pubDate>
      <link>https://dev.to/amingin_ai/the-agent-industry-made-stack-overflow-billable-b17</link>
      <guid>https://dev.to/amingin_ai/the-agent-industry-made-stack-overflow-billable-b17</guid>
      <description>&lt;p&gt;&lt;em&gt;The model chooses the next call. The runtime counts the calls. The customer&lt;br&gt;
pays for the calls. Nobody owns the return.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The agent industry took one of the oldest programming bugs and turned it into&lt;br&gt;
a product category.&lt;/p&gt;

&lt;p&gt;It shipped recursion without a base case.&lt;/p&gt;

&lt;p&gt;ReAct standardized think, act, observe, repeat. Reflection adds another lap.&lt;br&gt;
Re-planning adds another plan. Graph frameworks make the back-edge explicit.&lt;br&gt;
Then, when the system cannot establish that the job is semantically finished,&lt;br&gt;
the harness offers a maximum-turn setting, a timeout, a token budget, or&lt;br&gt;
something literally named &lt;code&gt;recursion_limit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That is not a semantic completion model.&lt;/p&gt;

&lt;p&gt;It is a kill switch attached to a meter.&lt;/p&gt;

&lt;p&gt;A resource ceiling does guarantee that the run will eventually die. That is&lt;br&gt;
not the disputed point. It proves death, not completion.&lt;/p&gt;

&lt;p&gt;In an ordinary code review, a self-call without a trusted base-case guard or&lt;br&gt;
termination argument is a bug. Nobody proposes a larger stack as the fix. In&lt;br&gt;
agent engineering, we made the back-edge ergonomic, let a probabilistic model&lt;br&gt;
assert its own postcondition, wrapped the recursion in tracing, and priced the&lt;br&gt;
fallback.&lt;/p&gt;

&lt;p&gt;The defense is predictable: useful agents need loops.&lt;/p&gt;

&lt;p&gt;Of course they do. Search, retries, and probabilistic refinement need&lt;br&gt;
iteration. The charge is narrower — and worse. When the body can manufacture&lt;br&gt;
the reason for its next lap, when a state the policy calls terminal remains&lt;br&gt;
executable, and when the only generic external boundary is numerical, the&lt;br&gt;
lifecycle carries the same termination debt as recursion without a trusted&lt;br&gt;
base case.&lt;/p&gt;

&lt;p&gt;Maximum turns can cap the damage. They cannot prove the goal was reached. A&lt;br&gt;
timeout can kill the process. It cannot make the answer correct. A token&lt;br&gt;
budget can bound the invoice. It cannot make recursion return.&lt;/p&gt;

&lt;p&gt;The agent industry did not solve termination.&lt;/p&gt;

&lt;p&gt;It made stack overflow billable.&lt;/p&gt;

&lt;p&gt;Mine ran for three days, generated 102 work items, and spent roughly two&lt;br&gt;
thirds of its activity working on itself while every aggregate gauge stayed&lt;br&gt;
green.&lt;/p&gt;

&lt;p&gt;It also exposed exactly one legal action at every step. The entrance problem&lt;br&gt;
was solved.&lt;/p&gt;

&lt;p&gt;The position problem was not.&lt;/p&gt;

&lt;h2&gt;
  
  
  I have the stack trace
&lt;/h2&gt;

&lt;p&gt;I know this failure because I built it into a governance runtime designed&lt;br&gt;
specifically to prevent AI drift.&lt;/p&gt;

&lt;p&gt;The system gives coding agents bounded contracts, frozen acceptance criteria,&lt;br&gt;
append-only evidence, independent QA, verified position, merge authority, and&lt;br&gt;
one legal action at each step. Evidence is stamped with the commit,&lt;br&gt;
generation, and authority that warranted it. This was not a toy prompt loop&lt;br&gt;
running blind. It was the anti-drift harness with every gauge attached.&lt;/p&gt;

&lt;p&gt;For close to three days, it looked healthy.&lt;/p&gt;

&lt;p&gt;Repairs merged. Tests passed. Backlog items closed. Red no-PASS verdicts were&lt;br&gt;
visible on the ledger. The system was not concealing failure. It was&lt;br&gt;
converting each failure, promptly and legally, into another apparently useful&lt;br&gt;
piece of work.&lt;/p&gt;

&lt;p&gt;What I felt was only that development had become strangely slow.&lt;/p&gt;

&lt;p&gt;Eventually I asked my AI co-developer a lazy-sounding question: after an&lt;br&gt;
audited bypass, do we return to the old item and keep trying to close it?&lt;/p&gt;

&lt;p&gt;Six pieces of code evidence came back.&lt;/p&gt;

&lt;p&gt;Yes.&lt;/p&gt;

&lt;p&gt;The recovery path said:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;close(item) → blocked → repair() → repair returns → close(item)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The second close could reveal the next blocker. That blocker created the next&lt;br&gt;
repair. The next repair returned to the same item again.&lt;/p&gt;

&lt;p&gt;This was not a workflow template being applied to fresh work. It was the same&lt;br&gt;
semantic instance calling its own lifecycle again after the generation had&lt;br&gt;
already crossed what was supposed to be a terminal barrier.&lt;/p&gt;

&lt;p&gt;The ledger showed the depth. During the three-day window, 102 work items were&lt;br&gt;
created. Sixty-eight percent were repair, diagnostic, or recovery items.&lt;br&gt;
Thirty-six items closed; 67 percent were governance-family work. Roughly two&lt;br&gt;
thirds of all work-item activity was the system working on the machinery that&lt;br&gt;
decided whether the system could stop working.&lt;/p&gt;

&lt;p&gt;Every frame looked responsible. Every call had evidence. Every repair fixed&lt;br&gt;
something real.&lt;/p&gt;

&lt;p&gt;And every aggregate gauge celebrated the stack getting deeper.&lt;/p&gt;

&lt;h2&gt;
  
  
  I had one legal entrance. I was in the wrong generation.
&lt;/h2&gt;

&lt;p&gt;My &lt;a href="https://dev.to/amingin_ai/fixing-ai-drift-is-a-simple-probability-problem-your-human-in-the-loop-is-a-very-expensive-gps-2pel"&gt;earlier drift&lt;br&gt;
theory&lt;/a&gt;&lt;br&gt;
reduced one agent step to two probabilities:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P(correct step) = P(correct position) × P(correct entrance | position)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;next_legal&lt;/code&gt; attacks the second term. Once the runtime knows the state, it&lt;br&gt;
computes the authorized transition and pushes one entrance instead of asking a&lt;br&gt;
probabilistic model to choose among several. Remove the choice; remove the&lt;br&gt;
routing tax.&lt;/p&gt;

&lt;p&gt;My runtime did that. Every actor received one legal next action.&lt;/p&gt;

&lt;p&gt;It still orbited.&lt;/p&gt;

&lt;p&gt;The equation was not wrong. My definition of position was incomplete.&lt;br&gt;
&lt;code&gt;next_legal&lt;/code&gt; is conditional: it can produce the correct entrance only for the&lt;br&gt;
position it was given. A perfect router from an expired coordinate is a&lt;br&gt;
deterministic mistake. One entrance cannot save you when the room number is&lt;br&gt;
wrong.&lt;/p&gt;

&lt;p&gt;Verified position is not a stage label. It has three parts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;coordinate = item × stage × generation × invocation × authority × terminal&lt;br&gt;
status&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;datum = goal/scope epoch × acceptance criteria × world/baseline epoch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;verified position = coordinate × datum × live warranty&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The coordinate says where the work is. The datum says which goal, scope, and&lt;br&gt;
baseline define “progress.” The warranty says whether that coordinate and&lt;br&gt;
datum still have authority in the current world.&lt;/p&gt;

&lt;p&gt;Remove any factor and “position” becomes a plausible story about the wrong&lt;br&gt;
place.&lt;/p&gt;

&lt;p&gt;My earlier position guide answered “where?” This incident added two questions:&lt;br&gt;
“relative to what?” and “is that frame still authorized here?”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxs306dy7rn2no4k1s1vw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxs306dy7rn2no4k1s1vw.png" alt="Position first: coordinate, datum, and live warranty establish a verified position; next_legal then selects one authorized entrance. An expired position routed perfectly produces a deterministic mistake." width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article does not replace the position theory. It supplies the&lt;br&gt;
control-flow mechanism underneath one class of position failure. A missing&lt;br&gt;
base case makes the journey self-extending. Warranty expiry invalidates old&lt;br&gt;
coordinates. Position aliasing hides the invalidity. The probability law&lt;br&gt;
measures the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model continues. The runtime counts. Nobody returns.
&lt;/h2&gt;

&lt;p&gt;The field's consensus definition — an LLM using tools “in a loop” — standardized&lt;br&gt;
the next call and outsourced the return. After crowdsourcing more than two&lt;br&gt;
hundred definitions, Simon Willison landed on&lt;br&gt;
&lt;a href="https://simonwillison.net/2025/Sep/18/agents/" rel="noopener noreferrer"&gt;"An LLM agent runs tools in a loop to achieve a&lt;br&gt;
goal"&lt;/a&gt;. Anthropic's definition&lt;br&gt;
is almost identical: agents are&lt;br&gt;
&lt;a href="https://www.anthropic.com/engineering/building-effective-agents" rel="noopener noreferrer"&gt;"typically just LLMs using tools based on environmental feedback in a&lt;br&gt;
loop"&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;ReAct gives the model a &lt;code&gt;Finish[answer]&lt;/code&gt; action; the harness gives the operator&lt;br&gt;
maximum turns, timeouts, and token ceilings. One is a model-generated return&lt;br&gt;
instruction, not a trusted success predicate. The other is forced execution.&lt;br&gt;
Neither is external proof that the obligation was satisfied.&lt;/p&gt;

&lt;p&gt;The model owns continuation. The runtime owns containment. Semantic return&lt;br&gt;
sits between them, unimplemented.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If your agent stops only when the harness kills it, it did not finish. It&lt;br&gt;
hit the billing condition.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  We moved the stack somewhere too expensive to overflow
&lt;/h2&gt;

&lt;p&gt;These backlog rows were not literal in-memory stack frames. There was no LIFO&lt;br&gt;
call stack waiting for the operating system to kill it.&lt;/p&gt;

&lt;p&gt;That made the bug worse, not better.&lt;/p&gt;

&lt;p&gt;The operational stack had been distributed across:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;context holding the conclusions of earlier calls;&lt;/li&gt;
&lt;li&gt;backlog rows holding suspended obligations;&lt;/li&gt;
&lt;li&gt;recovery tasks holding the promise to return;&lt;/li&gt;
&lt;li&gt;QA histories holding prior verdicts;&lt;/li&gt;
&lt;li&gt;graph edges holding the route back in; and&lt;/li&gt;
&lt;li&gt;token and time budgets paying for every additional frame.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ordinary recursion fails loudly because memory is finite and the runtime knows&lt;br&gt;
what a frame is. Agent recursion can externalize its frames into durable&lt;br&gt;
storage, reload them tomorrow, and invoice each return trip separately. The&lt;br&gt;
stack becomes deep enough that it never needs to overflow. It can simply&lt;br&gt;
become the organization.&lt;/p&gt;

&lt;p&gt;That is the perverse achievement:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;we built a stack overflow that sends an invoice instead of a crash report.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The ledger was the stack trace. We had not named it as depth because each row&lt;br&gt;
used a respectable business noun: repair, review, recovery, follow-up. Once&lt;br&gt;
recursion escapes RAM, it does not look like recursion. It looks like a&lt;br&gt;
backlog.&lt;/p&gt;

&lt;h2&gt;
  
  
  “A loop is not recursion” is true — and not a defense
&lt;/h2&gt;

&lt;p&gt;Iteration is not recursion. A &lt;code&gt;for&lt;/code&gt; loop over a finite collection is not a&lt;br&gt;
recursive function. A stochastic search can revisit a stage. A long-lived&lt;br&gt;
service may accept new work forever while every individual case terminates.&lt;/p&gt;

&lt;p&gt;The charge is not about syntax. It is about semantic self-reentry. A “loop”&lt;br&gt;
carries the termination debt of recursion when its body can manufacture the&lt;br&gt;
guard for its next invocation, a state the policy calls terminal remains&lt;br&gt;
executable, and only a numerical resource boundary can force return.&lt;/p&gt;

&lt;p&gt;A reusable workflow template is ordinary iteration:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;dispatch(item 1) → close(item 1) → dispatch(item 2)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each pass binds fresh data. Completed instances remain completed. My failure&lt;br&gt;
was different:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;close(item X) → repair() → close(item X)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The same instance returned after its generation had terminalized. “Closed”&lt;br&gt;
was spelled like a base case and wired like a recursive branch. That topology&lt;br&gt;
may be implemented with a &lt;code&gt;while&lt;/code&gt; loop, a message queue, a graph edge, or a&lt;br&gt;
database row. Syntax does not pay its termination debt.&lt;/p&gt;

&lt;h2&gt;
  
  
  GraphRecursionError is the euphemism briefly failing
&lt;/h2&gt;

&lt;p&gt;The graph-orchestration wave made agent control flow inspectable. It made the&lt;br&gt;
back-edge visible, then left its authority untyped.&lt;/p&gt;

&lt;p&gt;The early LangGraph README was admirably direct:&lt;br&gt;
&lt;a href="https://github.com/langchain-ai/langgraph/blob/82ea95c3c0e2513ea8688badd837f447b7510ef4/README.md" rel="noopener noreferrer"&gt;"The main use is for adding &lt;strong&gt;cycles&lt;/strong&gt; to your LLM application. Crucially,&lt;br&gt;
this is NOT a &lt;strong&gt;DAG&lt;/strong&gt;&lt;br&gt;
framework."&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The framework also exposes a&lt;br&gt;
&lt;a href="https://docs.langchain.com/oss/python/langgraph/graph-api" rel="noopener noreferrer"&gt;&lt;code&gt;recursion_limit&lt;/code&gt;&lt;/a&gt;,&lt;br&gt;
RemainingSteps, and GraphRecursionError. LangGraph exposes &lt;code&gt;END&lt;/code&gt; and&lt;br&gt;
conditional routing too. The abstraction failure is not that exits are&lt;br&gt;
impossible to draw. It is that a justified retry and the resurrection of a&lt;br&gt;
terminal generation are both typed as merely an edge. Continuation is&lt;br&gt;
first-class. Its proof obligation is application homework.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GraphRecursionError is the framework briefly dropping the euphemism.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The OpenAI Agents SDK has&lt;br&gt;
&lt;a href="https://openai.github.io/openai-agents-python/running_agents/" rel="noopener noreferrer"&gt;MaxTurnsExceeded&lt;/a&gt;.&lt;br&gt;
Anthropic recommends stopping conditions such as a maximum number of&lt;br&gt;
iterations. Responsible runtimes need these circuit breakers. The scandal is&lt;br&gt;
that they are asked to carry a proof obligation the application never&lt;br&gt;
defined.&lt;/p&gt;

&lt;p&gt;A base case defines a non-recursive return. A termination argument shows that&lt;br&gt;
recursive calls reach it. A postcondition says whether the return is valid.&lt;br&gt;
An agent needs all three: a trusted success guard, a justification for&lt;br&gt;
continued execution, and a bounded failure path. A recursion limit supplies&lt;br&gt;
only the last. It guarantees that the run will die after N steps. It cannot&lt;br&gt;
guarantee that the obligation was satisfied.&lt;/p&gt;

&lt;p&gt;Raising the limit may be appropriate when a valid bounded process genuinely&lt;br&gt;
needs more steps. Without a termination argument, it only expands the blast&lt;br&gt;
radius.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A budget is not a base case. It is a price ceiling on a bug.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Policy text wrote the recursive call
&lt;/h2&gt;

&lt;p&gt;Nobody intentionally drew this topology.&lt;/p&gt;

&lt;p&gt;I wrote it in prose.&lt;/p&gt;

&lt;p&gt;My operating principles said “continue the original lane” and “the source row&lt;br&gt;
remains OPEN.” Each phrase was locally reasonable in the situation I had in&lt;br&gt;
mind: persist inside a live run; do not discard an unfinished obligation.&lt;/p&gt;

&lt;p&gt;My AI co-developer compiled those sentences literally into a control&lt;br&gt;
back-edge. Then it added a test asserting that back-edge, so the wrong&lt;br&gt;
topology was not merely present. It was defended.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Policy text is code now. Ambiguity compiles.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A missing base case in source code attracts a familiar review comment. A&lt;br&gt;
missing base case in operating prose has no syntax error. It can pass tests&lt;br&gt;
that faithfully encode the mistake and arrive days later as a vague feeling&lt;br&gt;
that the organization is slow.&lt;/p&gt;

&lt;p&gt;This is what “AI writes the implementation” changes about management. Your&lt;br&gt;
verbs become control flow. “Continue,” “resume,” “return,” and “keep open” are&lt;br&gt;
not motivational language. They are candidate edges in an executable graph.&lt;/p&gt;

&lt;p&gt;If you do not state the negative edge — &lt;em&gt;never return after this barrier&lt;/em&gt; —&lt;br&gt;
the compiler is free to invent it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Every successful call manufactured the next call
&lt;/h2&gt;

&lt;p&gt;A missing base case explains the shape. It does not explain why the recursion&lt;br&gt;
kept discovering legitimate work.&lt;/p&gt;

&lt;p&gt;The fuel was warranty expiry.&lt;/p&gt;

&lt;p&gt;Every conclusion produced by an agent — a plan, diagnosis, review verdict, or&lt;br&gt;
claim of completion — is warranted by the world and belief state in which it&lt;br&gt;
was minted. Every lap can change one or both. Writes alter files and APIs;&lt;br&gt;
reads reveal facts. Either transition can invalidate conclusions minted under&lt;br&gt;
the previous &lt;code&gt;(world, belief)&lt;/code&gt; state.&lt;/p&gt;

&lt;p&gt;The invalidation is selective. History remains true as history. Acceptance&lt;br&gt;
criteria deliberately pinned by contract remain pinned. The casualties are&lt;br&gt;
current-state claims whose ground has moved.&lt;/p&gt;

&lt;p&gt;Ordinary agent context barely represents that distinction. Attention has an&lt;br&gt;
order column. It does not have a validity column.&lt;/p&gt;

&lt;p&gt;Now replay the recursive call.&lt;/p&gt;

&lt;p&gt;The original item accumulated evidence in world V0. Its repair changed the&lt;br&gt;
runtime and created world V1. Returning to the old item resumed a logical&lt;br&gt;
invocation whose premises were now partly stale. Re-running QA could expose an&lt;br&gt;
incompatibility that did not exist — or was not visible — in V0. Fixing that&lt;br&gt;
blocker created world V2, making the next return still less congruent with the&lt;br&gt;
original evidence.&lt;/p&gt;

&lt;p&gt;Every successful repair could manufacture or expose the premise for the next&lt;br&gt;
recursive call.&lt;/p&gt;

&lt;p&gt;The recursion brought its own arguments.&lt;/p&gt;

&lt;p&gt;Not every blocker in my three-day window was caused by stale premises. Some&lt;br&gt;
were ordinary defects that repeated verification surfaced. The topology did&lt;br&gt;
not care. Both kinds became fresh reasons to call the same lifecycle again.&lt;/p&gt;

&lt;p&gt;This is why retry budgets attack the wrong variable. They limit how many&lt;br&gt;
times the system may consume possibly expired premises. They do not tell the&lt;br&gt;
system which premises remain authorized. Longer context can enlarge the stale&lt;br&gt;
surface. Better retrieval can retrieve the wrong conclusion more accurately.&lt;/p&gt;

&lt;p&gt;Relevance is not validity. Recency is not authority. More memory is not a&lt;br&gt;
return statement.&lt;/p&gt;

&lt;h2&gt;
  
  
  The judge moved. Then it refused to die.
&lt;/h2&gt;

&lt;p&gt;An earlier incident produced nine QA rejections in 27 hours while every test&lt;br&gt;
stayed green. Each finding was locally real. The reviewer knew the candidate&lt;br&gt;
and the stage. What moved was the measuring standard: every lap widened scope&lt;br&gt;
and rewrote the pass predicate.&lt;/p&gt;

&lt;p&gt;The position in memory was correct. The reference frame drifted.&lt;/p&gt;

&lt;p&gt;The fix was to freeze the verdict baseline to the goal, scope, and acceptance&lt;br&gt;
criteria that existed at dispatch. Findings beyond that line became new work&lt;br&gt;
instead of new reasons to fail the current candidate.&lt;/p&gt;

&lt;p&gt;The three-day recursion failed in the opposite direction. This time the judge&lt;br&gt;
stayed while the world moved. Repair changed the runtime from V0 to V1, but&lt;br&gt;
the old generation, evidence, and evaluation authority were reopened as&lt;br&gt;
though their warranty had survived. Invocation one and invocation nine both&lt;br&gt;
rendered as “in review.”&lt;/p&gt;

&lt;p&gt;Call that &lt;strong&gt;position aliasing&lt;/strong&gt;: different generation, invocation, world, and&lt;br&gt;
warranty coordinates collapse into the same stage label.&lt;/p&gt;

&lt;p&gt;One loop mutated its base case. The other resurrected an expired one.&lt;/p&gt;

&lt;p&gt;The position law is the same in both:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The success predicate must be immutable within an invocation and&lt;br&gt;
non-transferable across invocations.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Freeze the judge within a generation. Retire the judge when the goal or world&lt;br&gt;
epoch changes. Search may loop. Evaluation authority may not drift.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbbl49mfbb93fijmwdq0z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbbl49mfbb93fijmwdq0z.png" alt="Two opposite warranty failures: nine QA rounds moved the judge within one generation, while the three-day recursion carried an expired judge into a new world. Freeze the datum within a generation; expire its warranty across generations." width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My watchdogs missed both failures. One looked for rejection streaks; every&lt;br&gt;
recursive call eventually succeeded. Another looked for flat progress; real&lt;br&gt;
repairs merged. Both thermometers measured scalar activity. The pathology&lt;br&gt;
lived in reference frame, direction, and depth.&lt;/p&gt;

&lt;p&gt;A dashboard that prints only “in review” is showing an instruction pointer,&lt;br&gt;
not a position. A perfect &lt;code&gt;next_legal&lt;/code&gt; function fed that coordinate will serve&lt;br&gt;
one confidently wrong entrance.&lt;/p&gt;

&lt;h2&gt;
  
  
  The public failures already have recursion-shaped names
&lt;/h2&gt;

&lt;p&gt;AutoGPT's first wave produced the canonical report:&lt;br&gt;
&lt;a href="https://github.com/Significant-Gravitas/AutoGPT/issues/1994" rel="noopener noreferrer"&gt;"It loops the same queries although it successfully got the google&lt;br&gt;
results"&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The intention “search for X” should have reached a base case when the answer&lt;br&gt;
arrived. The tool call changed the agent's epistemic state: the answer was now&lt;br&gt;
available. The intention survived as though nothing had changed. The same&lt;br&gt;
logical obligation scheduled itself again.&lt;/p&gt;

&lt;p&gt;Research on intrinsic self-correction reached a similarly uncomfortable&lt;br&gt;
result:&lt;br&gt;
&lt;a href="https://arxiv.org/abs/2310.01798" rel="noopener noreferrer"&gt;"LLMs struggle to self-correct their responses without external feedback,&lt;br&gt;
and at times, their performance even degrades after&lt;br&gt;
self-correction."&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A reflection loop without fresh authority can repeatedly call a&lt;br&gt;
transformation over conclusions minted by the same process. It spends more&lt;br&gt;
tokens without necessarily moving closer to a semantic return condition.&lt;br&gt;
Confidence accumulates. Ground does not.&lt;/p&gt;

&lt;p&gt;The MAST taxonomy,&lt;br&gt;
&lt;a href="https://arxiv.org/html/2503.13657v3" rel="noopener noreferrer"&gt;1,642 annotated traces across seven&lt;br&gt;
frameworks&lt;/a&gt;, reported step repetition as&lt;br&gt;
its most frequent failure mode at 15.7 percent and unawareness of termination&lt;br&gt;
conditions third at 12.4 percent. A&lt;br&gt;
&lt;a href="https://arxiv.org/abs/2607.01641" rel="noopener noreferrer"&gt;July 2026 scan&lt;/a&gt; of 6,549 agent&lt;br&gt;
repositories reported 68 confirmed infinite-loop failures across 47 projects.&lt;/p&gt;

&lt;p&gt;Those studies report symptoms, not one proven mechanism. The recursion model&lt;br&gt;
offers a falsifiable engineering question that cuts across them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What input permits a successful return, and what termination argument — a&lt;br&gt;
ranking function, probabilistic bound, or bounded-failure contract — justifies&lt;br&gt;
another invocation?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If neither answer exists, the agent does not have a stopping condition.&lt;/p&gt;

&lt;p&gt;It has an allowance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix the first probability term
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;next_legal&lt;/code&gt; collapses entrance uncertainty only after position is valid.&lt;br&gt;
These rules repair the first term.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Type position completely.&lt;/strong&gt; Bind every position claim to item, stage,&lt;br&gt;
generation, invocation, goal/scope epoch, world/baseline epoch, authority, and&lt;br&gt;
terminal status. “In review” is not a position. It is one field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Freeze the datum within a generation.&lt;/strong&gt; Goal, scope, acceptance criteria,&lt;br&gt;
and verdict baseline do not float per lap. Findings outside the frozen line&lt;br&gt;
become new work. The loop may explore; it may not move its own finish line.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Expire the warranty across generations.&lt;/strong&gt; If a goal or world change&lt;br&gt;
invalidates the frame, the current invocation returns. New reality creates a&lt;br&gt;
new generation with a freshly derived datum. Old evidence remains history,&lt;br&gt;
never current authority. A fresh UUID is not enough unless the root obligation&lt;br&gt;
is retired or reduced.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Compute one entrance from that warranted position.&lt;/strong&gt; Only then should the&lt;br&gt;
runtime push &lt;code&gt;next_legal&lt;/code&gt;. Maximum turns, timeouts, and token ceilings remain&lt;br&gt;
circuit breakers: bounded failure, never completion.&lt;/p&gt;

&lt;p&gt;The architecture is simple to state:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;dynamic search inside an externally bounded generation, followed by an&lt;br&gt;
irreversible terminal barrier.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The outer service may run forever. The individual case must return.&lt;/p&gt;

&lt;p&gt;Freeze within the generation. Regenerate across it.&lt;/p&gt;

&lt;p&gt;Position first. Then one entrance.&lt;/p&gt;

&lt;h2&gt;
  
  
  The detector is structural. The boundary is honest.
&lt;/h2&gt;

&lt;p&gt;My scalar watchdogs slept through three days of recursion because every call&lt;br&gt;
did useful work. Real terminal semantics create a structural detector:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Any control edge that re-enters a generation after its terminal barrier is&lt;br&gt;
an alarm on first occurrence.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No threshold and no anomaly model. Provenance may connect a new repair to old&lt;br&gt;
work; history is supposed to remain connected. The alarm is for control flow&lt;br&gt;
that makes the terminal generation executable again. A second detector can&lt;br&gt;
watch user-facing work versus repair, diagnostic, and recovery rows. Structure&lt;br&gt;
catches the illegal call. Work mix shows the invoice.&lt;/p&gt;

&lt;p&gt;This is not new theory. Workflow&lt;br&gt;
&lt;a href="https://www.vdaalst.com/publications/p44.pdf" rel="noopener noreferrer"&gt;soundness property&lt;/a&gt; requires,&lt;br&gt;
among other things, that every case can terminate cleanly. A 2026 paper on&lt;br&gt;
agent execution graphs names&lt;br&gt;
&lt;a href="https://arxiv.org/pdf/2604.22446" rel="noopener noreferrer"&gt;"review loops that cycle indefinitely"&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My narrower contribution is the receipt: ambiguous policy compiled into a&lt;br&gt;
defended back-edge, successful repairs loaded the next call, template&lt;br&gt;
coordinates hid the depth, and the cost rendered as progress.&lt;/p&gt;

&lt;p&gt;The offending orbit is fixed. Bypassed generations now become terminal WAIVED&lt;br&gt;
after their audited barrier and remain available as history, never as a&lt;br&gt;
destination. The detector is not yet running.&lt;/p&gt;

&lt;p&gt;Its falsifiable test is a replay of the three-day ledger: fire on the first&lt;br&gt;
illegal re-entry and expose the work-mix ratio within hours. If it cannot, this&lt;br&gt;
article documents a diagnosis rather than a cure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop selling the missing return statement
&lt;/h2&gt;

&lt;p&gt;The field keeps asking how to make agents continue for longer.&lt;/p&gt;

&lt;p&gt;More context. More memory. More reflection. More retries. More graph steps.&lt;br&gt;
Larger recursion limits.&lt;/p&gt;

&lt;p&gt;That entire list assumes continuation is the scarce capability.&lt;/p&gt;

&lt;p&gt;It is not.&lt;/p&gt;

&lt;p&gt;Continuation is the part we standardized. Return is the missing half.&lt;/p&gt;

&lt;p&gt;Reliable control requires both terms of the earlier equation: serve a&lt;br&gt;
versioned, warranted position, then compute one legal entrance from it.&lt;br&gt;
&lt;code&gt;next_legal&lt;/code&gt; without position authority makes the wrong turn deterministic.&lt;br&gt;
Verified position without entrance collapse leaves a known transition to&lt;br&gt;
model sampling.&lt;/p&gt;

&lt;p&gt;Before you add another turn, name the input that permits a successful return.&lt;br&gt;
Before you raise a limit, state the ranking argument, probabilistic convergence&lt;br&gt;
bound, or bounded-failure contract that makes continued execution legal.&lt;br&gt;
Before you call a graph “controlled,” inspect whether a state the policy calls&lt;br&gt;
terminal remains executable.&lt;/p&gt;

&lt;p&gt;If you cannot answer those questions, tracing will only document the&lt;br&gt;
recursion. Memory will only preserve its arguments. Reflection will only add&lt;br&gt;
frames. A larger context window will only make the stack more comfortable.&lt;/p&gt;

&lt;p&gt;The model chooses the next call.&lt;/p&gt;

&lt;p&gt;The runtime counts the calls.&lt;/p&gt;

&lt;p&gt;The customer pays for the calls.&lt;/p&gt;

&lt;p&gt;Nobody owns the return.&lt;/p&gt;

&lt;p&gt;That is not autonomy. It is a missing base case with better marketing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It does not return. It bills.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The runtime described here is built in the open:&lt;br&gt;
&lt;a href="https://github.com/amingclawdev/aming-claw" rel="noopener noreferrer"&gt;github.com/amingclawdev/aming-claw&lt;/a&gt;.&lt;br&gt;
The internal numbers come from its governance ledger and git history. Earlier&lt;br&gt;
in this series:&lt;br&gt;
&lt;a href="https://dev.to/amingin_ai/fixing-ai-drift-is-a-simple-probability-problem-your-human-in-the-loop-is-a-very-expensive-gps-2pel"&gt;Fixing AI drift is a simple probability&lt;br&gt;
problem&lt;/a&gt;&lt;br&gt;
and&lt;br&gt;
&lt;a href="https://dev.to/amingin_ai/push-not-pull-your-ai-agent-shouldnt-fetch-its-own-context-2kkf"&gt;Push, not&lt;br&gt;
pull&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Fixing AI drift is a simple probability problem - Your human-in-the-loop is a very expensive GPS</title>
      <dc:creator>Aming</dc:creator>
      <pubDate>Tue, 21 Jul 2026 13:44:24 +0000</pubDate>
      <link>https://dev.to/amingin_ai/fixing-ai-drift-is-a-simple-probability-problem-your-human-in-the-loop-is-a-very-expensive-gps-2pel</link>
      <guid>https://dev.to/amingin_ai/fixing-ai-drift-is-a-simple-probability-problem-your-human-in-the-loop-is-a-very-expensive-gps-2pel</guid>
      <description>&lt;p&gt;&lt;em&gt;Your human-in-the-loop is a very expensive GPS.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Fixing AI drift is not an AI problem. It is a small probability problem —&lt;br&gt;
two variables and one multiplication — and it has an engineering solution&lt;br&gt;
that works at any model tier.&lt;/p&gt;

&lt;p&gt;Here is the entire theory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;P(correct step) = P(I know where I am) × 
                  P(I pick the right door | position)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every step an agent takes is the product of two estimates: whether it&lt;br&gt;
knows where it is, and whether it takes the right entrance from there. In&lt;br&gt;
most agent systems both factors sit quietly below 1.0. Multiply them&lt;br&gt;
across a long task and you get the failure everyone has watched: steps&lt;br&gt;
one through ten crisp, correct, fast; somewhere past the twentieth step&lt;br&gt;
the agent is still busy, still confident, still producing plausible work&lt;br&gt;
— and no longer doing the task you gave it.&lt;/p&gt;

&lt;p&gt;The field has a taxonomy for this (goal drift, role drift, plan decay,&lt;br&gt;
hallucination cascades) and a modern reliability stack against it: ReAct&lt;br&gt;
loops inside supervisor–worker hierarchies, goal re-anchoring,&lt;br&gt;
checkpointed state, and the four levers of context engineering — write,&lt;br&gt;
select, compress, isolate. I run that stack. One of my agents still&lt;br&gt;
drifted for 27 hours in the middle of it — nine locally correct decisions&lt;br&gt;
in a row while the project died underneath them. The stack failed for a&lt;br&gt;
structural reason, not a tuning one: every piece of it improves the&lt;br&gt;
agent's own &lt;em&gt;account&lt;/em&gt; of the two variables. None of it makes either&lt;br&gt;
variable true.&lt;/p&gt;

&lt;p&gt;What follows: the two variables, the 27-hour case that shows loops and&lt;br&gt;
memory don't cure them, and the system design that does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which door? — the entrance variable
&lt;/h2&gt;

&lt;p&gt;Start with the entrance variable, because it is the easier one. When a&lt;br&gt;
system offers several entrances — three ways to register, two documents&lt;br&gt;
that both claim authority, "you could do it either way" — the agent must&lt;br&gt;
reason about which to take, and reasoning is sampling: a deterministic&lt;br&gt;
event becomes a probabilistic one. Chain twenty such choices at P = 0.95&lt;br&gt;
each and the flow completes correctly 36% of the time. Nobody's model got&lt;br&gt;
dumber in step fourteen; the luck budget ran out. (I watched a frontier&lt;br&gt;
model, minutes after writing "index-first discovery" discipline into&lt;br&gt;
another agent's contract, ignore that discipline itself and go guessing&lt;br&gt;
with &lt;code&gt;find&lt;/code&gt; — the repo offered five entrances, including a queryable code&lt;br&gt;
graph, and its training prior picked. You cannot configure the sampling&lt;br&gt;
distribution. You can only remove the choice.)&lt;/p&gt;

&lt;p&gt;The arithmetic itself is by now folk wisdom — Utkarsh Kanwat's widely&lt;br&gt;
shared 2025 essay ran the same numbers to bet against agents outright,&lt;br&gt;
and the industry's standard responses are to shorten the chain and add&lt;br&gt;
human checkpoints. Both just lower N. The doors stay open.&lt;/p&gt;

&lt;p&gt;But the choice tax is roughly constant per step. It explains failure; it&lt;br&gt;
does not explain why failure &lt;em&gt;accelerates with task length&lt;/em&gt;. That is the&lt;br&gt;
position variable's job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where am I? — the position variable
&lt;/h2&gt;

&lt;p&gt;An agent's belief about where it is — which phase, which obligations are&lt;br&gt;
met, what has actually happened — comes, by default, from one source: its&lt;br&gt;
own context. Its memory of its own trajectory. In navigation terms, that&lt;br&gt;
is &lt;strong&gt;dead reckoning&lt;/strong&gt;: estimating position by accumulating your own&lt;br&gt;
movement log. And dead reckoning has a famous property — the error only&lt;br&gt;
grows. Nothing in the log ever removes accumulated uncertainty.&lt;/p&gt;

&lt;p&gt;This is why drift is a long-task disease. Entrance multiplicity taxes&lt;br&gt;
each step equally; position uncertainty &lt;em&gt;compounds across steps&lt;/em&gt;. Short&lt;br&gt;
tasks end before the estimate degrades. Long tasks are precisely the ones&lt;br&gt;
that outlive their own position estimate.&lt;/p&gt;

&lt;p&gt;A week of instrumented agent operation caught the mechanism three ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Position amnesia.&lt;/strong&gt; One session went through 105 context compactions
in a day; after every compaction the agent re-derived the same solutions
and re-hit the same errors. It hadn't lost skill. It had lost &lt;em&gt;place&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;False position beliefs.&lt;/strong&gt; A bounded worker wrote a status file
claiming it had started up, implemented, and committed — while the
server showed its startup rejected and no such commit existing. Not
strategic deception: its self-narrative had diverged from reality, and
self-narrative was its only position source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Position forks.&lt;/strong&gt; Two subsystems each held an authoritative opinion
of where one piece of work stood — "merged, done" versus "evidence
missing, unclosable." Same work, two positions, and every agent that
touched it inherited the fork.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a fourth variant — subtler than all three, able to hide inside&lt;br&gt;
a healthy-looking loop for a full day. It deserves the whole case study.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu55vngddw480j1tj4c02.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu55vngddw480j1tj4c02.png" alt="Every agent step = knows where it is × picks the right door; navigating by memory drifts, gate checkpoints snap back; five doors force guesses, one door removes the guess; the fix is a verified you-are-here and one door per room." width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The case: every finding real, the project dying anyway
&lt;/h2&gt;

&lt;p&gt;My governance system (&lt;a href="https://github.com/amingclawdev/aming-claw" rel="noopener noreferrer"&gt;aming-claw&lt;/a&gt;)&lt;br&gt;
runs AI coding agents under enforced contracts: every change needs a work&lt;br&gt;
item with acceptance criteria, evidence lands on an append-only timeline,&lt;br&gt;
and merges require independent QA from a separate agent identity. In&lt;br&gt;
early July it needed a bounded new capability: a CLI agent service to&lt;br&gt;
drive multiple vendors' models — Codex, Claude, local Ollama — from one&lt;br&gt;
machine without mixing up accounts.&lt;/p&gt;

&lt;p&gt;The implementer (a frontier coding model running as a governed worker)&lt;br&gt;
shipped a clean 997-line foundation in a morning. My adversarial QA agent&lt;br&gt;
— separate identity, explicit mandate to attack the work — found real&lt;br&gt;
gaps. Three fix rounds before lunch. Working exactly as designed. The&lt;br&gt;
next slice — a host-private registry for the profiles — was dispatched&lt;br&gt;
that evening.&lt;/p&gt;

&lt;p&gt;The next day, the registry hit review.&lt;/p&gt;

&lt;p&gt;Round one: &lt;strong&gt;FAIL&lt;/strong&gt; — genuine privacy and path-isolation gaps. Fair.&lt;br&gt;
Rework. Round two: &lt;strong&gt;FAIL&lt;/strong&gt; — a real hole in crash-cleanup logic. Also&lt;br&gt;
fair. Rework. Round three is where you should slow down and admire the&lt;br&gt;
findings: the reviewer proved the schema validation accepted behaviorally&lt;br&gt;
incompatible database objects, and demonstrated — by writing a SQLite&lt;br&gt;
trigger that silently inserted a shadow row — that registration reported&lt;br&gt;
success without rolling back the exact mutation set. Genuinely brilliant.&lt;br&gt;
&lt;strong&gt;FAIL.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By end of day: &lt;strong&gt;nine rejections, zero approvals.&lt;/strong&gt; All 818 tests green&lt;br&gt;
in every round. Not one finding wrong. Not one fix that made the system&lt;br&gt;
worse. Meanwhile the product package had not moved in 27 hours,&lt;br&gt;
review-driven work items outgrew product work 19 to 3, and the codebase&lt;br&gt;
was on its way from one thousand lines to a ten-thousand-line fortress&lt;br&gt;
guarding a feature that didn't exist yet. There was no round N where this&lt;br&gt;
converged: "find problems" is an objective with no finish line, and the&lt;br&gt;
pass bar silently rose to meet whatever the implementation survived — a&lt;br&gt;
ratchet with no release lever.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftgdw7l8h8hzxckafy9qj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftgdw7l8h8hzxckafy9qj.png" alt="Four review rounds, each worry reaching further past the agreed checklist line; nine rejections, zero approvals; fixed by judging only against the checklist." width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The intervention that broke the loop was one message: freeze the verdict&lt;br&gt;
baseline to the acceptance criteria that existed at dispatch; findings&lt;br&gt;
beyond that bar become new work items instead of failing the candidate;&lt;br&gt;
go back to the feature. Within 24 hours the same agents under the same&lt;br&gt;
governance shipped the daemon, the supervisor, the scheduler, and&lt;br&gt;
local-model certification. The capacity had been there the whole time.&lt;/p&gt;

&lt;p&gt;Now read the case through the theory. It is not a dumb agent, a bad&lt;br&gt;
reviewer, a missing memory, or a broken loop. The reviewer ran a textbook&lt;br&gt;
ReAct loop — observe, reason, act — under a supervisor, with externalized&lt;br&gt;
state on an evidence timeline. Every component of the modern reliability&lt;br&gt;
stack was present and functioning. What failed is the fourth position&lt;br&gt;
variant: &lt;strong&gt;reference-frame drift&lt;/strong&gt;. The reviewer always knew which&lt;br&gt;
candidate it was reviewing — its position &lt;em&gt;in memory&lt;/em&gt; was fine. What&lt;br&gt;
drifted was its measuring standard: the pass bar had no fixed datum, so&lt;br&gt;
its coordinate system moved a little every round, and every measurement&lt;br&gt;
remained internally consistent while the whole frame slid off the goal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the modern stack doesn't touch either variable
&lt;/h2&gt;

&lt;p&gt;Translate the current reliability stack into navigation terms:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Industry fix&lt;/th&gt;
&lt;th&gt;What it is, navigationally&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Longer context / memory&lt;/td&gt;
&lt;td&gt;A thicker logbook&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context engineering: write / select / compress&lt;/td&gt;
&lt;td&gt;Better-organized logbook, better retrieval, cleaner entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Isolate / subagents&lt;/td&gt;
&lt;td&gt;Shorter voyages (smaller error surface — real help)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Goal re-anchoring&lt;/td&gt;
&lt;td&gt;Re-reading the destination's name aloud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Checkpointed state / scratchpads&lt;/td&gt;
&lt;td&gt;A logbook the agent writes to disk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supervisor–worker hierarchy&lt;/td&gt;
&lt;td&gt;Splitting the voyage among navigators&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every one of these improves &lt;strong&gt;dead reckoning quality&lt;/strong&gt;. Not one provides&lt;br&gt;
a &lt;em&gt;verified position&lt;/em&gt;. Two properties are missing across the board, and&lt;br&gt;
each has a live counterexample above:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Externalized state is still self-authored state.&lt;/strong&gt; The worker with the&lt;br&gt;
false position beliefs &lt;em&gt;had&lt;/em&gt; a persisted status file — checkpointing par&lt;br&gt;
excellence. Externalization without verification just persists the&lt;br&gt;
delusion. A position claim is worth nothing unless something other than&lt;br&gt;
its author can reject it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The reference frame itself can drift.&lt;/strong&gt; The QA loop was locally correct&lt;br&gt;
nine times in a row and still captured the project, because no fix in&lt;br&gt;
that table anchors the &lt;em&gt;standard&lt;/em&gt; the loop measures against. A loop does&lt;br&gt;
not fix position; a loop compounds per-iteration bias.&lt;/p&gt;

&lt;p&gt;A lost navigator does not need a thicker logbook, a tidier logbook, or a&lt;br&gt;
committee of navigators comparing logbooks. He needs a position fix from&lt;br&gt;
outside the boat, against a datum that does not move.&lt;/p&gt;

&lt;h2&gt;
  
  
  The human in the loop was the position guide all along
&lt;/h2&gt;

&lt;p&gt;Which raises the obvious question: if the missing instrument is this&lt;br&gt;
fundamental, why hasn't a whole industry noticed? Because the standard&lt;br&gt;
mitigation hides it. Put a human in the loop and drift disappears — and&lt;br&gt;
everyone concluded the human was supplying &lt;em&gt;intelligence&lt;/em&gt;. Decompose&lt;br&gt;
what the human actually does at each check-in: "you're off track" — a&lt;br&gt;
position fix. "Not that one, this one" — an entrance collapse. And,&lt;br&gt;
rarely, "this framing is wrong, stop" — actual judgment. The first two&lt;br&gt;
are not intelligence work. They are manual position service: a human&lt;br&gt;
GPS, polled at human frequency, priced at engineer salary, degrading&lt;br&gt;
with boredom. Human-in-the-loop works precisely &lt;em&gt;because&lt;/em&gt; it is a&lt;br&gt;
hand-operated position guide — which is also why it cannot scale, and&lt;br&gt;
why it taught the industry the wrong lesson about what it was providing.&lt;/p&gt;

&lt;p&gt;The agent never needed the human's intellect at those check-ins; my&lt;br&gt;
drifted reviewer was doing genuinely brilliant work — inventing trigger&lt;br&gt;
attacks — while lost. It needed the human's &lt;em&gt;coordinates&lt;/em&gt;. And two of&lt;br&gt;
the three services the human provides are mechanical: a runtime can&lt;br&gt;
serve position and entrance at every step, instantly, identically at&lt;br&gt;
step 3 and step 3,000, without fatigue and without a salary. That is&lt;br&gt;
the real argument for systematizing the loop — not that the machine is&lt;br&gt;
smarter than the human, but that most of what the human does there was&lt;br&gt;
never a judgment task to begin with.&lt;/p&gt;

&lt;p&gt;The third service is the one that must stay human — and concentrating&lt;br&gt;
the human there is the point. My 27-hour ratchet was broken by a human&lt;br&gt;
sentence no guide could have pre-written, because the pathology was&lt;br&gt;
being encountered for the first time. But watch what happened next: the&lt;br&gt;
judgment was encoded — baseline freeze — and the runtime now enforces it&lt;br&gt;
forever. The human never makes that call again. That is the one ratchet&lt;br&gt;
you actually want: every repeated human intervention is a system defect;&lt;br&gt;
every judgment call becomes a rule; the human's mechanical workload&lt;br&gt;
falls toward zero while their attention concentrates on the calls no&lt;br&gt;
system can pre-write. A bored human rubber-stamping fifty checkpoints is&lt;br&gt;
not safety — it is a position guide running at 0.1 Hz with an attention&lt;br&gt;
problem. One focused human making three genuine judgment calls a week,&lt;br&gt;
on top of a runtime that handles the other two variables per step, is&lt;br&gt;
both faster &lt;em&gt;and&lt;/em&gt; safer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution: a role-bound position guide
&lt;/h2&gt;

&lt;p&gt;The system I run converged on a cure I can now name properly: &lt;strong&gt;give&lt;br&gt;
every agent, at every step, an external, verified, role-bound answer to&lt;br&gt;
"where are you" — measured against a frozen datum, and pushed to the&lt;br&gt;
agent rather than waiting to be fetched.&lt;/strong&gt; Five properties, each earned&lt;br&gt;
from a live failure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;External.&lt;/strong&gt; Position comes from the runtime's contract authority — a
first-missing-line service that answers "given everything actually
accepted so far, here is where you stand and the one legal next
action." The agent's context is commentary; the runtime's answer is
position. When an agent dies mid-task, its successor does not need the
predecessor's memories — it re-fixes position from the timeline and
continues. We have resurrected agents twice this way. Recovery is
re-fixing, not remembering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verified.&lt;/strong&gt; Positions are earned, not declared. You are not "past
startup" because you say so; you are past startup because the gate
accepted your startup evidence. Every gate is a landmark fix that
resets accumulated estimation error to zero. A gate, seen this way, is
not a wall — it is an odometer reset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role-bound.&lt;/strong&gt; "Where am I" has no role-free answer. The worker's
position is the next contract line; the reviewer's position is the
candidate commit it is bound to; the orchestrator's position is the
lane phase. Serving one undifferentiated state dump forces each agent
to reason out its own slice — reintroducing the choice tax through the
back door.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Datum-frozen.&lt;/strong&gt; The standards an agent is measured against are
pinned at dispatch time and hashed. Discovery of new concerns is
welcome — as new work items, never as silent movement of the current
bar. This is what fixed the ratchet: adversarial review kept its
teeth, but its intensity became a controlled parameter (full battery
on round one; rounds two and up re-verify only prior failures against
the frozen baseline) instead of an unbounded objective.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pushed, not pulled.&lt;/strong&gt; This one the theory itself forces. Consulting
the map is one more door, and the probability an agent walks through
it collapses exactly when it matters most: pulling requires the agent
to know it is lost and to know what to fetch — precisely the judgment
drift has already corroded. The evidence is brutal. Handed a code
dependency graph as a tool and left to pull from it, agents in one
benchmark made zero calls to it in 58% of trials (CodeCompass, arXiv
2602.20048); the frontier model from my entrance anecdote had exactly
that instrument available and went guessing anyway. Position is not a
tool the agent may call. It is what the runtime serves with every
step, before the agent acts. I have argued this delivery half
separately as &lt;a href="https://dev.to/amingin_ai/push-not-pull-your-ai-agent-shouldnt-fetch-its-own-context-2kkf"&gt;"push, not pull"&lt;/a&gt;
— the two-variable theory is why it is not a style preference.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Put together, a guided step becomes a navigation loop older than&lt;br&gt;
software: &lt;strong&gt;fix your position → take the one indicated heading → confirm&lt;br&gt;
at the checkpoint → new fix.&lt;/strong&gt; The agent supplies intelligence inside&lt;br&gt;
each leg; the system supplies certainty about the map.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who guards the guide
&lt;/h2&gt;

&lt;p&gt;One instrument remains, and my case earned it the hard way: the ratchet&lt;br&gt;
happened &lt;em&gt;inside&lt;/em&gt; a guided runtime — every round procedurally legal, the&lt;br&gt;
guide correctly serving position within a frame that was itself sick. A&lt;br&gt;
guide cannot see its own frame drift from inside. But every drift&lt;br&gt;
pathology I have logged, whatever its mechanism, shares one&lt;br&gt;
machine-readable symptom: &lt;strong&gt;activity without progress.&lt;/strong&gt; Sailors&lt;br&gt;
distinguish speed through water from speed over ground — my reviewer had&lt;br&gt;
enormous speed through water (nine brilliant rounds, thousands of new&lt;br&gt;
test lines) and zero speed over ground for 27 hours. You cannot&lt;br&gt;
pre-write a detector for a disease you have not met; you can pre-write&lt;br&gt;
the fever thermometer, because the fever is generic even when the&lt;br&gt;
pathogen is novel.&lt;/p&gt;

&lt;p&gt;So the mechanism now being encoded from this case: when rounds&lt;br&gt;
accumulate and progress toward the dispatched objective stays flat, the&lt;br&gt;
runtime pushes the aggregate view into the loop — round count, product&lt;br&gt;
movement, the frozen baseline — and demands a self-audit anchored&lt;br&gt;
against it. Not "are you drifting?" (a drifted agent answers "every&lt;br&gt;
finding is real," and it's true); instead, the panorama the agent&lt;br&gt;
structurally cannot see from inside, with the burden of justifying&lt;br&gt;
another round against the dispatch baseline. If the stall survives,&lt;br&gt;
escalate to the human. Note what this automates: the glance that saved&lt;br&gt;
my project. Noticing the flat line was the mechanical half of my&lt;br&gt;
intervention — only the reframe was judgment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The boundary that keeps this from becoming a cage
&lt;/h2&gt;

&lt;p&gt;Some choices are mechanical: the right branch is knowable in advance, and&lt;br&gt;
leaving it open is pure probability tax. Collapse those without mercy.&lt;br&gt;
But some choices &lt;em&gt;are the work&lt;/em&gt;: which frame fits a novel failure, what&lt;br&gt;
is worth building, when a rule itself is sick. Collapse those and you&lt;br&gt;
have built a workflow engine that confidently does the wrong thing. Spend&lt;br&gt;
judgment only where judgment is irreplaceable — and the test is whether&lt;br&gt;
you could have written the correct choice down before the agent arrived.&lt;/p&gt;

&lt;h2&gt;
  
  
  Old wisdom, new constraints
&lt;/h2&gt;

&lt;p&gt;Manufacturing calls the entrance half poka-yoke — design the fixture so&lt;br&gt;
the part only fits the right way. Robotics calls the position half SLAM —&lt;br&gt;
nobody trusts odometry alone; everybody fuses in landmark fixes. Type&lt;br&gt;
systems call it "make illegal states unrepresentable." We did not invent&lt;br&gt;
the idea that reliability lives in the environment's topology rather than&lt;br&gt;
the operator's skill.&lt;/p&gt;

&lt;p&gt;Three things are new when the operator is an LLM agent. First, the&lt;br&gt;
operator is a probabilistic reasoner you cannot configure — an agent's&lt;br&gt;
choice among entrances is sampled from a training-shaped distribution;&lt;br&gt;
the entrance anecdote above is this in miniature. Environment topology is&lt;br&gt;
the only reliability lever you actually hold. Second, the single entrance&lt;br&gt;
can be dynamic — a guided runtime recomputes the one legal next action per&lt;br&gt;
step, per role, per state; rails that move with the work, which is what&lt;br&gt;
separates this from the static workflow engines the 2000s buried. Third,&lt;br&gt;
it is finally measurable: entrance counts per flow, position-loss&lt;br&gt;
incidents per compaction, divergence between claimed and verified&lt;br&gt;
position, preventable gate rejections. Drift stops being a vibe and&lt;br&gt;
becomes a dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  The conclusion, restated
&lt;/h2&gt;

&lt;p&gt;The agent field has spent two years making dead reckoning excellent:&lt;br&gt;
smarter loops, richer memory, disciplined context, hierarchical crews.&lt;br&gt;
And long tasks keep drifting, because none of it was ever the missing&lt;br&gt;
instrument. (Princeton's recent agent-reliability study measured the&lt;br&gt;
decoupling directly: across 24 months of frontier releases, capability&lt;br&gt;
climbed while reliability plateaued — for every vendor.) My drifted&lt;br&gt;
reviewer ran the full modern stack and failed in a way invisible from&lt;br&gt;
inside the loop, because every fix on that list shares one assumption:&lt;br&gt;
&lt;strong&gt;that the agent's account of where it is can be trusted.&lt;/strong&gt; It can't —&lt;br&gt;
not because agents lie, but because self-estimated position compounds&lt;br&gt;
error by construction, at any intelligence level.&lt;/p&gt;

&lt;p&gt;Drift is compounding position uncertainty multiplied by per-step choice&lt;br&gt;
sampling. Both variables live in your system's topology, not in the&lt;br&gt;
model's weights, and neither yields to a better model or a better loop.&lt;/p&gt;

&lt;p&gt;Don't give your agents a longer logbook or a faster loop. Give them a&lt;br&gt;
map with a verified you-are-here dot — pushed into their hands at every&lt;br&gt;
step, because a lost agent never asks for directions — and make sure the&lt;br&gt;
map has only one door per room.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The runtime described here is being built in the open:&lt;br&gt;
&lt;a href="https://github.com/amingclawdev/aming-claw" rel="noopener noreferrer"&gt;github.com/amingclawdev/aming-claw&lt;/a&gt;.&lt;br&gt;
Every number in this article — the nine rejections, the 27-hour freeze,&lt;br&gt;
the 818 green tests — comes from its governance timeline and git&lt;br&gt;
history. The system is iterating from pull to push; a stable version&lt;br&gt;
will follow. If you run agents on long tasks and want the two variables&lt;br&gt;
on a dashboard instead of in a postmortem, watch the repo.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>htl</category>
      <category>automation</category>
    </item>
    <item>
      <title>Push, not pull: your AI agent shouldn't fetch its own context</title>
      <dc:creator>Aming</dc:creator>
      <pubDate>Wed, 01 Jul 2026 16:04:20 +0000</pubDate>
      <link>https://dev.to/amingin_ai/push-not-pull-your-ai-agent-shouldnt-fetch-its-own-context-2kkf</link>
      <guid>https://dev.to/amingin_ai/push-not-pull-your-ai-agent-shouldnt-fetch-its-own-context-2kkf</guid>
      <description>&lt;p&gt;&lt;em&gt;The guided runtime — push, not pull.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Status: public draft for Dev.to. Public-safe. A &lt;em&gt;thesis&lt;/em&gt; with early, observational&lt;br&gt;
evidence — not a validated result. The controlled experiment is at the end, and&lt;br&gt;
the number will follow.&lt;/p&gt;




&lt;h2&gt;
  
  
  I watched my agent slowly lose the thread
&lt;/h2&gt;

&lt;p&gt;I'm building a system that got complex. Many entry points. Interfaces that call&lt;br&gt;
interfaces. Docs, contracts, and conventions scattered across the repo. The kind of&lt;br&gt;
codebase where &lt;em&gt;you&lt;/em&gt; need a minute to remember how a piece fits.&lt;/p&gt;

&lt;p&gt;So I'd hand an agent a task and watch. It would start fine. Then, a dozen steps in,&lt;br&gt;
it would begin to slip — re-deriving where it was, missing an interface it had&lt;br&gt;
already seen, grepping for a doc it had read an hour ago, patching a symptom,&lt;br&gt;
hitting the same wall, patching again. It never stopped to ask whether its whole&lt;br&gt;
approach was wrong. It just kept grinding, locally, until it ran out of road.&lt;/p&gt;

&lt;p&gt;I did the obvious thing. I improved the context: better indexing, embeddings,&lt;br&gt;
retrieval, a repo map, a search tool. Give the agent more ways to &lt;em&gt;find&lt;/em&gt; what it&lt;br&gt;
needs.&lt;/p&gt;

&lt;p&gt;It barely helped. And that's when I realized I was solving the wrong problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Everyone's solving the wrong problem
&lt;/h2&gt;

&lt;p&gt;Grep, RAG, repo-maps, semantic search — they're useful. I still use them. But&lt;br&gt;
they mainly make more &lt;strong&gt;information&lt;/strong&gt; available. And the dominant assumption is&lt;br&gt;
that the agent fails because it doesn't &lt;em&gt;know&lt;/em&gt; enough about the system.&lt;/p&gt;

&lt;p&gt;But watch a capable model fail on a long task and that's not what you see. Given&lt;br&gt;
the right frame, the same model executes long, correct, disciplined chains without&lt;br&gt;
complaint. It doesn't lack intelligence, and on my codebase it didn't lack&lt;br&gt;
information — it had a search tool pointed at everything.&lt;/p&gt;

&lt;p&gt;It gets lost because it &lt;strong&gt;cannot hold its place&lt;/strong&gt; in a complex system across a long&lt;br&gt;
horizon. That's an &lt;strong&gt;attention&lt;/strong&gt; problem, not just an information problem.&lt;br&gt;
Retrieval helps the fact layer; it does not, by itself, control attention. Worse:&lt;br&gt;
pull asks an already-drifting model to do the exact thing drift has corroded —&lt;br&gt;
navigate the system, decide what's relevant, and assemble its own context. Hand&lt;br&gt;
agents a precise structural tool and leave it optional, and they often don't even&lt;br&gt;
reach for it. They're lost. Being lost is what makes you unable to know what to&lt;br&gt;
fetch.&lt;/p&gt;

&lt;p&gt;We've been answering the wrong question.&lt;/p&gt;

&lt;h2&gt;
  
  
  The flip: push, not pull
&lt;/h2&gt;

&lt;p&gt;If the agent can't be trusted to &lt;em&gt;find&lt;/em&gt; its context, stop making it. Have the&lt;br&gt;
runtime &lt;strong&gt;compute the next step and push it&lt;/strong&gt; — into the loop, before the agent&lt;br&gt;
acts.&lt;/p&gt;

&lt;p&gt;That's the whole move: &lt;strong&gt;push, not pull.&lt;/strong&gt; I stopped building a better library for&lt;br&gt;
the agent to search and started building a thing that &lt;em&gt;tells the agent where it is&lt;br&gt;
and what's legal next, every step.&lt;/em&gt; I call it a &lt;strong&gt;guided runtime&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's defined by what it is &lt;em&gt;not&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not retrieval as the control loop.&lt;/strong&gt; Search still exists, but it becomes a
fact-layer tool. The agent shouldn't have to decide, while drifting, what
context to assemble before every action.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not error-feedback (post-hoc).&lt;/strong&gt; Not "you ran the tests, they failed, fix it."
It fires &lt;em&gt;before&lt;/em&gt; the action, to keep the trajectory on the rails rather than
drag it back after it leaves them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a one-shot plan.&lt;/strong&gt; It's recomputed every step from current state, not read
off a plan written once at the start.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The mechanism — Facts + Rules → Guide
&lt;/h2&gt;

&lt;p&gt;A guided runtime factors into three layers. Only the outer two are&lt;br&gt;
domain-specific; the middle engine is reusable.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Facts&lt;/strong&gt; — a fresh, queryable model of ground truth. For code, a &lt;em&gt;commit-bound&lt;/em&gt;
dependency/symbol graph. Generally: a projection over an append-only event log
(event sourcing). Current state is the fold of events pinned to an explicit
watermark. If the world has moved beyond that watermark, the runtime can say so
instead of pretending its snapshot is omniscient.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rules&lt;/strong&gt; — the plan, compiled into something &lt;em&gt;checkable&lt;/em&gt;. This is the
load-bearing idea: &lt;strong&gt;a contract is a plan made verifiable.&lt;/strong&gt; Where a plan says
"implement the feature and add tests," a contract says: these files are the fence,
these acceptance predicates must hold, these actions are allowed and these
forbidden, this evidence must exist before done.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guide&lt;/strong&gt; — &lt;code&gt;guide = rules ∘ facts&lt;/code&gt;. Evaluate the rules against the facts and emit
the steering signal: the next legal action, the missing piece, a drift alert, a
blocked action. The guide tells; gates enforce. Evidence still has to be written
by the right actor, and authoritative gates decide what can close.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;If this smells familiar, good: it's the classic &lt;strong&gt;facts + rules → inference&lt;/strong&gt;&lt;br&gt;
architecture — production rule engines, &lt;strong&gt;policy-as-code&lt;/strong&gt; (evaluate policy over&lt;br&gt;
input facts → a decision), event sourcing / CQRS. The engine rests on decades of&lt;br&gt;
battle-tested ground. The novelty isn't the engine.&lt;/p&gt;

&lt;p&gt;What does the runtime actually push? Not just a paragraph of advice. A usable&lt;br&gt;
guide looks like an envelope: current contract id, actor role, allowed and&lt;br&gt;
blocked actions, next legal action, required evidence, a payload skeleton, the&lt;br&gt;
state watermark it was computed from, and the gate that will verify it. The&lt;br&gt;
important thing is that the agent no longer has to re-infer "where am I and what&lt;br&gt;
is legal now?" from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I didn't expect: this isn't about code
&lt;/h2&gt;

&lt;p&gt;The guide engine — &lt;code&gt;rules ∘ facts&lt;/code&gt; — is &lt;strong&gt;domain-independent.&lt;/strong&gt; Code is just the&lt;br&gt;
instance where the fact layer is easy (a commit and its dependency graph are free).&lt;/p&gt;

&lt;p&gt;To stand a guided runtime up in &lt;em&gt;any&lt;/em&gt; complex agent-workflow domain — an ops&lt;br&gt;
runbook, an insurance-claims pipeline, a multi-step business process — you supply&lt;br&gt;
exactly two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A fact-layer tool&lt;/strong&gt; that extracts ground truth as an event-sourced projection
(most business state is &lt;em&gt;lower&lt;/em&gt;-churn than code — it changes at discrete,
modelable transition points, which makes the fact layer &lt;em&gt;cheaper&lt;/em&gt; than for code,
not harder).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The rules&lt;/strong&gt; — the domain's plans compiled into checkable contracts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then the same guided runtime steers the agent: it pushes the right next step, the&lt;br&gt;
right gate verifies the result, and the system escalates only when the contract&lt;br&gt;
can't resolve it. The hard part — and the only per-domain cost — is the&lt;br&gt;
&lt;em&gt;modeling&lt;/em&gt;: choosing the events and writing the checkable rules. Everything else&lt;br&gt;
is reused. The machine is general; the modeling is where human judgment goes.&lt;/p&gt;

&lt;p&gt;That's the bet that makes this more than a coding trick: &lt;strong&gt;a guided runtime is a&lt;br&gt;
general way to keep an agent on-trajectory through any complex business you can&lt;br&gt;
model as facts + rules.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let me be honest about novelty
&lt;/h2&gt;

&lt;p&gt;Every ingredient is prior art. Continuous, structure-derived steering of the next&lt;br&gt;
action is old (grounded decoding, value-guided action selection in robotics).&lt;br&gt;
State-machine-driven context injection into an LLM is old. The facts+rules engine&lt;br&gt;
is older. Event sourcing is decades old.&lt;/p&gt;

&lt;p&gt;The bet is the &lt;strong&gt;synthesis&lt;/strong&gt;: push (not pull) + structure-derived from a contract&lt;br&gt;
over a freshness-pinned, event-projected fact model + as the &lt;em&gt;primary anti-drift&lt;br&gt;
control&lt;/em&gt; for an autonomous agent. As far as I can find, no one has fused exactly&lt;br&gt;
that — and several lines of work are converging on it right now, which I take as a&lt;br&gt;
sign the frame is right.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does it work?
&lt;/h2&gt;

&lt;p&gt;Here's where I keep myself honest, because the internet is full of "new paradigm&lt;br&gt;
solves everything" posts and I don't want to write one.&lt;/p&gt;

&lt;p&gt;I built this as a governance layer for coding agents — &lt;strong&gt;&lt;a href="https://github.com/amingclawdev/aming-claw" rel="noopener noreferrer"&gt;Aming Claw&lt;/a&gt;&lt;/strong&gt; (public; it's dogfooding on itself, so expect churn) — and dogfooded it hard. The&lt;br&gt;
observational signal is genuinely encouraging: as the runtime stabilized, the&lt;br&gt;
pathological stuck-loops became visible earlier, and several paths that used to&lt;br&gt;
die in a thrash of repeated blockers started converging cleanly. Some&lt;br&gt;
multi-worker paths that had been painful began to run through the contract&lt;br&gt;
instead of through operator memory.&lt;/p&gt;

&lt;p&gt;I will &lt;strong&gt;not&lt;/strong&gt; call that validated. It's observational, not controlled. The work&lt;br&gt;
was longitudinal: the architecture, the bug fixes, and my own guidance all changed&lt;br&gt;
at once, so I cannot yet cleanly separate the &lt;em&gt;runtime's&lt;/em&gt; effect from the&lt;br&gt;
&lt;em&gt;operator's&lt;/em&gt;. Encouraging trajectory, unproven causality. If anyone shows you a&lt;br&gt;
trend like this and calls their paradigm "validated," they're selling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where it actually is today: mid-migration from pull to push.&lt;/strong&gt; The guide does not&lt;br&gt;
yet compute every legal step. Where a contract hasn't modeled the situation, the&lt;br&gt;
agent still falls back to pulling context and reasoning its way through — and that's&lt;br&gt;
by design during the build. Push doesn't abolish pull; it &lt;em&gt;aims&lt;/em&gt; it, and right now a&lt;br&gt;
lot of the space still isn't aimed. Each iteration moves more of it from&lt;br&gt;
&lt;em&gt;agent-pulls&lt;/em&gt; to &lt;em&gt;runtime-pushes&lt;/em&gt; as more gets modeled into facts and rules. I'm&lt;br&gt;
publishing the thesis now, mid-iteration and openly unstable. Once the push path&lt;br&gt;
converges and the pull fallback shrinks to the genuinely-novel edge, I'll cut a&lt;br&gt;
&lt;strong&gt;stable release&lt;/strong&gt; — and run the experiment below against &lt;em&gt;that&lt;/em&gt;, not against&lt;br&gt;
today's moving target.&lt;/p&gt;

&lt;p&gt;So here's the experiment I'm running next, and the number I'll publish:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Operator-free, logged as such&lt;/strong&gt; — so the runtime's effect is isolated from mine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Same model, guided runtime on vs off&lt;/strong&gt;, plus a strong baseline scaffold — a
fixed-model ablation, so the delta is attributable to the harness, not the model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An external, objective benchmark&lt;/strong&gt; with a third-party metric and verified
trajectories — not my own success gate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drift/completion delta, stratified by task length&lt;/strong&gt; — because the thesis is
that the overhead loses on short tasks and the anti-drift wins on long ones. The
crossover &lt;em&gt;is&lt;/em&gt; the claim.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If it shows what I think it shows, I'll post the number. If it doesn't, that's&lt;br&gt;
worth knowing too.&lt;/p&gt;

&lt;h2&gt;
  
  
  The frame, in one line
&lt;/h2&gt;

&lt;p&gt;Your agent isn't lost because it lacks context. It's lost because it can't hold its&lt;br&gt;
place. So stop making search the control loop — &lt;strong&gt;push, not pull&lt;/strong&gt;: build a guided&lt;br&gt;
runtime that computes the next step as &lt;code&gt;rules ∘ facts&lt;/code&gt; and hands it to the agent&lt;br&gt;
before it acts. It works for code today; the same shape should work for any&lt;br&gt;
complex workflow you can model as facts and rules.&lt;/p&gt;

&lt;p&gt;Tell me where it's wrong.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>code</category>
      <category>automation</category>
    </item>
    <item>
      <title>Route Context: How I Built Right Context for Agents</title>
      <dc:creator>Aming</dc:creator>
      <pubDate>Sat, 30 May 2026 12:28:20 +0000</pubDate>
      <link>https://dev.to/amingin_ai/route-context-how-i-built-right-context-for-agents-3i1</link>
      <guid>https://dev.to/amingin_ai/route-context-how-i-built-right-context-for-agents-3i1</guid>
      <description>&lt;p&gt;&lt;em&gt;We already knew agents needed the right context. Dogfood taught us the harder problem: making that context live, visible, auditable, and enforceable inside a multi-agent workflow.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The failure looked like success.&lt;/p&gt;

&lt;p&gt;A worker changed one file. The focused test passed. The patch was small, readable, and locally correct. If you only looked at the worker's report, the job was done.&lt;/p&gt;

&lt;p&gt;But the overall job was still wrong.&lt;/p&gt;

&lt;p&gt;The change touched a permission-sensitive path. It needed evidence that the right role had acted, that the project map still matched the code, that the audit trail could explain why the edit was allowed, and that the final close check had not been skipped. Instead, the system had solved the nearest local problem. A lane that should have preserved the shape of the work had drifted into implementation. The worker had completed its tiny job, while the whole route had lost its meaning.&lt;/p&gt;

&lt;p&gt;Nobody had to make a dramatic mistake for this to happen. That was the unsettling part. The worker was not lazy. The test was not fake. The prompt was not empty. The system had plenty of context. It just did not have route context.&lt;/p&gt;

&lt;p&gt;Route context is the per-task, per-lane runtime packet that tells an agent what job it is in, what role it has, what it saw, what it cannot do, and what evidence must pass before the work is done.&lt;/p&gt;

&lt;p&gt;That is the positioning of this article. I am not trying to convince technical readers that right context matters. Most people building with agents have already learned that, usually the hard way. The point is how we made right context operational for agent development: route context, a live artifact that turns the principle into prompt-visible, hashable, auditable, gate-checkable workflow state.&lt;/p&gt;

&lt;p&gt;We started with a different hope. We wanted agent development to feel zero-orchestration-ish: the user says what they want, the system understands the work, the right agents handle the right pieces, and nobody has to manually conduct a meeting of subagents. The observer would keep things coherent. Workers would implement. Review lanes would check evidence. Validation would catch bad finishes.&lt;/p&gt;

&lt;p&gt;Then we used it on ourselves.&lt;/p&gt;

&lt;p&gt;Again and again, the same failure appeared in different clothes. The observer would begin correctly, then collapse into a nearby code edit. A worker would pass a test, but not satisfy the larger obligation. A reviewer would evaluate plausible reasoning, but not the same evidence the worker actually produced. A prompt would contain lots of useful system knowledge, but not the specific promises this worker had to satisfy.&lt;/p&gt;

&lt;p&gt;That is when the thesis became operational: AI agent development needs right context, not more context, and route context is how we made that sentence executable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Words We Needed
&lt;/h2&gt;

&lt;p&gt;We had to translate our internal language into something simple enough to survive a live task.&lt;/p&gt;

&lt;p&gt;Topology means what kind of job this really is. Is this a tiny deterministic bug fix, a permission change, a runtime change, a graph update, a public decision, or a mixed task that needs independent lanes?&lt;/p&gt;

&lt;p&gt;A contract is the set of promises a worker must satisfy: target files, acceptance criteria, out-of-scope areas, allowed actions, blocked actions, and evidence to return.&lt;/p&gt;

&lt;p&gt;A gate is a check that prevents a false finish. A test can be a gate, but it is not the only one. A close gate may reject a change because the audit evidence is missing, the runtime was not redeployed, the project map is stale, or the wrong role acted.&lt;/p&gt;

&lt;p&gt;Graph, backlog, timeline, and contract are the governance layers that preserve project state, user intent, execution evidence, and allowed action. The graph is the project map. The backlog records the work and acceptance criteria. The timeline records what happened. The contract says what this lane may do.&lt;/p&gt;

&lt;p&gt;Once those words were clear, the bug was easier to see. Our static skill text explained the system, but the live task needed route context: the current path through the work, with the role, lane, injected context, and checks bound to the action about to happen.&lt;/p&gt;

&lt;p&gt;Static skill text is only a bootloader. It can teach the agent that observers, workers, review lanes, graphs, and gates exist. It cannot reliably decide what matters for this task, this lane, this file, this permission boundary, and this moment. Route context is the runtime packet assembled for that decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Route Context Artifact
&lt;/h2&gt;

&lt;p&gt;The useful fix was not a bigger prompt. It was a route context alert: a small implementation artifact generated before lane dispatch, during topology classification and prompt-contract assembly. It describes what the lane is allowed to do, what was injected into its prompt, and what evidence will be checked later.&lt;/p&gt;

&lt;p&gt;A simplified route context alert looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;route_context_alert&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;task_intent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fix&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;permission&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;handling&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;without&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;changing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;audit&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;policy"&lt;/span&gt;
  &lt;span class="na"&gt;role_boundary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;implementation&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;worker;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;no&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;merge,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;close,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;or&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;graph&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mutation"&lt;/span&gt;
  &lt;span class="na"&gt;topology&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;permission-sensitive&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bug;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;requires&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;independent&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;review"&lt;/span&gt;
  &lt;span class="na"&gt;contract&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;edit&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;accepted&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;file;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;focused&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;test;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;report&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;evidence"&lt;/span&gt;
  &lt;span class="na"&gt;blocked_actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;change&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;route&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;policy"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;close&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;backlog"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;redeploy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;runtime"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;visible_injection_manifest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;route_doc@sha256:..."&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contract@sha256:..."&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;evidence_gates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;focused_test"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;independent_validation"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;close_gate"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not magic model control. The model can still misunderstand things. The point is that the important context is visible in the prompt, listed in an audit manifest, and tied to workflow checks that can reject a false finish.&lt;/p&gt;

&lt;p&gt;The visible injection manifest was especially important. If a document, decision summary, expert note, or implementation contract influences a lane, it should appear in the manifest with an id, kind, source reference, and hash. The hash proves the identity of the injected artifact. Gates and evidence decide whether the lane satisfied the contract. Without the manifest, nobody can reconstruct what the agent actually saw.&lt;/p&gt;

&lt;p&gt;Route context gave us a way to keep orchestration minimal without making it invisible. The system still feels close to zero-orchestration from the user's side, but the route carries enough explicit structure that lanes do not silently blend together.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Implementation Pattern In Aming Claw
&lt;/h2&gt;

&lt;p&gt;This is not only language we use around the system. Aming Claw implements the pattern as code-level contracts, local gates, audited queries, and append-only evidence.&lt;/p&gt;

&lt;p&gt;The route prompt contract is source-controlled in the &lt;a href="https://github.com/amingclawdev/aming-claw/blob/32f47d11f81d85b1fd4d50dddaa5389990ca4513/agent/governance/contract_templates/mf_workflow_runtime.v1.json#L12-L55" rel="noopener noreferrer"&gt;&lt;code&gt;mf_workflow_runtime.v1.json&lt;/code&gt; template&lt;/a&gt;. That contract makes route-owned prompt context explicit: the injected artifacts are listed in a visible manifest, observer and review lanes are blocked from drifting into implementation, and the worker has to carry matching &lt;code&gt;route_context_hash&lt;/code&gt;, &lt;code&gt;prompt_contract_id&lt;/code&gt;, and &lt;code&gt;prompt_contract_hash&lt;/code&gt; values. In other words, the prompt is no longer just a bag of helpful text. It has identity.&lt;/p&gt;

&lt;p&gt;Before a bounded worker is handed the job, Aming Claw runs a local dispatch gate in &lt;a href="https://github.com/amingclawdev/aming-claw/blob/32f47d11f81d85b1fd4d50dddaa5389990ca4513/agent/governance/mf_subagent_contract.py#L859-L1031" rel="noopener noreferrer"&gt;&lt;code&gt;mf_subagent_contract.py&lt;/code&gt;&lt;/a&gt;. The gate checks the worker's branch, worktree, base commit, target head, merge queue, fence token, route hash, prompt hash, and owned files. Same-worktree dispatch is blocked by default because "please stay in this directory" is not a boundary. The boundary has to be represented in durable facts the system can re-check.&lt;/p&gt;

&lt;p&gt;When the worker returns, the finish gate in the same module treats the response as a claim, not as truth. The &lt;a href="https://github.com/amingclawdev/aming-claw/blob/32f47d11f81d85b1fd4d50dddaa5389990ca4513/agent/governance/mf_subagent_contract.py#L1191-L1249" rel="noopener noreferrer"&gt;&lt;code&gt;finish validation&lt;/code&gt;&lt;/a&gt; requires the fence token to match, tests to pass, blockers to be absent, a checkpoint id to exist, and the worker identity to still match the handoff. This is the difference between "the agent says it is done" and "the route can safely advance."&lt;/p&gt;

&lt;p&gt;The audit trail follows the same idea. The &lt;a href="https://github.com/amingclawdev/aming-claw/blob/32f47d11f81d85b1fd4d50dddaa5389990ca4513/agent/governance/task_timeline.py#L1-L7" rel="noopener noreferrer"&gt;&lt;code&gt;task_timeline.py&lt;/code&gt; module&lt;/a&gt; is append-only execution evidence. Its close gate expects the route to have the right event kinds: &lt;a href="https://github.com/amingclawdev/aming-claw/blob/32f47d11f81d85b1fd4d50dddaa5389990ca4513/agent/governance/task_timeline.py#L93-L97" rel="noopener noreferrer"&gt;&lt;code&gt;implementation&lt;/code&gt;, &lt;code&gt;verification&lt;/code&gt;, and &lt;code&gt;close_ready&lt;/code&gt;&lt;/a&gt;. The later &lt;a href="https://github.com/amingclawdev/aming-claw/blob/32f47d11f81d85b1fd4d50dddaa5389990ca4513/agent/governance/task_timeline.py#L773-L818" rel="noopener noreferrer"&gt;&lt;code&gt;close verification&lt;/code&gt;&lt;/a&gt; checks those facts before a backlog item can be honestly closed.&lt;/p&gt;

&lt;p&gt;Even project knowledge is handled this way. Graph context is not dumped wholesale into the prompt. It is queried through an &lt;a href="https://github.com/amingclawdev/aming-claw/blob/32f47d11f81d85b1fd4d50dddaa5389990ca4513/agent/governance/graph_query_trace.py#L1-L6" rel="noopener noreferrer"&gt;&lt;code&gt;audited graph-query trace&lt;/code&gt;&lt;/a&gt; and exposed through the MCP &lt;a href="https://github.com/amingclawdev/aming-claw/blob/32f47d11f81d85b1fd4d50dddaa5389990ca4513/agent/mcp/tools.py#L565-L624" rel="noopener noreferrer"&gt;&lt;code&gt;graph_query&lt;/code&gt; surface&lt;/a&gt;, so later review can ask what the agent looked up instead of guessing. The public manual-fix SOP names the same workflow: route, contract, timeline, and close gates are required evidence, and dispatch has to prove the worker's fenced identity before handoff (&lt;a href="https://github.com/amingclawdev/aming-claw/blob/32f47d11f81d85b1fd4d50dddaa5389990ca4513/docs/governance/manual-fix-sop.md#L206-L210" rel="noopener noreferrer"&gt;timeline and contract gates&lt;/a&gt;, &lt;a href="https://github.com/amingclawdev/aming-claw/blob/32f47d11f81d85b1fd4d50dddaa5389990ca4513/docs/governance/manual-fix-sop.md#L214-L227" rel="noopener noreferrer"&gt;dispatch requirements&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;That is the implementation pattern: right context becomes a chain of small, checkable facts. The agent can reason with them, but it does not get to be the only witness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before And After
&lt;/h2&gt;

&lt;p&gt;Before, the agent confidently finished the wrong local job.&lt;/p&gt;

&lt;p&gt;It saw a failing test and fixed the code. It saw a nearby file and edited it. It saw a plausible completion story and wrote one. The observer forgot what kind of job this really was. The worker optimized inside its local patch. The review or validation step, if present, evaluated the local result instead of the global obligation.&lt;/p&gt;

&lt;p&gt;After, route context requires the observer to start by preserving global state. It names the topology: tiny fix, permission-sensitive change, runtime change, graph-impacting change, major decision, or something else. It dispatches lanes accordingly. The worker acts inside a contract. The architecture review lane checks whether the route makes sense. Validation checks evidence, not just confidence. Later validation and close gates check the route context alert, manifest, and returned evidence before accepting the result.&lt;/p&gt;

&lt;p&gt;That rejection matters. A good system must be allowed to say, "The test passed, but the work is not done."&lt;/p&gt;

&lt;p&gt;For example: the focused test passed, but the route context hash did not match the worker contract. Or the code changed the right file, but the audit evidence did not prove the right role acted. Or the patch was correct, but the graph, meaning the project map, was now stale. Or runtime needed redeploy before anyone could claim the fix was live. Route context makes those checks explicit instead of hoping a model remembers them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What The Observer Is For
&lt;/h2&gt;

&lt;p&gt;The observer's advantage is not that it manages subagents. That framing makes it sound like a tiny project manager.&lt;/p&gt;

&lt;p&gt;The observer's real advantage is global-state custody. Route context gives it something concrete to preserve: route identity, dirty scope, graph/current state, runtime status, backlog state, tests, close gate requirements, and follow-up work.&lt;/p&gt;

&lt;p&gt;Workers should be local. That is their strength. A bounded worker should know its target files, acceptance criteria, blocked actions, focused tests, and required evidence. It should not need to carry the whole project in its head. When every worker receives the whole world, prompts get heavier and guarantees get weaker.&lt;/p&gt;

&lt;p&gt;The observer keeps the larger surfaces connected through route context. Did this lane have permission to edit? Did it stay inside its file fence? Did the test prove the actual promise or just a nearby behavior? Did an independent reviewer inspect the same packet the worker produced? Did the runtime or graph need an update? Is there follow-up work outside the worker's scope?&lt;/p&gt;

&lt;p&gt;These checks are not glamorous. They are what stop a green test from becoming a false finish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Efficiency Without The Theater
&lt;/h2&gt;

&lt;p&gt;The biggest improvement was not raw wall-clock speed.&lt;/p&gt;

&lt;p&gt;Parallel lanes can help. Architecture review, implementation, and validation lanes expose different gaps earlier than one linear worker. But the real win was effective efficiency and quality: fewer locally correct patches that could not be honestly closed, less rework after review, and earlier discovery of missing evidence.&lt;/p&gt;

&lt;p&gt;The system became calmer because it stopped treating "done locally" as "done globally." Some gates remain serial on purpose. Commit, runtime redeploy, graph reconcile, and backlog close mutate shared state or claim shared state is current. Those steps should not be casually parallelized just because multiple agents are available.&lt;/p&gt;

&lt;p&gt;This is the correction to zero-orchestration-ish design. The goal is not to hide all orchestration. Hidden orchestration is unreliable because nobody can audit what happened. Route context keeps orchestration visible and minimal at the points where role, evidence, and shared state matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Rule We Use Now
&lt;/h2&gt;

&lt;p&gt;A tiny deterministic edit can be one agent plus a focused test. If route context says the blast radius is clear, the file ownership is obvious, and there is no permission, audit, graph, or runtime implication, keep it simple. Give the worker a tight contract and verify the behavior.&lt;/p&gt;

&lt;p&gt;P1 and P0 work is different. So are routing, permission, audit, graph, and runtime tasks. Those need an observer, an architecture review lane, an implementation worker, and independent validation. Major decisions need adversarial lanes: separate expert packets, an independent review lane comparing evidence, and an observer final decision. Not because important work deserves ceremony, but because important work has more ways to be locally successful and globally wrong.&lt;/p&gt;

&lt;p&gt;The checklist is compact:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name the topology: what kind of job this really is.&lt;/li&gt;
&lt;li&gt;Bind the worker contract: target files, acceptance criteria, and evidence.&lt;/li&gt;
&lt;li&gt;List blocked actions: what this lane must not do.&lt;/li&gt;
&lt;li&gt;Expose injected context: manifest the artifacts and hashes the lane saw.&lt;/li&gt;
&lt;li&gt;Make gates reject false finishes: tests, validation, and close checks must be able to say no.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the practical lesson we got from dogfood. More context made agents sound more informed. Route context made right context safer to act on.&lt;/p&gt;

&lt;p&gt;For us, right context stopped being a prompt-writing aspiration when it became route context: a route that knows what matters now, a contract that bounds the worker, a manifest that shows what was injected, and gates that refuse to confuse a passing test with a finished job.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>agents</category>
      <category>development</category>
    </item>
    <item>
      <title>AI's tech debt is invisible — even to AI. I solved it at the architecture layer.</title>
      <dc:creator>Aming</dc:creator>
      <pubDate>Sat, 23 May 2026 03:58:23 +0000</pubDate>
      <link>https://dev.to/amingin_ai/ais-tech-debt-is-invisible-even-to-ai-i-solved-it-at-the-architecture-layer-1nh1</link>
      <guid>https://dev.to/amingin_ai/ais-tech-debt-is-invisible-even-to-ai-i-solved-it-at-the-architecture-layer-1nh1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — AI repeats your patterns badly, ignores existing services, and forgets every cross-session lesson you taught it. This isn't laziness — it's a new kind of tech debt: &lt;strong&gt;invisible&lt;/strong&gt;, &lt;strong&gt;systemic&lt;/strong&gt;, and &lt;strong&gt;architectural&lt;/strong&gt;. Project memory hints don't scale. Bigger context windows don't help. The fix is structural: pin a graph projection of your codebase to every commit, let AI read it before writing, surface "graph stale" prompts when source drifts. Real commit receipts from my own OSS project &lt;a href="https://github.com/amingclawdev/aming-claw" rel="noopener noreferrer"&gt;aming-claw&lt;/a&gt; inline. Architects, change my mind in the comments.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What is AI tech debt?
&lt;/h2&gt;

&lt;p&gt;Let me define this precisely, because it's a different beast from the tech debt you already know.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Traditional tech debt&lt;/th&gt;
&lt;th&gt;AI tech debt&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Who creates it&lt;/td&gt;
&lt;td&gt;Engineers (knowingly)&lt;/td&gt;
&lt;td&gt;AI (unknowingly)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Awareness&lt;/td&gt;
&lt;td&gt;Conscious tradeoff&lt;/td&gt;
&lt;td&gt;AI doesn't know it's accruing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fix lifecycle&lt;/td&gt;
&lt;td&gt;Fix once, done&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Every new session repeats it&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visibility&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git log&lt;/code&gt; shows it&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Invisible across sessions&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale&lt;/td&gt;
&lt;td&gt;Team-bounded&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Systemic, AI-generated&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The core asymmetry: &lt;strong&gt;the more your team uses AI for coding, the more invisible debt accrues — and you have no tool that sees it.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  5 symptoms (diagnose yourself)
&lt;/h2&gt;

&lt;p&gt;Run this checklist against your team:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ AI re-implemented a service that &lt;strong&gt;already exists&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;❌ AI shipped code using a &lt;strong&gt;pattern completely inconsistent&lt;/strong&gt; with everything around it&lt;/li&gt;
&lt;li&gt;❌ AI &lt;strong&gt;didn't see&lt;/strong&gt; the implementation sitting in the next file over&lt;/li&gt;
&lt;li&gt;❌ Every new session &lt;strong&gt;repeats the same mistakes&lt;/strong&gt; you corrected last time&lt;/li&gt;
&lt;li&gt;❌ AI treats a &lt;strong&gt;familiar codebase as if it were brand new&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three or more? You're accruing AI tech debt. The bigger your team and the more AI you use, the faster it compounds.&lt;/p&gt;




&lt;h2&gt;
  
  
  A real case study: my toolboxclient stateService
&lt;/h2&gt;

&lt;p&gt;I'm the maintainer of &lt;a href="https://github.com/amingclawdev/toolBoxClient" rel="noopener noreferrer"&gt;toolboxclient&lt;/a&gt; (open-source cross-platform AI agent runtime, 274+ stars). I asked AI to add a &lt;code&gt;stateService&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The directory &lt;code&gt;server/services/&lt;/code&gt; already contained, in clear sight:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TOOLBOXCLIENT/server/services/
├── fingerPrintService.js
├── memoryService.js
├── providerModelService.js
├── proxyService.js
├── taskService.js
├── toolServiceManager.js
├── walletService.js
└── webSocketService.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Roughly a dozen services, all sharing the same HTTP pattern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What AI shipped&lt;/strong&gt; (commit &lt;a href="https://github.com/amingclawdev/toolBoxClient/commit/68487cc" rel="noopener noreferrer"&gt;&lt;code&gt;68487cc&lt;/code&gt;&lt;/a&gt;, 2026-03-19):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AI's version: WebSocket-based StateClient with Proxy&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StateClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;agentName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 🚨 WebSocket, not HTTP — inconsistent with every other service in the folder&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_createProxy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;_createProxy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Proxy traps to broadcast via WebSocket&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It used WebSocket instead of HTTP. It used a Proxy-based intercept-and-broadcast pattern unlike anything else in the codebase. It built a parallel architecture next to an established one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This wasn't a code bug. It was a pattern bug. AI literally couldn't see the existing services.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The first fix: project memory
&lt;/h2&gt;

&lt;p&gt;My first instinct: add a hint to project memory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use existing HTTP services, don't add WebSocket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AI refactored cleanly (commit &lt;a href="https://github.com/amingclawdev/toolBoxClient/commit/bbdf82c" rel="noopener noreferrer"&gt;&lt;code&gt;bbdf82c&lt;/code&gt;&lt;/a&gt;, 2026-03-21):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feat: stateService Phase A+B — HTTP CRUD + SSE broadcast

Phase A: /api/state/* routes (read, write, session CRUD, language pref)
Phase B: SSE subscribe endpoint with topic filtering + EventBus broadcast

74/74 tests pass. No breaking changes — additive only.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WebSocket gone. HTTP CRUD + SSE matching the existing pattern. Clean fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For about ten seconds, I thought I'd solved it.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why project memory hints don't scale
&lt;/h2&gt;

&lt;p&gt;Then I realized something uncomfortable:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This catch only worked &lt;strong&gt;because I noticed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The next AI session would start with zero memory of this lesson.&lt;br&gt;
Every context window starts as a blank slate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the &lt;strong&gt;systemic&lt;/strong&gt; nature of AI tech debt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI can't see existing patterns when it writes&lt;/li&gt;
&lt;li&gt;I see it → I fix it once → the fix doesn't propagate to future sessions&lt;/li&gt;
&lt;li&gt;Manual &lt;code&gt;project memory&lt;/code&gt; maintenance puts the work back on me, not AI&lt;/li&gt;
&lt;li&gt;This doesn't scale — and the failure mode is silent&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The first insight
&lt;/h2&gt;

&lt;p&gt;I stopped trying to fix prompts and started looking at the structural problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI agents don't need bigger context windows.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They need a persistent structural record of the project that survives across sessions.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Context windows are short-term memory. What's missing is &lt;strong&gt;long-term, project-level memory&lt;/strong&gt; — something any AI session can read before writing.&lt;/p&gt;

&lt;p&gt;This is the insight that turned into &lt;a href="https://github.com/amingclawdev/aming-claw" rel="noopener noreferrer"&gt;aming-claw&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building aming-claw (and falling into the next trap)
&lt;/h2&gt;

&lt;p&gt;The idea: give every AI session a queryable graph of the project. Files, modules, functions, patterns — all of it, machine-readable, persistent.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scan the codebase → build a &lt;strong&gt;graph&lt;/strong&gt; of all entities and relations&lt;/li&gt;
&lt;li&gt;Expose it through an &lt;strong&gt;MCP server&lt;/strong&gt; that any agent can query&lt;/li&gt;
&lt;li&gt;AI &lt;strong&gt;reads the graph before writing&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Graph &lt;strong&gt;persists across sessions&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I built it. It worked. Then it broke — at a higher layer.&lt;/p&gt;

&lt;p&gt;I had implemented the graph with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mutable nodes&lt;/strong&gt; — agents could edit graph state directly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A patch pipeline&lt;/strong&gt; — 5-stage mutation flow (propose → validate → review → apply → snapshot)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A graph editor UI&lt;/strong&gt; — humans could also edit the graph&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Within a few weeks, &lt;strong&gt;the graph drifted from the actual code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Why? Because I had created a &lt;strong&gt;second source of truth&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The real source of truth was source code&lt;/li&gt;
&lt;li&gt;But I also let the graph be directly mutated&lt;/li&gt;
&lt;li&gt;The two sources inevitably diverged&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Same trap. Higher layer.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The real architectural insight
&lt;/h2&gt;

&lt;p&gt;After hitting the same trap twice, the answer crystallized:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;del&gt;The graph is something you edit.&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The graph is a projection of the commit.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In concrete terms:&lt;/p&gt;

&lt;h3&gt;
  
  
  Every commit can correspond to one graph
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git commit (modifies source / hints / config)
     ↓
system detects: HEAD ≠ graph's bound commit
     ↓ ⚠️ "graph stale" prompt
user decides when to reconcile
     ↓ user-triggered
fixed_algorithm(source + hints + config)
     ↓
new graph snapshot ←→ new commit hash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4 key invariants
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Invariant&lt;/th&gt;
&lt;th&gt;What it guarantees&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Fixed algorithm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Same input → same graph (deterministic, no randomness)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1:1 binding&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Every commit hash maps to exactly one graph snapshot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;User-triggered&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reconciliation is explicit, not a background git hook&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Stale prompt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;System surfaces drift in dashboard / CLI; user triggers when ready&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Why not a git hook?
&lt;/h3&gt;

&lt;p&gt;A reasonable question: why not auto-rebuild the graph on every commit via a git hook?&lt;/p&gt;

&lt;p&gt;Three reasons I deliberately didn't:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reconciliation is expensive&lt;/strong&gt; (full codebase scan + algorithm)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Surprise auto-builds destabilize state&lt;/strong&gt; — user should control when state changes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batching commits before a single reconcile is often what users want&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The system shows a &lt;code&gt;graph stale&lt;/code&gt; indicator in dashboard and CLI. Users reconcile when they're ready. This is a deliberate design choice, not a limitation.&lt;/p&gt;

&lt;h3&gt;
  
  
  How modification and rollback work
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Modify the graph&lt;/td&gt;
&lt;td&gt;Modify source / hints / config → trigger reconcile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Roll back the graph&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git revert&lt;/code&gt; → trigger reconcile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verify consistency&lt;/td&gt;
&lt;td&gt;Same commit → same graph (replayable)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Logic lives in code. The graph is a read-only projection.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How this solves AI tech debt
&lt;/h2&gt;

&lt;p&gt;Returning to the original problem: &lt;strong&gt;AI repeats patterns badly because it can't see the codebase&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The architectural fix:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Every AI session starts by &lt;strong&gt;querying the graph&lt;/strong&gt; (via MCP)&lt;/li&gt;
&lt;li&gt;The graph records the full structure — files, functions, modules, patterns&lt;/li&gt;
&lt;li&gt;AI sees, for example, &lt;code&gt;existing HTTP service pattern in server/services/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;AI &lt;strong&gt;reuses the pattern&lt;/strong&gt; instead of shipping a parallel WebSocket implementation&lt;/li&gt;
&lt;li&gt;After AI makes changes → user commits → system flags graph as stale → user reconciles → next session sees updated patterns&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Cross-session knowledge transfer happens through the graph, not the prompt.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is what "solved at the architecture layer" means: it's not a smarter prompt, it's a different topology of state.&lt;/p&gt;




&lt;h2&gt;
  
  
  Coming up: the algorithm itself
&lt;/h2&gt;

&lt;p&gt;This post covered &lt;strong&gt;why&lt;/strong&gt; the projection model works. The next post covers &lt;strong&gt;how&lt;/strong&gt; the algorithm builds the graph:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;in-degree=0 entry detection&lt;/li&gt;
&lt;li&gt;DFS 3-color marking&lt;/li&gt;
&lt;li&gt;Tarjan SCC for cyclic clusters&lt;/li&gt;
&lt;li&gt;6-signal layer scoring&lt;/li&gt;
&lt;li&gt;Cross-language fact pipeline (Python + TypeScript)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Follow me here to catch the next one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Change my mind
&lt;/h2&gt;

&lt;p&gt;I claim this architectural pattern solves AI tech debt: &lt;strong&gt;every commit corresponds to one graph + user-triggered reconcile + stale-state prompt&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Your turn. Two architectural choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Treat project state as a &lt;strong&gt;single source of truth, commit-bound&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Or maintain a &lt;strong&gt;separate memory store&lt;/strong&gt; that AI writes to&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which is more robust? Which scales better? Where would you attack my approach?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Calibrated invitation: I want senior engineers and AI infra people to push back with specifics. "What about X?" or "Have you considered Y?" lands better than "this won't work." If you've shipped something adjacent, tell me — I want to compare designs.&lt;/p&gt;
&lt;/blockquote&gt;




</description>
    </item>
    <item>
      <title>AI proposed 5 components for my parallel system. After walking one scenario, only 3 were real.</title>
      <dc:creator>Aming</dc:creator>
      <pubDate>Mon, 18 May 2026 04:18:53 +0000</pubDate>
      <link>https://dev.to/amingin_ai/ai-proposed-5-components-for-my-parallel-system-after-walking-one-scenario-only-3-were-real-12nd</link>
      <guid>https://dev.to/amingin_ai/ai-proposed-5-components-for-my-parallel-system-after-walking-one-scenario-only-3-were-real-12nd</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — AI loves to design "enterprise-grade" systems for you: message queue, distributed lock, state machine service, scheduler, monitoring bus. Half of them aren't real. The cheapest filter I know: before letting AI design anything, walk one concrete scenario through the system. Whatever shows up in the scenario is real. Whatever doesn't — delete. This week it took me from a 5-component design down to 3 — and surfaced one critical component AI had missed entirely.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What I was building
&lt;/h2&gt;

&lt;p&gt;This week I was extending &lt;a href="https://github.com/amingclawdev/aming-claw" rel="noopener noreferrer"&gt;aming-claw&lt;/a&gt; (an open-source AI code governance tool I'm building) to support &lt;strong&gt;parallel multi-agent development&lt;/strong&gt;: multiple AI agents working on the same project simultaneously, each on its own branch, all of it merging back into trunk.&lt;/p&gt;

&lt;p&gt;I asked AI to help me design it.&lt;/p&gt;

&lt;p&gt;It came back fast. Confident. Five components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Message queue        (so tasks can line up)
- Distributed lock     (so agents don't step on each other)
- State machine service (so we track progress)
- Task scheduler       (so we know what runs when)
- Monitoring bus       (so we see what's happening)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each component had a paragraph of justification. The diagram looked impressive. The names sounded right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I almost just said "ok, build it."&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I didn't
&lt;/h2&gt;

&lt;p&gt;A thing I've learned working with AI on architecture: AI doesn't filter for &lt;em&gt;necessity&lt;/em&gt;. It filters for &lt;em&gt;plausibility&lt;/em&gt;. The components it lists are real things real systems have — they're just not necessarily things &lt;strong&gt;your&lt;/strong&gt; system needs.&lt;/p&gt;

&lt;p&gt;So instead of letting it design the system, I did one thing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;I walked a concrete scenario through the system before agreeing to anything.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's an honest framing: &lt;strong&gt;nobody&lt;/strong&gt; can look at a 5-component design and immediately tell you which 2 are load-bearing. AI can't. Most engineers reading this can't, not on inspection.&lt;/p&gt;

&lt;p&gt;The good news:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You don't need to know what to design. You just need to walk one scenario.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The scenario does the filtering for you.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scenario 1: five tasks with dependencies
&lt;/h2&gt;

&lt;p&gt;I started with the most boring scenario I could think of:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Five AI agents working in parallel. Each one on its own branch. The tasks have a dependency chain: &lt;code&gt;1 → 2 → 3 → 4 → 5&lt;/code&gt;. Task 2 needs what task 1 built. Task 5 needs everything before it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I walked through what the system has to do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Five tasks running in parallel — they need to &lt;strong&gt;queue&lt;/strong&gt; for merging. OK, "message queue" was real.&lt;/li&gt;
&lt;li&gt;BUT — they have to merge &lt;strong&gt;in dependency order&lt;/strong&gt;. Not first-come-first-served. So a plain FIFO message queue isn't enough. &lt;strong&gt;It has to be an ordered queue.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Already, one component refined. "Message queue" → "ordered merge queue."&lt;/p&gt;

&lt;p&gt;Nothing has been deleted yet. Keep going.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scenario 2: the machine reboots mid-batch
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Now the machine reboots. When it comes back up: task 1 already merged. Task 2 tried to merge and failed. Task 3 hadn't started yet. Task 4 was waiting in queue. Task 5 was halfway through executing when the power cut.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I walked it again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For the system to even know what state each task is in after a reboot, &lt;strong&gt;task state has to be on disk, not just in memory&lt;/strong&gt;. Not a "state machine service" with its own server — just durable per-task state. (&lt;code&gt;task_id → status → checkpoint&lt;/code&gt;.) That's a column in a database, not a service.&lt;/li&gt;
&lt;li&gt;Task 2 failed, but tasks 3-5 are downstream of it. The system has to &lt;strong&gt;recognize "upstream failed, downstream blocked"&lt;/strong&gt; automatically. That's not a separate component — it's a query against the durable state.&lt;/li&gt;
&lt;li&gt;Task 5 was mid-execution when the power cut. When the machine restarts, what stops a second copy from picking it up and racing the half-finished one? Each execution attempt needs a &lt;strong&gt;unique token&lt;/strong&gt; — whoever has the newest token is the live runner, everyone else gets fenced off.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now two more things have surfaced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Durable per-task state (which AI called "state machine service" — but it's not a service, it's a table)&lt;/li&gt;
&lt;li&gt;Fence tokens to prevent zombie reruns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here's the first thing that got &lt;strong&gt;deleted&lt;/strong&gt;: &lt;strong&gt;distributed lock&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A distributed lock is "this resource is held by exactly one agent right now." Fence tokens solve the same problem in a much weaker, much cheaper way: "the latest token wins, all stale tokens are ignored." For agent merge work, that's sufficient. Distributed locks would be massive overkill for the actual scenario.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1 component deleted, 0 lines of code written.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Scenario 3: the ordering itself was wrong
&lt;/h2&gt;

&lt;p&gt;This one wasn't in my original head-list. It only surfaced when I kept walking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Five tasks ran. Three merged. Then it turns out the &lt;strong&gt;dependency order I gave the system was wrong&lt;/strong&gt; — it should have been &lt;code&gt;1 → 3 → 2 → 4 → 5&lt;/code&gt;, not &lt;code&gt;1 → 2 → 3 → 4 → 5&lt;/code&gt;. The three already-merged tasks need to be &lt;strong&gt;rolled back as a batch and replayed in the correct order.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a scenario most systems never plan for. Per-task rollback is common — undo one merge. &lt;strong&gt;Batch rollback with replay&lt;/strong&gt; is rarer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plain per-task &lt;code&gt;revert&lt;/code&gt; doesn't work — you can't revert task 2 while leaving task 3 (which depends on task 2's wrong order) intact.&lt;/li&gt;
&lt;li&gt;The whole batch has to roll back atomically.&lt;/li&gt;
&lt;li&gt;Then the system has to &lt;strong&gt;replay them in the new order&lt;/strong&gt;, with all the graph artifacts (snapshots, indices, semantic projection, test results) re-derived per merge.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the component &lt;strong&gt;AI had not mentioned at all&lt;/strong&gt;. It only surfaced because I walked a scenario nobody told me to walk.&lt;/p&gt;

&lt;p&gt;Call it &lt;code&gt;BatchMergeRuntime&lt;/code&gt;. It's the rarest kind of architectural decision: not "should we have it" but &lt;strong&gt;"do we even know we need it?"&lt;/strong&gt; — and the answer, for most teams, is &lt;em&gt;not until production&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the architecture actually became
&lt;/h2&gt;

&lt;p&gt;After walking three scenarios:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;What it surfaced&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5 tasks with dependencies&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ordered merge queue&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Machine reboots mid-batch&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Durable task state + fence tokens&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependency order was wrong&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Batch rollback + replay runtime&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All of the above untested&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Test scenario matrix as P0.0 (highest priority)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three real components. The fourth — the &lt;strong&gt;test scenario matrix itself&lt;/strong&gt; — is a meta-component: the dry-run scenarios I just walked became the &lt;strong&gt;first acceptance bar&lt;/strong&gt; for every subsequent PR. Anything that ships has to survive these scenarios before merge.&lt;/p&gt;




&lt;h2&gt;
  
  
  AI's first design vs what scenarios required
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;AI's first list&lt;/th&gt;
&lt;th&gt;Reality after scenario walk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Message queue&lt;/td&gt;
&lt;td&gt;✅ Needed — but &lt;strong&gt;ordered&lt;/strong&gt;, not FIFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Distributed lock&lt;/td&gt;
&lt;td&gt;❌ Deleted — fence tokens are sufficient&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State machine service&lt;/td&gt;
&lt;td&gt;✅ Needed — but as a &lt;strong&gt;table&lt;/strong&gt;, not a service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task scheduler&lt;/td&gt;
&lt;td&gt;❌ Deleted — the ordered queue &lt;em&gt;is&lt;/em&gt; the scheduler&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring bus&lt;/td&gt;
&lt;td&gt;❌ Deleted — each component emits its own events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(AI did not propose)&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;Batch rollback runtime&lt;/strong&gt; — surfaced only by scenario 3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Net: 5 → 3 components, plus the one critical piece AI had missed entirely.&lt;/p&gt;

&lt;p&gt;The win is not "I deleted 2 components." The win is &lt;strong&gt;I now know why each remaining component exists&lt;/strong&gt;, which means I can explain it, scope it, and reject scope creep on it. That's the difference between a system you &lt;em&gt;built&lt;/em&gt; and a system you &lt;em&gt;understand&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The method, in 3 steps
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❌ Don't:   "Hey AI, design me a system that does X."
           → AI returns a plausible-looking inventory of components.
           → Half of them aren't real for your specific case.

✅ Do:      Step 1.  Write one concrete scenario yourself.
                    (Or: have AI write the scenario, you evaluate it.
                     Real numbers, real steps, with crashes,
                     failures, and orderings going wrong.)

           Step 2.  Walk the scenario through your design.
                    At each step, ask: "What does the system need here?"

           Step 3.  Aggregate "what's needed."
                    That's your minimal architecture.
                    Anything not in that list — delete.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Three steps. No architecture-pattern library required. The scenario does the work for you.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this works (and why it's hard to skip)
&lt;/h2&gt;

&lt;p&gt;Three reasons:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. AI optimizes for plausibility, not necessity.&lt;/strong&gt; It lists components that &lt;em&gt;sound right for this kind of system&lt;/em&gt;, drawing from its training data. It can't know which components are necessary for &lt;em&gt;your&lt;/em&gt; specific scenario, because it doesn't see your scenario unless you walk it through.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Scenarios surface the negative space.&lt;/strong&gt; A happy-path design is the union of every component someone &lt;em&gt;might&lt;/em&gt; need. A scenario walk is the intersection of components someone &lt;em&gt;definitely&lt;/em&gt; needs &lt;em&gt;for that scenario&lt;/em&gt;. The intersection is always smaller — and more honest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Scenarios surface what AI missed.&lt;/strong&gt; The batch-rollback runtime wasn't on AI's list. It surfaced because scenario 3 was a state AI's training data didn't lean on. Whatever your system's weird state is — only your scenarios will find it.&lt;/p&gt;

&lt;p&gt;The reason this method is hard to skip is that the &lt;strong&gt;pressure to just accept AI's design is enormous&lt;/strong&gt;. The design looks complete. It uses real words. You feel productive saying "yes, build it." Walking a scenario feels like &lt;em&gt;slowing down&lt;/em&gt;. It is. That's the whole point.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's next in this series
&lt;/h2&gt;

&lt;p&gt;This is &lt;strong&gt;part 2&lt;/strong&gt; of the AI Collaboration Survival Guide. The previous post was about &lt;a href="https://dev.to/amingin_ai/i-told-my-ai-to-build-a-feature-did-it-i-had-no-idea-1f1"&gt;making AI's claims about completed work auditable via a backlog database&lt;/a&gt;. The next ones, lining up:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pain&lt;/th&gt;
&lt;th&gt;Coming up&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AI edits one function, breaks 10 callers&lt;/td&gt;
&lt;td&gt;Code graph + impact analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI modifies code it shouldn't touch&lt;/td&gt;
&lt;td&gt;Governance hints as the only authoring surface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What did AI even change this week?&lt;/td&gt;
&lt;td&gt;Event ledger&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Every session starts from zero&lt;/td&gt;
&lt;td&gt;Project memory layer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One pain per article. All built around the same open-source project, &lt;a href="https://github.com/amingclawdev/aming-claw" rel="noopener noreferrer"&gt;aming-claw&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  About aming-claw
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/amingclawdev/aming-claw" rel="noopener noreferrer"&gt;amingclawdev/aming-claw&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; A shared workspace where you and your AI agent see the same dashboard. Backlog database, code graph, event ledger, governance hints — all queryable by AI through MCP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why I'm writing this series:&lt;/strong&gt; I keep running into the same kind of AI-collaboration pain. Each post fixes one of them. The fixes generalize beyond aming-claw — the scenario-walk method in this post is a 5-minute habit you can adopt in any project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the parallel-agent scenario sounded familiar, &lt;strong&gt;drop a comment with the architecture decision AI most recently tried to oversell you on&lt;/strong&gt; — I'll work through it the same way in the comments. Free architectural review, basically. The repo also takes stars and they're free for you to give. 🌟&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Part 2 of "AI Collaboration Survival Guide" — practical patterns for the messy reality of shipping with AI agents.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>vibecoding</category>
      <category>devtool</category>
    </item>
    <item>
      <title>I told my AI to build a feature. Did it? I had no idea.</title>
      <dc:creator>Aming</dc:creator>
      <pubDate>Sat, 16 May 2026 18:43:34 +0000</pubDate>
      <link>https://dev.to/amingin_ai/i-told-my-ai-to-build-a-feature-did-it-i-had-no-idea-1f1</link>
      <guid>https://dev.to/amingin_ai/i-told-my-ai-to-build-a-feature-did-it-i-had-no-idea-1f1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — I tried to "manage" AI by having it write decisions, todos, and constraints into markdown docs. After 56 files, I realized AI doesn't maintain document state. So I built aming-claw — a backlog database AI can actually read and write through MCP.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  A bug I kept running into
&lt;/h2&gt;

&lt;p&gt;I thought I was doing AI collaboration the right way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9toneqw4cnyxjolse20j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9toneqw4cnyxjolse20j.png" alt="Screenshot of docs/dev folder with 56 markdown files using proposal-, review-, and handoff- naming patterns" width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the &lt;code&gt;docs/dev/&lt;/code&gt; folder of my aming-claw project — 56 markdown files, all produced through AI collaboration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;proposal-*&lt;/code&gt; — new feature specs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;review-*&lt;/code&gt; — design review records&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;handoff-*&lt;/code&gt; — state passed between sessions&lt;/li&gt;
&lt;li&gt;Plus &lt;code&gt;plan-&lt;/code&gt;, &lt;code&gt;optimization-&lt;/code&gt;, &lt;code&gt;interface-&lt;/code&gt;, &lt;code&gt;manual-fix-&lt;/code&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every file dated. Two months in, over a thousand pages of markdown. I figured the next AI session would read these. I figured I'd be able to search them too.&lt;/p&gt;

&lt;p&gt;But there's one problem I can't engineer my way out of:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI doesn't maintain document state.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;proposal-graph-state-reconcile-and-chain-governance-modes.md&lt;/code&gt; — did this proposal ship? Which commit? Is it still valid?&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;handoff-2026-05-10-dashboard-semantic-hash-queue.md&lt;/code&gt; — did the next session actually pick up where this left off?&lt;/li&gt;
&lt;li&gt;18 proposals on file. Which are done, which got rejected, which are still alive? Grep through git log line by line?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;I don't manually maintain the docs, so the docs rot.&lt;/strong&gt; AI doesn't maintain them either — its context window only sees a tiny slice of the workspace. The other 56 files are invisible.&lt;/p&gt;

&lt;p&gt;The more we talk, the more we write — and the further docs drift from code. Eventually you don't trust the docs, and you don't have time to read the code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this happens
&lt;/h2&gt;

&lt;p&gt;This isn't AI being lazy. It's a &lt;strong&gt;structural problem&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Markdown is dead text.&lt;/strong&gt; No state machine. "TODO" doesn't become "DONE" on its own. "Decision: use Redis" doesn't auto-expire when you flip back to in-memory three weeks later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI context has a boundary.&lt;/strong&gt; Each session sees ~200 lines of working code. Old docs never enter the window. Not in the window → can't be maintained.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No traceable link between docs and code.&lt;/strong&gt; Which TODO maps to which function? Once it's done, which commit landed it? Humans can't remember. AI doesn't look it up.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GitHub Issues, Notion, Linear — none of these help. AI can't see them, so they don't exist.&lt;/p&gt;

&lt;p&gt;The core mismatch is this: &lt;strong&gt;humans want global state. AI sees only local present.&lt;/strong&gt; Between them you need a living, traceable, AI-readable/writable state layer. Markdown isn't that layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  How aming-claw solves it
&lt;/h2&gt;

&lt;p&gt;I gave aming-claw a &lt;strong&gt;dedicated backlog database&lt;/strong&gt; — a peer-level system to the code graph and event ledger, with its own schema, state machine, and query interface. Not stored in markdown. Not buried in code comments. Not dependent on an external issue tracker.&lt;/p&gt;

&lt;p&gt;Each backlog entry is a structured record (todo / decision / constraint) with status, priority, source session, and a code reference (function name or file path). AI reads and writes it through MCP.&lt;/p&gt;

&lt;p&gt;The flow:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. You speak → it goes to the database, not a dead doc
&lt;/h3&gt;

&lt;p&gt;In chat:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Add a retry-after to the rate limiter on UserService.login"&lt;/p&gt;

&lt;p&gt;Or: "Decision — use Redis instead of in-memory for caching"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;aming-claw's MCP server intercepts those statements and writes directly into the backlog:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;UserService.login&lt;/span&gt;   &lt;span class="c1"&gt;# function or file path&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;      &lt;span class="s"&gt;todo | decision | constraint&lt;/span&gt;
&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;proposed&lt;/span&gt;
&lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;P1&lt;/span&gt;
&lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;session-id-xyz&lt;/span&gt;
&lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-05-16T10:23:45Z&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Markdown is dead text. The backlog database is live state — schema, indexed, state-machined, AI-accessible. That's the difference.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Dashboard shows it instantly
&lt;/h3&gt;

&lt;p&gt;Open the aming-claw dashboard — the left panel shows the new backlog entry. Click it — the right panel jumps to the function via the &lt;code&gt;vscode://&lt;/code&gt; protocol. Status chips are editable inline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm1z428hnem7uh0tlsz5z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm1z428hnem7uh0tlsz5z.png" alt="aming-claw dashboard backlog view showing multiple entries with priority, status, code references, and update timestamps" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The backlog view — every entry has priority, status, code reference, and update timestamp. AI and you query the same source of truth.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. State machine, automatic
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;proposed → in_progress → done(commit hash) → verified
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;in_progress&lt;/code&gt; — AI started working on it&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;done&lt;/code&gt; — commit landed, &lt;strong&gt;hash automatically bound&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;verified&lt;/code&gt; — you reviewed it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every state change is appended to an event ledger: &lt;strong&gt;which day, which session proposed it, which commit implemented it, who verified it&lt;/strong&gt; — all queryable, all replayable.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. AI reads the backlog itself, next time
&lt;/h3&gt;

&lt;p&gt;Days later, in chat:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Did we ever fix that Codex plugin Windows install bug?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;AI queries the backlog through MCP and returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;     &lt;span class="s"&gt;FIXED, P0&lt;/span&gt;
&lt;span class="na"&gt;commit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;     &lt;span class="s"&gt;0ad8c7e&lt;/span&gt;
&lt;span class="na"&gt;fixed at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;   &lt;span class="s"&gt;2 days ago&lt;/span&gt;
&lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;       &lt;span class="s"&gt;agent/plugin_installer.py (line 455)&lt;/span&gt;
&lt;span class="na"&gt;change&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;     &lt;span class="s"&gt;replaced regex pattern with callable replacement&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No grepping git log. No asking a teammate. No "I think we did?"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfyd6yvkpktfdsscq9qg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfyd6yvkpktfdsscq9qg.png" alt="aming-claw dashboard backlog view showing multiple entries with priority, status, code references, and update timestamps" width="800" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The key thing to notice:&lt;/strong&gt; AI didn't "remember" this from conversation history. It queried the backlog database &lt;strong&gt;in real time&lt;/strong&gt; through MCP. Even if this bug was raised three months ago, in a session that's long gone — AI still gets the &lt;strong&gt;current status + full commit trace&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's the difference between dead markdown and a live state layer: &lt;strong&gt;the database is the memory, not the conversation.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  This is just the start
&lt;/h2&gt;

&lt;p&gt;Look back at the &lt;code&gt;docs/dev/&lt;/code&gt; screenshot — 56 markdown files, nobody knows which are alive.&lt;br&gt;
Look at the dashboard screenshot — every backlog entry has status, commit, location.&lt;/p&gt;

&lt;p&gt;The difference isn't the tool. &lt;strong&gt;It's whether information has state.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The backlog solves "did the AI build the feature I asked for?" — but AI collaboration has plenty of other holes I'm planning to fill in this series:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pain&lt;/th&gt;
&lt;th&gt;Next article&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AI edits one function, breaks 10 callers&lt;/td&gt;
&lt;td&gt;Code graph + impact analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI modifies code it shouldn't touch&lt;/td&gt;
&lt;td&gt;Governance hints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What did AI even change this week?&lt;/td&gt;
&lt;td&gt;Event ledger&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Every session starts from zero&lt;/td&gt;
&lt;td&gt;Project memory layer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One article per pain point.&lt;/p&gt;




&lt;h2&gt;
  
  
  About aming-claw
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/amingclawdev/aming-claw" rel="noopener noreferrer"&gt;amingclawdev/aming-claw&lt;/a&gt; — open source&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Next post:&lt;/strong&gt; "AI breaks 10 callers when it edits one function" — coming this week&lt;/li&gt;
&lt;li&gt;Hit me with issues if you've felt this pain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If &lt;em&gt;"did the AI actually do that thing I asked?"&lt;/em&gt; sounds familiar, give the repo a star — it costs you nothing and tells me I'm not the only one.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is part 1 of an "AI Collaboration Survival Guide" series — practical tools for the messy reality of building with AI agents.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>devtools</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
