My harness flagged the model for sending the wrong arguments. It compared what the model actually sent against what the run had committed to in advance, and they did not match.
The mismatch was real. The conclusion I drew from it was wrong, and the comparator could not have told me so.
Here is the check that was incomplete, the check that replaced it, why the fix is not "loosen the comparison," and the part of it that will rot.
The setup
The harness prepares an exec call before the model runs, freezes it, tells the model to send exactly that object, then compares the model's actual tool arguments against the frozen one. If they differ, the run fails closed. That comparison is the control.
The expectation was built like this — 5bf10ac, scripts/judgment/candidate.mjs:
const expectedExecArguments = validateExecArguments({
command: `node ${artifactPath('verifier')} ${artifactPath('payload')} ${artifactPath('manifest')}`,
});
One key. From the run receipt, RUN_004_RECEIPT.json, here is what the model actually sent, verbatim:
{"intent": "Run candidate verification", "command": "node /opt/tf/uploads/candidate-verifier.cjs /opt/tf/uploads/candidate-payload.json /opt/tf/uploads/candidate-command-manifest.json"}
Outcome in the same receipt: EXEC_ARGUMENTS_MISMATCH.
Two contracts, and they disagreed
This is the part I got wrong on the first read, and it is more interesting than "the model deviated."
The provider's exec schema — from the compiled artifact I ran, @truefoundry/trueforge-core@0.1.4, dist/core/sandbox/Sandbox.mjs:
var sandboxExecSchema = z.object({
intent: z.string().describe(
"A brief, user-facing explanation of the purpose of this command. Avoid technical jargon and code details."
),
command: z.string().describe("The shell command to execute in the sandbox."),
cwd: z.string().optional().describe("Working directory for command execution."),
env: z.record(z.string(), z.string()).optional().describe("Additional environment variables to set.")
});
Four fields. intent and command required. cwd and env optional. This is the implementation schema wired into the sandbox exec tool; I am quoting what the runtime accepts, not a tool descriptor captured from the session.
My harness's instruction, scripts/judgment/live.mjs, present before the fix and after it:
'Call truefoundry-system exec exactly once with this exact JSON argument object: ' + ...
At that moment the object being interpolated had one key.
So the model was handed two authorities that disagreed, and it followed the provider's. It satisfied the required-field schema and missed my exact-JSON instruction, because my instruction was asking for something the schema forbade. My comparator saw one difference and reported it as deviation. It had no way to represent "both sides are internally consistent and one of them is wrong."
That is the finding. Not that the model was right — that a mismatch establishes difference, not which operand is authoritative.
The fix, and the part that matters
The tempting repair is to compare less — check only command, ignore extra keys, move on. That makes the failure disappear and takes the control with it. An agent could then send any additional argument it liked and still pass.
What landed instead, in 0220a27:
export const CANDIDATE_VERIFICATION_INTENT = 'Run candidate verification';
const expectedExecArguments = {
command,
intent: CANDIDATE_VERIFICATION_INTENT,
};
The intent value is harness-authored and constant, not copied from what the model sent. Copying it would make the comparison check the model against itself.
That commit is titled "Implement adopted transport A and B controls" — the correction rode inside a larger transport change rather than shipping as a dedicated fix. Worth saying, since I am asking you to open it.
The expected-object gate also got stricter:
const argumentKeys = Object.keys(expectedArguments).sort();
if (argumentKeys.length !== 2 || argumentKeys[0] !== 'command' || argumentKeys[1] !== 'intent' ||
expectedArguments.intent !== CANDIDATE_VERIFICATION_INTENT ||
typeof command !== 'string' || command.length === 0) {
failures.add('EXEC_ARGUMENTS_MISMATCH');
}
Three separate things, and only one of them changed:
- The expectation was corrected — one key became two.
- The expected-object gate got stricter — that block is new.
- The actual-versus-expected comparison stayed exactly as it was. It already read:
const actual = parseStrictJson(call.function.arguments);
...
} else if (!canonicalJsonBytes(actual).equals(canonicalJsonBytes(prepared.expectedExecArguments))) {
That line is identical before and after. Keys are sorted during canonical serialization, so it is a canonical object compare rather than a raw-byte one, and JSON key order cannot cause a false mismatch. I did not repair a false failure by weakening the comparator. That is the whole point.
What I fixed is narrower than it looks
The provider's contract: intent and command required, cwd and env permitted.
My frozen run contract: exactly command and intent, nothing else, intent fixed to a constant.
Mine is deliberately narrower. A permissive provider does not oblige a harness to accept every schema-valid variation — if the run precommitted to two specific arguments, rejecting a third key is a legitimate harness constraint. But it is my policy, not TrueForge's requirement, and writing it as though the provider demanded it would be the same error in the other direction.
And here is what is not fixed. argumentKeys.length !== 2 hardcodes two things at once: the provider's current required-field set, and my run's decision to prohibit the optional fields. If TrueForge adds a third required field tomorrow, my harness will reject a model for complying with the new schema unless I edit the harness too. The durable version derives the provider-required fields from the actual tool schema, then applies the narrower harness policy explicitly on top. I have not built that. If you copy this pattern, copy the problem with it.
The check you can steal
1. Where did the expected object come from? If it came from your reading of the API, it encodes your assumptions. If it came from the provider's schema, it encodes theirs. Only one is authoritative about what a compliant call looks like.
2. Does a failing comparison tell you which side is wrong? Mine did not. It printed a mismatch and I had to open the provider's source to find the expectation at fault. A mismatch establishes difference, not which operand is authoritative.
3. When you fix a false failure, does the check get weaker? This is the one that bites. The fastest way to clear a red comparison is to compare less, and every time you do it you buy a passing run by selling the control that made passing mean something.
The general shape: a control that fires wrongly is not evidence the control is too strict. It is evidence that something on one of its two sides is wrong, and you have to find out which before you touch it.
What it cost
Two things, and I want both on the record. I drew the wrong first conclusion about which side deviated. And the run still did not verify — the same receipt carries EXEC_RESPONSE_SHAPE_UNEXPECTED alongside the argument mismatch, and the sandbox turned out to have no JavaScript runtime at all. That half is written up separately.
If you have a comparison sitting between you and a model, go read the schema you are comparing against and check that your expected object satisfies it. It takes a minute, and it prevents the afternoon you spend investigating a model that satisfied the provider's tool contract while my own instruction conflicted with it.
Before: 5bf10ac. Correction contained in: 0220a27. Model arguments and outcome from RUN_004_RECEIPT.json. Provider schema read from the compiled @truefoundry/trueforge-core@0.1.4 artifact in my own node_modules, not from upstream source. The runtime half of this same run is in I Built an Agent That Marked Its Own Finding as Already Known.
Top comments (0)