01 · The contract
Three parties have to agree, and only two of them are yours
A tool call has to survive three separate agreements: what the checkpoint was trained to emit, what the chat template tells it to emit, and what the parser is defined to accept. The template renders your tool schema into the prompt and instructs an envelope. The parser scans the reply for that envelope and lifts the call out. Neither knows what the other was configured with.
Flip both switches. The payload the model writes is identical in every cell — the paper is explicit that it is the same bytes, only the wrapper changes.
Three of the four cells return zero parsed calls out of 200 cases; the fourth returns 196. Fixing only the template moves nothing. Fixing only the parser moves nothing. Both main effects are exactly zero and the entire effect sits in the interaction, which is why no amount of staring at either component finds the fault.
What makes it silent rather than loud is the shape of the failure. The request returns HTTP 200. The tool_calls array comes back empty. The call text stays in content as ordinary prose. Downstream, that is byte-for-byte what a model that simply declined to use a tool looks like — and the author confirms it is not a parser bug: replaying the parser's own rules over 4,254 stored turns found zero cases where it rejected something its own grammar would have accepted.