WORKBENCH

What makes a task long-horizon?

Why do agents that succeed at 10-step tasks fail at 100-step ones?

Listen · 14 min0:00 / 14:14

A long task, for an AI agent (a model that works by taking actions, like reading a file or running a command, and looking at what happened), is one where it has to make many choices in a row before anything tells it whether it’s on track. Fixing one typo is short. Moving forty files to a new config format, where each change depends on the one before, is long.

Long tasks are where agents fall apart, and Anthropic’s job postings for the team that trains Claude to code name this gap directly. You’ve seen the small version already: a web agent that has to get through ten pages to finish a checkout, where each page goes right 95% of the time, finishes only about 60% of the time. The good news is that the damage follows simple arithmetic. You can predict it, measure it, and tell which fix will actually help before you pay for it.

This builds on Is that improvement real?, for how much to trust a handful of runs, and sits next to Managing context, which is about what piles up in the model’s memory as a task drags on. It sets up the rest of the track: turning tasks into something a model can practise on in What is an RL environment?, writing checks that can’t be fooled in Rewards and verifiers, and building the machinery around the model in Inside an agent harness.

Today

Nothing is strictly required first, though Is that improvement real? helps with the error bars and Managing context is the sibling lesson about what fills up as tasks get long. Plan on one evening to read and build the code that runs the model, and one session of model runs, costing a few dollars to a few tens of dollars depending on the model (the cost math is in Build It).

The Problem

You give a coding agent a small job: rename a config key in one file and fix the one test that uses it. It nails it. You give it ten of those, one after another, in the same repo. It nails nine of them, and on the tenth it is confidently editing a file it already edited, undoing its own work.

Then you give it a real migration: forty files, each change depending on the one before. It runs for an hour, reports success, and the test suite fails. Somewhere around file 12 it misread a value, and every file after that was built on the misread. Every individual edit looks reasonable. The whole thing is wrong.

The model didn’t get dumber between task 1 and task 40. Each step is about as likely to go right as before. What changed is that you asked it to be right forty times in a row, with nobody checking in between. That is the whole subject of this lesson, and you can put numbers on it.

When the Anthropic Code RL posting says “long-horizon autonomous engineering tasks”, this is the problem it’s pointing at. Short tasks are mostly solved. The frontier is getting a model to stay correct across hundreds of steps, which means getting the per-step error rate down, getting the model to notice and fix its own mistakes, and figuring out how to train any of that when the only signal comes at the very end.

The Idea

A horizon is how many decisions you make before anyone tells you how you did

Start with a scene. You’re learning to bake. In one version, a teacher stands next to you and says “too much flour” the moment you pour it. In the other, you bake alone and the only feedback is whether the cake tastes good three hours later. Same recipe, same number of actions. The second one is far harder to do well and far harder to learn from, because when the cake is bad you don’t know which of the forty things you did caused it.

An agent’s work is a trajectoryThe full record of one attempt at a task: every observation the agent saw, every action it took, in order. Also called a rollout or an episode.: look at something, decide, act, see the result, repeat. Each turn of that loop is a step. A coding agent’s step is usually one tool call: read a file, run a command, write an edit.

The horizonHow many steps an agent has to take before it gets feedback on whether it is succeeding. Long horizon means many decisions between checks. of a task is how many of those steps happen between the start and the moment you learn whether it worked. That is the definition to hold onto. It’s not the number of tokens, and not wall-clock time, though both tend to go up with it. A model that writes a 3,000-token essay in one shot has made one decision about one thing, and is graded once. An agent that does 60 tool calls and is graded only when the final test suite runs has a horizon of 60.

FIG_001[ SHORT VS LONG HORIZON ]
SHORT HORIZON · CHECK EVERY STEPACT✓ACT✓ACT✗FIX✓MISTAKE SEEN AT ONCELONG HORIZON · ONE CHECK AT THE ENDFAILMISTAKE AT STEP 12, FOUND AT STEP 40WHICH OF THE 40 STEPS CAUSED THE FAIL? THE SIGNAL DOESN’T SAY.
Top: every step gets a check, so a mistake is noticed one step after it happens. Bottom: forty steps run with no feedback, and the only signal is a pass or fail at the very end. Same work, very different problem.

So a task gets long-horizon in two ways at once. There are more chances to be wrong, and mistakes stay hidden longer. Let’s take them one at a time, starting with the arithmetic.

Being right forty times in a row

Say an agent does each step correctly with probability p, and any wrong step ruins the task. The steps are independent: getting step 5 right doesn’t change the odds for step 6. Then the chance of finishing an n-step task is the chance of getting every step right:

P(success) = p × p × ... × p = p^n

That’s the whole model. It is far more brutal than intuition says.

Predict firstwrite it down

An agent gets each step right 99% of the time. That sounds excellent. What fraction of 100-step tasks does it finish? And at what length does it drop to a coin flip?

Reveal

About 37%. 0.99^100 ≈ 0.366. A “99% reliable” agent fails most 100-step tasks.

The coin-flip length is where p^n = 0.5, so n = ln(0.5) / ln(p). For p = 0.99 that’s about 69 steps. There’s a handy shortcut: when p is close to 1, ln(p) ≈ -(1 - p), so the 50% length is about 0.69 / (1 - p). One mistake per 100 steps gives a 50% length near 69 steps. One per 1,000 gives about 693. (I checked all of these in Python on this Mac.)

That shortcut, 0.69 / (1 - p), is the most useful line in the lesson. It says the length an agent can handle is inversely proportional to its per-step failure rateThe chance a single step goes wrong, 1 - p. A 2% failure rate means p = 0.98.. Halve the failure rate and you double the length. Going from 98% to 99% per step sounds like a rounding error; it doubles how long a task the agent can do. Going from 99% to 99.9% multiplies it by ten.

Per-step success pFailure rateSuccess at 10 stepsSuccess at 100 steps50% length
0.9010%35%~0%~7 steps
0.955%60%0.6%~14 steps
0.982%82%13%~34 steps
0.991%90%37%~69 steps
0.9990.1%99%90%~693 steps

This is also why the gap between “a demo that works” and “a system that works” is so big for agents. A demo is usually one short run. Reliability across many steps is a different, much harder number.

The curve has a name in other fields. A constant chance of failing at every step is a constant hazard rateThe chance of failing in the next step, given you haven’t failed yet. If it’s the same at every step, survival decays exponentially, like radioactive decay., and survival under a constant hazard decays exponentially. Your agent has a half-lifeThe number of steps after which half the runs have failed. Under a constant hazard it’s ln(2) / failure rate, the same formula as radioactive decay., just like a radioactive atom. Hold onto that; it comes back with METR.

Feel it: twenty-four agents

Here are 24 simulated agents doing the same task. Each square is one step. Set p and the task length, and watch how many make it.

FIG_002[ TWENTY-FOUR RUNS ]
steps
Runs finished
-
Predicted
-
Steps that were right
-

□ right · ▣ mistake, recovered · ■ fatal mistake · | check caught a bug, block redone

Each row is one run, each square one step. With r = 0, the first mistake (orange) kills the run and everything after it is wasted work (grey). Note the third readout: almost every step is right, yet most long runs fail. Then raise r, and then turn on verification.

Two things to try. First, at p = 0.95 and 40 steps, read the “steps that were right” readout. It says about 95%. And yet only a few runs finish. Per-step accuracy and end-to-end success are wildly different numbers, and if someone quotes you one, ask for the other.

Second, the grey squares. Every step after the fatal mistake is work the agent did, tokens you paid for, that could never lead to success. On long tasks the expensive failure isn’t the run that crashes at step 3. It’s the run that makes a quiet mistake at step 12 and keeps going, confidently, until step 40.

Real agents don’t die at the first mistake

If p^n were the full story, agents would be hopeless: no current model has a per-step error rate of 0.1% on hard steps, yet agents do finish tasks of a hundred-plus tool calls. The missing piece is that a mistake isn’t always fatal.

Watch a good engineer work. They mistype a path, the command fails, they fix it. That mistake cost one step. They write a function with an off-by-one bug, the test fails, they fix it. That one cost a few steps. Only some mistakes kill a project: the ones nobody notices until too late, and the ones you can’t undo.

FIG_003[ THREE FATES OF A MISTAKE ]
WRONG STEPat step k1 · LOUD, RIGHT AWAYcommand errors, file not found → fix next step · cost: 1 step2 · CAUGHT LATERa test fails 6 steps on → find it, redo · cost: rework3 · SILENT OR IRREVERSIBLEnothing checks it, or it can’t be undone · cost: the run
The same wrong step can cost one step, cost some rework, or kill the run. Which one you get depends on how soon the mistake becomes visible and whether the action can be undone, not on how big the mistake was.

So split each step into two questions. Did it go right (probability p)? And if it went wrong, does the agent notice and fix it before it matters (probability r, for recoveryNoticing a mistake and repairing it before it causes the task to fail. Re-reading a file, seeing an error message, re-running a test.)? A step only ruins the task if it goes wrong and isn’t recovered:

chance a step is fatal  = (1 - p) × (1 - r)
effective success  q    = p + (1 - p) × r
P(success, n steps)     = q^n

This is still a constant-hazard model, just with a smaller hazard. And notice what it means for the half-life: 0.69 / ((1 - p)(1 - r)). Recovery and per-step accuracy multiply. An agent that recovers from half its mistakes has exactly the same horizon as one that makes half as many mistakes. That’s important for training: you can get longer horizons by making the model more careful, or by making it better at noticing and fixing, and the second might be easier.

Predict firstwrite it down

Agent A gets 97.5% of steps right and never recovers. Agent B gets 95% of steps right, but notices and fixes half its mistakes. Which one has the longer horizon?

Reveal

Neither. They’re the same. Agent B’s fatal-step rate is 0.05 × 0.5 = 0.025, which is exactly A’s. Both have q = 0.975 and a 50% length of about 27 steps.

But they’re not the same agent in practice. B uses more steps (every recovered mistake costs at least one extra step), and B’s behaviour depends on its mistakes being detectable. Put B in an environment where errors are silent (no error messages, no tests) and its r collapses toward zero, and its horizon halves. A is robust to that. This is one reason the same model scores very differently on different harnesses.

Verification: making mistakes loud

Recovery only works if the mistake shows up somewhere the agent can see it. So the natural engineering move is to make mistakes visible on purpose: run the tests after each edit, type-check after each file, diff the output against expectations. A verifierAnything that checks the agent’s work and reports a pass or fail: a test suite, a type checker, a linter, a script that compares output to a known answer. turns fate 3 in Figure 003 into fate 2.

The model for that, which the next figure draws: every k steps, run a check. If the last block of k steps contains a fatal mistake, the check catches it with probability c (its catch rateThe fraction of real bugs a verifier detects. A test suite with 60% catch rate misses 4 in 10 bugs. Related to recall.), and the agent throws the block away and redoes it, with up to 3 attempts. If the check misses it, the bug is silent and the run is doomed.

b = q^k                      a block of k steps is clean
f = (1 - b) × c              a block is bad and the check catches it
P(block passes) = b × (1 + f + f^2)       (up to 3 attempts)
P(success, n steps) = P(block passes)^(n / k)

I checked this closed form against a brute-force simulation in Python: at p = 0.95, k = 5, c = 0.9, 40 steps, the formula says 74.2% and 40,000 simulated runs gave 74.4%.

Predict firstwrite it down

p = 0.95, no recovery, 40 steps. Without checks, success is 0.95^40 ≈ 13%. Now run a check after every single step, with up to 3 tries per step. What’s the success rate if the check is perfect (c = 1)? What if the check catches only half of the bugs (c = 0.5)?

Reveal

With a perfect check: about 99.5%. Each step now fails only if all three tries are wrong, 0.05^3 ≈ 0.0001, and 0.9999^40 ≈ 0.995.

With a check that catches half: about 35%. Better than 13%, but nowhere near 99%. Every time a bug slips past the check, that’s a silent fatal mistake, and you get a fresh chance of one at every step. Checking more often with a weak verifier mostly buys you more chances to be fooled.

The lesson: verifier quality matters more than verifier frequency. This is the same reason Rewards and verifiers spends a whole lesson on how hard it is to write checks that can’t be gamed.

Now play with all of it at once.

FIG_004[ SUCCESS VS STEPS ]
50% horizon · p^n
-
50% horizon · recovery
-
50% horizon · verify
-
Success at 10 / 40 / 100
-
Work per finished step
-

Dashed: plain p^n. Thin: with recovery. Blue: with verification every k steps. Dots mark the 50% horizon of each. Watch the horizon readouts, and the cost readout: verification is not free, each check and each redo costs steps.

Things to find:

What METR actually measured

Everything so far counts in steps. That’s natural for a harness, but steps aren’t comparable across tasks: one step of “write a regex” and one step of “design the database schema” are not the same size. METR, a nonprofit that evaluates frontier AI systems, wanted one number that means the same thing across very different tasks. Their answer was to measure tasks in human time.

The paper is Kwa et al. (2025), “Measuring AI Ability to Complete Long Tasks” (later versions are titled ”…Long Software Tasks”; it appeared at NeurIPS 2025). Here’s what they did, stated carefully:

  1. They collected about 170 software and research-engineering tasks from three suites: HCAST, RE-Bench, and a set of 66 new very short tasks (SWAA), ranging from a few seconds to many hours for a human.
  2. They paid skilled humans to do the tasks and recorded how long each took. That gives every task a length in human minutes.
  3. They ran many AI models (from GPT-2 in 2019 to models from early 2025) through the tasks in an agent scaffold and recorded pass or fail.
  4. For each model, they fit a logistic curveAn S-shaped curve that goes smoothly from near 1 down to near 0. Here: probability of success against the log of task length. of success probability against the logarithm of human task time.
  5. The model’s 50% time horizon is the human task length where that fitted curve crosses 50%.
FIG_005[ THE TIME HORIZON, SCHEMATIC ]
100%50%0%80%1 MIN10 MIN1 HR8 HRHUMAN TIME TO DO THE TASK (LOG SCALE)50% HORIZON80% HORIZON● PASS○ FAIL
A sketch of METR's method for one model, not their data. Each dot is a task: its human completion time and whether the model passed. Fit an S-curve through them; where it crosses 50% is the model's time horizon. The 80% horizon is the same idea at a stricter bar, and it's much shorter.

The headline results, as the paper states them: frontier models of early 2025 (Claude 3.7 Sonnet was the top one) had a 50% time horizon of around 50 minutes on these tasks, and the 50% horizon of the frontier model has doubled roughly every seven months since 2019, possibly faster in 2024. The 80% horizon is several times shorter than the 50% one. They also report that the gains seem to come mostly from greater reliability and better ability to adapt to mistakes, which is exactly the p and r of the last section.

Read that carefully, because it is easy to over-read:

Now connect it to the math. Toby Ord (2025, “Is there a half-life for the success rates of AI agents?”) reanalysed METR’s data and found it fits well with exactly the constant-hazard model from earlier: a constant chance of failing per minute of human task time, so success decays exponentially with task length, and each model has its own half-life. Under that model, “horizon doubles every 7 months” is the same statement as “the per-minute failure rate halves every 7 months”. METR’s own fit uses a logistic curve on log time instead, which decays more slowly at long lengths than an exponential does. You’ll fit both to your own data and see which one your agent looks like.

What makes long tasks hard (beyond the arithmetic)

The p^n math treats every step as an independent coin flip. Real long tasks are worse in ways that coin flips don’t capture, and each of these is a research and engineering problem in its own right.

State tracking. The agent has to remember what it has done and what’s still true. Which files did I edit? Did I already rename that function? What was the value in file 12? Humans offload this to the codebase, notes and git status; an agent has to either keep it in context or re-derive it. Mistakes here are the “edited the same file twice” failure from The Problem. Per-step error rate goes up as the task goes on, because there’s more state to keep straight, which breaks the constant-p assumption in the bad direction.

Context limits. Every step adds tool output to the conversation. A 200-step trajectory can easily run past a context windowThe maximum amount of text (in tokens) a model can see at once: the system prompt, the conversation so far, and all tool output.. Even before it’s full, the relevant fact from step 12 is buried under 150 steps of logs. Something has to summarise, drop or retrieve old content, and every summary can lose the one detail that mattered. That whole problem is Managing context.

Sparse and delayed feedback. On short tasks, feedback comes right away. On long ones, you may not know whether step 12 was right until step 40 runs the tests (Figure 001). This is what makes recovery hard: r is high for mistakes that cause an immediate error and near zero for mistakes that only show up much later.

Planning and decomposition. A long task needs a plan: what to do first, what depends on what, when a subgoal is done. A bad plan can make every individual step correct and the whole task wrong. Good agents (and good engineers) split a long task into chunks that can each be checked, which is the “verify every k steps” model again, done by the agent itself.

Verification and self-correction. The agent needs to check its own work and believe the check. Two failure modes: not checking (low r), and checking but trusting a weak check (low c), which is worse because it feels safe. An agent that writes a test that always passes and then reports success is the long-horizon version of this.

Irreversible actions. Some steps can’t be undone: dropping a database table, sending an email, git push --force, deleting a file nobody backed up. For those, r = 0 by definition, no matter how smart the agent is. A good harness makes irreversible actions rare (sandboxes, dry runs, version control, asking first), which is a way of raising r from the outside.

Why long tasks are hard to learn, not just hard to do

Here’s the training side, which is the “Code RL” part of the job posting. In reinforcement learning, an agent tries tasks, gets a rewardA number the environment gives the agent to say how well it did. For a coding task, often 1 if the tests pass and 0 if not., and the training algorithm nudges the model to make rewarded actions more likely and unrewarded ones less likely.

For a 3-step task with a reward at the end, it’s fairly clear which steps to credit. For a 60-step task with a single pass/fail at the end, it’s not. Did it fail because of step 12, or step 47, or both? This is the credit assignmentWorking out which of many earlier actions deserve the credit (or blame) for a reward that arrives later. problem, and it’s the core difficulty of long-horizon RL.

FIG_006[ CREDIT ASSIGNMENT ]
· · ·123456383940REWARD0 (FAIL)THE ACTUAL BUG”SOMETHING IN HERE WAS BAD” IS ALL THE SIGNAL SAYS
One reward at the end of a long trajectory. The simplest methods give every step the same share of the blame: the 39 fine steps get pushed down along with the one bad one. Learning still works on average, over many runs, but the signal per run gets noisier the longer the trajectory is.

The intuition for why length hurts: the reward is one number, but it’s a verdict on the whole trajectory, so each individual step’s contribution is buried under the randomness of all the others. Methods like REINFORCE, PPO and GRPO differ in how they try to reduce that noise (a learned value estimate in PPO, comparing a group of attempts at the same task in GRPO), but none of them gets to know which step was the bug. The practical levers are the same ones from this lesson, seen from the training side: denser feedback (intermediate rewards, tests that run partway), shorter effective horizons (decomposed tasks), and many more samples.

Benchmarks, briefly and carefully

A few benchmarks you’ll see cited for long-horizon agent work:

Benchmark numbers move fast and depend heavily on the scaffold (the harness around the model), so for current scores, check the benchmark’s own leaderboard rather than trusting any number written down months ago, including here.

Build It

You’ll build three things: a task suite where you control the length, a small agent harness that runs a real model through it, and an analysis script that fits the curves from this lesson to your data. Then you add a verifier and see whether the curve moves the way Figure 004 says.

The task is a dependency chain of config files. It’s a toy, but it has the shape of real migrations: each step needs the agent to read something, compute something from what it found earlier, and write it down, and an early mistake poisons everything after it.

Each task is a folder of n small Python files, m00.py to m{n-1}.py. File m00.py has a known value. Every other file has a rule in a comment saying how to compute its value from earlier files, and a placeholder:

# m07.py
# RULE: VALUE = (VALUE of m06 * 3 + LEN of NAME in m04) % 1000
NAME = "pelican"
VALUE = None

The agent must fill in every VALUE. Because rules reference earlier files, including ones a few steps back, the agent has to track state across the whole task.

Everything goes in ~/workbench/horizon/.

Set up the folder, a venv and an API keyAgent: fine
mkdir -p ~/workbench/horizon && cd ~/workbench/horizon
python3 -m venv .venv && source .venv/bin/activate
pip install anthropic numpy scipy matplotlib   # or your provider's SDK
export ANTHROPIC_API_KEY=...                    # never commit this; put it in your shell profile or a .env you gitignore

Any LLM API with tool calling works. Use a small, cheap model for this. You want it to make mistakes at 20 to 40 steps; a frontier model may be so reliable on these toy rules that you need to make them harder (more back-references, string operations) before you see failures.

Budget first. Each step is about two model calls (read, then write), and every call resends the whole conversation so far. If each call adds about 150 tokens of context, a task of n steps costs roughly 1600·n + 300·n² input tokens. That’s about 15k tokens at 5 steps and 540k at 40 steps. A sweep of lengths 5, 10, 20, 40 with 10 tasks each is about 8M input tokens; the verify run roughly doubles it. Multiply by your model’s current price (check the provider’s pricing page; prompt caching cuts the cost of resent context a lot). Put a hard token cap in the harness so a stuck agent can’t spend your budget.

Write the task generator and the graderHands only
# tasks.py
import random
from dataclasses import dataclass
from pathlib import Path

WORDS = ["pelican", "otter", "cobalt", "ember", "quartz", "lichen", ...]

@dataclass
class Rule:
    prev: int        # index of the file whose VALUE is used (always k-1)
    mul: int         # VALUE = (VALUE of prev * mul + extra) % 1000
    ref: int | None  # optional second file whose NAME length is added
    ...

def make_task(n: int, seed: int, root: Path) -> list[int]:
    """Write m00.py .. m{n-1}.py into root. Return the true VALUE for every file."""
    ...

def read_values(root: Path, n: int) -> list[int | None]:
    """Parse VALUE out of each file the agent wrote. None if missing or unparseable."""
    ...

def grade(rules, truth, written) -> dict:
    """Return:
      global_ok:  list[bool], written[k] == truth[k]
      local_ok:   list[bool], written[k] is correct GIVEN the agent's own written[k-1] (and ref)
      success:    all(global_ok)
    """
    ...

Two grading ideas matter here.

Global correctness asks “is this file’s value the true one?” One mistake at file 12 makes files 12 to 39 globally wrong, even if the agent did every later computation perfectly from the wrong input.

Local correctness asks “given what the agent wrote in the earlier files, did it compute this file correctly?” That isolates each step. The fraction of locally correct steps is your measured per-step reliability p̂. That’s the number the whole model hangs on, so get this function right.

Hints: seed a random.Random(seed) so every task is reproducible. Have ref point 2 to 5 files back about half the time, so state tracking matters. Unit-test grade on a hand-made wrong answer before you trust it.

Build the harness, and test it on a fake agent firstHands only

The harness is a loop: send the conversation and the tool list to the model, run whatever tool it asks for, append the result, repeat until it says it’s done, hits max_steps, or hits the token cap.

# harness.py
import json, time
from pathlib import Path

TOOLS = [
    # name, description, JSON schema for arguments
    {"name": "list_files", ...},
    {"name": "read_file", ...},     # args: path
    {"name": "write_file", ...},    # args: path, content
    {"name": "done", ...},          # agent declares it is finished
]

def run_tool(root: Path, name: str, args: dict) -> str:
    """Run one tool inside root only. Refuse paths that escape root."""
    ...

def run_episode(agent, root: Path, n: int, max_steps: int, token_cap: int, trace: Path) -> dict:
    """Run until done / max_steps / token_cap. Append every call and result to trace (JSONL).
    Return steps used, tokens used, why it stopped."""
    ...

For the real model, the exact tool-calling request and response format depends on your SDK and version, so follow its docs (for Anthropic, the Messages API “tool use” guide). Keep the model code behind a small interface, something like agent.step(messages, tools) -> (tool_name, args, tokens_used), so you can swap it.

Then, before spending a cent, write a FakeAgent with the same interface. It walks the files in order, reads each one, and writes the correct value with probability p, else a wrong one. Run 200 fake episodes at p = 0.95 for each length and check: does your grader’s p̂ come out near 0.95? Does end-to-end success track 0.95^n? If your measurement pipeline can’t recover a number you planted, it won’t recover one you didn’t.

Run the real sweepAgent: review after

Run the real model on lengths 5, 10, 20, 40, with 10 tasks per length (different seeds). Use a plain system prompt: what the files are, what the tools do, “fill in every VALUE, then call done”. Don’t give hints about checking your work yet; that’s the next experiment.

Save one JSON line per episode: n, seed, success, local_ok list, global_ok list, steps used, tokens used, stop reason. Also count recoveries: files whose first write was locally wrong but whose final value is locally right (the model went back and fixed it). You can find these in the trace.

Then have an agent review your harness and sweep code for anything that would make the comparison unfair: tasks of different difficulty at different lengths, a max_steps that’s too tight for n = 40, the token cap cutting off long runs (that’s a failure, but a different kind; record it separately), retries on API errors that silently change the trajectory.

Fit the three modelsHands only
# fit.py
import numpy as np
from scipy.optimize import minimize_scalar, minimize

def fit_pn(lengths, successes, trials):
    """Fit one q so that P(success at n) = q**n. Maximise the binomial log-likelihood:
    sum over lengths of  k*log(q**n) + (t-k)*log(1 - q**n)."""
    ...

def fit_logistic(lengths, successes, trials):
    """METR-style: P = 1 / (1 + exp(-(a - b*log2(n)))). Fit a, b. Return them and the 50% length 2**(a/b)."""
    ...

Compute and compare four numbers:

  1. p̂, the measured local per-step success rate from the grader.
  2. q̂ from fit_pn on end-to-end success.
  3. The prediction p̂^n at each length, with no fitting at all.
  4. r̂, the measured recovery rate: recoveries divided by locally wrong first writes. Then the recovery-aware prediction with q = p̂ + (1 - p̂)·r̂.

The question you’re answering: can you predict long-task success from short-task step reliability? Plot measured success vs n with error bars (see Measure), with p̂^n, the recovery-aware curve, the fitted q̂^n and the fitted logistic on top.

Add a verifier and rerunHands only

Add one tool, check(), that reports which of the files written so far break their rule given the earlier written values, i.e. it reports local errors. Add a catch_rate parameter: each broken file is reported only with that probability, so you can make the verifier imperfect on purpose. Change the system prompt to say “call check() after every few files and fix anything it reports”.

Rerun the sweep with catch_rate = 1.0, then with catch_rate = 0.5 at n = 20 and n = 40. Measure success, steps used and tokens used. Before you run, use Figure 004 to predict how the curve should move.

Done when
  • The fake agent at p = 0.95 gives p̂ within about ±0.01 of 0.95 over 200 episodes, and its success tracks 0.95^n.
  • You have real-model results for 4 lengths × 10 tasks, with and without the verifier, and a plot with all the fitted curves.
  • You can say, with a number, how well p̂^n predicted long-task success, and whether recovery explains the gap.
  • You can say what the verifier cost (steps and tokens) and what it bought (horizon).

Measure

Fill these in. Use the trace files, not your memory of watching runs.

Length nRunsSucceededSuccess ± SEp̂ (local)p̂^nRecoveries / wrong first writesMean stepsMean tokens
510
1010
2010
4010
FitParameter(s)50% length
p̂^n (no fitting)p̂ =
q̂^n fittedq̂ =
recovery-aware (p̂ + (1-p̂)r̂)^nr̂ =
logistic in log2(n)a =, b =
VerifiernSuccessMean stepsMean tokensChecks called
none20
catch_rate = 1.020
catch_rate = 0.520
none40
catch_rate = 1.040
catch_rate = 0.540

Error bars first. With 10 runs per length, the standard errorHow much a measured average would jump around if you repeated the experiment. For a success rate p over N runs it’s about sqrt(p(1-p)/N). of a success rate near 50% is sqrt(0.25 / 10) ≈ 0.16, so “50%” really means “somewhere from about 20% to 80%”. Don’t read anything into a 10-point difference. I simulated this with the fake agent: at true p = 0.95 with 10 runs per length, the q̂ fitted from end-to-end success ranged from about 0.931 to 0.965 across repeats (90% of the time). That’s a 50% length of anywhere from 10 to 19.5 steps from the same agent. With 30 runs per length it tightens to 0.940 to 0.960. This is why per-step reliability p̂ is so useful: a 40-step task gives you 40 step measurements but only one success measurement.

What the numbers should look like. I can’t run your model for you, so these are the shapes to expect and why, not values:

Break It

1. Make mistakes silent. In read_file, strip the RULE comment out of files after the agent has written them once, so re-reading can’t reveal a mistake. Recovery should drop toward zero, and success should fall toward p̂^n. This is the “detectability” point from the second Predict: the same model’s horizon depends on whether the environment makes errors visible.

2. Starve the context. Keep only the last 6 tool results in the conversation (drop older ones). Rules that reference files 5 back now need a re-read the agent may not think to do. Watch p̂ fall for back-reference steps specifically, and fall more at higher n. This is the bridge to Managing context, and it breaks the independent-steps assumption in the expected direction.

3. Add one irreversible action. Add a delete_file tool and a rule in one file that says “if VALUE is even, delete m03.py”. Any run that deletes the wrong file can’t finish, because the value it needs is gone. Count how often it happens. Then add git-style undo (keep a backup and an undo tool) and see r for that step jump. Most of what makes a harness “safe” is turning r = 0 steps into r > 0 steps.

4. Game your own verifier. Change check() to report only on the last file written. An agent can now pass every check while building on a wrong value from earlier. Success should drop below even the no-verifier case if the model trusts the check and stops re-reading. A weak verifier that the agent believes is worse than none, which is the whole worry behind Rewards and verifiers.

Explain It Back

Answer out loud, in plain words, as if in an interview. Then check.

1. What makes a task “long-horizon”? Is a 5,000-token essay long-horizon?

The number of sequential decisions an agent has to make before it gets feedback on whether it’s succeeding. Long tasks have many steps between checks, so there are more chances to make a mistake and mistakes stay hidden longer. A long essay written in one pass and graded once is a lot of tokens but essentially one decision with one grade; it can still fail in compounding ways, but the defining long-horizon problems (state tracking across actions, delayed feedback, credit assignment across steps) are much weaker. A 60-tool-call refactor graded only by the final test run is long-horizon.

2. An agent is 99% reliable per step. How does it do on 100-step tasks, and how does that scale?

If any mistake is fatal and steps are independent, 0.99^100 ≈ 37%. The 50% length is ln 0.5 / ln p ≈ 0.69 / (1 - p), about 69 steps. Horizon scales inversely with the failure rate: halve the failure rate and the horizon doubles, so going from 99% to 99.9% per step is a 10x longer horizon. Real agents do better than this because they recover from some mistakes; with recovery rate r the fatal rate is (1 - p)(1 - r), so recovery and per-step accuracy are interchangeable for horizon. And they do worse if per-step accuracy decays over the run (context, state tracking), which p^n doesn’t capture.

3. What does METR’s “50% time horizon” measure, and what are the caveats?

They timed skilled humans on about 170 software and research-engineering tasks, ran AI agents on the same tasks, and for each model fit success probability against log human task time. The 50% time horizon is the human task length at which the model succeeds half the time: around 50 minutes for the best early-2025 models, doubling about every 7 months since 2019. Caveats: it’s human time, not how long the model runs; it’s tied to that task suite (well-specified, auto-scored, mostly self-contained); 50% is a low reliability bar and the 80% horizon is several times shorter; and the doubling is an empirical trend, not a law. Under a constant-hazard reading (Ord 2025), doubling the horizon means halving the per-minute failure rate.

4. You add “run the tests after every edit” to your agent. When does that help a lot, and when barely?

It helps when the tests actually catch the mistakes the agent makes (high catch rate), and when errors are fixable (not irreversible). Then a bad edit is caught one step later and retried, so the fatal rate per step drops from 1 - q to roughly (1 - q)^attempts plus whatever the tests miss. It barely helps when the tests are weak: every missed bug is still a silent fatal mistake, so success is bounded by the miss rate no matter how often you check. It also costs steps, tokens and wall time, and more if the test suite is slow. Checking very rarely is cheap but makes each failed block expensive to redo. So: improve the verifier before you increase the frequency.

5. Why is RL on long tasks harder than on short ones, and what helps?

With one reward at the end of a long trajectory, the training signal says “something in these 60 steps was good or bad” but not which step. The per-step signal is buried under the randomness of all the other steps, so the gradient estimate is noisier the longer the trajectory, and you need many more samples to learn the same thing. Also, rewards get rarer: if the model’s long-task success rate is near 0, almost every trajectory gets reward 0 and there’s little to learn from. Helps: denser feedback (intermediate checks, partial credit that can’t be gamed), curricula that start short and get longer, decomposing tasks, value estimates or group baselines (PPO, GRPO) to reduce variance, and good verifiers so that the reward is actually right.

Go Deeper

Connections

This lesson is the “why” behind most of the Agents & RL track. Managing context attacks one cause of per-step reliability falling over a long run. What is an RL environment? turns your task suite into something a model can be trained on, and Rewards and verifiers is about making c high and hard to game. RL with verifiable rewards is where credit assignment over long trajectories stops being a figure and becomes a loss function. Inside an agent harness is the engineering side: sandboxes, undo and checkpoints, all ways to raise r from outside the model.

For the statistics in Measure, Is that improvement real? goes deeper on why 10 runs can’t distinguish 40% from 60%, and how many you actually need.