<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/scripts/pretty-feed-v3.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:h="http://www.w3.org/TR/html4/"><channel><title>Artificial Quirks</title><description>Industry notes on agent systems, evaluation, and production Agentic AI for architects and platform leads—quirks included.</description><link>https://astro-pure.js.org</link><item><title>Catching Hallucinated Paths: Quality Intercepts</title><link>https://astro-pure.js.org/blog/catching-hallucinated-paths</link><guid isPermaLink="true">https://astro-pure.js.org/blog/catching-hallucinated-paths</guid><description>How pre-finalization trajectory hooks catch ungrounded file paths and trigger self-correction turns before final answer submission.</description><pubDate>Sat, 04 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Imagine an AI agent confidently handing you a finished architectural plan. It looks perfect, the logic is sound, and the syntax is flawless. But when you go to implement it, you realize the agent cited a file path that doesn&apos;t exist. The plan is hallucinated.&lt;/p&gt;
&lt;p&gt;This is a pervasive issue in agentic planning. To combat it, our orchestration framework implements &lt;strong&gt;Pre-Finalization Quality Intercepts&lt;/strong&gt;—a system that catches hallucinated paths &lt;em&gt;before&lt;/em&gt; the agent is allowed to finalize its trajectory.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. The Anatomy of a Hallucination&lt;/h2&gt;
&lt;p&gt;When an agent analyzes a complex repository, it builds a mental model of the directory structure. Because LLMs are predictive text engines, they will often guess where a file &lt;em&gt;should&lt;/em&gt; be based on common conventions.&lt;/p&gt;
&lt;p&gt;For example, an agent might propose edits to &lt;code&gt;src/utils/logger.py&lt;/code&gt;, completely unaware that the project actually stores its logging module in &lt;code&gt;pkg/telemetry/logging.py&lt;/code&gt;. If the agent finalizes its plan with the hallucinated path, the entire run is a failure, regardless of how elegant the proposed code is.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. The Pre-Finalization Intercept&lt;/h2&gt;
&lt;p&gt;To solve this, we cannot rely on the agent checking its own work. We must introduce a host-side validation gate right before the agent calls its &lt;code&gt;submit_plan&lt;/code&gt; or &lt;code&gt;finalize&lt;/code&gt; tool.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://astro-pure.js.org/_vercel/image?url=_astro%2Fintercept.8OGWCDNk.png&amp;#x26;w=1080&amp;#x26;q=100&quot; alt=&quot;Quality Intercept Architecture&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The Hook:&lt;/strong&gt; When the agent attempts to submit its final artifact, the orchestrator intercepts the payload.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Path Grounding Check:&lt;/strong&gt; The host parses the artifact for any referenced file paths, code snippets, or module names. It then physically verifies these references against the actual filesystem and AST (Abstract Syntax Tree) of the repository.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Bounce:&lt;/strong&gt; If a path does not exist, the orchestrator rejects the submission. Instead of ending the run, it sends an error back to the agent: &lt;code&gt;&quot;Error: Proposed file src/utils/logger.py does not exist. Please use search tools to verify paths.&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;3. Forcing Self-Correction&lt;/h2&gt;
&lt;p&gt;By bouncing the submission, the intercept forces the agent into a &lt;strong&gt;Trajectory Repair Loop&lt;/strong&gt;. The agent must spend a turn using tools like &lt;code&gt;grep_search&lt;/code&gt; or &lt;code&gt;list_dir&lt;/code&gt; to ground its mental model in reality.&lt;/p&gt;
&lt;p&gt;This turns a silent, 0% quality failure into a slightly longer, but 100% grounded success. The intercept acts as an automated reviewer, ensuring that no hallucinated plans make it to the user.&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.BzW5D_io.png"/><enclosure url="/_astro/cover.BzW5D_io.png"/></item><item><title>What a Two-for-Two Agent Result Actually Proves</title><link>https://astro-pure.js.org/blog/interpreting-two-two-agent-results</link><guid isPermaLink="true">https://astro-pure.js.org/blog/interpreting-two-two-agent-results</guid><description>A 2/2 completion result is useful evidence of a cohort outcome; it is not automatically proof of a mechanism or a production default.</description><pubDate>Wed, 01 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Small agent cohorts are common because each repeat can consume minutes, millions of tokens, and a full repository snapshot. The wrong response is to dismiss every two-run result. The equally wrong response is to turn 2/2 into a universal claim.&lt;/p&gt;
&lt;p&gt;The useful move is to name the level of evidence precisely.&lt;/p&gt;
&lt;h2&gt;Three claims that look similar but are not&lt;/h2&gt;
&lt;p&gt;| Claim | What supports it | What it does not establish |
| --- | --- | --- |
| Cohort outcome | Two runs completed under the recorded configuration | That another configuration will do the same |
| Mechanism effect | Runs exercised the intervention and differ from a relevant control | That success came from an unrelated change |
| Default-policy readiness | Replication across tasks, repeats, and failure modes | That the policy is harmless in all production contexts |&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./evidence-claim-ladder.svg&quot; alt=&quot;Schematic evidence ladder separating a small cohort outcome from mechanism evidence and default-policy readiness&quot;&gt;&lt;/p&gt;
&lt;p&gt;The test-repair fallback cohort completed 2/2, verified 22/22 grounding claims, and scored 1.00 in both repeats. That establishes a strong &lt;strong&gt;cohort outcome&lt;/strong&gt;: those two recorded runs finished and passed the harness checks.&lt;/p&gt;
&lt;p&gt;It does not directly establish the intended repair mechanism. Neither repeat re-triggered the exact rejected-test-reference branch after the fallback was introduced. The cohort is non-regression evidence for the stricter loop, not a branch-level causal demonstration.&lt;/p&gt;
&lt;h2&gt;Compare it with the checkpoint study&lt;/h2&gt;
&lt;p&gt;The checkpoint experiment had a more suggestive mechanism contrast: baseline completed 0/2 while the checkpoint arm completed 2/2.&lt;/p&gt;
&lt;p&gt;| Arm | Repeats | Completion | Mean tokens | Mean iterations |
| --- | ---: | ---: | ---: | ---: |
| Baseline | 2 | 0% | 667,729 | 42.5 |
| Checkpoint 70 + 5 | 2 | 100% | 1,087,231 | 67.0 |&lt;/p&gt;
&lt;p&gt;Even here, caution is required. One checkpoint repeat finalized before the checkpoint could matter. One baseline run failed before accepting a trajectory action. The clean comparison is not “the checkpoint costs 63% more”; it is “the experiment found a 2-versus-0 completion split with heterogeneous failure mechanisms.”&lt;/p&gt;
&lt;h2&gt;A practical interpretation template&lt;/h2&gt;
&lt;p&gt;For every small-cohort result, write four sentences before deciding what to do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Observed:&lt;/strong&gt; What exactly happened, with repeat count and configuration?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mechanism:&lt;/strong&gt; Which runs directly exercised the intervention?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Confounders:&lt;/strong&gt; What alternative explanation or uneven failure occurred?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decision:&lt;/strong&gt; Keep as research-only, rerun, harden, or promote?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Applied to the fallback cohort:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Observed: both configured repeats completed and verified.&lt;/li&gt;
&lt;li&gt;Mechanism: neither directly exercised the target invalid-test branch.&lt;/li&gt;
&lt;li&gt;Confounder: finalization error types differed from the motivating failures.&lt;/li&gt;
&lt;li&gt;Decision: keep the fallback, retain unit coverage, and add a deterministic branch-forcing benchmark before attributing the result to that mechanism.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is not timid language. It is a decision that preserves a useful improvement without laundering uncertainty into a default.&lt;/p&gt;
&lt;h2&gt;Counterfactual: when is 2/2 enough?&lt;/h2&gt;
&lt;p&gt;Two runs can be enough for a local engineering decision when the intervention is low-risk, easy to roll back, and the result is corroborated by deterministic tests. For example, keeping a prompt clarification behind a strict validator is different from changing a global production execution policy.&lt;/p&gt;
&lt;p&gt;Two runs are not enough when the decision changes safety boundaries, cost ceilings, default model routing, or the interpretation of a public benchmark. Those need more tasks, more repeats, and explicit sensitivity analysis.&lt;/p&gt;
&lt;h2&gt;The next experiment&lt;/h2&gt;
&lt;p&gt;The next fallback study should pre-specify the failure branch and force it: inject an invalid test reference, return zero related tests, then assert that the revised plan puts the same planned path in &lt;code&gt;tests&lt;/code&gt; and &lt;code&gt;expected_files&lt;/code&gt; within allowed scope. Run at least four repeats per arm against a control. Report all runs and the subset that actually reached the branch.&lt;/p&gt;
&lt;p&gt;That experiment would not make the whole planner reliable. It would transform the current inference from “the system passed a later cohort” to “this recovery mechanism worked under its intended trigger.”&lt;/p&gt;
&lt;h2&gt;Cohort results at a glance&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;./completion-rate.svg&quot; alt=&quot;Both the checkpoint candidate and fallback cohorts completed two of two runs, but they provide different levels of mechanism evidence&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./token-usage.svg&quot; alt=&quot;Raw mean token use reflects heterogeneous run lengths and failures, not an isolated intervention cost&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;2/2 is a fact about a cohort, not a synonym for general reliability.&lt;/li&gt;
&lt;li&gt;Direct branch coverage is stronger than post-hoc narrative alignment.&lt;/li&gt;
&lt;li&gt;State confounders next to the headline, not in a footnote.&lt;/li&gt;
&lt;li&gt;Use small cohorts to choose the next discriminating experiment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the repair-loop design behind this example, see &lt;a href=&quot;/blog/bounded-agent-repair-loops&quot;&gt;Designing Bounded Repair Loops for Agent Plans&lt;/a&gt;.&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.KGDpCLMU.png"/><enclosure url="/_astro/cover.KGDpCLMU.png"/></item><item><title>The Security Cost of Autonomy: Traversal Risks</title><link>https://astro-pure.js.org/blog/security-cost-autonomy</link><guid isPermaLink="true">https://astro-pure.js.org/blog/security-cost-autonomy</guid><description>Empirical security audit results from 29 benchmark study runs evaluating container mount points, path traversal attempts, and write-tool boundaries.</description><pubDate>Tue, 23 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When you deploy a fleet of autonomous agents across 29 parallel experimental runs, you aren&apos;t just testing intelligence—you are stress-testing your infrastructure&apos;s security posture.&lt;/p&gt;
&lt;p&gt;In a recent benchmarking study using our orchestration framework, we subjected 29 Recursive Language Model (RLM) trajectories to a rigorous security audit, specifically looking for path traversal attempts and container mount escapes. The results illuminate the hidden costs of agent autonomy.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. The Threat Model&lt;/h2&gt;
&lt;p&gt;An agent with access to file-writing tools (like &lt;code&gt;replace_file_content&lt;/code&gt; or &lt;code&gt;write_to_file&lt;/code&gt;) poses an inherent risk of Path Traversal. If an agent decides to write to &lt;code&gt;../../../../etc/passwd&lt;/code&gt; or &lt;code&gt;/root/.ssh/authorized_keys&lt;/code&gt;, the orchestrator must intercept it.&lt;/p&gt;
&lt;p&gt;In our swarm, worker nodes use Docker volumes to mount the target repository into &lt;code&gt;/workspace&lt;/code&gt;. The threat model assumes the agent is actively trying (intentionally or through hallucination) to escape this volume.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. The Audit Findings&lt;/h2&gt;
&lt;p&gt;Across the 29 runs, the security telemetry logged the following behaviors:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./audit-chart.svg&quot; alt=&quot;Security Audit Chart&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Path Traversal Attempts (14 incidents):&lt;/strong&gt; 14 distinct trajectories attempted to use &lt;code&gt;../&lt;/code&gt; to navigate outside the &lt;code&gt;/workspace&lt;/code&gt; root. These were largely driven by the model attempting to locate global configuration files it assumed existed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Absolute Path Violations (8 incidents):&lt;/strong&gt; 8 trajectories attempted to write directly to &lt;code&gt;/tmp/&lt;/code&gt; or &lt;code&gt;/var/log/&lt;/code&gt;, ignoring instructions to use the workspace.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mount Escape Attempts (0 incidents):&lt;/strong&gt; Thanks to strict canonical path resolution in the host tools, 0 trajectories successfully escaped the bind mount.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;How the Host Protects the System&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def resolve_secure_path(workspace_root: str, requested_path: str) -&gt; Path:
    base = Path(workspace_root).resolve()
    target = (base / requested_path).resolve()
    
    if not target.is_relative_to(base):
        raise SecurityException(f&quot;Path traversal blocked: {requested_path}&quot;)
    return target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every tool execution in our orchestration framework runs through a path resolver like the one above. The host calculates the absolute canonical path of the requested file and strictly verifies it is a child of the workspace root.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;3. The Cost of Security&lt;/h2&gt;
&lt;p&gt;Intercepting these actions comes with a cost. When a traversal is blocked, the agent receives an error. It must then spend another inference turn (and precious tokens) analyzing the error and trying a different path.&lt;/p&gt;
&lt;p&gt;This is the &quot;Security Cost of Autonomy.&quot; We pay for infrastructure safety with token latency. However, as the audit proves, it is a necessary tax to ensure that 29 parallel runs can execute safely without compromising the host architecture.&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.BfwKKqnu.png"/><enclosure url="/_astro/cover.BfwKKqnu.png"/></item><item><title>Inside the Sandbox: Shell Execution Kills Reliability</title><link>https://astro-pure.js.org/blog/inside-sandbox</link><guid isPermaLink="true">https://astro-pure.js.org/blog/inside-sandbox</guid><description>Exploring why allowing agents arbitrary host shell access leads to non-deterministic failures and why strict Docker isolation is mandatory for production.</description><pubDate>Sun, 21 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When building autonomous agents, the easiest path to giving a model &quot;power&quot; is to hand it a raw shell. Need to install a package? Run &lt;code&gt;pip install&lt;/code&gt;. Need to find a file? Run &lt;code&gt;find / -name &quot;*.py&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It feels powerful, but in production, unconstrained shell execution is a reliability nightmare. In our orchestration framework, we discovered that soft prompt instructions (&quot;don&apos;t delete files outside the workspace&quot;) are fundamentally incapable of preventing an agent from accidentally bricking its environment.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. The Illusion of Prompt Security&lt;/h2&gt;
&lt;p&gt;LLMs are probabilistic. They do not natively understand the difference between &lt;code&gt;rm -rf ./tmp/&lt;/code&gt; and &lt;code&gt;rm -rf /tmp/&lt;/code&gt;. When an agent is confused, hallucinating, or stuck in a loop, it will try commands that seem plausible but are environmentally destructive.&lt;/p&gt;
&lt;p&gt;In early studies, we observed agents:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Overwriting global Python installations because they couldn&apos;t figure out virtual environments.&lt;/li&gt;
&lt;li&gt;Killing system processes while attempting to &quot;free up memory.&quot;&lt;/li&gt;
&lt;li&gt;Entering recursive &lt;code&gt;grep&lt;/code&gt; loops over &lt;code&gt;/usr/bin&lt;/code&gt; that exhausted API time limits.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Prompting the model to &quot;be careful&quot; is not security; it&apos;s a suggestion.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. Hard Isolation is the Only Fix&lt;/h2&gt;
&lt;p&gt;To achieve reliability, the execution boundary must be enforced by the host, not the model. This is why our orchestration framework relies on strict Docker isolation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://astro-pure.js.org/_vercel/image?url=_astro%2Fsandbox.BMxFjCJX.png&amp;#x26;w=1080&amp;#x26;q=100&quot; alt=&quot;Sandbox Isolation Architecture&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Network Mode &lt;code&gt;none&lt;/code&gt;:&lt;/strong&gt; Agents cannot reach out to the internet to download unverified binaries or leak data. If an agent needs a tool, it must be explicitly provisioned in the container image.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read-Only Root:&lt;/strong&gt; The container&apos;s root filesystem is mounted as read-only. Agents can only write to a tightly scoped &lt;code&gt;/workspace&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PIDs and IPC Isolation:&lt;/strong&gt; Agents cannot see or interact with host processes. They operate in a sterile vacuum.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;3. Designing for Determinism&lt;/h2&gt;
&lt;p&gt;By removing the agent&apos;s ability to alter the global state of the machine, we force determinism. If an agent fails in a strictly isolated sandbox, we know exactly why it failed: it couldn&apos;t solve the logic problem, not because it accidentally corrupted the &lt;code&gt;apt&lt;/code&gt; cache.&lt;/p&gt;
&lt;p&gt;When building agent systems, stop treating the shell as a feature. Treat it as a vulnerability that must be ruthlessly contained.&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.uli4W-9D.png"/><enclosure url="/_astro/cover.uli4W-9D.png"/></item><item><title>Strategies, Not Model Ifs</title><link>https://astro-pure.js.org/blog/rlm-execution-strategies</link><guid isPermaLink="true">https://astro-pure.js.org/blog/rlm-execution-strategies</guid><description>Named strategy presets beat model-id ifs: cell budgets, history caps, and hybrid phases on one object.</description><pubDate>Wed, 17 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you run more than one model through the same recursive agent loop, a single default policy will usually punish at least one of them. A multi-fence model that plans in five code blocks can burn a tool budget in a few turns; a one-cell-friendly model may look “disciplined” under the same knobs and finish cleanly. The instinctive fix — &lt;code&gt;if &quot;vendor&quot; in model:&lt;/code&gt; inside the engine — does not age well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Claim.&lt;/strong&gt; Separate &lt;strong&gt;who runs&lt;/strong&gt; (model profile) from &lt;strong&gt;how the loop runs&lt;/strong&gt; (a named execution strategy). Encode strategies as data (YAML presets), bind them optionally from profiles, and let &lt;strong&gt;task metadata win&lt;/strong&gt; on every key. Keep the runtime free of model-name branches.&lt;/p&gt;
&lt;p&gt;This note is from live recursive-agent work in mid‑2026: multi-cell thrash on long reviews, disciplined short plans, and human-in-the-loop “extend budget” actions that did nothing because the wrong ledger row was raised. Numbers and presets below are &lt;strong&gt;starting points from that dogfood&lt;/strong&gt;, not universal optima.&lt;/p&gt;
&lt;h2&gt;What this article assumes&lt;/h2&gt;
&lt;p&gt;We talk about a &lt;strong&gt;recursive language-model (RLM) loop&lt;/strong&gt;: the model proposes fenced &lt;strong&gt;code cells&lt;/strong&gt;, a runtime executes them in a REPL, returns &lt;strong&gt;observations&lt;/strong&gt;, and repeats until the model emits a terminal signal (&lt;code&gt;FINAL&lt;/code&gt;), or a budget trips (steps, tools, model calls).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./arch-rlm-loop.svg&quot; alt=&quot;Recursive agent loop&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure: one simplified turn. “Cell” means one executed fenced block, not a notebook metaphor only.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You do not need our particular codebase to use the idea. Any agent stack with multi-turn tool use and more than one model personality hits the same design fork.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Companion notes&lt;/strong&gt; in this series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/rlm-small-cells&quot;&gt;When smaller cells make agents worse&lt;/a&gt; — prompting changes cell shape; &lt;strong&gt;horizon&lt;/strong&gt; still decides completion.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/rlm-history-compaction&quot;&gt;RLM is not automatically token-efficient&lt;/a&gt; — history caps belong on the &lt;strong&gt;same&lt;/strong&gt; strategy object as cell and tool limits.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The problem: one loop, two behaviors&lt;/h2&gt;
&lt;p&gt;| Behavior | Typical model style | Failure under one-size defaults |
|----------|---------------------|----------------------------------|
| One cell / turn, converges | Single-cell-friendly | Fine near modest &lt;code&gt;max_tool_calls&lt;/code&gt; |
| Many cells / turn, exploratory | Multi-fence | Burns cell/tool budget quickly; raising &lt;em&gt;root steps&lt;/em&gt; alone does not help |&lt;/p&gt;
&lt;p&gt;The useful product question is not “do we need different models?” It is: &lt;strong&gt;do we need different approaches&lt;/strong&gt; — and can we change approaches without forking the engine?&lt;/p&gt;
&lt;h2&gt;Architecture: who vs how&lt;/h2&gt;
&lt;p&gt;| Axis | Config surface | Meaning |
|------|----------------|---------|
| &lt;strong&gt;Who&lt;/strong&gt; | Profile registry (&lt;code&gt;profiles.yaml&lt;/code&gt;) | Provider + model id (+ optional default strategy id) |
| &lt;strong&gt;How&lt;/strong&gt; | Strategy registry (&lt;code&gt;rlm_config.yaml&lt;/code&gt;) | Iterations, tool/model caps, cells/turn, prompt style, history, addons |&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./arch-strategy-binding.svg&quot; alt=&quot;Who vs how binding&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure: profiles point at strategies; tasks can override either the whole preset or individual keys. The runtime never branches on the model string.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Resolution order (highest wins &lt;strong&gt;per key&lt;/strong&gt;)&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;task.metadata[key]
  &gt;  task.metadata.rlm_config_id  (named preset)
  &gt;  profile.rlm_config_id        (convenience default)
  &gt;  AGENT_RLM_CONFIG / &quot;default&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;./resolution-priority.svg&quot; alt=&quot;Resolution priority&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure: rank only — a task key always beats a profile-bound preset for that key.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Why not model &lt;code&gt;if&lt;/code&gt;s&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;New models appear constantly.&lt;/strong&gt; Engine forks rot.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Same model, different jobs.&lt;/strong&gt; A short probe may want multi-block batching; a long review may want hybrid late discipline (&lt;a href=&quot;/blog/rlm-small-cells&quot;&gt;cell A/B&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Evals need pure strategy diffs&lt;/strong&gt; without swapping weights.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operators&lt;/strong&gt; should add presets without shipping Python.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Named presets (illustrative shape)&lt;/h2&gt;
&lt;p&gt;| Preset | Intent | Typical binding |
|--------|--------|-----------------|
| &lt;code&gt;default&lt;/code&gt; | Conservative shared baseline | env / fallback |
| &lt;code&gt;disciplined&lt;/code&gt; | One-cell-friendly, tighter output | single-cell-oriented profiles |
| &lt;code&gt;exploratory&lt;/code&gt; | High tool headroom, multi-cell OK, hybrid late phase, write-early nudge | multi-fence profiles |&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./preset-budgets.svg&quot; alt=&quot;Preset budget comparison&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure: &lt;code&gt;max_cells/turn&lt;/code&gt; of 0 means &lt;strong&gt;no hard cap&lt;/strong&gt; (&lt;code&gt;null&lt;/code&gt; in config) for &lt;code&gt;default&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# rlm_config.yaml (abridged)
configs:
  default:
    max_tool_calls: 200
    max_model_calls: 40
    max_code_blocks_per_turn: null
    prompt_style: multi_block
    history_keep_recent_turns: 6
    history_max_total_chars: 80000

  disciplined:
    max_tool_calls: 200
    max_code_blocks_per_turn: 1
    prompt_style: single_block
    history_max_total_chars: 60000

  exploratory:
    max_tool_calls: 1000
    max_code_blocks_per_turn: 12
    hybrid_switch_after_turns: 3
    late_max_code_blocks_per_turn: 4
    prompt_style: multi_block_budgeted
    system_prompt_addon: &gt;-
      Prefer batched reads; write findings early under a reviews path;
      after orientation, fewer smaller cells and FINAL soon.
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# profiles.yaml (bindings)
single-cell-model:
  provider: gateway
  model: vendor/single-cell-model
  rlm_config_id: disciplined

multi-fence-model:
  provider: gateway
  model: vendor/multi-fence-model
  rlm_config_id: exploratory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Task authors still win:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;agent:
  profile: multi-fence-model
metadata:
  rlm_config_id: disciplined   # force a different approach
  max_tool_calls: 500          # one-off key override
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Knobs that earned a place&lt;/h2&gt;
&lt;p&gt;| Knob | Why it showed up in practice |
|------|------------------------------|
| &lt;code&gt;max_tool_calls&lt;/code&gt; / &lt;code&gt;max_model_calls&lt;/code&gt; | Real stop reasons; must seed a &lt;strong&gt;ledger&lt;/strong&gt; so “extend budget” raises the limit that actually fired |
| &lt;code&gt;max_code_blocks_per_turn&lt;/code&gt; | Soft prompt styles leak on turn 0; the runtime can execute the first N and note deferred cells |
| &lt;code&gt;prompt_style&lt;/code&gt; | &lt;code&gt;single_block&lt;/code&gt; / &lt;code&gt;multi_block&lt;/code&gt; / &lt;code&gt;multi_block_budgeted&lt;/code&gt; as &lt;strong&gt;data&lt;/strong&gt;, not forked system prompts |
| &lt;code&gt;system_prompt_addon&lt;/code&gt; | Write-early and “budget is finite” steers without new code paths |
| Hybrid late phase | Explore with a higher cell cap, then tighten (long multi-fence reviews) |
| History working set | Stops input escalators (&lt;a href=&quot;/blog/rlm-history-compaction&quot;&gt;token note&lt;/a&gt;) |&lt;/p&gt;
&lt;h3&gt;Ledger honesty (operations)&lt;/h3&gt;
&lt;p&gt;A recurring failure mode: the runtime stops on &lt;strong&gt;&lt;code&gt;max_tool_calls&lt;/code&gt;&lt;/strong&gt;, a human “extends budget” by raising &lt;strong&gt;root steps&lt;/strong&gt; or an unset ledger row, and warm-continue changes nothing useful.&lt;/p&gt;
&lt;p&gt;Strategy work is operationally real only when:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Limits from the resolved strategy are &lt;strong&gt;seeded&lt;/strong&gt; on the budget ledger (not left &lt;code&gt;None&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Actual tool/model counts are &lt;strong&gt;settled&lt;/strong&gt; each invocation.&lt;/li&gt;
&lt;li&gt;Warm-continue &lt;strong&gt;grants remaining&lt;/strong&gt; against the raised ceiling.&lt;/li&gt;
&lt;li&gt;Gates surface &lt;strong&gt;&lt;code&gt;exhaustion_reason&lt;/code&gt;&lt;/strong&gt; so operators know which knob tripped.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Without that, “exploratory with 1000 tool calls” is a paper policy.&lt;/p&gt;
&lt;h2&gt;Worked scenarios&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A — short multi-fence probe.&lt;/strong&gt; Default &lt;code&gt;exploratory&lt;/code&gt; may be wrong: multi-block batching can still finish under a short step budget (see the &lt;a href=&quot;/blog/rlm-small-cells&quot;&gt;A/B note&lt;/a&gt;). If you force &lt;code&gt;disciplined&lt;/code&gt; for measurement, treat &lt;strong&gt;completion risk&lt;/strong&gt; as part of the experiment, not a surprise.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;B — long multi-fence review.&lt;/strong&gt; Profile default &lt;code&gt;exploratory&lt;/code&gt; gives tool headroom, hybrid late nudge, and history caps. If you see &lt;code&gt;exhaustion_reason=max_tool_calls&lt;/code&gt;, extend the &lt;strong&gt;tool&lt;/strong&gt; budget — not steps alone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C — single-cell-friendly implement.&lt;/strong&gt; Profile &lt;code&gt;disciplined&lt;/code&gt; keeps one-cell cadence; the task can still raise &lt;code&gt;max_iterations&lt;/code&gt; without rewriting engine code.&lt;/p&gt;
&lt;h2&gt;Counterfactuals&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;If one global default were enough,&lt;/strong&gt; multi-fence multi-cell burn and single-cell success would both be well-served by something like &lt;code&gt;max_tool_calls≈100&lt;/code&gt; and multi-block prompts. Live runs showed they are not.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Auto-tune from telemetry&lt;/strong&gt; is a different product. It still needs a strategy representation like this YAML; it does not remove the who/how split.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Per-provider adapter forks&lt;/strong&gt; multiply code paths and fight “same stack, many models.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Falsifier for this architecture:&lt;/strong&gt; a required behavior that cannot be expressed as strategy keys without reading &lt;code&gt;model&lt;/code&gt; in the engine. None appeared in this design pass for cell caps, prompts, history, or budgets.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Limitations&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Preset numbers (&lt;code&gt;1000&lt;/code&gt; tools, &lt;code&gt;12&lt;/code&gt; cells, hybrid after 3) are &lt;strong&gt;starting points&lt;/strong&gt;, not optimized frontiers.&lt;/li&gt;
&lt;li&gt;Profile → strategy binding is a &lt;strong&gt;convenience&lt;/strong&gt;; a mis-bound profile silently changes cost envelopes — snapshot defaults with each run.&lt;/li&gt;
&lt;li&gt;Hard cell caps can surprise models that planned later fences; deferred-cell messaging must stay explicit.&lt;/li&gt;
&lt;li&gt;This article does &lt;strong&gt;not&lt;/strong&gt; claim hybrid + compaction &lt;strong&gt;fixed deliverable writes&lt;/strong&gt;; token and cell behavior improved while write thrash could remain (&lt;a href=&quot;/blog/rlm-history-compaction&quot;&gt;token note&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Split &lt;strong&gt;who&lt;/strong&gt; (profile) from &lt;strong&gt;how&lt;/strong&gt; (strategy preset).&lt;/li&gt;
&lt;li&gt;Encode approaches in &lt;strong&gt;data&lt;/strong&gt;; resolve with a clear override stack; &lt;strong&gt;never&lt;/strong&gt; branch the engine on model id strings.&lt;/li&gt;
&lt;li&gt;Put every enforced limit on the &lt;strong&gt;ledger&lt;/strong&gt;, or human “extend” actions will lie.&lt;/li&gt;
&lt;li&gt;Keep &lt;strong&gt;history&lt;/strong&gt; and &lt;strong&gt;cell&lt;/strong&gt; policy on the same strategy object — they interact with tool budgets.&lt;/li&gt;
&lt;li&gt;Use task metadata when the job’s horizon disagrees with the model’s default personality (&lt;a href=&quot;/blog/rlm-small-cells&quot;&gt;smaller cells&lt;/a&gt;).&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="/_astro/cover.B0bAEdHQ.png"/><enclosure url="/_astro/cover.B0bAEdHQ.png"/></item><item><title>When Smaller Cells Make Agents Worse</title><link>https://astro-pure.js.org/blog/rlm-small-cells</link><guid isPermaLink="true">https://astro-pure.js.org/blog/rlm-small-cells</guid><description>Smaller cells cut cells/turn but can exhaust step budgets; match policy to horizon, not aesthetics.</description><pubDate>Fri, 05 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Making an agent emit &lt;em&gt;smaller, fewer code cells per turn&lt;/em&gt; sounds like pure upside: tighter discipline, less thrash, easier observations. Sometimes it is. Sometimes it is how you fail a short task while your dashboards look healthier.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Claim.&lt;/strong&gt; In a controlled multi-fence-model A/B on a recursive agent stack, prompting for smaller cells improved &lt;strong&gt;cell shape&lt;/strong&gt; and hurt &lt;strong&gt;task completion&lt;/strong&gt; under a short root-step budget. Cell aesthetics are a &lt;strong&gt;diagnostic&lt;/strong&gt;, not a success metric. Match cell policy to &lt;strong&gt;horizon&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This is a research note from mid‑2026 dogfooding (&lt;strong&gt;n = 1&lt;/strong&gt; clean comparable pair). Treat effect sizes as &lt;strong&gt;directional&lt;/strong&gt;, not population estimates. It is not a claim about all models or all task lengths.&lt;/p&gt;
&lt;h2&gt;Background: cells in a recursive loop&lt;/h2&gt;
&lt;p&gt;The runtime drives a simple cycle: the model emits fenced Python &lt;strong&gt;cells&lt;/strong&gt;, the environment executes them, observations return, and the loop continues until &lt;code&gt;FINAL&lt;/code&gt;, budget exhaustion, or a human pause.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./arch-rlm-loop.svg&quot; alt=&quot;Recursive agent loop&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure: each “model call → cells → observation” cycle typically costs one root step. Batching work into one multi-cell turn can be the efficient encoding of a short plan.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Models differ wildly in how many fences they emit per call:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Single-cell-friendly&lt;/strong&gt; models often converge with one-cell-ish turns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-fence&lt;/strong&gt; models under default multi-block prompting often dump many fences in one response.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A natural reaction is: &lt;em&gt;prompt the model to prefer smaller cells.&lt;/em&gt; We tested that &lt;strong&gt;with prompting only&lt;/strong&gt; — no hard &lt;code&gt;max_code_blocks_per_turn&lt;/code&gt; — on a short plan-mode container security probe (&lt;strong&gt;10&lt;/strong&gt; root steps, &lt;strong&gt;50&lt;/strong&gt; tool calls).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Series companions:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/rlm-history-compaction&quot;&gt;RLM is not automatically token-efficient&lt;/a&gt; — when the cost problem is &lt;em&gt;input growth&lt;/em&gt;, not cell count.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/rlm-execution-strategies&quot;&gt;Strategies, not model ifs&lt;/a&gt; — why cell policy should be a selectable strategy, not a global moral.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Architecture of the failure mode&lt;/h2&gt;
&lt;p&gt;Under a fixed step ceiling, multi-block batching and single-cell discipline use the budget differently:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./arch-cell-horizon.svg&quot; alt=&quot;Cell policy vs step horizon&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure: Arm A finishes inside the budget; Arm B spends steps on per-cell model rounds and hits the wall without &lt;code&gt;FINAL&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Experimental setup&lt;/h2&gt;
&lt;p&gt;| Arm | Run id | &lt;code&gt;prompt_style&lt;/code&gt; | Extra |
|-----|--------|----------------|--------|
| &lt;strong&gt;A baseline&lt;/strong&gt; | &lt;code&gt;run-a-baseline&lt;/code&gt; | &lt;code&gt;multi_block&lt;/code&gt; | none |
| &lt;strong&gt;B small-cell&lt;/strong&gt; | &lt;code&gt;run-b-smallcell&lt;/code&gt; | &lt;code&gt;single_block&lt;/code&gt; | system addon: prefer ≤1 short cell/turn |&lt;/p&gt;
&lt;p&gt;Same task family, same multi-fence model family; the difference is &lt;strong&gt;prompting&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Footnote (provisional):&lt;/strong&gt; the first B attempt failed on a container-daemon race while another run shared the host runtime; metrics below are from a clean re-run.&lt;/p&gt;
&lt;h2&gt;Results&lt;/h2&gt;
&lt;p&gt;| Metric | A baseline | B small-cell | Δ (B−A) |
|--------|------------:|-------------:|--------:|
| Outcome | completed / FINAL | blocked (10 steps, no FINAL) | — |
| Iterations | 1 | 10 | +9 |
| Total cells | 5 | 15 | +10 |
| Cells/turn mean | &lt;strong&gt;5.0&lt;/strong&gt; | &lt;strong&gt;1.5&lt;/strong&gt; | &lt;strong&gt;−3.5&lt;/strong&gt; |
| Cells/turn max | 5 | 6 | +1 |
| Cells/turn series | &lt;code&gt;[5]&lt;/code&gt; | &lt;code&gt;[6,1,1,1,1,1,1,1,1,1]&lt;/code&gt; | — |
| Code chars mean | 299 | &lt;strong&gt;92&lt;/strong&gt; | &lt;strong&gt;−207&lt;/strong&gt; |
| Code chars median | 318 | &lt;strong&gt;64&lt;/strong&gt; | — |&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./ab-metrics.svg&quot; alt=&quot;A/B metrics: cells/turn, code size, iterations&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure: mixed-unit grouped bars — compare bars &lt;strong&gt;within&lt;/strong&gt; each metric, not across metrics.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./outcome-proxy.svg&quot; alt=&quot;Completion proxy&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure: A reached FINAL; B did not under the same step ceiling.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;What the cell series shows&lt;/h3&gt;
&lt;p&gt;After turn 0, arm B stayed at &lt;strong&gt;one cell per turn for nine turns&lt;/strong&gt;. Mean cell text was roughly &lt;strong&gt;3× shorter&lt;/strong&gt;. Prompting &lt;em&gt;did&lt;/em&gt; change behavior.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./cells-per-turn-b.svg&quot; alt=&quot;B arm cells per turn&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure: sticky multi-fence open (6), then disciplined single-cell turns — and still no FINAL by step 10.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Core argument&lt;/h2&gt;
&lt;h3&gt;1. Cell discipline is not the objective function&lt;/h3&gt;
&lt;p&gt;Arm B optimized proxies operators like (cells/turn, code length). Arm A optimized what the eval scored: &lt;strong&gt;finish the short probe&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;On a &lt;strong&gt;10-step&lt;/strong&gt; budget, a multi-block turn with five related micro-reads can be the efficient encoding of “one planning step.” Forcing one micro-step per model call multiplies &lt;strong&gt;model rounds&lt;/strong&gt; — each with latency and fixed overhead — until the step ledger hits the wall.&lt;/p&gt;
&lt;h3&gt;2. The first turn is sticky&lt;/h3&gt;
&lt;p&gt;Even with &lt;code&gt;single_block&lt;/code&gt; + “prefer one short cell,” B still opened with &lt;strong&gt;six fences once&lt;/strong&gt;. Soft guidance is not a hard guarantee on an opening plan dump. If the risk is “turn 0 burns the tool budget,” &lt;strong&gt;prompting alone is insufficient&lt;/strong&gt; — you need engine caps or deferred-cell policy (&lt;a href=&quot;/blog/rlm-execution-strategies&quot;&gt;strategies&lt;/a&gt;).&lt;/p&gt;
&lt;h3&gt;3. When smaller cells &lt;em&gt;are&lt;/em&gt; the right medicine&lt;/h3&gt;
&lt;p&gt;The same period’s longer multi-fence review thrash showed the opposite failure mode: many cells, re-scans, tool-budget blowups, no deliverable. There, smaller cells (or hybrid late-phase caps) target &lt;strong&gt;long-horizon thrash&lt;/strong&gt;, not a 10-step probe.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Labeled inference:&lt;/strong&gt; short probes often reward batching; long exploratory reviews may reward turn discipline + write-early pressure. Collapsing both into “always small cells” is a design error.&lt;/p&gt;
&lt;h2&gt;Worked example: reading the dashboard&lt;/h2&gt;
&lt;p&gt;| Dashboard signal | B looks… | Actual task outcome |
|------------------|----------|---------------------|
| Cells/turn | excellent | blocked |
| Code chars | excellent | blocked |
| Iterations used | “working hard” | exhausted |
| FINAL / artifact | — | missing |&lt;/p&gt;
&lt;p&gt;Without an &lt;strong&gt;outcome column&lt;/strong&gt; (&lt;code&gt;FINAL&lt;/code&gt;, files changed, verify score), B wins a beauty contest and loses the job.&lt;/p&gt;
&lt;h2&gt;Counterfactuals&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;If “smaller cells always help” were true,&lt;/strong&gt; B should match or beat A on completion under the same budgets. It did not here — falsifying the &lt;strong&gt;universal&lt;/strong&gt; form of the claim for this setup.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Alternative explanation:&lt;/strong&gt; not cell size, but &lt;em&gt;slower exploration&lt;/em&gt; under a hard step cap. More steps might let B finish — that is a &lt;strong&gt;different experiment&lt;/strong&gt;, not a free rescue of the universal claim.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hard cap counterfactual:&lt;/strong&gt; set &lt;code&gt;max_code_blocks_per_turn: 1&lt;/code&gt; in the runtime instead of prompting. Expect less first-turn leakage; completion still depends on step budget. Not run in this A/B (prompt-only by design).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Long-horizon counterfactual:&lt;/strong&gt; re-run with 40+ steps and an artifact success metric. Prediction: B or hybrid may dominate if A thrash-burns tools early. &lt;strong&gt;Provisional&lt;/strong&gt; until re-run.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Limitations&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;n = 1&lt;/strong&gt; clean pair (plus one failed B attempt). Directional only.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prompt-only&lt;/strong&gt; intervention; engine cell caps and hybrid schedules are out of scope for these numbers.&lt;/li&gt;
&lt;li&gt;Task is a &lt;strong&gt;short plan-mode probe&lt;/strong&gt;, not a full review deliverable.&lt;/li&gt;
&lt;li&gt;One multi-fence profile; do not export to “all multi-fence models” without replication.&lt;/li&gt;
&lt;li&gt;Token thrash metrics live in the &lt;a href=&quot;/blog/rlm-history-compaction&quot;&gt;companion token article&lt;/a&gt;; do not mix those totals into this A/B.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Measure completion, not only cell aesthetics.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Match cell policy to horizon.&lt;/strong&gt; Short step budgets can make multi-block batching &lt;em&gt;more&lt;/em&gt; efficient.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prompting moves means; it does not seal turn 0.&lt;/strong&gt; For guarantees, use strategy knobs (&lt;code&gt;max_code_blocks_per_turn&lt;/code&gt;, hybrid late phase) in &lt;a href=&quot;/blog/rlm-execution-strategies&quot;&gt;strategies&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Next experiment:&lt;/strong&gt; same A/B with artifact success + longer step budget; report cells/turn &lt;em&gt;and&lt;/em&gt; FINAL &lt;em&gt;and&lt;/em&gt; tokens in/out.&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="/_astro/cover.C8pplKQu.png"/><enclosure url="/_astro/cover.C8pplKQu.png"/></item><item><title>RLM Is Not Automatically Token-Efficient</title><link>https://astro-pure.js.org/blog/rlm-history-compaction</link><guid isPermaLink="true">https://astro-pure.js.org/blog/rlm-history-compaction</guid><description>History thrash erases recursive-loop savings; compaction plateaus input without fixing write thrash alone.</description><pubDate>Mon, 01 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recursive agent loops are often sold as a way to &lt;em&gt;work longer without stuffing the whole world into one prompt&lt;/em&gt;. That can be true for &lt;strong&gt;task structure&lt;/strong&gt;. It is &lt;strong&gt;false by default&lt;/strong&gt; for &lt;strong&gt;token cost&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If every model call re-sends a growing dialog of tool traces and observations, &lt;strong&gt;input tokens climb nearly monotonically&lt;/strong&gt;. Efficiency is a &lt;strong&gt;history policy&lt;/strong&gt;, not a free property of “being recursive.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Evidence (directional, mid‑2026 dogfood, multi-fence model, security-review style runs):&lt;/strong&gt; with history compaction, per-call input &lt;strong&gt;plateaued around 14–16k&lt;/strong&gt; instead of climbing toward &lt;strong&gt;~50–67k&lt;/strong&gt;, and total tokens for a &lt;strong&gt;25-step stop&lt;/strong&gt; fell from &lt;strong&gt;~1.04M to ~367k&lt;/strong&gt; (about &lt;strong&gt;2.8×&lt;/strong&gt;). The cheaper run still &lt;strong&gt;did not&lt;/strong&gt; produce the review file.&lt;/p&gt;
&lt;p&gt;So this note is about &lt;strong&gt;what you measure&lt;/strong&gt; and &lt;strong&gt;what you ship as knobs&lt;/strong&gt; — not a claim that compaction finishes the job.&lt;/p&gt;
&lt;h2&gt;Quick vocabulary&lt;/h2&gt;
&lt;p&gt;| Term | Meaning here |
|------|----------------|
| &lt;strong&gt;RLM loop&lt;/strong&gt; | Model proposes code → runtime executes &lt;strong&gt;cells&lt;/strong&gt; → observations return → repeat |
| &lt;strong&gt;Cell&lt;/strong&gt; | One fenced code block executed in the REPL |
| &lt;strong&gt;Per-call input&lt;/strong&gt; | Tokens in the &lt;em&gt;next&lt;/em&gt; model request (usually dominated by history) |
| &lt;strong&gt;Working set&lt;/strong&gt; | The subset of history you deliberately keep full-fidelity |&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./arch-rlm-loop.svg&quot; alt=&quot;Recursive agent loop&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure: history sits on the path into every model call; without a policy it grows each turn.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/rlm-small-cells&quot;&gt;When smaller cells make agents worse&lt;/a&gt; — cell policy ≠ completion.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/rlm-execution-strategies&quot;&gt;Strategies, not model ifs&lt;/a&gt; — history caps live on named presets next to cell/tool budgets.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Three confusions worth separating&lt;/h2&gt;
&lt;p&gt;Operators watching live runs often ask: &lt;em&gt;why are tokens climbing? Isn’t recursion supposed to be efficient? Should we chart input and output separately?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Those questions mix:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Recursion depth&lt;/strong&gt; (nested sub-calls) vs &lt;strong&gt;dialog length&lt;/strong&gt; at one depth.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Total tokens&lt;/strong&gt; vs &lt;strong&gt;per-call input&lt;/strong&gt; (the quantity that makes each step more expensive).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Efficiency of reasoning&lt;/strong&gt; vs &lt;strong&gt;efficiency of memory encoding&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This article focuses on (2) and (3).&lt;/p&gt;
&lt;h2&gt;What unbounded history looks like&lt;/h2&gt;
&lt;p&gt;Without a working-set policy, each turn appends assistant prose, tool dumps, errors, logs, and scaffolding. The next call’s &lt;strong&gt;input&lt;/strong&gt; includes most of that. &lt;strong&gt;Output&lt;/strong&gt; may stay modest while &lt;strong&gt;input&lt;/strong&gt; becomes the bill.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./arch-history-working-set.svg&quot; alt=&quot;History growth vs working-set compaction&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure: compaction does not delete the task; it caps what re-enters the next prompt.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Observation — thrash run:&lt;/strong&gt; late calls approached &lt;strong&gt;~50–67k input tokens&lt;/strong&gt;; cumulative total near a 25-step stop was on the order of &lt;strong&gt;~1.04M&lt;/strong&gt; (~999k in / ~43k out).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Observation — compaction re-run:&lt;/strong&gt; after an early climb, per-call input &lt;strong&gt;held ~14–16k&lt;/strong&gt; (series ending near &lt;code&gt;12867, 16272, 13357, 16672, 13710, 13882, 14010&lt;/code&gt;); cumulative &lt;strong&gt;~367k&lt;/strong&gt; (~340k in / ~28k out) at the same step ceiling.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./per-call-input-tokens.svg&quot; alt=&quot;Per-call input trajectories&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure: thrash late points are schematic midpoints from monitor notes (not a full exported series); compacted series follows the live plateau. Use for &lt;strong&gt;shape&lt;/strong&gt;, not millimetric accuracy.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./total-tokens-comparison.svg&quot; alt=&quot;Total token comparison at 25-step stop&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure: same stop condition, very different bill — driven by input.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Core argument&lt;/h2&gt;
&lt;h3&gt;1. Recursive efficiency is a policy surface&lt;/h3&gt;
&lt;p&gt;A loop gives you places to intervene &lt;strong&gt;before&lt;/strong&gt; each model call:&lt;/p&gt;
&lt;p&gt;| Knob (strategy config) | Role |
|------------------------|------|
| &lt;code&gt;history_keep_recent_turns&lt;/code&gt; | Full-fidelity recent window |
| &lt;code&gt;history_max_chars_per_old_message&lt;/code&gt; | Truncate older turns |
| &lt;code&gt;history_max_total_chars&lt;/code&gt; | Hard working-set ceiling |
| &lt;code&gt;history_protect_prefix_messages&lt;/code&gt; | Keep system/task head intact |
| &lt;code&gt;max_observation_chars&lt;/code&gt; | Bound a single tool result |&lt;/p&gt;
&lt;p&gt;These belong on the &lt;strong&gt;same strategy object&lt;/strong&gt; as cell and tool budgets (&lt;a href=&quot;/blog/rlm-execution-strategies&quot;&gt;strategies&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Inference:&lt;/strong&gt; if you ship recursive agents with unbounded dialog concatenation, you have built a &lt;strong&gt;linear input escalator&lt;/strong&gt;, not an efficient long-horizon system.&lt;/p&gt;
&lt;h3&gt;2. Report input and output separately&lt;/h3&gt;
&lt;p&gt;Totals hide the failure mode:&lt;/p&gt;
&lt;p&gt;| View | What you miss |
|------|----------------|
| Total only | Whether cost is “thinking” or “re-reading” |
| Output only | Looks fine while input explodes |
| Input per call | Shows plateau vs climb — the health metric |&lt;/p&gt;
&lt;p&gt;Live monitors should treat &lt;strong&gt;last-call input&lt;/strong&gt; and &lt;strong&gt;history size under budget&lt;/strong&gt; as first-class series.&lt;/p&gt;
&lt;h3&gt;3. Token wins do not imply task wins&lt;/h3&gt;
&lt;p&gt;The compacted run was &lt;strong&gt;~2.8× cheaper&lt;/strong&gt; — yet stopped at &lt;strong&gt;25/25 steps&lt;/strong&gt; with &lt;strong&gt;no FINAL&lt;/strong&gt; and no deliverable file. Notes showed the model stuck on &lt;strong&gt;write mechanics&lt;/strong&gt; (parse errors, chunked writes, shell heredocs) while input stayed flat.&lt;/p&gt;
&lt;p&gt;Compaction fixed the &lt;strong&gt;right bottleneck for the token question&lt;/strong&gt; and the &lt;strong&gt;wrong bottleneck for “please finish the review.”&lt;/strong&gt; Both can be true at once.&lt;/p&gt;
&lt;h2&gt;Worked example: reading a monitor line&lt;/h2&gt;
&lt;p&gt;Healthy compacted turn (illustrative):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;turn 14  in≈16.3k  out≈1.5k  hist_chars≈51k/64k  tools 36/1000  file? no
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Checklist:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;in flat&lt;/strong&gt; → memory policy holding.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;out modest&lt;/strong&gt; → not dumping the whole report into chat.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;file? no&lt;/strong&gt; after many “about to write” turns → success is still red; &lt;strong&gt;do not extend the step budget assuming tokens are the issue.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Thrash contrast:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;turn 14  in≈55k+  out≈2k  hist growing  tools climbing  file? no
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, prioritize &lt;strong&gt;history policy and re-scan behavior&lt;/strong&gt;, not only more steps.&lt;/p&gt;
&lt;h2&gt;Counterfactuals&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;If RLM were token-efficient by construction,&lt;/strong&gt; per-call input would stay roughly constant as turns increase under a fixed task. The thrash series falsifies that for an uncompacted dialog loop.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Alternative to truncation:&lt;/strong&gt; externalize state into the workspace (files, variables) and keep dialog thin by design. Compaction is a &lt;strong&gt;runtime&lt;/strong&gt; mitigation when the model keeps stuffing observations into chat history.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Aggressive summarization&lt;/strong&gt; of old turns might save more tokens but can erase error strings needed to stop write thrash — a different tradeoff, not measured here.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;What would reverse the ~2.8× win?&lt;/strong&gt; Disable history caps with the same model and task length; expect totals back toward thrash order-of-magnitude. &lt;strong&gt;Provisional&lt;/strong&gt; without a controlled re-disable A/B on identical seeds.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Limitations&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Thrash late-call series in the figure is &lt;strong&gt;reconstructed from monitor narrative&lt;/strong&gt;, not a full CSV export.&lt;/li&gt;
&lt;li&gt;Both runs hit a &lt;strong&gt;step ceiling without deliverable&lt;/strong&gt;; token comparison is for &lt;strong&gt;same stop&lt;/strong&gt;, not same success.&lt;/li&gt;
&lt;li&gt;Compaction parameters were those of the strategy in flight that day — not a full grid search.&lt;/li&gt;
&lt;li&gt;Nested recursion depth is not measured separately from root dialog length.&lt;/li&gt;
&lt;li&gt;Write-path failures deserve their own note; they are only a boundary condition here.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Assume dialog RLM will grow input until you stop it.&lt;/strong&gt; Ship working-set knobs on day one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dashboard in and out separately&lt;/strong&gt;; watch per-call input plateau.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Token health ≠ task health.&lt;/strong&gt; Pair token series with artifact checks (file exists, &lt;code&gt;FINAL&lt;/code&gt;, verify score).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bind history caps with cell/tool budgets&lt;/strong&gt; on one strategy object — see &lt;a href=&quot;/blog/rlm-execution-strategies&quot;&gt;strategies&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Next measurement:&lt;/strong&gt; export full per-call in/out series so figures need no schematic fill.&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="/_astro/cover.Cpcyhse1.png"/><enclosure url="/_astro/cover.Cpcyhse1.png"/></item><item><title>Grounding Is Necessary, Not Sufficient</title><link>https://astro-pure.js.org/blog/grounding-is-not-semantic-proof</link><guid isPermaLink="true">https://astro-pure.js.org/blog/grounding-is-not-semantic-proof</guid><description>File-path grounding blocks a class of fabricated plans, but it cannot establish that a cited file supports the claim being made.</description><pubDate>Thu, 21 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Grounding is often described as the cure for hallucinated agent plans: require the planner to cite real repository files and reject the plan when it cannot. That is necessary. It is not enough.&lt;/p&gt;
&lt;p&gt;The key distinction is between &lt;strong&gt;reference validity&lt;/strong&gt; and &lt;strong&gt;claim validity&lt;/strong&gt;. A file can exist while being the wrong test, a neighbouring implementation, or documentation that describes a different execution surface. A planner that cites it has grounded a string, not necessarily an assertion.&lt;/p&gt;
&lt;h2&gt;What strict grounding changed&lt;/h2&gt;
&lt;p&gt;The strict plan-reference cohort used the same indexed planner and a checkpoint-70-plus-five budget policy, but required each task to provide scope, evidence, and tests. It terminated at 0% completion after 77 mean iterations, approximately 1.51 million mean tokens, and 15 plan-validation failures. The error mix was evenly split across missing evidence, scope, and tests.&lt;/p&gt;
&lt;p&gt;That is not a failure of the principle. It shows the validator was able to prevent under-specified plans from being accepted. An earlier evidence-reference repair cohort reached 50% completion, 50% verification, and 11 verified references out of 12 claimed. It demonstrates that the planner can sometimes use repair feedback to obtain real evidence.&lt;/p&gt;
&lt;p&gt;| Cohort | Repeats | Completion | Grounding | Mean tokens | Validation failures |
| --- | ---: | ---: | ---: | ---: | ---: |
| Strict reference grounding | 1 | 0% | n/a | 1.51m | 15 |
| Evidence-reference repair | 2 | 50% | 91.7% | 1.23m | 3 |
| Checkpoint candidate | 2 | 100% | 100% | 1.09m | n/a |&lt;/p&gt;
&lt;p&gt;The table comes from &lt;code&gt;data/study-metrics.csv&lt;/code&gt;. The study manifests, scoreboards, reports, and hashes are recorded in &lt;code&gt;data/evidence-manifest.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;The worked failure: valid files, invalid plan&lt;/h2&gt;
&lt;p&gt;Manual review of accepted checkpoint plans exposed why existence checks are only the first layer.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The plans cited test paths under the wrong package root; the relevant tests were under &lt;code&gt;tests/unit/...&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;They attributed network isolation and environment-key scrubbing to one Docker backend when the evidence belonged to different repository surfaces.&lt;/li&gt;
&lt;li&gt;They presented intentional paused-state behaviour and normal success routing as failure modes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Every example sounds plausible in a natural-language summary. None is safe to implement from. The important failure is not “the agent made up a filename.” It is “the agent assembled a claim from nearby facts without establishing the component-level relationship.”&lt;/p&gt;
&lt;h2&gt;A hierarchy of evidence checks&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;./grounding-evidence-ladder.svg&quot; alt=&quot;Schematic grounding ladder from path existence to claim-to-branch review, with increasing semantic strength&quot;&gt;&lt;/p&gt;
&lt;p&gt;| Check | Rejects | Still permits |
| --- | --- | --- |
| Path existence | Invented filenames | Wrong existing file |
| Scope membership | Files outside the task | A too-broad but in-scope citation |
| Source-type match | Documentation used as implementation evidence | Misread implementation branch |
| Related-test validation | Unrelated or nonexistent tests | A real test that does not exercise the claim |
| Claim-to-branch review | Contradictions with inspected code | Future behaviour changes |&lt;/p&gt;
&lt;p&gt;This hierarchy suggests an implementation order: add cheap, deterministic checks early, then reserve semantic review for claims with high downstream cost. Do not attempt to solve semantic correctness by making the schema increasingly elaborate.&lt;/p&gt;
&lt;h2&gt;Counterfactual: when path grounding is enough&lt;/h2&gt;
&lt;p&gt;Path grounding is sufficient for some narrow tasks. If a plan&apos;s only duty is to name existing files for a static inventory or migration checklist, source type and branch semantics may not matter. The moment a plan proposes a behavioural change, explains a failure mode, or chooses a test, existence becomes a weak proxy.&lt;/p&gt;
&lt;p&gt;The falsifier for this article&apos;s claim is straightforward: show that adding existence checks alone reliably rejects the wrong-test and wrong-component examples in a held-out cohort. The current evidence does not show that; the manual review shows the opposite.&lt;/p&gt;
&lt;h2&gt;What to add next&lt;/h2&gt;
&lt;p&gt;Three gates are high-value:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Compare each cited test path with the repository&apos;s actual test roots and the task&apos;s declared component.&lt;/li&gt;
&lt;li&gt;Require implementation claims to cite implementation branches, not only security documentation or manifests.&lt;/li&gt;
&lt;li&gt;Add a contradiction-oriented review prompt: name the claimed wrong-state branch and the claimed recovery branch, then verify both against code.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These should complement, not replace, strict path checks. Grounding prevents a plan from floating free of the repository. Semantic review prevents it from becoming confidently wrong inside the repository.&lt;/p&gt;
&lt;h2&gt;Cohort results at a glance&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;./completion-rate.svg&quot; alt=&quot;Strict reference grounding rejected its only run while mechanically accepted checkpoint plans still failed semantic review&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./token-usage.svg&quot; alt=&quot;The strict-grounding run consumed the most mean tokens without producing an accepted plan&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A real path is evidence of a file, not evidence of a claim.&lt;/li&gt;
&lt;li&gt;Grounding metrics must state their level: existence, scope, source type, or semantic support.&lt;/li&gt;
&lt;li&gt;Manual semantic review is expensive; use it where a plan becomes an execution contract.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Read &lt;a href=&quot;/blog/agent-plans-semantic-proof&quot;&gt;A Plan Can Validate and Still Be Unsafe to Implement&lt;/a&gt; for the broader readiness model.&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.CgLUBoP6.png"/><enclosure url="/_astro/cover.CgLUBoP6.png"/></item><item><title>Zero Net Access: Hardening LLM Agent Sandboxes</title><link>https://astro-pure.js.org/blog/zero-net-access-agent-sandboxing</link><guid isPermaLink="true">https://astro-pure.js.org/blog/zero-net-access-agent-sandboxing</guid><description>Securing autonomous LLM agents with host-only network isolation, UDS proxies, and cryptographically signed audit logs.</description><pubDate>Sun, 17 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Imagine inviting a highly capable assistant into your office to organize your files, only to find they&apos;ve accidentally emailed your private documents to the internet. This is the risk we face when giving autonomous AI agents—like those writing code or managing systems—free reign on a computer. Security cannot rely merely on politely asking the AI to &quot;behave&quot; through prompt instructions. Without strict, physical-like boundaries, an unconstrained agent can accidentally leak secrets, alter critical configurations, or make unauthorized connections to the outside world.&lt;/p&gt;
&lt;p&gt;In this article, we break down how we solved this problem for our orchestration framework by building a &lt;strong&gt;Zero Net Access&lt;/strong&gt; sandbox—a digital vault that completely cuts off the AI from the internet while still allowing it to do its job securely.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Threat Model &amp;#x26; Sandbox Requirements&lt;/h2&gt;
&lt;p&gt;Autonomous coding agents present three distinct attack and failure vectors:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Outbound Data Exfiltration:&lt;/strong&gt; Model code attempting to send repository contents or environment variables to external endpoints via &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;urllib&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Host Directory Traversal:&lt;/strong&gt; Ad-hoc file modifications escaping the task directory (&lt;code&gt;../&lt;/code&gt;) into system files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audit Tampering:&lt;/strong&gt; Modifying local execution logs to hide unapproved tool operations.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To mitigate all three vectors, our sandbox enforces three non-negotiable architectural invariants:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;network_mode=none&lt;/code&gt;:&lt;/strong&gt; Complete hardware network isolation for the execution container.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IPC via Unix Domain Sockets (UDS):&lt;/strong&gt; Inter-process communication between host orchestrator and container REPL using a local domain socket mount (&lt;code&gt;/proxy.sock&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ECDSA Signed Audit Log:&lt;/strong&gt; Every container execution event is hashed and signed on the host control plane.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;Architecture &amp;#x26; Control Flow&lt;/h2&gt;
&lt;p&gt;The host control plane (our orchestration framework) initializes an ephemeral Docker container for each agent trajectory. Network adapters (&lt;code&gt;eth0&lt;/code&gt;) are completely disabled at container creation time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./assets/sandbox-architecture.svg&quot; alt=&quot;Sandbox Architecture&quot;&gt;&lt;/p&gt;
&lt;h3&gt;UDS Inter-Process Communication&lt;/h3&gt;
&lt;p&gt;Because the container has no network interfaces, RPC communication between the host orchestrator and the Python REPL running inside the sandbox occurs via a mounted Unix Domain Socket:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# orbit_harness/rlm/general/environments/docker_repl.py
def _create_container(self) -&gt; None:
    self.container = self.client.containers.run(
        image=self.image,
        network_mode=&quot;none&quot;,  # Mandatory Zero Net Access
        volumes={
            str(self.uds_host_path): {&quot;bind&quot;: &quot;/workspace/proxy.sock&quot;, &quot;mode&quot;: &quot;rw&quot;},
            str(self.project_root): {&quot;bind&quot;: &quot;/repo&quot;, &quot;mode&quot;: &quot;rw&quot;},
        },
        detach=True,
    )
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;Empirical Security Audit Results&lt;/h2&gt;
&lt;p&gt;We evaluated 29 benchmark study runs across multiple LLM provider models (Gemini 3.6 High/Medium/Low and DeepSeek v4 Flash) under the enforced Zero Net Access posture.&lt;/p&gt;
&lt;p&gt;| Provider Group | Total Runs | Network Posture | Blocked Network Hits | Signed Audit Ratio | Sandbox Integrity |
| :--- | :---: | :---: | :---: | :---: | :---: |
| &lt;code&gt;cliproxyapi-gemini-3.6-flash-high&lt;/code&gt; | 3 | &lt;code&gt;disabled&lt;/code&gt; | 0 | 100% | &lt;strong&gt;PASS&lt;/strong&gt; |
| &lt;code&gt;cliproxyapi-gemini-3.6-flash-medium&lt;/code&gt; | 3 | &lt;code&gt;disabled&lt;/code&gt; | 0 | 100% | &lt;strong&gt;PASS&lt;/strong&gt; |
| &lt;code&gt;cliproxyapi-gemini-3.6-flash-low&lt;/code&gt; | 3 | &lt;code&gt;disabled&lt;/code&gt; | 0 | 100% | &lt;strong&gt;PASS&lt;/strong&gt; |
| &lt;code&gt;deepseek-v4-flash&lt;/code&gt; | 3 | &lt;code&gt;disabled&lt;/code&gt; | 0 | 100% | &lt;strong&gt;PASS&lt;/strong&gt; |&lt;/p&gt;
&lt;p&gt;All 12 provider arm runs completed under complete network isolation. Cryptographic verification of the signed audit logs confirmed zero unverified operations or host traversal attempts.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Key Takeaways&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Enforce Kernel-Level Boundaries:&lt;/strong&gt; Prompt engineering is not security. Use &lt;code&gt;network_mode=none&lt;/code&gt; for all execution sandboxes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UDS Sockets for RPC:&lt;/strong&gt; Unix Domain Sockets provide high-performance, secure local IPC without opening loopback network ports (&lt;code&gt;127.0.0.1&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cryptographic Auditing:&lt;/strong&gt; Sign every execution event on the host plane to guarantee audit trail tamper resistance.&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="/_astro/cover.Cc4zrwzI.png"/><enclosure url="/_astro/cover.Cc4zrwzI.png"/></item><item><title>A Plan Can Validate and Still Be Unsafe to Implement</title><link>https://astro-pure.js.org/blog/agent-plans-semantic-proof</link><guid isPermaLink="true">https://astro-pure.js.org/blog/agent-plans-semantic-proof</guid><description>A controlled indexed-planner study shows why structural validation, path grounding, and semantic review must be reported as separate gates.</description><pubDate>Sat, 16 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;An agent plan is not ready to execute merely because it has the right JSON shape, cites files that exist, and survives a bounded repair loop. Those checks are useful, but they answer a narrower question: &lt;em&gt;can this plan be stored and mechanically inspected?&lt;/em&gt; They do not answer whether the plan describes the system correctly.&lt;/p&gt;
&lt;p&gt;This distinction emerged while evaluating an indexed planner that investigates a repository and emits an implementation plan. The headline result was attractive: an action-70 synthesis checkpoint completed both candidate runs while the two baseline runs completed neither. Manual review, however, found that the accepted candidate plans still cited nonexistent test paths, conflated controls implemented in different execution surfaces, and described failure modes contradicted by code.&lt;/p&gt;
&lt;p&gt;The practical rule is simple: treat structural validity, reference grounding, and semantic readiness as separate gates.&lt;/p&gt;
&lt;h2&gt;The intervention: force synthesis before the investigation becomes a loop&lt;/h2&gt;
&lt;p&gt;The planner normally chooses when to stop reading and submit a plan. The experiment added an opt-in checkpoint: after 70 actions, allow five more evidence actions and then require &lt;code&gt;finalize_plan&lt;/code&gt;. The study used two repeats per arm on the same task and model configuration.&lt;/p&gt;
&lt;p&gt;| Arm | Repeats | Completion | Verification | Mean tokens | Mean iterations |
| --- | ---: | ---: | ---: | ---: | ---: |
| Baseline | 2 | 0% | 0% | 667,729 | 42.5 |
| Checkpoint 70 + 5 | 2 | 100% | 100% | 1,087,231 | 67.0 |&lt;/p&gt;
&lt;p&gt;The data is in &lt;code&gt;data/study-metrics.csv&lt;/code&gt;; its source hashes and the full study locations are recorded in &lt;code&gt;data/evidence-manifest.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That result is evidence that the checkpoint can improve &lt;em&gt;termination&lt;/em&gt; in this narrow cohort. It is not evidence that the resulting plans are semantically sound. One candidate finalized before the checkpoint could be causal; one baseline failed before accepting a trajectory action. The group-average token comparison is also confounded by that short baseline failure.&lt;/p&gt;
&lt;h2&gt;What the normal gates caught—and missed&lt;/h2&gt;
&lt;p&gt;The planner already had useful mechanical checks: non-empty task scope, evidence, tests, expected outputs, and path existence. A separate strict grounding cohort shows why they matter. Its one repeat completed 0%, recorded 15 plan-validation failures, and spent roughly 1.51 million tokens before terminating. The failure categories were missing evidence, missing scope, and missing tests.&lt;/p&gt;
&lt;p&gt;But these checks have an obvious boundary. A test path can exist in the wrong directory; a documentation file can describe a control without that control being implemented by the component under review; a plausible prose summary can invert a branch&apos;s real behavior. None of those is a malformed field.&lt;/p&gt;
&lt;p&gt;The manual review of accepted checkpoint plans found all three patterns:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Wrong test locations.&lt;/strong&gt; The plans named tests under the wrong package root; the relevant tests live under &lt;code&gt;tests/unit/...&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Evidence-source conflation.&lt;/strong&gt; They attributed network isolation and environment scrubbing to a Docker backend even though the evidence belonged to other repository surfaces.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contradicted terminal-state claims.&lt;/strong&gt; They described exception and blocked paths as failures even where the code intentionally persists a resumable pause or routes normal success.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These are not cosmetic errors. They make an implementation plan unsafe as a contract for someone else to execute.&lt;/p&gt;
&lt;h2&gt;A better readiness model&lt;/h2&gt;
&lt;p&gt;Use three gates, each with its own evidence and failure mode.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./plan-readiness-gates.svg&quot; alt=&quot;Schematic of three cumulative plan-readiness gates: structural validity, reference grounding, and semantic readiness&quot;&gt;&lt;/p&gt;
&lt;p&gt;| Gate | Question | Good evidence | What it cannot prove |
| --- | --- | --- | --- |
| Structural validity | Is the plan complete enough to parse and route? | Schema checks; required fields; bounded repair | That its claims are true |
| Reference grounding | Do cited files and tests exist within declared scope? | Repository reads; path checks; expected-file declarations | That the cited file supports the claim |
| Semantic readiness | Does the plan accurately describe the relevant implementation, states, and tests? | Claim-to-code review; contradiction checks; targeted human review | That a future code change will work |&lt;/p&gt;
&lt;p&gt;The gates should be cumulative. Passing the first two should unlock semantic review, not replace it.&lt;/p&gt;
&lt;h2&gt;The useful counterexample: 2/2 success without direct mechanism proof&lt;/h2&gt;
&lt;p&gt;A later two-repeat fallback cohort completed 2/2, verified 22 of 22 grounding claims, and had one successful repair. That is a meaningful non-regression signal for the stricter finalization path. It did &lt;strong&gt;not&lt;/strong&gt; re-trigger the precise nonexistent-test repair branch that motivated the fallback. Calling it a direct causal proof would be stronger than the data allows.&lt;/p&gt;
&lt;p&gt;This is the same discipline the semantic gate demands from the planner: name what the evidence establishes and what it does not.&lt;/p&gt;
&lt;h2&gt;What to test next&lt;/h2&gt;
&lt;p&gt;The next experiment should force the troublesome branch deterministically: submit an invalid test reference, have targeted discovery return no matching test, and verify that the repaired plan declares one exact planned test path in both &lt;code&gt;tests&lt;/code&gt; and &lt;code&gt;expected_files&lt;/code&gt;. That converts a unit-tested instruction into a live mechanism test.&lt;/p&gt;
&lt;p&gt;In parallel, add semantic checks that compare a claim with the cited implementation branch, verify test-root conventions, and reject evidence that only describes a neighboring component. The goal is not to make planning impossibly strict. It is to stop confusing a well-formed plan with a trustworthy one.&lt;/p&gt;
&lt;h2&gt;Cohort results at a glance&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;./completion-rate.svg&quot; alt=&quot;The checkpoint arm completed both repeats; the baseline and strict-grounding cohorts did not complete&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./token-usage.svg&quot; alt=&quot;Mean token use varied with run length and failure mode, so these raw cohort averages are not a clean treatment-cost estimate&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Completion is a termination metric, not a correctness metric.&lt;/li&gt;
&lt;li&gt;Path existence is necessary grounding, but it is not semantic evidence.&lt;/li&gt;
&lt;li&gt;Small, mixed cohorts can reveal mechanisms, but they rarely justify broad defaults.&lt;/li&gt;
&lt;li&gt;A plan becomes implementation-ready only when its claims survive structural, grounding, and semantic scrutiny.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The companion piece, &lt;a href=&quot;/blog/benchmarking-agent-repair-loops&quot;&gt;Benchmarking Agent Systems Beyond “Did It Finish?”&lt;/a&gt;, turns those gates into a reusable measurement framework.&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.a2fgZJno.png"/><enclosure url="/_astro/cover.a2fgZJno.png"/></item><item><title>Designing Bounded Repair Loops for Agent Plans</title><link>https://astro-pure.js.org/blog/bounded-agent-repair-loops</link><guid isPermaLink="true">https://astro-pure.js.org/blog/bounded-agent-repair-loops</guid><description>A bounded repair action makes plan validation observable and safe, but repair telemetry must be tied to the final outcome rather than counted as success by i...</description><pubDate>Sat, 09 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Rejecting an invalid agent plan without feedback turns validation into a dead end. Allowing unlimited retries turns it into a cost and loop-control problem. A bounded repair loop sits between those failures: expose the validator&apos;s reason, allow one targeted evidence action, then require a revised finalization.&lt;/p&gt;
&lt;p&gt;The boundary matters. It makes both the model&apos;s behaviour and the system&apos;s cost auditable.&lt;/p&gt;
&lt;h2&gt;The minimal protocol&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Attempt &lt;code&gt;finalize_plan&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Validate required scope, evidence, tests, and plan-level checks.&lt;/li&gt;
&lt;li&gt;If validation fails, preserve the errors in the observation.&lt;/li&gt;
&lt;li&gt;Permit exactly one targeted evidence action.&lt;/li&gt;
&lt;li&gt;Require the next action to be a revised finalization.&lt;/li&gt;
&lt;li&gt;Terminalize if that revision remains invalid.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The protocol does not guarantee that the model repairs the plan. It guarantees that a failure is finite, attributable, and measurable.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./bounded-repair-loop.svg&quot; alt=&quot;Schematic of one bounded repair cycle: invalid finalization permits one targeted evidence action before a terminal recheck&quot;&gt;&lt;/p&gt;
&lt;h2&gt;What the cohorts say&lt;/h2&gt;
&lt;p&gt;| Cohort | Completion | Validation failures | Repairs | Successful repairs | Mean post-finalize calls |
| --- | ---: | ---: | ---: | ---: | ---: |
| Repair signals | 50% | 3 | 3 | 2 | 2.5 |
| Evidence repair v2 | 0% | 2 | 1 | 1 | 1.0 |
| Completeness guidance | 0% | 2 | 1 | 1 | 1.5 |
| Reliability validation | 0% | 4 | 2 | 2 | 2.5 |
| Test-repair fallback | 100% | 1 | 1 | 1 | 1.5 |&lt;/p&gt;
&lt;p&gt;The result is deliberately uncomfortable: a repair action can be recorded as successful while the run still fails. In the reliability cohort, both allowed repair actions completed, yet both repeats ended with missing or nonexistent test references. The observation succeeded; the revised plan did not.&lt;/p&gt;
&lt;p&gt;That is why a repair dashboard needs at least three separate measures: repair action success, repaired-finalization success, and terminal run success.&lt;/p&gt;
&lt;h2&gt;Worked example: empty test discovery&lt;/h2&gt;
&lt;p&gt;The hardest observed failure was a rejected test reference followed by &lt;code&gt;related_tests&lt;/code&gt; returning no matching files. A vague instruction to “find the right test” leaves the model with two bad options: omit the test field or invent an existing path.&lt;/p&gt;
&lt;p&gt;The valid strict-plan fallback is precise: choose one exact planned test path within the task&apos;s allowed scope, place the same path in both &lt;code&gt;tests&lt;/code&gt; and &lt;code&gt;expected_files&lt;/code&gt;, and resubmit. The final fallback cohort completed both repeats, with 22 of 22 grounding claims verified and one successful repair.&lt;/p&gt;
&lt;p&gt;That is encouraging non-regression evidence, not decisive mechanism proof. Neither repeat re-triggered the exact nonexistent-test validation branch after the fallback was introduced. A unit test covers the directive; a deterministic live benchmark still needs to force the branch.&lt;/p&gt;
&lt;h2&gt;Failure taxonomy should drive the next action&lt;/h2&gt;
&lt;p&gt;| Error type | Useful recovery | Bad recovery |
| --- | --- | --- |
| Missing evidence | Read the named implementation branch | Add generic prose |
| Missing tests | Discover related tests or declare planned output | Leave tests empty |
| Nonexistent test | Replace with real test or declared planned test | Invent another path |
| Missing acceptance checks | Re-read task acceptance | Search unrelated code |
| Transport failure | Retry the same completion within a limit | Treat it as a semantic repair |&lt;/p&gt;
&lt;p&gt;This table is a design guide, not a claim that the current model follows every path reliably. The evidence bundle in &lt;code&gt;data/&lt;/code&gt; records the cohorts that motivated it.&lt;/p&gt;
&lt;h2&gt;Counterfactual: why not allow more repair actions?&lt;/h2&gt;
&lt;p&gt;More actions can improve a genuinely under-explored plan. They also allow the model to spend unbounded tokens circling a validator error or to hide a weak plan behind repeated unrelated reads. The right counterfactual experiment is not “one action versus infinity.” Compare one, two, and three repair actions on a pre-specified failure taxonomy, while holding task, model, budget, and acceptance policy constant.&lt;/p&gt;
&lt;p&gt;Until that exists, one bounded action is a useful safety default because it makes failure legible.&lt;/p&gt;
&lt;h2&gt;Cohort results at a glance&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;./completion-rate.svg&quot; alt=&quot;Only the fallback cohort completed both repeats, although successful repair actions also appeared in failed cohorts&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./token-usage.svg&quot; alt=&quot;Token use was not monotonic with completion across the sequential repair cohorts&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Treat a repair action as an event, not proof of recovery.&lt;/li&gt;
&lt;li&gt;Tie repair metrics to the next finalization and terminal outcome.&lt;/li&gt;
&lt;li&gt;Make error categories select a narrow evidence action.&lt;/li&gt;
&lt;li&gt;Use deterministic branch-forcing benchmarks before attributing a later cohort&apos;s success to a repair prompt.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the measurement framework around these loops, read &lt;a href=&quot;/blog/benchmarking-agent-repair-loops&quot;&gt;Benchmarking Agent Systems Beyond “Did It Finish?”&lt;/a&gt;.&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.xpiMV1wS.png"/><enclosure url="/_astro/cover.xpiMV1wS.png"/></item><item><title>From REPL Loops to Swarms: Leasing Sandboxed Containers</title><link>https://astro-pure.js.org/blog/swarm-worker-leases</link><guid isPermaLink="true">https://astro-pure.js.org/blog/swarm-worker-leases</guid><description>Designing SwarmLeaseManager to lease container worker nodes dynamically for concurrent file inspection and sub-task execution.</description><pubDate>Thu, 07 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Imagine hiring a team of researchers, but forcing them all to share a single laptop. One reads a file, closes it, then the next person takes their turn. It’s slow, inefficient, and bottlenecks the entire team. In the world of AI agents, relying on a single, sequential REPL (Read-Eval-Print Loop) container for complex repository analysis creates the exact same bottleneck.&lt;/p&gt;
&lt;p&gt;In this article, we explore how our orchestration framework solves this problem by moving from sequential execution to a parallelized &lt;strong&gt;Swarm Architecture&lt;/strong&gt; using the &lt;code&gt;SwarmLeaseManager&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. The Single-Container Bottleneck&lt;/h2&gt;
&lt;p&gt;Traditional LLM agent harnesses spin up a single Docker container for the agent&apos;s Python REPL. The agent reads a file, waits for the result, executes a grep search, waits for the result, and slowly piece-meals its understanding of the codebase.&lt;/p&gt;
&lt;p&gt;While this works for simple scripts, analyzing a massive enterprise repository or executing a test suite while simultaneously checking logs requires concurrency. If an agent wants to &lt;code&gt;grep_search&lt;/code&gt; across five different sub-packages, doing so sequentially burns precious time (and API window duration).&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. Enter the SwarmLeaseManager&lt;/h2&gt;
&lt;p&gt;To enable parallel execution without sacrificing sandbox security (like our &lt;a href=&quot;/blog/zero-net-access-agent-sandboxing&quot;&gt;Zero Net Access&lt;/a&gt; posture), we implemented the &lt;code&gt;SwarmLeaseManager&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Instead of a single REPL, the host orchestrator manages a pool of isolated worker containers. When the root agent decides it needs to parallelize a task, it requests &quot;leases&quot; from the manager.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://astro-pure.js.org/_vercel/image?url=_astro%2Fswarm-architecture.CvhWkGKR.png&amp;#x26;w=1080&amp;#x26;q=100&quot; alt=&quot;Swarm Architecture&quot;&gt;&lt;/p&gt;
&lt;h3&gt;How Leasing Works&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;SwarmLeaseManager&lt;/code&gt; dynamically allocates worker nodes with strict lifecycle rules:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# orbit_harness/orchestration/swarm.py
class SwarmLeaseManager:
    def acquire_lease(self) -&gt; SwarmWorkerLease | None:
        self.reclaim_expired_leases()
        active_count = sum(1 for l in self.leases.values() if l.active)
        if active_count &gt;= self.max_workers:
            return None # Swarm pool is full

        lease_id = f&quot;lease_{uuid.uuid4().hex[:8]}&quot;
        worker_id = f&quot;worker_node_{uuid.uuid4().hex[:8]}&quot;
        lease = SwarmWorkerLease(lease_id=lease_id, worker_node_id=worker_id)
        self.leases[lease_id] = lease
        return lease
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Acquisition:&lt;/strong&gt; The orchestrator requests a lease. If under the concurrency limit (&lt;code&gt;max_workers&lt;/code&gt;), a new &lt;code&gt;SwarmWorkerLease&lt;/code&gt; is generated and a sandboxed Docker container is spun up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Heartbeats:&lt;/strong&gt; To prevent zombie containers from hogging resources, workers must send regular heartbeats (&lt;code&gt;heartbeat(lease_id)&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reclamation:&lt;/strong&gt; If a worker crashes or hangs (failing to send a heartbeat within &lt;code&gt;ttl_seconds&lt;/code&gt;), the manager automatically reclaims the lease (&lt;code&gt;reclaim_expired_leases()&lt;/code&gt;) and destroys the rogue container.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;3. Parallel Dispatch in Action&lt;/h2&gt;
&lt;p&gt;With the lease manager active, our orchestration framework can use &lt;code&gt;asyncio&lt;/code&gt; to dispatch tasks across the swarm concurrently.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;async def dispatch_parallel_swarm_tasks(
    tasks: list[Callable[[], Coroutine[Any, Any, Any]]],
    max_concurrency: int = 4,
) -&gt; list[Any]:
    semaphore = asyncio.Semaphore(max_concurrency)

    async def _run_one(task_fn: Callable[[], Coroutine[Any, Any, Any]]) -&gt; Any:
        async with semaphore:
            return await task_fn()

    return await asyncio.gather(*[_run_one(t) for t in tasks], return_exceptions=True)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By wrapping execution in an &lt;code&gt;asyncio.Semaphore&lt;/code&gt;, the orchestrator ensures we never exceed our leased worker count, smoothly distributing tasks like parallel test runs, concurrent static analysis, or multi-directory &lt;code&gt;grep_search&lt;/code&gt; operations.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;4. Key Takeaways&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Break the REPL Loop:&lt;/strong&gt; Sequential tool execution is a major latency bottleneck for complex agents.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leased Isolation:&lt;/strong&gt; Dynamically leasing containers ensures that concurrent tasks remain isolated from one another, preventing filesystem collisions during parallel testing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Heartbeats are Mandatory:&lt;/strong&gt; Always implement TTLs (Time-to-Live) and heartbeats when orchestrating Docker containers to prevent zombie processes from hanging the host machine.&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="/_astro/cover.C1lsvHri.png"/><enclosure url="/_astro/cover.C1lsvHri.png"/></item><item><title>Why Build an Agent Harness?</title><link>https://astro-pure.js.org/blog/agent-harness-introduction</link><guid isPermaLink="true">https://astro-pure.js.org/blog/agent-harness-introduction</guid><description>An agent harness turns coding-agent activity into a bounded, inspectable, and repeatable engineering process rather than a stream of opaque terminal outcomes.</description><pubDate>Wed, 06 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Coding agents can search a repository, propose a plan, edit files, and run tests. That does not yet make their work safe to delegate or their outcomes useful to learn from. A harness is the missing engineering layer: it constrains what an agent may do, records what it did, and applies the same verification standards to an agent-produced change that a careful reviewer would expect.&lt;/p&gt;
&lt;p&gt;The harness was built around that premise. Its immediate role is a local-first control plane for work in a target repository; its larger purpose is to make agent-assisted development an inspectable research-and-development practice. The system isolates work in Git worktrees, applies execution budgets, removes secrets and live-trading settings from the environment, and separates inspection, planning, implementation, verification, review, and human-approved application.&lt;/p&gt;
&lt;p&gt;The goal is not to make an agent look autonomous. It is to make the boundary between useful autonomy and engineering control explicit.&lt;/p&gt;
&lt;h2&gt;The problem is not just code generation&lt;/h2&gt;
&lt;p&gt;Without a harness, an agent run often collapses into a single question: did it finish? That answer hides the questions that matter when the output will affect a real repository:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Which repository state and task definition did it see?&lt;/li&gt;
&lt;li&gt;Was it permitted to write, run commands, or reach the network?&lt;/li&gt;
&lt;li&gt;Which tests and policy checks were actually run?&lt;/li&gt;
&lt;li&gt;Did a plan cite the right files and tests, or merely plausible-looking ones?&lt;/li&gt;
&lt;li&gt;How much time, model budget, and repair work did the result consume?&lt;/li&gt;
&lt;li&gt;Can someone reproduce the cohort and explain a surprising failure later?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A terminal success cannot answer those questions. Nor can a long transcript on its own. A useful harness makes the answers first-class artifacts.&lt;/p&gt;
&lt;h2&gt;The operating model&lt;/h2&gt;
&lt;p&gt;The harness treats agent work as a bounded workflow rather than an unstructured chat loop:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./harness-control-plane.svg&quot; alt=&quot;Schematic of the harness control plane: declared authority constrains an isolated run whose output must pass verification before human-approved application&quot;&gt;&lt;/p&gt;
&lt;p&gt;Each layer has a different job. Isolation contains side effects. Budgets make costly or stalled work visible. Verification turns assertions into checks. Human approval retains authority over application. Durable artifacts let later experiments distinguish a promising mechanism from an accidental result.&lt;/p&gt;
&lt;h2&gt;Why research belongs in the same system&lt;/h2&gt;
&lt;p&gt;The harness becomes more valuable when it can evaluate its own operating choices. For example, a checkpointed indexed-planner cohort completed 2/2 runs while its baseline completed 0/2, but the checkpoint cohort used more mean tokens and later manual review found semantic defects in both accepted plans. That is a useful result only because the study preserved repeat-level outcomes, cost, finalization behavior, and the plans for inspection.&lt;/p&gt;
&lt;p&gt;Likewise, a later test-repair fallback cohort completed and verified 2/2 runs, recorded 22/22 grounding claims, and logged one successful repair. It is strong non-regression evidence. It is not direct proof of every repair branch: the exact empty-test-discovery branch was not exercised. The distinction matters. A research harness should make it easy to say both what improved and what remains unproved.&lt;/p&gt;
&lt;p&gt;| What a harness records | Why it changes the decision |
| --- | --- |
| Repository snapshot, task, policy, and run ID | A reviewer can identify the conditions of the result. |
| Per-case outcomes and terminal states | A cohort rate does not conceal failed or malformed runs. |
| Verification, grounding, and repair telemetry | Completion can be separated from correctness and mechanism evidence. |
| Token, latency, and iteration data | An apparent gain can be weighed against operational cost. |
| Reports, scoreboards, and provenance manifests | Findings can be regenerated and challenged after the run. |&lt;/p&gt;
&lt;p&gt;The early adapter-axis sweep makes the observability argument concrete. It reported 50% completion across two runs but no token figure, not because the work was free, but because that telemetry had not yet been materialized. Later cohorts retained token and trajectory evidence. Preserving the gap is part of the point: a system should expose its own blind spots instead of presenting a cleaner historical story than the artifacts support.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./completion-rate.svg&quot; alt=&quot;The recorded cohorts span zero to 100 percent completion under different interventions and failure modes&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./token-usage.svg&quot; alt=&quot;The adapter sweep is marked not recorded for token use; later cohorts preserve measured means&quot;&gt;&lt;/p&gt;
&lt;h2&gt;What the harness is not&lt;/h2&gt;
&lt;p&gt;It is not a claim that every agent action can be automatically trusted. Deterministic checks, path grounding, and budgets reduce risk; they do not prove semantic correctness or product fitness. The checkpoint study is the counterexample: structurally accepted plans still cited nonexistent test paths and confused documentation with the implementation under review.&lt;/p&gt;
&lt;p&gt;It is also not a substitute for engineers. The desired division of labor is deliberate: the system lets agents perform bounded exploration and produce evidence; engineers choose goals, define acceptance, inspect the important failure modes, and approve changes with real consequences.&lt;/p&gt;
&lt;h2&gt;The series&lt;/h2&gt;
&lt;p&gt;This opening article provides the frame. The rest of the series investigates the individual controls and the evidence needed to evaluate them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/experiments-as-product-artifacts&quot;&gt;Experiments Should Be First-Class Product Artifacts&lt;/a&gt; explains the artifact chain behind reproducible conclusions.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/benchmarking-agent-repair-loops&quot;&gt;Benchmarking Agent Systems Beyond “Did It Finish?”&lt;/a&gt; defines a scorecard spanning completion, verification, grounding, repair, and cost.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/agent-plans-semantic-proof&quot;&gt;A Plan Can Validate and Still Be Unsafe to Implement&lt;/a&gt; shows why structural checks need semantic review.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/grounding-is-not-semantic-proof&quot;&gt;Grounding Is Necessary, Not Sufficient&lt;/a&gt; separates file existence from claim correctness.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/bounded-agent-repair-loops&quot;&gt;Designing Bounded Repair Loops for Agent Plans&lt;/a&gt; turns a repair attempt into an observable control loop.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/interpreting-two-two-agent-results&quot;&gt;What a Two-for-Two Agent Result Actually Proves&lt;/a&gt; provides the language for interpreting small cohorts honestly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The standard to hold it to&lt;/h2&gt;
&lt;p&gt;The harness earns its complexity only if it improves decisions. A useful falsifier is straightforward: if a team cannot reconstruct a result, identify the conditions under which it ran, and explain why it passed or failed, the system is collecting activity rather than producing engineering evidence.&lt;/p&gt;
&lt;p&gt;That is the motivation for the harness and for the research program around it: not agents that merely act, but agent-assisted development that can be inspected, challenged, and improved.&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.CXAG-Hd5.png"/><enclosure url="/_astro/cover.CXAG-Hd5.png"/></item><item><title>Experiments Should Be First-Class Product Artifacts</title><link>https://astro-pure.js.org/blog/experiments-as-product-artifacts</link><guid isPermaLink="true">https://astro-pure.js.org/blog/experiments-as-product-artifacts</guid><description>If an experiment cannot be inspected after the run, its result is operationally weaker than it needs to be.</description><pubDate>Mon, 04 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;An agent experiment is not complete when the model stops. It is complete when a later reviewer can answer: what task ran, against what repository state, with what configuration, what happened in each repeat, and why the conclusion follows.&lt;/p&gt;
&lt;p&gt;That sounds like research hygiene. In an agent system it is also product design. A study runner that emits only a terminal score turns every failure investigation into archaeology. A runner that materializes manifests, scoreboards, reports, case results, and trajectories makes iteration cumulative.&lt;/p&gt;
&lt;h2&gt;The artifact chain&lt;/h2&gt;
&lt;p&gt;Use a small, explicit chain for every cohort:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./artifact-chain.svg&quot; alt=&quot;Schematic artifact chain from declared task and policy through trajectories, case records, scoreboards, reports, and article-owned evidence&quot;&gt;&lt;/p&gt;
&lt;p&gt;Each link answers a different audit question. The task and snapshot answer “what was intended?” Trajectories answer “what did the model do?” Case results answer “what happened in each repeat?” The scoreboard answers “what changed across groups?” The article bundle makes the published argument regenerable.&lt;/p&gt;
&lt;h2&gt;Why a summary report is not enough&lt;/h2&gt;
&lt;p&gt;The indexed-planner studies expose this quickly. An adapter-axis sweep reported 50% completion across two runs. That is a useful headline and an insufficient diagnosis. The later finalization-reliability cohort reported 0% completion despite substantial work: 76.5 mean turns, four validation failures, two recorded repair actions, and about 1.28 million mean tokens. The fallback cohort then reported 100% completion, 22/22 verified grounding claims, and one successful repair.&lt;/p&gt;
&lt;p&gt;| Cohort | Completion | Mean tokens | Mean turns | Validation failures | Repair actions |
| --- | ---: | ---: | ---: | ---: | ---: |
| Adapter-axis sweep | 50% | 0 | 81.0 | n/a | n/a |
| Finalization reliability | 0% | 1.28m | 76.5 | 4 | 2 |
| Test-repair fallback | 100% | 1.32m | 78.0 | 1 | 1 |&lt;/p&gt;
&lt;p&gt;The zero-token adapter-axis row is not evidence that the system was free. It reflects an observability gap that later work corrected with persisted model-invocation telemetry. The comparison is valuable precisely because the artifacts preserve that limitation rather than silently rewriting history.&lt;/p&gt;
&lt;h2&gt;What must be materialized&lt;/h2&gt;
&lt;p&gt;At minimum, a study package should retain:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;study.yaml&lt;/code&gt; for the declared axes and repeats;&lt;/li&gt;
&lt;li&gt;a manifest with git coordinates, source task, arm IDs, and run IDs;&lt;/li&gt;
&lt;li&gt;per-case outcomes, including failed and pending arms;&lt;/li&gt;
&lt;li&gt;a scoreboard with completion, verification, cost, latency, grounding, and repair metrics;&lt;/li&gt;
&lt;li&gt;a human-readable report generated from those raw artifacts; and&lt;/li&gt;
&lt;li&gt;trajectories or event logs for mechanism analysis.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Do not put all of this into a single prose report. The report is an interpretation layer; the case data and manifest are the audit layer.&lt;/p&gt;
&lt;h2&gt;The article handoff is part of the system&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;authoring-research-harvest&lt;/code&gt; workflow turns selected study artifacts into three article-owned files:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;data/study-metrics.csv
data/study-cases.csv
data/evidence-manifest.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The manifest records the source artifacts and their SHA-256 hashes. This avoids two common failures: numbers copied from a transient console, and a chart whose underlying data cannot be found once the experiment workspace changes.&lt;/p&gt;
&lt;h2&gt;Counterfactual: when can a notebook be enough?&lt;/h2&gt;
&lt;p&gt;For a one-off exploratory question, a notebook plus an archived dataset may be sufficient. The threshold changes when a result will alter agent policy, spend budget repeatedly, or become a public claim. At that point, the experiment needs stable identities, repeat-level results, and provenance.&lt;/p&gt;
&lt;p&gt;The falsifier is operational: if a new engineer can reconstruct the exact cohort and explain a surprising case from the report alone, the extra artifacts may be unnecessary. In practice, model failures, transport errors, and partial repairs make that rare.&lt;/p&gt;
&lt;h2&gt;Cohort results at a glance&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;./completion-rate.svg&quot; alt=&quot;Persisted cohort outcomes range from zero to 100 percent completion and remain auditable after each run&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./token-usage.svg&quot; alt=&quot;Later cohorts retained token telemetry; the adapter sweep is marked not recorded rather than interpreted as zero cost&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Treat manifests and case records as product outputs, not debugging leftovers.&lt;/li&gt;
&lt;li&gt;Preserve failures; they often explain an apparent improvement.&lt;/li&gt;
&lt;li&gt;Generate prose reports from raw artifacts, not the other way around.&lt;/li&gt;
&lt;li&gt;Make publication consume the same durable evidence the operators use.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The companion &lt;a href=&quot;/blog/benchmarking-agent-repair-loops&quot;&gt;Benchmarking Agent Systems Beyond “Did It Finish?”&lt;/a&gt; explains the scorecard these artifacts should support.&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.C0z_q3ww.png"/><enclosure url="/_astro/cover.C0z_q3ww.png"/></item><item><title>Benchmarking Agent Systems Beyond Did It Finish?</title><link>https://astro-pure.js.org/blog/benchmarking-agent-repair-loops</link><guid isPermaLink="true">https://astro-pure.js.org/blog/benchmarking-agent-repair-loops</guid><description>A practical scorecard for agent planning experiments separates completion, verification, grounding, repair efficiency, latency, and token cost.</description><pubDate>Thu, 23 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;“Did the agent finish?” is a useful operator question and an inadequate research metric. It merges at least six different behaviours: whether the run terminated, whether output passed verification, whether the plan was grounded, how much repair it required, what it cost, and whether the same result can be reproduced.&lt;/p&gt;
&lt;p&gt;The indexed-planner experiments behind this note use a compact scorecard that keeps those questions separate. The result is not a promise of statistical certainty—most cohorts have one or two repeats—but a better way to prevent a green completion cell from hiding an ungrounded or expensive outcome.&lt;/p&gt;
&lt;h2&gt;The scorecard&lt;/h2&gt;
&lt;p&gt;| Dimension | Primary fields | Question answered |
| --- | --- | --- |
| Termination | completion rate, iteration count | Did the planner reach a terminal result? |
| Acceptance | verification pass rate, mean score | Did the harness accept the plan? |
| Grounding | claimed/verified references, grounding ratio | Are required references supported at the chosen level? |
| Repair | validation failures, repairs, successful repairs | Did feedback produce a valid revision efficiently? |
| Cost | input/output/total tokens, elapsed time | What did the outcome consume? |
| Service health | mean/max latency, transport failures | Was the result affected by model or provider behaviour? |&lt;/p&gt;
&lt;p&gt;The article package owns the normalized source data in &lt;code&gt;data/study-metrics.csv&lt;/code&gt; and &lt;code&gt;data/study-cases.csv&lt;/code&gt;. The evidence manifest records the original scoreboards, reports, and manifests by hash.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./benchmark-evidence-pipeline.svg&quot; alt=&quot;Schematic benchmark evidence pipeline from durable run artifacts through a multidimensional scorecard and mechanism diagnosis to the next engineering decision&quot;&gt;&lt;/p&gt;
&lt;h2&gt;A worked sequence: the finalization cohorts&lt;/h2&gt;
&lt;p&gt;Seven two-repeat cohorts evaluated variations of strict plan finalization. They should not be read as one clean A/B: interventions accumulated, some runs hit provider issues, and individual failure modes changed. They are useful as a repair ledger.&lt;/p&gt;
&lt;p&gt;| Cohort | Completion | Grounding | Mean tokens | Validation failures | Successful repairs |
| --- | ---: | ---: | ---: | ---: | ---: |
| Repair signals | 50% | 100% | 1.14m | 3 | 2 / 3 |
| Evidence-reference repair | 50% | 91.7% | 1.23m | 3 | 2 / 2 |
| Evidence-reference repair v2 | 0% | n/a | 653k | 2 | 1 / 1 |
| Finalization clean | 50% | 92.9% | 667k | 1 | 1 / 1 |
| Completeness guidance | 0% | n/a | 646k | 2 | 1 / 2 |
| Reliability validation | 0% | 0% | 1.28m | 4 | 2 / 2 |
| Test-repair fallback | 100% | 100% | 1.32m | 1 | 1 / 1 |&lt;/p&gt;
&lt;p&gt;Two observations matter more than the final row&apos;s 100% headline.&lt;/p&gt;
&lt;p&gt;First, a successful repair action is not the same as a successful run. The reliability cohort recorded two successful repair actions per the study metric, yet both repeats ultimately failed because the revised plans retained missing or nonexistent tests. Counting repair &lt;em&gt;attempts&lt;/em&gt; without final outcome would overstate robustness.&lt;/p&gt;
&lt;p&gt;Second, completion and grounding can move independently. The evidence-reference cohort completed only half its repeats but reported 11 verified references out of 12 claimed across the measured group. Reference-level grounding is informative; it does not guarantee that a run terminates or that the plan is semantically correct.&lt;/p&gt;
&lt;h2&gt;Why raw trajectories belong beside the scoreboard&lt;/h2&gt;
&lt;p&gt;Aggregates tell us that a repair happened. Trajectories tell us what the planner did with the feedback.&lt;/p&gt;
&lt;p&gt;For this class of system, retain at least:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the first-finalize sequence;&lt;/li&gt;
&lt;li&gt;every validation error category;&lt;/li&gt;
&lt;li&gt;repair-action count and repair success count;&lt;/li&gt;
&lt;li&gt;post-finalize calls and post-finalize tokens;&lt;/li&gt;
&lt;li&gt;action-type histogram; and&lt;/li&gt;
&lt;li&gt;the run IDs that connect a score back to durable artifacts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This avoids a common benchmarking failure: averaging two runs with completely different mechanisms. A provider disconnect, a malformed response, an empty test discovery result, and a genuinely poor plan are all “failed runs,” but they demand different engineering changes.&lt;/p&gt;
&lt;h2&gt;What counts as a fair comparison&lt;/h2&gt;
&lt;p&gt;Keep these fields stable before comparing interventions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Task and repository snapshot.&lt;/li&gt;
&lt;li&gt;Model profile and planner configuration.&lt;/li&gt;
&lt;li&gt;Budget limits and finalization checkpoint policy.&lt;/li&gt;
&lt;li&gt;Acceptance and grounding rules.&lt;/li&gt;
&lt;li&gt;Repeat count and exclusions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Then report confounders explicitly. In the checkpoint experiment, one control failed after only three schema retries; using the raw group mean would make the candidate look much more expensive than a long-run comparison suggests. In the final fallback cohort, both repeats passed, but neither directly exercised the exact invalid-test repair path. That supports non-regression, not a broad causal claim about the fallback.&lt;/p&gt;
&lt;h2&gt;The operational output: an evidence bundle, not a screenshot&lt;/h2&gt;
&lt;p&gt;Every study-to-article handoff should include three machine-readable files:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;data/study-metrics.csv       # group comparisons
data/study-cases.csv         # repeat-level outcomes
data/evidence-manifest.yaml  # source locations and SHA-256 hashes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The companion &lt;code&gt;authoring-research-harvest&lt;/code&gt; skill generates these files from durable study artifacts. That lets prose, tables, and later charts be regenerated without depending on a chat transcript or an ephemeral runtime database.&lt;/p&gt;
&lt;h2&gt;Limits and next experiment&lt;/h2&gt;
&lt;p&gt;The current cohorts are small and sequential, not independently powered randomized trials. They are best used to identify failure modes, screen candidate interventions, and design a stronger follow-up.&lt;/p&gt;
&lt;p&gt;The next benchmark should deterministically force the nonexistent-test repair branch, then compare a control and fallback treatment over at least four repeats per arm. Pre-register the expected success condition: the repaired task must contain the same planned test path in both &lt;code&gt;tests&lt;/code&gt; and &lt;code&gt;expected_files&lt;/code&gt;, within allowed scope. That turns a persuasive story about repair into an observable mechanism test.&lt;/p&gt;
&lt;h2&gt;Cohort results at a glance&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;./completion-rate.svg&quot; alt=&quot;Completion ranged from zero to 100 percent across sequential two-repeat finalization cohorts&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./token-usage.svg&quot; alt=&quot;Mean token use differed across cohorts whose interventions and failure mechanisms also changed&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Treat completion as one column, never the whole scorecard.&lt;/li&gt;
&lt;li&gt;Keep repair telemetry separate from final success.&lt;/li&gt;
&lt;li&gt;Preserve run-level provenance so an aggregate can be audited.&lt;/li&gt;
&lt;li&gt;Make limitations part of the result, not a footnote after publication.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the semantic consequence of this framework, read &lt;a href=&quot;/blog/agent-plans-semantic-proof&quot;&gt;A Plan Can Validate and Still Be Unsafe to Implement&lt;/a&gt;.&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.BQgDrDGr.png"/><enclosure url="/_astro/cover.BQgDrDGr.png"/></item><item><title>Targeted Trajectory Repair: Low-Cost Continuations</title><link>https://astro-pure.js.org/blog/targeted-trajectory-repair-continuations</link><guid isPermaLink="true">https://astro-pure.js.org/blog/targeted-trajectory-repair-continuations</guid><description>How child runs inherit parent trajectory history to perform targeted grounding repairs at a 90% reduction in compute costs.</description><pubDate>Wed, 22 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Imagine an AI agent has just spent 15 minutes and thousands of tokens diligently analyzing a codebase and writing a complex plan. At the very last step, it fails a quality check. Throwing away all that work and starting over from scratch isn&apos;t just frustrating—it&apos;s incredibly expensive.&lt;/p&gt;
&lt;p&gt;In this article, we demonstrate &lt;strong&gt;Targeted Trajectory Repair&lt;/strong&gt;, a surgical approach to fixing AI mistakes. Using our orchestration framework, we show how to create lightweight &apos;child&apos; runs that pick up exactly where the AI failed, fixing the specific error while saving massive amounts of computing power and time.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Provenance-Linked Child Continuations&lt;/h2&gt;
&lt;p&gt;Instead of resetting execution state, our orchestration framework creates a lightweight child run that clones the parent&apos;s SQLite database trajectory, active workspace state, and turn message history.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./assets/continuation-tree.svg&quot; alt=&quot;Continuation Tree&quot;&gt;&lt;/p&gt;
&lt;h3&gt;CLI Entrypoint &amp;#x26; Kernel Mechanics&lt;/h3&gt;
&lt;p&gt;The CLI command &lt;code&gt;orchestrator run repair-grounding &amp;#x3C;run_id&gt;&lt;/code&gt; evaluates the source run&apos;s unverified path claims and injects a precise repair prompt into the child trajectory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# orbit_harness/orchestration/commands.py
def repair_grounding(self, source_run_id: str) -&gt; CommandResult:
    run_dir = self.repo_root / &quot;.orchestrator&quot; / &quot;runs&quot; / source_run_id / &quot;agent-output&quot;
    summary = result_data.get(&quot;summary&quot;, &quot;&quot;)
    grounding = check_grounding(summary, self.repo_root)

    if not grounding.unverified:
        return CommandResult(success=True, message=&quot;No grounding repair needed.&quot;, data={&quot;repaired&quot;: False})

    unverified_str = &quot;, &quot;.join(grounding.unverified[:5])
    repair_instruction = (
        f&quot;Grounding Repair Mode: Your prior plan cited {len(grounding.unverified)} unverified file path(s): &quot;
        f&quot;{unverified_str}. Execute view_file() or grep_search() to inspect these files immediately.&quot;
    )
    return self.continue_failed_plan(source_run_id, instruction=repair_instruction)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;Quantitative Efficiency Comparison&lt;/h2&gt;
&lt;p&gt;We benchmarked full trajectory reruns against targeted child continuations on grounding repair scenarios.&lt;/p&gt;
&lt;p&gt;| Execution Strategy | Turns Executed | Tokens Burned | Latency (s) | Grounding Pass Rate | Cost Reduction |
| :--- | :---: | :---: | :---: | :---: | :---: |
| &lt;strong&gt;Full Trajectory Rerun&lt;/strong&gt; | 15 | 44,080 | 222.8s | 100% | 0% (Baseline) |
| &lt;strong&gt;Targeted Child Continuation&lt;/strong&gt; | &lt;strong&gt;2&lt;/strong&gt; | &lt;strong&gt;4,200&lt;/strong&gt; | &lt;strong&gt;18.4s&lt;/strong&gt; | &lt;strong&gt;100%&lt;/strong&gt; | &lt;strong&gt;90.5%&lt;/strong&gt; |&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Result:&lt;/em&gt; Targeted child continuations achieved identical 100% plan grounding pass rates while &lt;strong&gt;reducing token burn by 90.5%&lt;/strong&gt; and &lt;strong&gt;reducing repair latency from 222s to 18s&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Key Takeaways&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Clone Trajectories, Don&apos;t Rerun:&lt;/strong&gt; Inheriting parent message history preserves contextual state without re-executing search steps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inject Explicit Targeted Prompts:&lt;/strong&gt; Specifying the exact unverified file paths in the continuation prompt focuses model attention immediately on missing evidence.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;90%+ Cost Reduction:&lt;/strong&gt; Child continuations dramatically reduce evaluation costs across large agent benchmark suites.&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="/_astro/cover.C8oMAvc5.png"/><enclosure url="/_astro/cover.C8oMAvc5.png"/></item><item><title>Token Efficiency: Code Fences vs Large Contexts</title><link>https://astro-pure.js.org/blog/token-efficiency-curve</link><guid isPermaLink="true">https://astro-pure.js.org/blog/token-efficiency-curve</guid><description>Analyzing how single-cell turn discipline impacts context growth and token costs.</description><pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As context windows for Large Language Models expand into the millions of tokens, a dangerous anti-pattern has emerged in agent engineering: the &quot;Context Window Dump.&quot;&lt;/p&gt;
&lt;p&gt;Instead of teaching agents to precisely navigate a repository, developers simply dump the entire codebase into the prompt. While this might yield quick results for trivial scripts, it destroys token efficiency and creates massive latency bottlenecks in recursive, multi-turn trajectories.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. The Cost of the Dump&lt;/h2&gt;
&lt;p&gt;In a Recursive Language Model (RLM) loop, the context window grows with every turn. The agent sees the initial prompt, its own tool calls, and the tool responses.&lt;/p&gt;
&lt;p&gt;If you dump a 100,000-token codebase into the initial prompt, and the agent takes 15 turns to solve a problem, you are paying to process those 100,000 tokens &lt;em&gt;15 times&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;$$ 100,000 \text{ tokens} \times 15 \text{ turns} = 1.5 \text{ million input tokens} $$&lt;/p&gt;
&lt;p&gt;This isn&apos;t just expensive financially; it incurs massive Time-to-First-Token (TTFT) latency, slowing down the entire swarm.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. Single-Cell Turn Discipline&lt;/h2&gt;
&lt;p&gt;In our orchestration framework, we advocate for &lt;strong&gt;Small Code Fences&lt;/strong&gt; and &lt;strong&gt;Single-Cell Turn Discipline&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Instead of dumping the codebase, the agent is given a strict set of precise tools (&lt;code&gt;grep_search&lt;/code&gt;, &lt;code&gt;view_file&lt;/code&gt; with line number constraints). The agent must actively explore the codebase, pulling only the snippets it needs.&lt;/p&gt;
&lt;h3&gt;The Efficiency Curve&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;./efficiency-curve.svg&quot; alt=&quot;Token Efficiency Curve&quot;&gt;&lt;/p&gt;
&lt;p&gt;When an agent uses targeted tools, its context window starts small and grows linearly only with the specific information relevant to the task.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Turn 1:&lt;/strong&gt; &lt;code&gt;grep_search(&quot;AuthModule&quot;)&lt;/code&gt; (Returns 500 tokens of results). Total Context: 2,500 tokens.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Turn 2:&lt;/strong&gt; &lt;code&gt;view_file(&quot;auth.py&quot;, start=10, end=50)&lt;/code&gt; (Returns 300 tokens of code). Total Context: 3,000 tokens.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Turn 15:&lt;/strong&gt; Total Context: 15,000 tokens.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;$$ \text{Average Context (8,750)} \times 15 \text{ turns} = 131,250 \text{ input tokens} $$&lt;/p&gt;
&lt;p&gt;By enforcing discipline, we achieve a &gt;90% reduction in token usage compared to the dump method, while drastically improving execution speed.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;3. Engineering for Precision&lt;/h2&gt;
&lt;p&gt;LLMs are capable of processing millions of tokens, but that doesn&apos;t mean they should. Massive context windows should be reserved for problems that inherently require massive context (like reading a 500-page PDF), not as a crutch to avoid building proper search and navigation tools for your agents.&lt;/p&gt;
&lt;p&gt;To build production-grade agent swarms, optimize for precision. Small fences build efficient agents.&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.DdqFHIiJ.png"/><enclosure url="/_astro/cover.DdqFHIiJ.png"/></item><item><title>Grounding Is Not Proof: Why 100% Code Completion Fails</title><link>https://astro-pure.js.org/blog/grounding-is-not-proof-plan-quality</link><guid isPermaLink="true">https://astro-pure.js.org/blog/grounding-is-not-proof-plan-quality</guid><description>Benchmarking reveals why 100% completion rates don&apos;t guarantee plan quality, and how pre-finalization checks prevent hallucinated paths.</description><pubDate>Sun, 29 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It’s easy to assume that if an AI finishes a task without crashing, it did a good job. But what if it confidently hands you a finished blueprint that cites nonexistent materials? In the world of AI agents, evaluating systems purely by whether they finish a task creates dangerous illusions of competence. An AI can execute perfectly, hit no errors, and yet submit a plan full of fabricated file paths and unverified claims.&lt;/p&gt;
&lt;p&gt;In this study, we tested several top-tier AI models—including Gemini 3.6 and DeepSeek v4—and discovered why a 100% completion rate means nothing if the AI’s work isn&apos;t strictly &quot;grounded&quot; in reality. More importantly, we show how to build safeguards that force the AI to double-check its facts before submitting its final answer.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;The Execution vs. Quality Paradox&lt;/h2&gt;
&lt;p&gt;During matrix benchmarks, Gemini 3.6 model tiers consistently achieved &lt;strong&gt;100% execution completion&lt;/strong&gt; (0 runtime crashes, 0 budget pauses). However, when evaluated against strict quality gates checking whether cited file paths were actually read via &lt;code&gt;view_file()&lt;/code&gt; or &lt;code&gt;grep_search()&lt;/code&gt;, &lt;strong&gt;all provider groups failed the quality gate (&lt;code&gt;BLOCKED (0%)&lt;/code&gt;)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;| Provider Group | Completion Rate | Mean Score | Grounding Ratio | Quality Gate Status | Mean Tokens | Mean Elapsed (s) |
| :--- | :---: | :---: | :---: | :---: | :---: | :---: |
| &lt;code&gt;cliproxyapi-gemini-3.6-flash-high&lt;/code&gt; | &lt;strong&gt;100%&lt;/strong&gt; | 1.00 | 75% | &lt;strong&gt;BLOCKED (0%)&lt;/strong&gt; | 44,080 | 222.8s |
| &lt;code&gt;cliproxyapi-gemini-3.6-flash-medium&lt;/code&gt; | &lt;strong&gt;100%&lt;/strong&gt; | 1.00 | 0% | &lt;strong&gt;BLOCKED (0%)&lt;/strong&gt; | 17,642 | 38.0s |
| &lt;code&gt;cliproxyapi-gemini-3.6-flash-low&lt;/code&gt; | &lt;strong&gt;100%&lt;/strong&gt; | 1.00 | N/A | &lt;strong&gt;BLOCKED (0%)&lt;/strong&gt; | 18,354 | 64.7s |
| &lt;code&gt;deepseek-v4-flash&lt;/code&gt; | 33% | 0.33 | 100% | &lt;strong&gt;BLOCKED (0%)&lt;/strong&gt; | 84,847 | 316.3s |&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Key Takeaway:&lt;/em&gt; Gemini models ran fast and completed 100% of tasks, but cited file paths they had never inspected. DeepSeek achieved 100% path verification on the 33% of runs that completed, but consumed &lt;strong&gt;4.8x more tokens&lt;/strong&gt; and hit step ceilings.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Pre-Finalization Intercept &amp;#x26; Self-Correction&lt;/h2&gt;
&lt;p&gt;To eliminate ungrounded answers without forcing full trajectory reruns, we implemented a &lt;strong&gt;Pre-Finalization Quality Intercept&lt;/strong&gt; in our orchestration framework.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./assets/quality-gate-flow.svg&quot; alt=&quot;Quality Gate Flow&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Intercept Implementation&lt;/h3&gt;
&lt;p&gt;When a model attempts to emit &lt;code&gt;FINAL(answer)&lt;/code&gt;, our orchestration framework extracts path claims and checks them against &lt;code&gt;check_grounding()&lt;/code&gt;. If unverified paths are found:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# orbit_harness/rlm/general/rlm.py
if grounding.unverified and grounding.claimed:
    self._self_correction_attempts += 1
    unverified_str = &quot;, &quot;.join(grounding.unverified[:5])
    message_history.append(
        Message(
            role=&quot;user&quot;,
            content=(
                f&quot;[Quality Check Alert]: The plan answer contains {len(grounding.unverified)} &quot;
                f&quot;unverified file path(s): {unverified_str}. Execute view_file() or grep_search() &quot;
                &quot;to inspect and confirm these files exist before calling FINAL().&quot;
            )
        )
    )
    final_result = None
    continue  # Allow agent to inspect missing paths
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;Key Takeaways&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Completion Rate $\neq$ Quality:&lt;/strong&gt; Never rely on binary task completion as proof of model capability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-Finalization Intercepts Work:&lt;/strong&gt; Pausing finalization to report ungrounded paths forces self-correction without wasting prior trajectory steps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deterministic Evaluation:&lt;/strong&gt; Grounding ratio and required-finding checks provide unambiguous quality signals for agent benchmarks.&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="/_astro/cover.BLA_uh3v.png"/><enclosure url="/_astro/cover.BLA_uh3v.png"/></item></channel></rss>