Study guides / CCDV-F / Domain 1

Applications & Integration · Lesson 11 of 11

1.11 - Versioning and Rolling Out Model Changes

Pin model versions deliberately and roll changes out the way you'd roll out any other behaviour-changing dependency upgrade.

Claude models are versioned, and pinning an exact model version string (rather than a loose, always-latest alias that can shift under you without a code change on your part) is what keeps a production feature's behaviour stable between deploys. Model output quality and even format habits — how strictly it follows a requested output schema, how verbose its default explanations are, how it handles an edge case in your prompt — can shift meaningfully between versions, even when the shift is an overall improvement in the aggregate. Treat a version bump the same way you'd treat upgrading any other dependency that materially changes behaviour: test against your own eval set (Domain 8) before rolling it out, not after discovering a regression in production.

Deprecation windows

Pinned model versions are eventually deprecated and retired on a published timeline, not removed without notice — which means pinning trades the risk of an unannounced behaviour shift for the responsibility of actively tracking deprecation announcements and migrating before a retirement date, rather than being silently auto-upgraded. A production system with no process for watching deprecation notices can end up scrambling at the last minute to requalify a new version under deadline pressure, which is a worse position than a planned, tested migration on your own schedule.

Rolling out gradually

For a feature with real usage volume, a staged rollout — a small percentage of traffic routed to the new model version, compared against the old version on real outcomes, before a full cutover — catches regressions a small offline eval set might miss, particularly ones that only show up on the long tail of real user inputs rather than the curated cases in your eval set. This is config-management discipline (Lesson 1.9) applied specifically to the model-version axis: the version string lives in config, which is what makes a percentage-based routing split between two versions straightforward to implement in the first place.

Key concept

"Latest" is convenient in development and risky in production. A feature that matters should know exactly which model version it's running, on purpose, and should have a deliberate, tested process for ever changing that.

What an eval set needs to catch before rollout

A pre-rollout eval set for a version change should specifically include the edge cases and format-sensitive prompts your feature depends on — not just a general sample of typical traffic. A feature that parses a strict JSON schema from Claude's output needs eval cases that check schema conformance under the new version specifically, since format adherence is exactly the kind of subtle behaviour that can shift between versions even when general answer quality improves. An eval set built only around "is the answer roughly right" can pass cleanly on a version bump that silently breaks a downstream parser expecting a specific structure.

Model aliases and dated version strings

Model identifiers typically come in two forms: a dated, immutable version string that always refers to exactly the same model behaviour indefinitely, and a rolling alias that Anthropic points at a newer underlying model over time without you changing anything in your own configuration. Aliases are convenient for local development and prototyping, where you want to pick up improvements automatically and don't yet have a production feature whose behaviour depends on staying fixed. The moment a feature is live and something downstream depends on its current behaviour, the dated version string is the correct choice specifically because it removes the possibility of an unannounced, un-opted-into change reaching production through the alias.

Communicating a version change beyond the engineering team

A model version rollout that changes user-visible behaviour — response tone, typical length, how it handles a known edge case — is a product change, not just an infrastructure change, even though nothing in the application's own code moved. Treating it purely as a backend deploy and skipping the usual change-communication a product change would get (a heads-up to support teams who field user complaints, a note in release communications, a rollback plan if user sentiment shifts) is a common gap: the eval set can look perfectly clean while the change still surprises people downstream of engineering who had no visibility into it happening.

Common exam distractor

An answer that frames a model version upgrade as purely a technical/backend concern, with no need for staged rollout or eval validation because "newer is presumably better," is a trap. Aggregate improvement across a general benchmark does not guarantee no regression on your specific feature's requirements.

Exam traps

Practice question

A production feature that parses Claude's output into a strict downstream format starts failing intermittently right after Anthropic releases a new model version, because the app was configured to always use the newest available model. What's the best fix going forward?

  • A Pin the application to a specific tested model version, and only move to a newer version after validating it against the eval set. Correct

    This is exactly the discipline that prevents an untested model change from silently breaking a production feature - treat a version change like any other tested dependency upgrade.

  • B Increase max_tokens to give the model more room to format its answer correctly.

    The failure is caused by an untested version change affecting output tendencies, not by an output length limit.

  • C Switch to a different, cheaper model tier, since cheaper models are more stable across versions.

    Model tier doesn't determine version stability - the fix is pinning and testing versions deliberately, at any tier.

  • D Disable extended thinking, since thinking-enabled requests are more sensitive to version changes.

    This isn't related to the actual cause - an unpinned, always-latest model configuration.

Build exercise: Pin a model version, build a format-focused eval set, and simulate a staged rollout comparison

Intermediate · 35 minutes

You'll practice:

  1. In your config, replace any "latest"-style model reference with an explicit pinned version string, stored alongside your other config values from Lesson 1.9.

    This is the change that gives you control over when behaviour shifts, instead of inheriting it silently.

    You should see: The application behaves identically across repeated runs and deploys, since the version is now fixed.

    Hints
    1. Where should this pinned version live relative to the rest of your API key and generation-parameter config?
    2. Keep the pinned version string in the same config source as your API key and max_tokens/temperature values, not hardcoded separately somewhere else in the codebase.
    3. // config.js
      export const MODEL = process.env.CLAUDE_MODEL_VERSION ?? "claude-sonnet-5-20260115";
  2. Write 8-10 eval cases specifically targeting the exact output format your feature depends on (e.g. a strict JSON schema, a required field set, a particular structure), not just general correctness.

    This is the specific gap the lesson calls out - a general quality eval set can miss a format regression entirely.

    You should see: A list of prompts each paired with a schema-conformance check (does the response parse as valid JSON, are all required fields present) rather than a subjective quality judgment.

    Hints
    1. If your feature's real failure mode is a downstream parser breaking, what should each eval case check for, beyond "is the answer good"?
    2. Each eval case should assert something mechanically checkable - valid JSON, required keys present, correct types - so a regression is caught by a pass/fail check, not a subjective read.
    3. const evalCases = [
        { prompt: "Extract name and age from: 'Sam is 34'", check: (out) => { const j = JSON.parse(out); return typeof j.name === "string" && typeof j.age === "number"; } },
        // ... 7-9 more covering edge cases like missing data, unusual phrasing, multiple entities
      ];
  3. Run the full eval set against your currently pinned version and against a newer candidate version, and compare pass rates before deciding whether to roll forward.

    This is the actual pre-rollout gate the lesson describes - comparing two versions on the same format-focused eval set rather than trusting a general impression that the new version is 'better'.

    You should see: A pass-rate comparison between the two versions on your format-focused eval set, surfacing any case where the newer version regresses even if its answers are otherwise more fluent.

    Hints
    1. If the newer version writes better prose but breaks the JSON schema on two of your ten cases, should you roll it out?
    2. Report pass/fail per case for both versions side by side - a version with better general writing but a lower schema-conformance pass rate is a regression for this feature, not an upgrade.
    3. for (const version of [currentVersion, candidateVersion]) {
        let passed = 0;
        for (const c of evalCases) {
          const out = await callModel(version, c.prompt);
          if (safeCheck(c.check, out)) passed++;
        }
        console.log(version, "pass rate:", passed, "/", evalCases.length);
      }

Sources