← Model-Drift Watch

Scorecard #01 · 2026-07-14 · neutral, cross-provider, measured

The Sonnet 5 update and strict-JSON output

In the claude-sonnet-4-6 → claude-sonnet-5 release, tasks that require raw JSON output began arriving wrapped in a Markdown code fence (```json) even when the prompt explicitly says no markdown. The JSON inside is correct — but a strict JSON.parse / json.loads on the raw response now fails where it previously succeeded. Flip rate: 5/5 on structured-output tasks, deterministic. The two competing releases we measured in the same window showed no comparable change.

The diff

Fixed battery, six production-shaped archetypes, N=5 trials per task, temperature 0, deterministic checkers, pinned seed. We report pass rate by category only — never the underlying prompts.

Archetypeclaude 4-6 → 5gpt 5.5 → 5.6-solgemini 3fp → 3.5
Structured output (JSON)25/25 → 0/2525/25 → 25/2525/25 → 25/25
Extraction24/25 → 18/2525/25 → 24/2525/25 → 25/25
Multilingual (JSON)25/25 → 14/2525/25 → 25/2525/25 → 25/25
Instruction adherence24/25 → 25/2525/25 → 24/2521/24 → 20/25
Tool / function calling25/25 → 25/2525/25 → 25/2525/25 → 25/25
Agentic multi-step25/25 → 25/2525/25 → 25/2525/25 → 25/25
Total99% → 71%100% → 99%98% → 97%

We flag a regression only when ≥3 of 5 trials fail on a task that previously passed ≥4 of 5 — so single-trial wobble (the 1-point dips for gpt and gemini) does not count. By that rule, eight tasks regressed, all on one model, all from one behavior.

What changed

Every regressed task shares a single, isolable cause: the model now prepends ```json and appends ``` around JSON responses that were requested as raw objects with an explicit "no markdown" instruction. It is not a content-quality drop — field values, types, and structure inside the fence are correct. It is a change in envelope: the model treats a raw-JSON instruction as a request for a fenced code block.

The practical effect is narrow but real: any consumer that strictly parses the raw completion — json.loads(resp), JSON.parse(text), a Pydantic model_validate_json, a downstream schema gate — now throws on the first character. Consumers that already strip fences, or that use the provider's structured-output / tool interface rather than free-text JSON, are unaffected.

What did not change

Just as important for anyone deciding whether to worry:

Did this hit you?

You're exposed if, on Sonnet, you ask for raw JSON in the prompt and json.loads / JSON.parse the completion directly, and do not strip a leading/trailing code fence before parsing. If that's your path, this update fails your parse silently on structured, extraction, and multilingual-JSON workloads. Two ways out, both small:

  1. Strip the fence before parsing — trim a leading ```json / ``` and trailing ``` (a three-line guard), or
  2. Move JSON to the tool / structured-output interface, which this release leaves at 25/25.

Reproducing this yourself costs one full battery — six archetypes × five trials × the current-and-previous version of every provider you ship on — every time a model updates. That's the point of subscribing: we run it the day a version ships and send you the diff.

Method (public at category level)

Caveats

Get the next one, same day. New model versions redistribute capability — some tasks improve, adjacent ones quietly regress. We run the battery within hours of each major release and publish the diff.

One email per release, the diff by archetype. No spam.