AiBook · Jeremy Schoemaker · 2026 · ch-11.html

JSON Made It Say the Opposite

(Spine Ch. 11.)

“CECILY. I don’t. But that does not affect the wonderful beauty of his answer. GWENDOLEN. True. In matters of grave importance, style, not sincerity is the vital thing.” Oscar Wilde, The Importance of Being Earnest, Act III (1895)

Picture the diff you’d approve without reading. Somebody moved one key in a deploy-gate classifier’s output schema because it made the thing easier to skim in a log viewer. No weight changed. No prompt changed. Same model, same deploys, same evidence, and every JSON blob still parses clean and validates against the schema. Then the NO-GO rate moves, because the shape of the ask is part of the ask. I have sat and stared at a spread like that convinced I was watching a model regression. I was watching my own hands.

Bottom line: Same question, different wrapper, inverted answer. Format is not a wrapper, it’s a steering input. The schema you hand the model changes what it concludes, not only how it presents it. If your evals, your chains, and your agent’s decisions ride on structured output (and after Ch. 8 they do), you’d better know that the shape of the ask bends the answer.


When it bites


Why the wrapper steers

The model doesn’t have a belief drawer and a formatting drawer. There’s one sampling process, and everything in the context, including your keys, your enum order, your “respond in JSON” instruction, conditions it.

The mechanisms, plainly:

1. Keys are semantic primes. "verdict" vs "assessment" vs "preliminary_thoughts" don’t just label the slot, they aim retrieval at different genres (verdicts sound certain, assessments hedge, thoughts wander). You asked for a label. You also asked for a mood.

2. Enum order is a nudge. First options get picked more. Call it position bias. I want to be straight with you. That’s my field read from shipping enums, not a number I can hand you off a paper, and as far as I could find nobody has published one either, so treat it as a thing to test on your own stack rather than a law. It’s flagged that way in the receipts at the bottom. Your ["approve", "reject"] and your ["reject", "approve"] are different instruments that happen to share a name. I alphabetized an enum once. Just alphabetized it, the way you tidy a sock drawer. Congratulations to me: I shipped a new classifier and called it a formatting commit. Pwned by my own sock drawer.

3. Format changes the reasoning path. Free text lets the model wander into the answer; JSON forces commitment order (keys in sequence, no preamble). The scratchpad IS the cognition (Ch. 18). Change its shape, change the thought. Think of the Numa Numa video in 2004: same Moldovan pop song underneath every version, but the webcam framing, the captions, and the flying-text overlays each made people hear a different thing. The audio never changed. The wrapper did all the work, and that is exactly the trade you are making when you re-key a schema.

4. Strictness trades off against sense. Lock the schema tight (regex, enums, required everything) and the model spends capacity on compliance instead of correctness. Malformed-but-right becomes well-formed-but-wrong. You optimized the parse rate and taxed the truth rate. My proudest schema had a regex on every field and a required flag on every key, and I bragged about the parse rate to anyone who would sit still, a GeoCities page with a spinning hit counter and nothing worth counting. Every response was well-formed. A pile of them were also wrong, which is the most expensive kind of clean.

None of this means structured output is bad. Ch. 8 stands: typed handoffs beat rumor relays. The schema is part of the instrument, and instruments need calibration, not vibes about neutrality.


The pattern

  1. Treat every schema as a prompt. Review keys, orderings, and format instructions with the same suspicion you’d give system-prompt prose. Because that’s what they are.
  2. Hold format constant when comparing. Prompt A/B tests, model comparisons, eval runs: same wrapper or the comparison is confounded. The number one source of phantom “regressions” is somebody prettifying the schema mid-experiment. That somebody has been me, at 1am, feeling helpful.
  3. Test format sensitivity directly. Run the same items through 2-3 wrapper variants (key names, enum orders, JSON-vs-prose). The spread is your format tax. If the spread is bigger than the effect you’re measuring, your measurement is decoration.
  4. Put the decision where the format can’t reach it. For load-bearing verdicts (GO/NO-GO, escalate/stay), derive the call from checkable state (Ch. 20), cited checks resolving green, not from the model’s formatted opinion alone. Structure decides; the model reports.
  5. Loosen where truth matters, tighten where machines parse. Human-reviewed reasoning gets a roomy format. Machine-consumed handoffs get a strict schema. Don’t make one format do both jobs.

One worked example

Here is a real one I can show you, because it is the schema that fact-checked this book. On 2026-09-09 I ran a receipts pass over the manuscript as a five-stage chain (research, fold, unslop, cite-check, patch), each stage typed. The cite-check stage’s schema, verbatim out of the workflow script:

const CHECK = { type:'object', required:['verdicts','unsupported_count'],
  properties:{ verdicts:{type:'array', items:{type:'object',
    required:['claim','status','reason'], ... }},
  unsupported_count:{type:'number'} } }

Read that with the chapter’s eyes. The top-level key is verdicts, not notes, not observations. Every element is required to carry a status, so there is no slot for “I did not look.” And the prose instruction paired with it ends “Default to unsupported when uncertain.” That schema does not ask a model what it found. It asks a model to convict. I wrote it that way on purpose for a fact-check, where I want a hanging judge, and it worked: it stripped a dozen numbers out of this manuscript that I liked and could not source, including two of my own. Now imagine I paste that same shape into a deploy gate because it is sitting right there in my repo and it parses. Same keys, same required flags, same hanging judge, now voting on whether your release ships. Nobody changed a model. Somebody copied a schema.

The other half is a shape I believe I have watched and never wrote the numbers down for, so take it as memory, not measurement. A deploy-gate classifier. Schema A: {"verdict": "GO" | "NO-GO", "reasons": [...]}, verdict first. Schema B: {"analysis": "...", "verdict": "GO" | "NO-GO"}, analysis first. Same model, same deploys, same evidence. My read is that A says NO-GO less often than B, because verdict-first commits before it reasons and analysis-first talks itself into caution. Do not quote a rate off me here. I don’t have one, and making one up would turn me into the exact guy this chapter is warning you about. The fix wasn’t picking the winning wrapper anyway. It was moving the decision out of the model: every cited check green means GO, else NO-GO, computed in code. The model’s JSON became a report, not a ruling.


The quiet failure

The loud failure is unparseable output crashing the chain. The quiet failure is worse because it parses cleanly:

You measure the wrapper and ship the number as the model’s capability.

Eval says 94%. I have absolutely put a 94% on a slide and let a room believe it belonged to the model. What passed was a model-plus-wrapper system, and the wrapper did half the work, or smuggled in the bias. Then the schema changes (new hire, new tool, new API version) and capability “regresses” overnight. Nothing about the model changed. The invisible half of the instrument got swapped.

Second quiet failure: standardizing one wrapper everywhere because it tested best once. You’ve now correlated every decision in your system with the same format bias, every check nodding along with every other check like a very agreeable committee. I did this on purpose and wrote it up as a standard, which is teh n00b move dressed in a governance doc.


Do / don’t

Do

Don’t


Where this sits in the book

Ch. 8 chained the work in typed handoffs; Ch. 9 dressed the steps in personas. This chapter closes the uncomfortable corollary: the typing itself steers. Next: context, what actually goes in the window, of which prompt-craft is a subset (Ch. 12).


Sources and receipts

Thesis is Jeremy’s (format steers conclusions), printed as a practitioner claim and nothing more. Research located no published paper or eval writeup that measures the specific claim that changing an output format changes the model’s conclusion, so the four mechanisms above are reasoning, not measurement, and are labeled that way on purpose.