The Clause That Was Written and Not Enforced
The architecture said from the start that a call runs only when its block is closed, its arguments parse, they validate against the schema that request advertised, policy has decided, and the tool_call line is flushed. For a stretch that schema clause was prose. A write without its required content created an empty file and reported success. The loop had executed a wish.
Admission now runs one JSON Schema validator against the schema that request advertised, for built-ins and for MCP tools alike. The loop still does not learn what a tool is. A failure records an invalid-call with reason schema, no durable tool_call, and a correction the model can read. Unknown schema vocabulary is ignored: this is admission, not a linter. MCP servers ship arbitrary schemas. A gate that pretended to understand every keyword would start inventing refusals.
Policy Is a Decision, Not a Vibe
Allow runs. Deny returns an error result. Ask offers the operator a choice, recorded as a permission. Sequential execution is the default so the record stays deterministic. A profile may parallelize tools declared read-only. Results project in the model's source order whatever the execution order was. A denied result is never dropped; a missing positional result would shift the model's matching.
At-Most-Once After a Crash
A side-effecting call is at-most-once. A tool_call found on load with no tool_result becomes unresolved intent, folded as a synthetic error, never re-run automatically. Re-running it would be the engine deciding the world is still the world it left. The operator may retry. The loop may not.