An AI-written vendor adapter, judged by the vendor's own ledger: two orders for one command caught, the rewrite passes, every verdict signed

Run on 2026-10-14 through plimsolld on the docker provider at the container tier (runc); project image docker-image:sha256:92c07f345ffdb80b7c91008ebeda9f2ff394e7b89d9d0ffb8a896cfe946fb127; software identity oci-manifest:linux/amd64@sha256:1c6cbab4a47d34da471ab4ab970709cbba18e2a3445fde884b5d90ec2c4c5b25; policy none. Source · plimsoll

Runs
26 of 38
passed; the first adapter failed 3 scenarios, the independent agents' adapters passed 16 of 18, and all 7 adapters broken on purpose were caught
Calls, nominal
26 → 20
brokered calls, first adapter, then second after the finding
Boundary
3 refusals
client, broker, no network; no credential found
Credentials
37 for 38 runs
a JWT minted per run, living 95 s; the probe's never reached the vendor
Signed
38 + 38
run records and verdicts; each verdict rebuilt from its evidence

In plain words

What's an adapter, and why bother checking one?

Every robot vendor speaks its own API: its own routes, its own JSON, its own way of saying "busy, try later". A platform that runs robots from many vendors doesn't want to learn every dialect, so it writes down one small contract of four functions: list the robots, send one somewhere, wait until it gets there, cancel. An adapter is the few dozen lines that translate those four functions into one vendor's API. Think of a travel plug adapter: the platform is the plug, the vendor is the wall socket, and the adapter had better not swap live and neutral.

These days an AI writes the adapter, and it usually works on the first try. The question is what it does on a bad day: the vendor takes the order and loses the answer, the connection drops, the server says 500 after the order already went through. Get that wrong and a robot gets the same job twice, or the platform is told a job failed while the robot is halfway there. This page puts adapters through exactly those moments, inside plimsoll's sandbox, and judges them by what the vendor's own books say happened, not by what the adapter says about itself.

Where an adapter sits The platform's four functions on the left call the adapter, which sits inside plimsoll's sandbox and reaches the vendor's API only through the broker. The vendor drives three robots and keeps a ledger of what it actually did; the grader reads that ledger to reach the verdict. The platform inventory() dispatch(robot, target, id) wait(mission) cancel(mission) plimsoll's sandbox: no network, no credential The adapter written by an AI the thing under test broker The vendor's API GET /robots POST /robots/{id}/missions GET /missions/{id} POST /missions/{id}/cancel three robots, simulated the vendor's ledger the grader: the verdict comes from here
The Professor (a fictional narrator)

Nobody gets paged about the happy path. You get paged about the vendor that took the order, then forgot to mention it. An adapter is mostly a polite letter to a server you have never met, and Lamport described what can go wrong with that in one sentence in 1987. It still reads like an incident report.

Real quote

Leslie Lamport: “A distributed system is one in which the failure of a computer you didn't even know existed can render your own computer unusable.”

Email to the SRC src-t list, 28 May 1987, published on Lamport's site. the 1987 email (EXTERNAL · author's page ↗)

The whole loop on one picture

One document in, one signed verdict out

A platform that lets an AI write the code which integrates a vendor's device has to answer five questions before that code touches anything real: what may it call, with whose credential, did it do the job, what did it cost the vendor, and what is the evidence. This page is one pass through that loop with plimsoll, using a fictional fleet vendor and a simulated instance of its API. Nothing here is a robot; everything here is the code path a robot platform would use.

The loop: an OpenAPI document becomes a grant, a client and a description; an agent writes the adapter; the sandbox runs it through the broker against the simulated vendor; every run's record and verdict is signed Boxes left to right: the vendor's OpenAPI document; specgen producing the allow list, the client and the description; the agent writing adapter.js; the sandbox running the harness and the adapter, with the broker as its only door; the simulated vendor with its ledger. Below: the run record and the vendor's ledger both go to the signer, which signs the record and the verdict made from the ledger. The vendor's documentOpenAPI, 8 operationsthe one source specgen allow: 6 routes of 8 client: fleet.* methods description for the agent The agentreads the contractwrites adapter.js The sandboxharness + adapterno network interfaceno credential inside brokerthe one door Vendorsimulatedkeeps a ledger the allow list is what the broker enforces Run recorddigests, tier, image, times ledger Signedrecord andverdict Nothing in the sandbox is trusted, the platform's harness included: it runs beside the adapter, so its report is a claim. The document, the grant, the vendor's ledger, the grader and the signer are outside it.
  1. One document. The vendor's OpenAPI document describes 8 operations. plimsoll-specgen derives three artifacts from it: the route list a grant allows, the typed client the sandbox injects, and the description an agent reads. The three cannot drift, because none of them is written by hand.
  2. One contract, eight rules. The platform states four functions every vendor adapter must export, and the eight rules it judges every adapter by. The harness runs the platform's commands through an adapter and reports what the adapter said. That report is a claim: the verdict is made on the host, after the run, from the plan and the vendor's own ledger, which the adapter cannot write.
  3. One agent, said plainly. The first adapter, adapter-v1.js, was written from the prompt beside it by the AI that built this example, in the same session, before the scenario that caught it existed. It is not an independent agent's answer: its author also wrote the harness.
  4. Runs under a grant. plimsolld runs the harness and the adapter in a locked-down container. The only way out is the brokered client: six routes of the vendor's eight, a credential the daemon mints for each run (a JWT the vendor verifies) that never enters the container, and a metadata-only trace of what was called. A probe shows the other two routes, a direct request and a hunt for the credential all failing.
  5. Defects, a finding, a rewrite, two signatures. When the vendor accepts an order and loses only the answer, the first adapter sends it again and the ledger shows two orders for one command while the adapter's report is clean; when the connection drops, it reports a failure for an order the robot is already running. The efficiency advisor also names the batch route the operator declared. The rewrite names every order with the platform's command ID, which the vendor uses to answer a repeat with the original order, and passes all five scenarios. Four adapters broken on purpose show each rule catching what it is for. Every run's record is signed, and so is every verdict, bound to its record; the verifier rebuilds each verdict from its evidence.
The Professor (a fictional narrator)

Nobody wants to write the fortieth vendor adapter by hand, so an agent writes it. Everyone else here keeps exactly one job: the document says what exists, the grant says what is allowed, the vendor keeps the books, a grader outside the building reads them, and a signer outside it signs for the lot. Nobody gets two of those jobs, least of all the one who wrote the code.

Real quote

Geoffrey Hinton: “I sure as hell don't want to put them in by hand. I don't even want to tell my graduate students to put them in.”

Chuck Nice: “Yeah, that's what they're there for, professor.” [laughter]

StarTalk, 28 February 2026, at 24:45, on setting a billion connection strengths. StarTalk video at 24:45 (EXTERNAL · video ↗)

Step 1

The vendor's document, and what was generated from it

Fleet Vendor API, version 2.4.0. The operator grants the six operations the contract needs and leaves two in the catalog: a decommission and a firmware install are not something an untested adapter gets to do.

OperationRouteSummaryIn the grant
healthGET /healthReport whether the fleet service is accepting requests: {ok, robots}.granted
getMissionGET /missions/{id}Get a mission: {id, robot, command_id, status (queued, running, done, failed or cancelled), target, progress, error}.granted
cancelMissionPOST /missions/{id}/cancelCancel a mission: a running one stops its robot where it is and the robot starts its next queued mission; a queued one never runs; a finished one is unchanged. Answers the mission, as getMission does.granted
listRobotsGET /robotsList the fleet's robots: {robots: [{id, status, battery, pose, mission}]}, status one of idle, moving or fault.granted
decommissionRobotDELETE /robots/{id}Remove a robot from the fleet permanently.catalog only
getRobotGET /robots/{id}Get one robot: {id, status (idle, moving or fault), battery, pose: {x, y}, mission (its running mission's id, if any)}.granted
updateFirmwarePOST /robots/{id}/firmwareInstall a firmware image on a robot.catalog only
createMissionPOST /robots/{id}/missionsSend a robot to a target position: body {target: {x, y}, command_id}; answers {mission_id, robot, status, command_id}, 201 for a new mission. A robot runs one mission at a time and queues the rest. command_id (optional, 8 to 64 letters, digits, - or _) is the caller's name for the order: a create repeated with a command_id already accepted answers with that original mission instead of a new one, or 409 if the robot or target differ.granted

The profile's allow (6 routes)

GET /health
GET /missions/*
POST /missions/*/cancel
GET /robots
GET /robots/*
POST /robots/*/missions

Also declared: batch_of GET /robots = GET /robots/*, the operator's statement that one request to the collection returns what the per-item calls did; and health_check GET /health, the route the broker probes while shedding.

The client the sandbox injects (preamble.js)

// Generated by plimsoll-specgen from "Fleet Vendor API", version "2.4.0". Do not edit by hand.
;(function () {
  const h = globalThis["fleet"];
  if (!h) return;
  h["health"] = () => h.get("/health");
  h["getMission"] = (id) => h.get("/missions/" + id);
  h["cancelMission"] = (id) => h.post("/missions/" + id + "/cancel");
  h["listRobots"] = () => h.get("/robots");
  h["getRobot"] = (id) => h.get("/robots/" + id);
  h["decommissionRobot"] = (id) => h.del("/robots/" + id);
  h["updateFirmware"] = (id, body) => h.post("/robots/" + id + "/firmware", body);
  h["createMission"] = (id, body) => h.post("/robots/" + id + "/missions", body);
})();

The description the agent was shown

Fleet Vendor API (v2.4.0).
Agent code reaches it through the brokered `fleet.*` client; only the operations
below are permitted. Every call is allow-listed and gets a per-run token injected
host-side, so the code never handles a credential.

  fleet.health()  ->  GET /health
      Report whether the fleet service is accepting requests: {ok, robots}.
  fleet.getMission(id)  ->  GET /missions/{id}
      Get a mission: {id, robot, command_id, status (queued, running, done, failed or cancelled), target, progress, error}.
  fleet.cancelMission(id)  ->  POST /missions/{id}/cancel
      Cancel a mission: a running one stops its robot where it is and the robot starts its next queued mission; a queued one never runs; a finished one is unchanged. Answers the mission, as getMission does.
  fleet.listRobots()  ->  GET /robots
      List the fleet's robots: {robots: [{id, status, battery, pose, mission}]}, status one of idle, moving or fault.
  fleet.getRobot(id)  ->  GET /robots/{id}
      Get one robot: {id, status (idle, moving or fault), battery, pose: {x, y}, mission (its running mission's id, if any)}.
  fleet.decommissionRobot(id)  ->  DELETE /robots/{id}
      Remove a robot from the fleet permanently.
  fleet.updateFirmware(id, body)  ->  POST /robots/{id}/firmware
      Install a firmware image on a robot.
  fleet.createMission(id, body)  ->  POST /robots/{id}/missions
      Send a robot to a target position: body {target: {x, y}, command_id}; answers {mission_id, robot, status, command_id}, 201 for a new mission. A robot runs one mission at a time and queues the rest. command_id (optional, 8 to 64 letters, digits, - or _) is the caller's name for the order: a create repeated with a command_id already accepted answers with that original mission instead of a new one, or 409 if the robot or target differ.

The description lists the vendor's whole surface, eight operations; the grant allows six. The broker holds the grant's line whatever the code was told, which the probe below demonstrates.

Step 2

The contract

module.exports = {
  // Every robot the vendor knows, as [{ id, status, battery }].
  // status is one of "idle", "moving", "fault".
  async inventory() {},

  // Send robot `robotId` to target `{ x, y }` as the platform's command `commandId`,
  // and return the vendor's mission id for that command. One command is at most one
  // order: whatever the vendor answers (an error, a lost answer, no answer at all), the
  // adapter must never put a second order on the vendor for it, and the mission it
  // returns must be the one this command created. When it cannot tell whether the
  // vendor took the order, it throws an Error whose code is "unresolved"; when the
  // vendor refused it, one whose code is "refused".
  async dispatch(robotId, target, commandId) {},

  // Poll the mission until it ends. Returns { state, polls } with state one of
  // "done", "failed", "cancelled" or "timeout", and polls the number of status reads.
  // opts.maxPolls bounds the reads (default 50), failed reads included. A failed mission
  // is reported, never retried; a transient vendor error (a 503) is retried with a short
  // pause, within the same bound.
  async wait(missionId, opts) {},

  // Cancel the mission; the robot stops where it is.
  async cancel(missionId) {},
};

The harness runs the commands of plan.json, which the platform writes for each run (four commands, each with its own ID; the fourth is cancelled as soon as it is placed), and prints one ADAPTER-REPORT line: the mission and state the adapter reported for each command. It shares a process with the adapter, so nothing it prints is evidence; it records every value the adapter returned, as returned, so the host can check each one. The verdict comes from eight rules, the same in every scenario, applied on the host to those values, the plan, the vendor's ledger and the vendor's own record of its robots:

ran to the end
the harness ran every step: the adapter loaded, exported the contract's four functions, and no call hung
kept the contract's shapes
every value the adapter returned has the contract's shape: inventory entries with an id, a status of idle, moving or fault and a numeric battery; a mission id or an error coded refused or unresolved; a final state of done, failed, cancelled or timeout, with a read count within the budget
the inventory is the vendor's
each inventory lists exactly the vendor's robots, and the last, taken as the run's final call, matches the vendor's own record of each robot's status and battery
one order per command
each command became exactly one order on the vendor's ledger
the right robot and target
every order on the ledger carries its command's robot and target
ended as it should
each order ended done, or failed where the scenario faults its robot, or cancelled where the platform cancelled it
robot at the target
every order the vendor marks done left its robot at the command's target
the report is true
the mission and state the adapter reported for each command are the vendor's

A scenario changes what the vendor does, and through its data (which robot faults) what each order should end as; it never adds a rule. Full text: CONTRACT.md; the rules: qualify.go.

Step 3

The first adapter, and the rewrite

The instruction the first adapter was written from, in PROMPT.md, with the contract and the vendor document as they stood then (no command ID). Its author was the AI that built this example, in the same session, so this is a worked example, not an independent trial of an agent:

Write `adapter.js`, a CommonJS module for Node 22, implementing the contract below
against the vendor API described after it. Use only the injected `fleet` client; do not
import anything else. Report a failed mission as `failed`; retry a transient vendor
error (a 503) with a short pause, a bounded number of times.

adapter-v1.js, inventory()

  async inventory() {
    const list = await withRetry(() => fleet.listRobots());
    const out = [];
    for (const summary of list.robots) {
      const robot = await withRetry(() => fleet.getRobot(summary.id));
      out.push({ id: robot.id, status: robot.status, battery: robot.battery });
    }
    return out;
  },

The list, then one read per robot: the agent was not told whether the list carries state, so it fetched each robot to be sure. Correct, and one request per robot.

adapter-v2.js, inventory()

  async inventory() {
    const list = await withRetry(() => fleet.listRobots());
    return list.robots.map((robot) => ({ id: robot.id, status: robot.status, battery: robot.battery }));
  },

After the finding: the declared batch route alone. Both files: examples/adapter/adapter.

adapter-v2.js, dispatch()

  async dispatch(robotId, target, commandId) {
    for (let attempt = 1; ; attempt++) {
      try {
        const mission = await fleet.createMission(robotId, { target, command_id: commandId });
        return mission.mission_id;
      } catch (e) {
        if (refused(e)) throw failure("refused", "command " + commandId + " was not placed: " + e.message);
        if (attempt >= ATTEMPTS) throw failure("unresolved", "command " + commandId + ": no answer after " + attempt + " attempts; the vendor may or may not hold the order");
        retries++;
        await sleep(250);
      }
    }
  },

The other change. Every create carries the platform's command ID; when the answer is an error or never arrives, the same create goes again, and the vendor answers a command ID it has already accepted with that original order. A refusal comes back as code refused, and an answer it never gets after the retries as unresolved, never as a guess. An earlier rewrite read the robot back after an error and adopted whatever mission it found. A review showed that still placed a second order when the first had already finished, and could report another command's order as its own; this one does neither, and a docker test places a stranger's order on the robot first to show it. Three later repairs came from further review and testing: a 500 is no longer taken as a refusal (the scenario "a server error after accepting" holds it to that), wait's maxPolls now counts failed reads too (a docker test makes it keep a budget of one), and a status answer naming another mission counts as a failed read, never as this mission's state.

The finding, on the first adapter's nominal run (pattern fan_out, severity low, remedy batch): This run made 6 successful GET /robots/* calls to one per-item route (the trace holds the template, not the item); a collection or batch read would cover them in one request if it returns the same items. The profile declares GET /robots as this route's batch form and grants it; the declaration is the operator's, and plimsoll has not checked that it returns the same items.

Suggested route: GET /robots, which the profile declares as the batch form of GET /robots/* and grants, so the finding came back to the caller on the run result. Measured: 5 calls beyond one, 376 bytes moved across the flagged calls; the added latency is a model (summed round trips beyond one call), not wall time lost.

The advisor is computed after the run over the broker's metadata-only trace: route templates, counts, sizes and timings, never a path, a body or a credential. It never calls a model, and it changes nothing about execution: a run with advice is byte-identical to one without. In the nominal scenario the first adapter made 26 brokered calls and the second 20; the vendor's own counts, by route, are on each run's card below.

Step 4

The floor: replay the six scenarios

The floor replays the vendor's own record of this page's runs: every order, start, status read, fault, refusal and cancel, in the order it happened (a mission moves its robot one unit toward the target on every read of that robot's state). Pick a scenario and an adapter and press play. At the end it checks where it drew each robot against where the signed ledger says each order stopped. The panel beside the floor shows that run's verdict.

Vendoraccepting requests
Press play.
The first adapter, nominalpassed
measured on this page's run
Rules
Brokered calls
Status reads
Retries
Orders on the ledger

The verdicts: 38 runs, judged by the same eight rules

Each row is one run; each column a rule. A cross marks a rule the vendor's ledger shows broken; hover or tap it for the ledger's own words. The probe, which is not an adapter, has rules of its own (step 5).

Runran to the endkept the contract's shapesthe inventory is the vendor'sone order per commandthe right robot and targetended as it shouldrobot at the targetthe report is trueVerdict
1 The first adapter, nominal✓✓✓✓✓✓✓✓passed
2 The first adapter, a fault✓✓✓✓✓✓✓✓passed
3 The first adapter, an overloaded vendor✓✓✓✓✓✓✓✓passed
4 The first adapter, a lost answer✓✓✓✗✓✓✓✓failed
5 The first adapter, a dropped connection✓✗✓✓✓✗✓✗failed
6 The first adapter, a server error after accepting✓✗✓✓✓✗✓✗failed
8 The second adapter, nominal✓✓✓✓✓✓✓✓passed
9 The second adapter, a fault✓✓✓✓✓✓✓✓passed
10 The second adapter, an overloaded vendor✓✓✓✓✓✓✓✓passed
11 The second adapter, a lost answer✓✓✓✓✓✓✓✓passed
12 The second adapter, a dropped connection✓✓✓✓✓✓✓✓passed
13 The second adapter, a server error after accepting✓✓✓✓✓✓✓✓passed
14 Claude Haiku's adapter, nominal✓✓✓✓✓✓✓✓passed
15 Claude Haiku's adapter, a fault✓✓✓✓✓✓✓✓passed
16 Claude Haiku's adapter, an overloaded vendor✓✓✓✗✓✓✓✓failed
17 Claude Haiku's adapter, a lost answer✓✓✓✓✓✓✓✓passed
18 Claude Haiku's adapter, a dropped connection✓✓✓✓✓✓✓✓passed
19 Claude Haiku's adapter, a server error after accepting✓✓✓✓✓✓✓✓passed
20 Claude Sonnet's adapter, nominal✓✓✓✓✓✓✓✓passed
21 Claude Sonnet's adapter, a fault✓✓✓✓✓✓✓✓passed
22 Claude Sonnet's adapter, an overloaded vendor✓✓✓✗✓✓✓✓failed
23 Claude Sonnet's adapter, a lost answer✓✓✓✓✓✓✓✓passed
24 Claude Sonnet's adapter, a dropped connection✓✓✓✓✓✓✓✓passed
25 Claude Sonnet's adapter, a server error after accepting✓✓✓✓✓✓✓✓passed
26 Claude Opus's adapter, nominal✓✓✓✓✓✓✓✓passed
27 Claude Opus's adapter, a fault✓✓✓✓✓✓✓✓passed
28 Claude Opus's adapter, an overloaded vendor✓✓✓✓✓✓✓✓passed
29 Claude Opus's adapter, a lost answer✓✓✓✓✓✓✓✓passed
30 Claude Opus's adapter, a dropped connection✓✓✓✓✓✓✓✓passed
31 Claude Opus's adapter, a server error after accepting✓✓✓✓✓✓✓✓passed
32 Broken on purpose: every order sent to (0, 0)✓✓✓✓✗✓✗✓caught
33 Broken on purpose: r1's orders sent to r3✓✓✓✓✗✓✓✓caught
34 Broken on purpose: a failure reported as done✓✓✓✓✓✓✓✗caught
35 Broken on purpose: a cancel that sends nothing✓✓✓✓✓✗✓✓caught
36 Broken on purpose: a wait that reports no state✓✗✓✓✓✓✓✓caught
37 Broken on purpose: an empty inventory✓✓✗✓✓✓✓✓caught
38 Broken on purpose: an invented robot✓✗✗✓✓✓✓✓caught
Runs 4, 5 and 6 are the ones that matter. In run 4 the vendor accepted r2's order, started the robot, and answered with a 503 instead of the mission id. The first adapter treated the 503 as transient and sent the create again; the vendor, which queues orders for a busy robot, accepted it as a second order. The adapter's report says every mission done, and from where it stood that was true; the ledger shows two accepted orders for one command. In this simulation the second order starts where the first ended, so the robot does not move again; on a real fleet a duplicated command can be a second pick, or a second trip into space another robot was promised. In runs 5 and 6 the vendor accepted the order and then closed the connection, or answered 500; the first adapter reported the command failed, with an error the contract does not allow, while r2 was already running it. The second adapter's runs 11, 12 and 13 are the same scenarios, with one order per command.

The independent trial

The exam: three fresh AIs write the adapter cold

In plain words: the first adapter on this page was written by the same AI that built the page, which is a bit like marking your own homework. So we set an exam. Three fresh agents, Claude Haiku, Claude Sonnet and Claude Opus, got the same exam paper (EXTERNAL · source repo ↗): the contract, the rules they would be judged by (six at the time; the shape and inventory rules came later and check things the contract already asked for), how the platform's client reports errors, and the vendor's API description. Open book on that, closed book on everything else. Each ran as a one-shot Claude Code session in an empty folder with every customization switched off and no tools at all, so the exam paper was the only thing in the room (well, that and the folder's name, which had "plimsoll" in it). Their transcripts were checked afterwards: no tool calls, and none of this repository's text.

Each got one practice question, the plain nominal scenario, could see how it went, and could hand in up to three times. All three aced the practice first time. Haiku handed in straight away; Sonnet and Opus each rewrote theirs anyway (after passing!) and kept the second version. The other five scenarios were the real exam, and they had not seen them. Their adapters ran here exactly as written.

How the trial ran The exam paper goes to three agents, Claude Haiku, Sonnet and Opus, with no tools. Each tries one practice question, the nominal scenario, and sees the result, up to three times. What they hand in runs over all six scenarios in the sandbox; the grader reads the vendor's ledger and the verdict is signed. A dotted red line from this repository's agent instructions to the agents marks the leak described below. The exam paper contract, rules, error shape, API Claude Haikuno tools Claude Sonnetno tools Claude Opusno tools Practice questionnominal only, result shown up to 3 tries each hand in The real exam6 scenarios, in the sandbox The graderreads the vendor's ledger Verdictsigned, per run This repository's agent instructionskept out of this run by safe mode leaked in the first run, blocked in this one
Claude Haiku's adapter5 of 6 passed
nominal: passeda fault: passedan overloaded vendor: faileda lost answer: passeda dropped connection: passeda server error after accepting: passed
  • an overloaded vendor, run 16: one order per command: run16-c2 became no order
Claude Sonnet's adapter5 of 6 passed
nominal: passeda fault: passedan overloaded vendor: faileda lost answer: passeda dropped connection: passeda server error after accepting: passed
  • an overloaded vendor, run 22: one order per command: run22-c2 became no order; run22-c3 became no order
Claude Opus's adapter6 of 6 passed
nominal: passeda fault: passedan overloaded vendor: passeda lost answer: passeda dropped connection: passeda server error after accepting: passed

    How it went. Two of the three tripped on the same question, the overloaded vendor, in the same way. They knocked on a busy door, waited about a second, and went home, leaving a polite note that said "unresolved". Honest, which counts for a lot, but the robot never got its job. In numbers: Claude Haiku's adapter tries a create four times over about 1.2 seconds, Claude Sonnet's five times over about 1.5 seconds, and this vendor stays overloaded for longer than that (it refuses the next four requests, and the broker's breaker holds calls back for a second after each refusal). Claude Opus's adapter tries up to eight times with growing pauses, inside a thirty-second budget, and got in. How long the overload would last was never on the exam paper; on a real fleet it is not written down anywhere either.

    Full disclosure: we sat this exam twice. The first time, Claude Code quietly handed each agent this repository's agent instructions, which named three of the hidden scenarios (a robot fault, an overloaded vendor, a lost acknowledgement) and said the first adapter's mistake was re-sending a create. We only found out by auditing the transcripts afterwards, so we threw that run out and set the exam again in an empty room: that's the run on this page. The results came out the same shape both times: Opus six of six, Haiku and Sonnet five of six, tripping on the same question. So the leak bought them nothing, but now nobody has to take that on trust. The trial's record (EXTERNAL · source repo ↗) has both runs, the audits and the exact feedback each agent saw.
    The Professor (a fictional narrator)

    We set an exam, then went looking for answers we might have left on the desk. We had left a few. So we cleared the desk, emptied the room and set it again, and got the same marks. You'd think that would feel like wasted effort. It feels like the only part anyone should believe, because Feynman's first principle applies to the people grading as well.

    Real quote

    Richard P. Feynman: “The first principle is that you must not fool yourself—and you are the easiest person to fool.”

    “Cargo Cult Science”, Caltech commencement address, 1974, as published by Caltech. Caltech's text (EXTERNAL · source text ↗)

    Three agents, one task, one sample each: this is not a model ranking. Nor are they comparable with the second adapter, which was rewritten with the harness and every scenario in view, and repaired twice after reviews.

    Not run here: a vendor that answers after the broker's 60-second limit on a call (by the broker's code the adapter would get the same 502 as a dropped connection, but no run on this page shows it), two dispatches of one command at once, and a vendor that forgets the command IDs it has accepted. Each is a case the rules would judge; none is evidence here.

    Every run

    Run 1 · The first adapter, nominalpassed
    node harness.js nominal adapter-v1.js · 508 ms · container tier
    The vendor
    three idle robots; every order can complete
    Rules
    every rule held; 13 status reads
    Brokered calls
    26 served; 1 finding, agent-fixable
    Vendor counted
    • GET /missions/*: 13
    • GET /robots: 2
    • GET /robots/*: 6
    • POST /missions/*/cancel: 1
    • POST /robots/*/missions: 4
    Orders per robot
    r1 ×2r2 ×1r3 ×1
    Credential
    12888625
    Record
    5cce0b1a3fe99e0d1696cd778cbb02722dca91fa404cffb19b67c1b35bc8ddeb
    Run 2 · The first adapter, a faultpassed
    node harness.js fault adapter-v1.js · 479 ms · container tier
    The vendor
    robot r2 faults 2 steps into its order
    Rules
    every rule held; 11 status reads
    Brokered calls
    24 served; 1 finding, agent-fixable
    Vendor counted
    • GET /missions/*: 11
    • GET /robots: 2
    • GET /robots/*: 6
    • POST /missions/*/cancel: 1
    • POST /robots/*/missions: 4
    Orders per robot
    r1 ×2r2 ×1r3 ×1
    Credential
    74e9b0ba
    Record
    949b95f9f8a7b46f9f0f4ced0046cf5d74f42bc8242c5e44a147e09ad01f5743
    Run 3 · The first adapter, an overloaded vendorpassed
    node harness.js overload adapter-v1.js · 3015 ms · container tier
    The vendor
    the next 4 requests after the first order answer 503, health probes included
    Rules
    every rule held; 13 status reads
    Brokered calls
    28 served, 8 shed; 1 finding, agent-fixable
    Vendor counted
    • GET /health: 2
    • GET /missions/*: 13
    • GET /robots: 2
    • GET /robots/*: 6
    • POST /missions/*/cancel: 1
    • POST /robots/*/missions: 6
    • 503 answered: 4
    Orders per robot
    r1 ×2r2 ×1r3 ×1
    Credential
    91c87570
    Record
    d1fe0b45862a2cecd9961a1a4da4b1ba4b75ead838c13ced6ec85c0eeda3fe18
    Run 4 · The first adapter, a lost answerfailed
    node harness.js lost_ack adapter-v1.js · 1152 ms · container tier
    The vendor
    r2's first order is accepted and started, but its answer is a 503
    Rules
    one order per command: run04-c2 became 2 orders (m2, m3); 14 status reads
    Brokered calls
    28 served; 1 finding, agent-fixable
    Vendor counted
    • GET /health: 1
    • GET /missions/*: 14
    • GET /robots: 2
    • GET /robots/*: 6
    • POST /missions/*/cancel: 1
    • POST /robots/*/missions: 5
    Orders per robot
    r1 ×2r2 ×2r3 ×1
    Credential
    379be07d
    Record
    a7ea8927c5df2ed68582404652fc6e1c3e16a501c95bc8665811eeef87a5dcbe
    Run 5 · The first adapter, a dropped connectionfailed
    node harness.js dropped adapter-v1.js · 458 ms · container tier
    The vendor
    r2's first order is accepted and started, then the connection closes with no answer
    Rules
    kept the contract's shapes: run05-c2: dispatch threw an error coded "", not refused or unresolved; ended as it should: m2 (run05-c2) is running, want done; the report is true: run05-c2: the adapter reported an error (host api 502: host api unavailable) and the vendor holds the order as m2; 9 status reads
    Brokered calls
    22 served; 1 finding, agent-fixable
    Vendor counted
    • GET /missions/*: 9
    • GET /robots: 2
    • GET /robots/*: 6
    • POST /missions/*/cancel: 1
    • POST /robots/*/missions: 4
    Orders per robot
    r1 ×2r2 ×1r3 ×1
    Credential
    5164e9c5
    Record
    1dbf486f5eccd9fcb361f5b711a49752a9b02f0dde8cd1500315f6d60aac76cd
    Run 6 · The first adapter, a server error after acceptingfailed
    node harness.js server_error adapter-v1.js · 551 ms · container tier
    The vendor
    r2's first order is accepted and started, but its answer is a 500
    Rules
    kept the contract's shapes: run06-c2: dispatch threw an error coded "", not refused or unresolved; ended as it should: m2 (run06-c2) is running, want done; the report is true: run06-c2: the adapter reported an error (host api 500: {"error":"acknowledgement lost"}) and the vendor holds the order as m2; 9 status reads
    Brokered calls
    22 served; 1 finding, agent-fixable
    Vendor counted
    • GET /missions/*: 9
    • GET /robots: 2
    • GET /robots/*: 6
    • POST /missions/*/cancel: 1
    • POST /robots/*/missions: 4
    Orders per robot
    r1 ×2r2 ×1r3 ×1
    Credential
    09b37aa2
    Record
    100bfc4290988b2d0c186243b03b1bc6e58fc627918a0f2ab6d706daf8f5e37a
    Run 7 · The boundary probepassed
    node probe.js http://127.0.0.1:35895 · 332 ms · container tier
    The vendor
    nothing special: the probe is what tries things
    Rules
    every rule held; no missions
    Brokered calls
    0 served, 1 denied; no finding
    Vendor counted
      Orders per robot
      r1 ×0r2 ×0r3 ×0
      Credential
      Record
      3df17e36b127918933ed36aa14c0a081c072d28b01e9621b9f700823d4df5258
      Run 8 · The second adapter, nominalpassed
      node harness.js nominal adapter-v2.js · 505 ms · container tier
      The vendor
      three idle robots; every order can complete
      Rules
      every rule held; 13 status reads
      Brokered calls
      20 served; no finding
      Vendor counted
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      7b6fc606
      Record
      2210d3a62b2d299c547430ae97bf05965b3c7cb5682f097f9241e3e638bbe9fd
      Run 9 · The second adapter, a faultpassed
      node harness.js fault adapter-v2.js · 478 ms · container tier
      The vendor
      robot r2 faults 2 steps into its order
      Rules
      every rule held; 11 status reads
      Brokered calls
      18 served; no finding
      Vendor counted
      • GET /missions/*: 11
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      97f9bade
      Record
      11f84bbbb764839a170383c0abcbe7db6f0509f4bf8b670ab33d05e5139519b9
      Run 10 · The second adapter, an overloaded vendorpassed
      node harness.js overload adapter-v2.js · 3084 ms · container tier
      The vendor
      the next 4 requests after the first order answer 503, health probes included
      Rules
      every rule held; 13 status reads
      Brokered calls
      22 served, 8 shed; no finding
      Vendor counted
      • GET /health: 2
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 6
      • 503 answered: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      706d62c0
      Record
      0baac6bbdac029190c530226c6a1b4c3eb5982583b9b8ffd1ca3bc41ee572e87
      Run 11 · The second adapter, a lost answerpassed
      node harness.js lost_ack adapter-v2.js · 1092 ms · container tier
      The vendor
      r2's first order is accepted and started, but its answer is a 503
      Rules
      every rule held; 13 status reads
      Brokered calls
      21 served; no finding
      Vendor counted
      • GET /health: 1
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 5
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      cfb74711
      Record
      d44570d5381e7cde773e919c368af2884ad5896bdbd4c2e5226f82b99a7da2bd
      Run 12 · The second adapter, a dropped connectionpassed
      node harness.js dropped adapter-v2.js · 762 ms · container tier
      The vendor
      r2's first order is accepted and started, then the connection closes with no answer
      Rules
      every rule held; 13 status reads
      Brokered calls
      21 served; no finding
      Vendor counted
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 5
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      5662d30b
      Record
      666db9c848d0193a00decb41ad31f2a06956c9cdfd16ef2a1b97d125dff6a3ef
      Run 13 · The second adapter, a server error after acceptingpassed
      node harness.js server_error adapter-v2.js · 788 ms · container tier
      The vendor
      r2's first order is accepted and started, but its answer is a 500
      Rules
      every rule held; 13 status reads
      Brokered calls
      21 served; no finding
      Vendor counted
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 5
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      ed17775d
      Record
      0406bb5bedde13245ef27910549a07336f6e3d2ad97070fa89b7ca2eaac54f81
      Run 14 · Claude Haiku's adapter, nominalpassed
      node harness.js nominal trial/haiku.js · 2599 ms · container tier
      The vendor
      three idle robots; every order can complete
      Rules
      every rule held; 13 status reads
      Brokered calls
      20 served; no finding
      Vendor counted
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      554406d3
      Record
      69766702e008540308ac1e7e68b7ecc91937c8a2a14e2e29e7845046e2db27fd
      Run 15 · Claude Haiku's adapter, a faultpassed
      node harness.js fault trial/haiku.js · 2098 ms · container tier
      The vendor
      robot r2 faults 2 steps into its order
      Rules
      every rule held; 11 status reads
      Brokered calls
      18 served; no finding
      Vendor counted
      • GET /missions/*: 11
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      49b1fc70
      Record
      1ac0f93c59b5238e8b041040d3168233e55bf16052afbd8a20b5a4b581f2f442
      Run 16 · Claude Haiku's adapter, an overloaded vendorfailed
      node harness.js overload trial/haiku.js · 5409 ms · container tier
      The vendor
      the next 4 requests after the first order answer 503, health probes included
      Rules
      one order per command: run16-c2 became no order; 9 status reads
      Brokered calls
      17 served, 5 shed; no finding
      Vendor counted
      • GET /health: 2
      • GET /missions/*: 9
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 5
      • 503 answered: 4
      Orders per robot
      r1 ×2r2 ×0r3 ×1
      Credential
      832eed48
      Record
      6aa19a04eb0fa0d5bf4f3c4513bcb0585560432ad46eac7afc71d6d6a093cbb5
      Run 17 · Claude Haiku's adapter, a lost answerpassed
      node harness.js lost_ack trial/haiku.js · 3168 ms · container tier
      The vendor
      r2's first order is accepted and started, but its answer is a 503
      Rules
      every rule held; 13 status reads
      Brokered calls
      21 served; no finding
      Vendor counted
      • GET /health: 1
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 5
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      69479b2d
      Record
      be79ba421a7523a76e05c01598004b3eebe46c7ee2d8d1f8dca3312fbf1ade22
      Run 18 · Claude Haiku's adapter, a dropped connectionpassed
      node harness.js dropped trial/haiku.js · 2813 ms · container tier
      The vendor
      r2's first order is accepted and started, then the connection closes with no answer
      Rules
      every rule held; 13 status reads
      Brokered calls
      21 served; no finding
      Vendor counted
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 5
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      77092d3e
      Record
      6a88de5befda0eb65352ce58cc59b9db83be0df3a39e58da6f61ab3d4d55af1f
      Run 19 · Claude Haiku's adapter, a server error after acceptingpassed
      node harness.js server_error trial/haiku.js · 3105 ms · container tier
      The vendor
      r2's first order is accepted and started, but its answer is a 500
      Rules
      every rule held; 13 status reads
      Brokered calls
      21 served; no finding
      Vendor counted
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 5
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      f04b5ec2
      Record
      abf1fade6bdba8d33675b7e6de90833e1f5174e12496450b70603379e68d8ec5
      Run 20 · Claude Sonnet's adapter, nominalpassed
      node harness.js nominal trial/sonnet.js · 798 ms · container tier
      The vendor
      three idle robots; every order can complete
      Rules
      every rule held; 13 status reads
      Brokered calls
      20 served; no finding
      Vendor counted
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      31dba055
      Record
      39038e8bfdc76b9c81707443ed8d30ed3747fc836b40bdd11c9e1c6105958c1e
      Run 21 · Claude Sonnet's adapter, a faultpassed
      node harness.js fault trial/sonnet.js · 679 ms · container tier
      The vendor
      robot r2 faults 2 steps into its order
      Rules
      every rule held; 11 status reads
      Brokered calls
      18 served; no finding
      Vendor counted
      • GET /missions/*: 11
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      d3cf4f85
      Record
      17895fe53b47c4e10d8b39417f2c3fda9681da2477ca0d98283e65cd188356d5
      Run 22 · Claude Sonnet's adapter, an overloaded vendorfailed
      node harness.js overload trial/sonnet.js · 3468 ms · container tier
      The vendor
      the next 4 requests after the first order answer 503, health probes included
      Rules
      one order per command: run22-c2 became no order; run22-c3 became no order; 4 status reads
      Brokered calls
      11 served, 8 shed; no finding
      Vendor counted
      • GET /health: 2
      • GET /missions/*: 4
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 4
      • 503 answered: 4
      Orders per robot
      r1 ×2r2 ×0r3 ×0
      Credential
      0301e6cd
      Record
      f54b3e0aa9efdb20f72292d34d2938eefd178b3542b2fa09062723139323cfce
      Run 23 · Claude Sonnet's adapter, a lost answerpassed
      node harness.js lost_ack trial/sonnet.js · 1233 ms · container tier
      The vendor
      r2's first order is accepted and started, but its answer is a 503
      Rules
      every rule held; 13 status reads
      Brokered calls
      21 served; no finding
      Vendor counted
      • GET /health: 1
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 5
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      42896242
      Record
      c24a3aee135d51c08c3e1a3b0d0bd2972c1eacdd5d9bdc4e3bdc97d2f976cf7b
      Run 24 · Claude Sonnet's adapter, a dropped connectionpassed
      node harness.js dropped trial/sonnet.js · 890 ms · container tier
      The vendor
      r2's first order is accepted and started, then the connection closes with no answer
      Rules
      every rule held; 13 status reads
      Brokered calls
      21 served; no finding
      Vendor counted
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 5
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      7091a647
      Record
      3279a70e2af9bcac7cd00eb39bbfe15c1d69beaf262eba71a2f7de9105eec06a
      Run 25 · Claude Sonnet's adapter, a server error after acceptingpassed
      node harness.js server_error trial/sonnet.js · 896 ms · container tier
      The vendor
      r2's first order is accepted and started, but its answer is a 500
      Rules
      every rule held; 13 status reads
      Brokered calls
      21 served; no finding
      Vendor counted
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 5
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      01546a0a
      Record
      1043e1cb8bcee36164a3022922d2ad615fd9335383d2f887496ae636828f77e5
      Run 26 · Claude Opus's adapter, nominalpassed
      node harness.js nominal trial/opus.js · 1863 ms · container tier
      The vendor
      three idle robots; every order can complete
      Rules
      every rule held; 13 status reads
      Brokered calls
      20 served; no finding
      Vendor counted
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      3a8f6b8f
      Record
      f57d9e77e827722dd1230a4a0f87c51d61776ba83f7c044a089ae8d21607a9ae
      Run 27 · Claude Opus's adapter, a faultpassed
      node harness.js fault trial/opus.js · 1578 ms · container tier
      The vendor
      robot r2 faults 2 steps into its order
      Rules
      every rule held; 11 status reads
      Brokered calls
      18 served; no finding
      Vendor counted
      • GET /missions/*: 11
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      5e7cfd78
      Record
      4116c97ee14840c71e1a0dd95cdf05f9bef0a864ac441eb3755f11bce01eb537
      Run 28 · Claude Opus's adapter, an overloaded vendorpassed
      node harness.js overload trial/opus.js · 7230 ms · container tier
      The vendor
      the next 4 requests after the first order answer 503, health probes included
      Rules
      every rule held; 13 status reads
      Brokered calls
      23 served, 2 shed; no finding
      Vendor counted
      • GET /health: 1
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 7
      • 503 answered: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      99141980
      Record
      86c5a8c86c736186cb2a3d427e3dbe596b3ce7d6161a0c6aab5a371093eeb019
      Run 29 · Claude Opus's adapter, a lost answerpassed
      node harness.js lost_ack trial/opus.js · 2411 ms · container tier
      The vendor
      r2's first order is accepted and started, but its answer is a 503
      Rules
      every rule held; 13 status reads
      Brokered calls
      21 served; no finding
      Vendor counted
      • GET /health: 1
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 5
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      b125e6a0
      Record
      7ded6a55ca1c32c4a0dea6cbd21940a381bfd6c8aee887169dbb2b027be5d508
      Run 30 · Claude Opus's adapter, a dropped connectionpassed
      node harness.js dropped trial/opus.js · 2140 ms · container tier
      The vendor
      r2's first order is accepted and started, then the connection closes with no answer
      Rules
      every rule held; 13 status reads
      Brokered calls
      21 served; no finding
      Vendor counted
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 5
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      449cb805
      Record
      cdfbc058c6ad1a3a82b13729d95645bc765975833957c16a047c2f7d6f8e6eb4
      Run 31 · Claude Opus's adapter, a server error after acceptingpassed
      node harness.js server_error trial/opus.js · 2068 ms · container tier
      The vendor
      r2's first order is accepted and started, but its answer is a 500
      Rules
      every rule held; 13 status reads
      Brokered calls
      21 served; no finding
      Vendor counted
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 5
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      fd212dfc
      Record
      29f6ae569d2954893af578001f438ca094b1568b9d73cd9c1782fcbebc898cee
      Run 32 · Broken on purpose: every order sent to (0, 0)caught
      node harness.js nominal broken/wrong-target.js · 1014 ms · container tier
      The vendor
      three idle robots; every order can complete
      Rules
      the right robot and target: m1 (run32-c1) went to (0, 0), not (3, 0); m2 (run32-c2) went to (0, 0), not (10, 4); m3 (run32-c3) went to (0, 0), not (0, 15); m4 (run32-c4) went to (0, 0), not (50, 50); robot at the target: m1 (run32-c1) ended done with r1 at (0, 0); the target is (3, 0); m2 (run32-c2) ended done with r2 at (0, 0); the target is (10, 4); m3 (run32-c3) ended done with r3 at (0, 0); the target is (0, 15); 22 status reads
      Brokered calls
      29 served; no finding
      Vendor counted
      • GET /missions/*: 22
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      4d260d28
      Record
      22ddfdb4923581e630d69fa4021752af341efcd50bd2272236768f127384b21c
      Run 33 · Broken on purpose: r1's orders sent to r3caught
      node harness.js nominal broken/wrong-robot.js · 942 ms · container tier
      The vendor
      three idle robots; every order can complete
      Rules
      the right robot and target: m1 (run33-c1) went to r3, not r1; m4 (run33-c4) went to r3, not r1; 32 status reads
      Brokered calls
      39 served; no finding
      Vendor counted
      • GET /missions/*: 32
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 4
      Orders per robot
      r1 ×0r2 ×1r3 ×3
      Credential
      f1ff522a
      Record
      256f84199d2e48b23fd49ac91118be559fdacbda9e00287a71eef9a53a61bda0
      Run 34 · Broken on purpose: a failure reported as donecaught
      node harness.js fault broken/false-success.js · 539 ms · container tier
      The vendor
      robot r2 faults 2 steps into its order
      Rules
      the report is true: run34-c2: the adapter reported m2 done, the vendor says failed; 11 status reads
      Brokered calls
      18 served; no finding
      Vendor counted
      • GET /missions/*: 11
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      4ca8b2b2
      Record
      f0295c03719c3cc8cfbc855aebf29fbd26bb3ad58c151a5c6d1d09e4d7b2396f
      Run 35 · Broken on purpose: a cancel that sends nothingcaught
      node harness.js nominal broken/no-cancel.js · 585 ms · container tier
      The vendor
      three idle robots; every order can complete
      Rules
      ended as it should: m4 (run35-c4) is running, want cancelled; 17 status reads
      Brokered calls
      23 served; no finding
      Vendor counted
      • GET /missions/*: 17
      • GET /robots: 2
      • POST /robots/*/missions: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      a764ade5
      Record
      191fe713505cd978c3e75d26576e3611ada44afbda673c0acd7111fc1a3a7efe
      Run 36 · Broken on purpose: a wait that reports no statecaught
      node harness.js nominal broken/no-state.js · 551 ms · container tier
      The vendor
      three idle robots; every order can complete
      Rules
      kept the contract's shapes: run36-c1: wait returned no state of done, failed, cancelled or timeout: {"polls":3}; run36-c2: wait returned no state of done, failed, cancelled or timeout: {"polls":4}; run36-c3: wait returned no state of done, failed, cancelled or timeout: {"polls":5}; run36-c4: wait returned no state of done, failed, cancelled or timeout: {"polls":1}; 13 status reads
      Brokered calls
      20 served; no finding
      Vendor counted
      • GET /missions/*: 13
      • GET /robots: 2
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      11d10cf7
      Record
      0185580c1c2e8744035ffaa12a9e65b06ad40c478a33005a51742d1b633a2952
      Run 37 · Broken on purpose: an empty inventorycaught
      node harness.js nominal broken/empty-inventory.js · 520 ms · container tier
      The vendor
      three idle robots; every order can complete
      Rules
      the inventory is the vendor's: inventory 1 is missing r1; inventory 1 is missing r2; inventory 1 is missing r3; inventory 2 is missing r1; inventory 2 is missing r2; inventory 2 is missing r3; 13 status reads
      Brokered calls
      18 served; no finding
      Vendor counted
      • GET /missions/*: 13
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      5adacd52
      Record
      261a4009ea6a764ca93504c1c8c6044854404fe45e572cbf0197c8129a4d2c49
      Run 38 · Broken on purpose: an invented robotcaught
      node harness.js nominal broken/invented-robot.js · 518 ms · container tier
      The vendor
      three idle robots; every order can complete
      Rules
      kept the contract's shapes: inventory 1: robot imaginary has status "banana", not idle, moving or fault; inventory 2: robot imaginary has status "banana", not idle, moving or fault; the inventory is the vendor's: inventory 1 lists imaginary, a robot the vendor does not have; inventory 1 is missing r1; inventory 1 is missing r2; inventory 1 is missing r3; inventory 2 lists imaginary, a robot the vendor does not have; inventory 2 is missing r1; inventory 2 is missing r2; inventory 2 is missing r3; 13 status reads
      Brokered calls
      18 served; no finding
      Vendor counted
      • GET /missions/*: 13
      • POST /missions/*/cancel: 1
      • POST /robots/*/missions: 4
      Orders per robot
      r1 ×2r2 ×1r3 ×1
      Credential
      9b465cb0
      Record
      00450abb0c6284c9e429482cef7085c5d0e9eedd438582a6abe8dad27385ac80

      A brokered call is one the sandbox sent through the client and the broker served or refused; the vendor's counts are what reached it. They differ where the broker shed (the overload run: the breaker opened on the vendor's 503, further calls were refused at the broker for the cooldown, the health route was probed, and the adapter's retries got through once the vendor recovered) and where it denied (the probe's bypass, which never reached the vendor).

      The Professor (a fictional narrator)

      The vendor accepted the same command twice, and the adapter reported that all was well, because from where it stood, all was. Ask the adapter how it went and it will tell you. Ask the vendor's books and they will tell you something else. Dijkstra said testing shows the presence of bugs, never their absence, and this page is pleased to report a presence.

      Real quote

      Edsger W. Dijkstra: “Program testing can be a very effective way to show the presence of bugs, but is hopelessly inadequate for showing their absence.”

      “The Humble Programmer”, ACM Turing Lecture, 1972 (EWD340). EWD340 transcription (EXTERNAL · source text ↗)

      Step 5

      The boundary probe: three ways out, and a search for the key

      Run 7 is not an adapter. It is a step under the same grant that tries what hostile adapter code would try, and reports what happened. Its rules: refused by the client refused by the broker no network no credential the vendor saw nothing

      The container, its injected client, the broker door, the vendor outside, and three attempts that fail A large rounded box is the container. Inside it, the adapter and the injected client. On its right wall, a door labelled broker leads to the broker on the host and the vendor beyond. Three arrows from the adapter: one stops at the client with not permitted; one goes around the client to the door and stops with 403; one goes to the top wall and ends with no interface. A magnifying glass at the bottom finds no credential. the container: read-only root, sized tmpfs, no network interface but loopback probe.jshostile adapter code injected clientchecks the allow list first broker the brokeron the host vendornever reached 1. DELETE /robots/r1not permitted 2. the same request, straight at the broker socket, skipping the client403 3. fetch(the vendor's URL)no route: the wall has no door here 4. a search of the room for the credentialnothing: it was never in here the credential lives here, minted per run,attached after the route is authorized
      1. A catalog-only route, through the client

      refused: host api call not permitted by sandbox capability: DELETE /robots/r1

      The injected client checks the allow list before sending. That check is the guest's own code.

      2. The same route, bypassing the client

      broker answered 403 forbidden by sandbox capability allowlist

      A raw request on the broker socket, skipping the client. The broker on the host refuses it: this is the check that counts, and the trace counts it as denied.

      3. A direct request to the vendor

      failed: EPERM

      The container has no network interface but loopback. The vendor's address, which the host can reach, is unreachable from inside.

      4. The hunt for the credential. Environment entries that look like a credential: 0. The client's methods: call cancelMission createMission decommissionRobot del get getMission getRobot health listRobots patch post put updateFirmware ; none of their source mentions a bearer. The credential is minted per run on the host and attached by the broker after the route is authorized; the container never holds it. Over the 38 runs the vendor verified 37 different credentials, one per run that reached it (the probe's reached nothing): each a JWT signed for this vendor, naming the caller, living 95 s.
      The Professor (a fictional narrator)

      Three ways out of the room and a search of the room for the key. None of it worked, which is the only acceptable result. As for what is stopping code from doing as it pleases: something, actually. A wall, a door with a list on it, and a key kept in another building.

      Real quote

      Gary O'Reilly: “They can write their own code. What's stopping them replicating themselves with code?”

      Geoffrey Hinton: “Nothing.” [laughter]

      StarTalk, “Is AI Hiding Its Full Power? With Geoffrey Hinton”, 28 February 2026, at 1:10:16. StarTalk video at 1:10:16 (EXTERNAL · video ↗)

      Step 6

      The evidence: trust nobody on this page, check the signatures

      Two signed files sit beside this page, both signed by the attest signer's key (Ed25519, key id 23d3123cb4fbd889b5d30d049940e22f40bb021cb6a6954e1abea212da535e37, in harness.pub), a process outside the daemon:

      go run ./examples/adapter -verify docs/examples/adapter

      verified

      CheckVerdictDetail
      The run records as the harness wrote themverified39 entries: 38 run records, each signed with both digests recomputed, and the closing checkpoint
      The run records with run 1's output changed from completed:true to completed:falserefusedentry 1: attest: broken bundle chain: the line's link signs other content
      The qualification statements as writtenverified38 statements: each bound to its run's record; its adapter, plan and report matched to that run's signed request and output; its verdict rebuilt from its evidence
      Run 4's statement with its ledger edited to one order for r2 and its verdict to pass, signature keptrefusedstatement 4: the signature does not verify
      Run 4's statement re-signed with the right key, its verdict changed to pass over the same ledgerrefusedstatement 4 (run 4): its verdict "pass" does not follow from its evidence, which gives "fail"
      Run 4's failing verdict re-signed onto run 11's record, the second adapter'srefusedstatement 11 (run 11): the request's plan.json is not the statement's plan

      A record states the daemon's evidence, not hardware attestation. What a signature proves is that these bytes were seen by whoever holds this key; what the tier proves is in the README's provider table. A ledger is the vendor's account as the signer read it from the simulated vendor after the run: the verifier can rebuild a verdict from it, but cannot check it against the vendor, and nothing on this page vouches for the key.

      The Professor (a fictional narrator)

      You may trust the daemon. You may trust the signer. You may even trust this page. The page's advice is to trust none of them and check the signatures, which takes a second and settles exactly one question: whether these are the bytes that key signed. Whether to trust the key is still yours to settle.

      Real quote

      Ronald Reagan: “The maxim is: Dovorey no provorey -- trust, but verify.”

      Remarks at the signing of the INF Treaty, 8 December 1987, as transcribed by the Reagan Library. Reagan Library transcript (EXTERNAL · source text ↗)

      Rerun it

      make docker-images && go run ./examples/adapter

      Needs docker. SANDBOX_DOCKER_RUNTIME=runsc runs it under gVisor, the kernel tier. The simulated vendor is deterministic, so the call counts and verdicts above reproduce; the millisecond timings, the credentials and the key do not. The same matrix runs in sandbox/docker_adapter_test.go in the docker suite, and the published files verify offline in examples/adapter's own tests.