A Control Architecture for Long-Horizon Agents
How to combine iterative coding loops, independent verification, append-only event ledgers, typed state, and external evaluation so an agent can improve without grading its own homework.

Long-horizon agents fail differently from chatbots. A chatbot can be wrong once. A long-running agent can preserve the wrong state, optimize around a weak evaluator, repeat the mistake across dozens of iterations, and produce a dashboard claiming that everything improved.
Four recent research directions make the architecture problem clearer. Harness-of-Harness shows that coding agents can improve across repeated planning, implementation, and testing loops when work is scoped into verifiable increments and evaluated independently. Cheap Verifiers, Large Blind Spots shows why an in-loop verifier cannot be treated as ground truth: the system's own dashboard can stay near 3% error while delivered error reaches 32%. Parsing the Stream shows how an append-only ledger can be folded into typed state and consumer-specific views. SCILAWS-BENCH shows a related evaluation trap: predictive fit and scientific validity can diverge, and a model may reproduce a familiar formula without discovering anything.
The practical conclusion is simple: the agent, its state, and its judge must be separate systems.
1. Build an iteration protocol, not an infinite session
A long task should be a sequence of bounded iterations. Each iteration starts from explicit state, produces a small deliverable, runs checks, and either promotes the result or rolls it back.
A useful contract is:
Iteration {
objective
allowed_scope
starting_revision
required_evidence[]
budget
stop_conditions[]
}
IterationResult {
resulting_revision
changes[]
test_evidence[]
unresolved_risks[]
proposed_next_step
}
The objective should be narrow enough that failure is local. “Build the product” is not an iteration. “Add password reset with one happy-path and two failure-path tests” can be one.
Version every promoted result. A worker should never overwrite the last known-good state without a recoverable revision boundary. This gives the supervisor a meaningful action when evidence fails: reject the iteration and return to a known state, rather than asking the same context to repair itself indefinitely.
2. Separate implementation checks from acceptance
Tests written or selected by the same worker are valuable, but they are not independent acceptance evidence. The worker knows what it implemented and can unconsciously shape checks around its own assumptions.
Use two gates:
- Implementation gate: fast unit tests, lint, type checks, local smoke tests, and worker-authored assertions.
- Acceptance gate: independently selected scenarios, hidden fixtures, deterministic invariants, or a separate evaluator that did not see the worker's chain of thought.
The acceptance gate should receive the artifact and the contract, not the persuasive story the worker tells about them. If an LLM judge is necessary, calibrate it against deterministic checks and periodically rotate or compare model families. Never let a single model both generate an answer and define the metric used to prove that answer improved.
3. Treat verifier blind spots as a production metric
Most cascade dashboards measure what the verifier rejects, not what the system gets wrong. Those are different quantities.
Maintain three samples:
- in-loop traffic, used for routing and fast feedback;
- hidden holdout traffic, evaluated outside the routing verifier;
- adversarial disagreement traffic, selected where worker and verifier are most likely to share a mistake.
Estimate blind-spot rate directly: among outputs that the verifier accepted, how many fail independent review? Track it by task type, worker model, verifier model, confidence band, and software version.
Escalation rate is not a reliability metric. A falling escalation rate may mean the student improved, or it may mean the verifier became easier to fool. Cost and quality must be plotted against independent ground truth, not only against decisions made inside the cascade.
4. Use an append-only event ledger as the source of truth
Raw conversation history is a poor state store. It is long, ambiguous, expensive to reread, and easy to summarize incorrectly. Instead, record events with stable types:
RunEvent {
sequence
timestamp
actor
type
payload_ref
parent_event
revision
}
Events might include objective-created, tool-called, artifact-written, test-passed, test-failed, review-rejected, revision-promoted, and run-stopped records.
The ledger should be append-only. Corrections arrive as new events that supersede earlier claims. This preserves auditability and lets the system reconstruct exactly what the agent knew when it acted.
Do not put large blobs directly in the ledger. Store content-addressed artifacts and reference them by hash. The event stream records causality; the artifact store holds files, logs, screenshots, and test outputs.
5. Fold events into typed state
Both humans and agents need a compact view, but they need different views. Incrementally fold the ledger into a typed run state:
RunState {
current_objective
active_revision
completed_steps[]
pending_steps[]
blockers[]
evidence_by_claim{}
budgets{}
latest_health
stop_reason
}
Compile an agent view containing the next actionable step, relevant files, constraints, and recent failures. Compile an observer view containing progress, evidence, risk, cost, and intervention controls. Both views derive from the same ledger, so the human does not monitor one story while the worker acts on another.
Typed state should not attempt to preserve every nuance. Keep raw events and artifacts for replay. The fold is an operational index, not a replacement for evidence.
6. Make claims point to evidence
Long-running agents often fail through narrative drift: “tests passed” becomes a durable fact even though only one local command ran, or “deployed” survives after a rollback.
Store claims as references:
Claim {
statement
status // proposed, supported, contradicted, expired
evidence_refs[]
evaluator
observed_at
validity_scope
}
A build log can support “the production build completed at revision X.” It cannot support “the live site works.” That requires a live probe. A screenshot can support “the page rendered at this viewport.” It cannot support “all users can authenticate.” Scope keeps evidence from being stretched beyond what it proves.
Expire claims when the environment changes. Deployment, dependency upgrades, credential rotation, model changes, and policy updates should invalidate affected claims automatically.
7. Define stop conditions outside the worker
The worker should not control whether it is allowed to continue. A supervisor must enforce budgets and stop conditions such as:
- repeated failure of the same acceptance check;
- widening diff without corresponding evidence;
- verifier disagreement above a threshold;
- tool calls outside the declared scope;
- loss of a required source, credential, or environment;
- budget exhaustion;
- state fold inconsistency;
- human intervention.
An emergency stop must revoke capabilities, not merely add a message asking the agent to stop. Network access, deployment credentials, write permissions, and tool grants should be short-lived and issued per iteration.
8. Evaluate novelty separately from correctness
SCILAWS-BENCH highlights a problem that extends beyond science. A model can produce the expected answer because it remembers a pattern, because it inferred the answer, or because the evaluator rewards a familiar form. These outcomes look identical if the metric checks only the final string.
For agent systems, separate:
- task correctness: did the result satisfy the contract?
- process validity: did the agent use allowed evidence and tools?
- generalization: does the behavior survive hidden variants?
- novel contribution: did the system add a capability not already encoded in retrieval or scaffolding?
This matters when claiming self-improvement. Reusing a cached fix is useful, but it is not evidence that the agent learned a new strategy. Promotion decisions should know the difference.
9. A minimal production stack
You do not need a research platform to apply these ideas. A practical first version can use:
- a Git repository or immutable artifact store for revisions;
- an append-only database table for run events;
- a deterministic fold that produces typed run state;
- a worker executing one bounded iteration at a time;
- an acceptance runner with hidden tests and independent probes;
- a policy service that issues scoped tool grants;
- a supervisor that enforces budgets, promotion, rollback, and stop conditions;
- an observer UI compiled from the same state used by the worker.
Instrument disagreements. Store every case where implementation tests pass but acceptance fails, where the verifier accepts an independently wrong result, or where the state fold contradicts the ledger. Those cases are more useful than average success scores because they expose the control plane's blind spots.
Long-horizon autonomy does not come from giving one model more context and more time. It comes from a system that can preserve progress without preserving false confidence. Small iterations create recoverable movement. Independent verification keeps the metric honest. Append-only traces preserve causality. Typed views keep humans and agents oriented. External stop conditions ensure that the system can still say no to itself.
The goal is not an agent that runs forever. It is an agent that can run for as long as evidence continues to justify the next step.