What antiproton measures today, what each number can tell you, and what none of them cover yet. Every figure on this page was measured on the deployed serverless object, never estimated and never taken from a Node process, and each section names the object, the commit and the committed record its numbers come from.
The standard, stated once. A figure counts only when it was measured on the deployed Durable Object. Every figure names the run it came from, the run names its object and the record under report/runs/ that a reader can open, and nothing measured in a Node process ever stands in for an on-object number.
Samples, not trends. Eight tasks by three trials and ten instances are samples. Runs of the same code on the same benchmark differ, a single instance passes and fails on the same commit, and no figure here should be read as a trend.
can the loop carry a multi-turn task on a real machine to a graded result · 10 instances, official scoring, the container without network, inside a deployed Durable Object
object bench-swe3 · 2026-09-11 · Worker at 60580fd · model deepseek-flash · driver bench/swebench/cf.ts · record report/runs/2026-09-11/swebench-swe3-mtwgij3r.json
The container has no network. Every command the agent runs starts in an empty network namespace: no interface, no route, no DNS. SWE-bench’s answer is a public commit, and with the network open this agent fetches it — an earlier run of the same ten instances with egress, kept only as a record under report/runs/2026-09-10, had the upstream fix fetched in six of nine archived transcripts, and is not a solve rate. In this run all ten transcripts are archived and were read: seven commands in six instances tried to reach GitHub, none received anything, and no patch came from outside the box. This is the condition SWE-bench’s published runs use, so this is the first number on this page comparable to them.
| instance | wall | model calls | prompt tok | cached | container | object | patch | |
|---|---|---|---|---|---|---|---|---|
| 12907 | ✓ | 213 s | 12 | 106,838 | 91 % | 98 % | 62 % | 1 file, +1 −1 |
| 13033 | ✗ | 910 s | 31 | 782,946 | 97 % | 100 % | 76 % | 1 file, +3 −1 · out of time |
| 13236 | ✓ | 547 s | 43 | 1,049,353 | 97 % | 99 % | 62 % | 1 file −7 |
| 13398 | ✗ | 1,139 s | 26 | 909,798 | 96 % | 99 % | 89 % | no patch · out of time |
| 13453 | ✓ | 424 s | 38 | 906,911 | 97 % | 99 % | 62 % | 1 file, +7 |
| 13579 | ✓ | 483 s | 35 | 1,076,061 | 98 % | 99 % | 58 % | 1 file, +13 −1 |
| 13977 | ✗ | 1,122 s | 35 | 1,083,156 | 97 % | 99 % | 83 % | no patch · out of time |
| 14096 | ✓ | 351 s | 21 | 315,753 | 96 % | 99 % | 66 % | 1 file, +8 |
| 14182 | ✓ | 439 s | 26 | 757,849 | 96 % | 98 % | 55 % | 1 file, +5 −3 |
| 14309 | ✓ | 431 s | 25 | 572,471 | 95 % | 98 % | 66 % | 1 file, +3 −1 |
| 7 / 10 | 6,059 s | 292 | 7,561,136 | 97 % | — | 73 % | shell×370 run×2 |
The run happens inside the deployment. The agent runs in the object with the instance’s own image as its machine, the model calls go out through the production queue, the grader applies the official test patch and runs the official tests in the same container before the runner releases it, and the container is never offered to the agent to destroy. The three misses are the three instances that ran out of the fifteen-minute budget; two of them left no patch and the third’s patch failed its test. Every solve landed in one file. With nothing to fetch the model works the task itself, which is why instances take four to nineteen minutes and why this number is lower than a number measured with the network open.
The object is billed for 73 % of wall clock — 4,419 s of 6,059, 527 s of it the runner grading. τ² bills the object for 3 %. Same substrate, opposite bill, and the difference is where the waiting happens: a model call leaves the object through the queue (1,103 s of provider time across 292 calls, none of it billed to the object), while a tool call runs inside it, and this task is 370 shell commands in a container. Whether long tool calls should leave the object the way model calls do is the open question below.
97 % of prompt tokens come from cache, so the gross figure overstates the bill by about thirty times: of 7.56 M, roughly 244 k were actually re-read. A cache rate is not a cost measure on its own; the instances that ran out of time re-read the most. The container is alive for 97–99 % of wall clock, and whether stopping it between calls would pay depends on run9’s compute-versus-storage rates, which are not known. run_js is not used in 372 tool calls; the two run calls are run9’s JavaScript inside the container, not the sandbox.
does it follow a written policy while a person changes their mind · 8 tasks × 3 trials, inside a deployed Durable Object
object bench-gid1 · 2026-09-11 · model deepseek-flash · driver bench/tau2/cf.ts · record report/runs/2026-09-11/tau2-gid1-mtwc7ppm.json
What it measures. The domain is a mounted plugin, the customer is a second model, and the score is the database — whether the agent left the world in the state the annotated solution leaves it in. The agent's own account of what it did is not evidence; the ending of every failed conversation is recorded beside the result so a zero can be attributed rather than guessed at.
It runs inside the deployment. The agent runs in the object, the model call goes out through the same queue production uses, and the transcript stays in the object afterwards. Only the customer is local, because τ²'s user is a second model with no access to the domain.
Two metrics, and they are not the same number. pass^k counts tasks that pass k trials in a row, out of 8; the trial count is the raw score over all 24 attempts. They can differ by ten points in one run, which is why both are reported and the /24 column is not optional.
The result: 21 of 24 trials, and 6 of 8 tasks survive all three. The three failures are tasks 1 and 5; every one ends on the simulated customer, not on a tool or the substrate. There is no Order not found and no tool failure in the run — the agent had working tools throughout.
The failure shape is a conversation that ends without the write. Task 5 fails twice: once the agent asked and the customer ended the call before answering, once it exchanged an item that should have been returned. Task 1 fails once, in a conversation the customer ended. So one of the three losses is the agent choosing the wrong action; two are conversations the customer ended.
Read this as a sample, not a score. The run before this one scored 75 % pass^1 on the same code, twelve points below this result, and the only change between them is a prompt sentence that measured as no change on the behaviour it targeted. Run-to-run variance of the shipping harness is wider than the differences this page could otherwise attribute. One run, including this one, does not fix a figure.
A gap in the agent's grounding, read from the transcripts. The agent tells the customer a refund will arrive “in 5–7 business days” in four of this run's conversations, one of them “per our policy”. The policy grants that timeline for cancellations and payment changes only (policy.md L92, L106); returns and exchanges say the customer receives an email (L126, L136), and no tool result carries the number. The agent holds the whole policy, reads a neighbouring section as backing, and states a commitment the company has not made. A general instruction to say only what the policy backs does not correct a section-level mismatch; what would is presenting the agent the section that governs the action, which is a change to how a policy is mounted rather than a prompt line.
Permissions: nothing is asked that the agent already has. Every customer question in this run, read in place, is either the confirmation τ²'s policy requires before a write or a choice only the customer can make — which variant, which card. That confirmation belongs to the benchmark's company, not to antiproton: the harness imposes no permission step, an absent mount policy allows the write, and a plugin carries one only by configuring it.
An approval-gated mount has no visible pending state. A plugin can configure approval; when it does, the operation is held with no marker that anything is waiting and no expiry. In the product a conversation resumes on the customer's next message, so it is not a dead end — but the gateway's approvals table records tool-level approvals, not “an operation is held and waiting”. Whether an approval-gated mount should show a pending state, and whether it should time out, is open.
Raw identifiers are the only affordance the agent has for a choice. The policy requires listing exact details before a write, and there is no other way to present a variant, so the run's replies quote identifiers directly — 250 table rows and 254 of them across the conversations. The content is right; the way to render a choice is missing.
| task | t1 | t2 | t3 | outcome |
|---|---|---|---|---|
| 0 | ✓ | ✓ | ✓ | |
| 1 | ✓ | ✓ | ✗ | The customer ended the call without answering; the agent wrote nothing. |
| 2 | ✓ | ✓ | ✓ | |
| 3 | ✓ | ✓ | ✓ | |
| 4 | ✓ | ✓ | ✓ | |
| 5 | ✗ | ✗ | ✓ | Twice lost: once the customer ended the call before answering “shall I proceed?”; once the agent exchanged an item the customer asked to return. Right on the third attempt. |
| 6 | ✓ | ✓ | ✓ | |
| 7 | ✓ | ✓ | ✓ |
The transcripts end on the agent's turn by construction, not by truncation. The runner posts a customer message to the object only when it is not the simulator's stop signal, so the final ###STOP###/###TRANSFER### is consumed by the loop and never archived. Every ending is the customer stopping or transferring; none is turn exhaustion. The zeros are the customer's, and the protocol — not the harness — is why the last turn is missing.
Substrate, not the loop, decides the bill: the object is billed for 3 % of wall clock, because a model call leaves the object through the queue. The failures are not the substrate's: no call is lost, no run stalls, no object fails to wake.
run_js is not used in this run, and the sandbox is offered on every turn.
the number an in-process runner cannot produce · the two runs above, same substrate
Cloudflare bills a Durable Object for the wall clock during which it is active, with no exemption for waiting on the network. So the question is never how long a run took but how much of it the object was awake for — and a model completion is almost entirely waiting.
Provider latency is billed as Workers CPU in the queue consumer, not as object duration, which is the whole reason the model call leaves the object. What stays inside is the tool call. On τ² the tools are a mounted plugin answering in milliseconds, so the object sleeps through almost the whole run; on SWE-bench the tool is a shell in a container, and the object is awake for as long as the command runs. The loop is the same in both; the bill is a property of what the tools do.
| τ² retail, per task | SWE-bench, per instance | |
|---|---|---|
| model calls | 8.9 | 29.2 |
| object wakeups | 27 | 66 |
| alarm passes per model call | 1.4 | 1.0 |
| object duration billed | 1.2 s | 442 s |
| of which the runner grading | — | 53 s |
The benchmark waits the way the console waits. Polling would measure the poller — every poll is a request that wakes the object — so the runner listens on the same hibernation-API socket the console uses, which costs the object nothing while it waits.
grouped by the question each one answers
answered · 10 instances · container without network · inside the deployed object
Whether the loop can carry a multi-turn task on a real machine to a graded result under SWE-bench’s own conditions. 7 / 10 on the deployed model, measured in the deployed object with the grader in the agent’s container and no route out of it. Ten instances is a sample, not a submission.
answered · 21 / 21, two backends
Not ours: createStorageConformance ships inside pi and runs unchanged on node:sqlite and on real Durable Object storage. It covers what our own tests would not, because ours encode our own assumptions — mixed-write atomicity, rollback across four tables, cursor before limit, admission order under concurrent commits. A contract, not a benchmark.
answered · on real infrastructure
Measured on Cloudflare rather than read from documentation. The load-bearing one: a Durable Object is billed for wall clock with no exemption for network I/O, and a completion is ~94 % waiting. That single fact is why the model call leaves the object — 40.8 s billed against 709.2 s waited over 79 calls.
a property, not a score · needs a licensed install
9 apps, 457 APIs, 362 of them (79 %) behind an access token. Nine end-to-end cases assert that no schema mentions access_token, the credential-reading tool is not mounted, an authenticated call succeeds without the agent ever logging in, and the token never appears in a tool result. It measures what the model cannot see, so there is no pass rate to report.
| gap | state | why it matters |
|---|---|---|
| SWE-bench on the deployed object | measured | Both benchmarks run in the object now. SWE-bench’s grader runs in the agent’s container through the object (bench/swebench/cf.ts), so its cost figures are a deployment’s: 73 % of wall clock billed to the object, against τ²’s 3–5 %. What remains open is whether long tool calls should leave the object the way model calls do. |
| AppWorld on the current loop | unported | The credential-custody property is asserted by tests that drove the old harness. The gateway is unchanged, but the assertion is not currently running. |
Whether run_js pays | switch, no arm | The sandbox is a runtime switch rather than a constant, so the ablation is one flag away — but it has not been run. It went unused on object in both benchmarks (SWE-bench 372 tool calls, τ² 24 trials), and the only run that reached for it was an earlier in-process matrix that is not on-object evidence. So there is no evidence yet that the sandbox pays on this substrate, in either direction. |
| Sample size | 8 × 3 and 10 | Eight tasks by three trials and ten instances, one model, one run each on the current code. The τ² section states how far two runs of the same code have differed; ten SWE-bench instances at up to nineteen minutes each are what one run affords. The numbers are samples of the harness, and the spread between samples is itself a finding this page does not yet have enough runs to state. |
| Multi-tenant load | not measured | Every figure here is one agent at a time. Nothing measures many tenants at once, which is the system’s whole premise. |
| τ² against the old harnesses | comment only | The one figure ever recorded for τ² under a domain policy on the prior harnesses — 8 / 8 vs 7 / 8 vs 5 / 8 over 8 tasks — is not a measurement of the current loop. It survives only as a comment in the deleted driver, and is kept here so it is not mistaken for one. |
| what | command |
|---|---|
| SWE-bench, inside the deployed object, no network | N=10 OBJ=swe3 node bench/swebench/cf.ts |
| … a single instance, with a trace | N=1 TRACE=1 OBJ=x node bench/swebench/cf.ts |
| … the contaminated condition, on purpose | NETWORK=open N=10 OBJ=x node bench/swebench/cf.ts |
| τ², inside the deployed object | OBJ=do1 N=8 TRIALS=3 node bench/tau2/cf.ts |
| … waiting by polling instead of push | WAIT=poll node bench/tau2/cf.ts |
| … a finished task’s transcript, after the fact | curl "$BASE/bench/trajectory?obj=do1&taskId=…" |
| Storage contract, in process | npm run pi-storage |
| … on real Durable Object storage | npm run pi-storage:do |
The benchmark starts one container per instance and hands it back when the run ends. If a release fails it now says so per instance — silence there is how two boxes were once found still running, one of them from an instance that had finished cleanly.