Grading a batch of controllers on every sandbox
These are fixed, hand-authored cart-pole controllers, tried as one batch: 64 candidate cart-pole controllers, each tried from 4 starting angles, 256 trials in all. Every trial was sent twice, as the same JavaScript program, to two different kinds of sandbox, 9 kinds in all, working at once. 256 of 256 trials got the same answer from both sandboxes, byte for byte, 57 of them across two different JavaScript engines, and 107 with a run in the cloud. Every run is signed into one bundle that anyone can check offline.
The trial program computes the score for these fixed formulas. A model that writes its own program needs a separate checker, so it cannot award itself a good score.
The scoreboard
16 of 64 candidates balanced the pole from every starting angle. The pattern is the textbook one: too little angle gain (kp) and the pole falls whatever the damping; no spin gain (kd) and it wobbles until it falls; and the strongest gains do worse again, mostly from the larger starting angles.
The candidates are a grid of gains made by hand, from too weak to fight gravity, through no damping (it wobbles until it falls), to very strong. No model wrote them. Each is a linear state-feedback law: the force on the cart is kp times the pole's lean plus kd times its spin plus the cart's position and speed (gains 1 and 1), capped at 20 newtons. Balanced means the pole stayed up all 500 steps and ended within 0.05 radians of upright with the cart within half a metre of the middle.
The sandboxes
| Sandbox | Provider | Tier | Where | Runs | Median run | Est. cost |
|---|---|---|---|---|---|---|
| WebAssembly engine | wasm | process | inside the daemon, on one laptop | 57 | 0.04 s | free |
| Docker, locked down | docker | container | one laptop | 57 | 0.69 s | free |
| Docker with gVisor | docker | kernel | one laptop | 57 | 0.76 s | free |
| NVIDIA OpenShell | openshell | container | a local OpenShell gateway, one laptop | 57 | 0.97 s | free |
| Kubernetes agent-sandbox, runc | agentsandbox | container | a kind cluster, one laptop | 56 | 0.30 s | free |
| Kubernetes agent-sandbox, gVisor | agentsandbox | kernel | a kind cluster, one laptop | 57 | 0.62 s | free |
| Kubernetes agent-sandbox, Kata Containers | agentsandbox | vm | a kind cluster, one laptop | 57 | 1.95 s | free |
| E2B microVM | e2b | vm | E2B's cloud | 57 | 1.35 s | $0.0040 |
| Docker Cloud Sandboxes microVM | dockercloud | vm | Docker's cloud | 57 | 3.17 s | $0.0034 |
These times describe this run. The rooms used different concurrency, locations and assigned work, so the median column is not a controlled provider-speed comparison.
A median run is the time from dispatch to answer that the run's signed record states, sandbox start included. Cost is that time multiplied by each cloud's list price per second; the provider's bill is the real figure. Where a sandbox is, is the operator's statement; the record states the provider and the tier.
Why the two answers should agree
The trial program uses only floating-point operations whose rounding the JavaScript standard specifies exactly (addition, subtraction, multiplication, division and comparison on 64-bit numbers), with sine and cosine as fixed polynomials instead of the engine's own, so every conforming engine should print the same bytes for a trial, a fingerprint of the whole trajectory included: node in most rooms, QuickJS in the WebAssembly engine. Agreement shows the answers match; it does not prove the simulator matches a real cart-pole or any sandbox secure.
What is signed, and what is stated
Signed by the harness key made for this run, after the client checked each run's record: every request (with the room it was sent to) and every answer, including the provider and the isolation tier the daemon reported and the run's start and end. A changed, missing or moved line fails the check below. Stated by the operator, in unsigned files beside the bundle: the batch and what each room is and where (rooms.json, with the engine and the list price), and when the run started and ended, which rooms sat out and why (run.json). A tier is the daemon's report: plimsoll's configuration and the provider's evidence plus a startup smoke test, never runtime attestation, and nothing here independently proves which machine ran the code.
Check it yourself
From a checkout of the repository:
go run ./examples/fanout-cartpole -verify
It checks every signature in bundle.jsonl under harness.pub (key 30f45e2d326e737ccc5a7f2f6f967255f14307076e885600af59cfde06059571), the chain that catches a line added, removed or moved, each signed record against the request and answer stored beside it, that each run's record states the provider and tier of the room it was sent to, and that this page is what the bundle and the two stated files render. It starts no sandbox.
Words on this page
- Cart-pole
- A cart on a rail with a pole hinged on top; the only thing a controller can do is push the cart left or right, and the job is to keep the pole up.
- Controller
- Code that decides, every step, how hard to push. Here every candidate is the same formula with different gains.
- Gain
- How strongly the controller reacts to something: kp to how far the pole leans, kd to how fast it is turning.
- Sandbox
- A place to run code someone else wrote without letting it reach the machine around it. Here each run gets a fresh one.
- Isolation tier
- How strong the wall is, weakest to strongest: process (a WebAssembly engine inside plimsoll's own process), container (Linux namespaces and a filter on system calls), kernel (gVisor, a separate kernel that answers the code's system calls), vm (a virtual machine with its own kernel).
- Fan-out, fan-in
- Sending pieces of one job to many workers at once, then gathering the answers into one result.
Run 2026-10-23 20:01 UTC. 64 candidates, 4 starting angles each. Rendered from the signed bundle by go run ./examples/fanout-cartpole.