Model announcements arrive faster than any team can evaluate them, and the anxiety they produce is mostly misplaced: for a well-bounded codebase, the great majority require no change at all.
What decides that is not how good you are at keeping up.
It is where your abstraction boundaries sit.
Only four things can actually change Strip the announcement of positioning and exactly four things can differ from what you already run: What changed Description The numbers Price, context window, rate limits, latency, benchmark scores.
Data about a model, not a new capability.
The identifier A new model string exists; possibly an old one is deprecated with a date.
The request or response surface A new parameter, a new response field, a new content type, a new tool-calling shape.
The behaviour The same request produces different text: different verbosity, different formatting, different refusal thresholds, different tool eagerness.
The first two are almost always configuration.
The third is the only one that reliably requires code.
The fourth requires evaluation, which is work but not development work — and is the one most likely to hurt you, because it arrives silently.
What requires nothing A new model existing.
If your model identifiers come from configuration or a catalogue rather than from literals in the code, a new model is a row.
Nothing ships.
A price change.
If prices are data, this is a data update.
If prices are constants in code, it is a release — and worse, a price change you do not notice is silent: everything reconciles perfectly against an out-of-date figure while you systematically under- or over-charge.
A benchmark score.
Benchmark results are not evidence about your workload.
They are a reason to run your evaluation set, and nothing more.
Why benchmarks do not transfer is the argument in full.
A larger context window.
Being able to send more is not a reason to send more.
The cost is linear in what you actually send and the quality is not monotonic in it.
What requires configuration A deprecation with a date.
The work is choosing a replacement and running the evaluation set, not editing code.
Put the date somewhere that pages a human, because a date in a document depends on somebody re-reading the document on the right day, which is the exact thing writing it down was supposed to avoid.
A new default in a client library.
An SDK upgrade that changes retry counts, timeouts or a default model is a behaviour change disguised as a dependency bump.
Pin, and read the changelog for defaults specifically.
A price change that crosses a routing threshold.
If you route on cost, a competitor’s price cut silently re-routes your traffic.
That is usually correct and should still be visible.
What requires code A new response field you want.
Reasoning-token accounting, per-part usage breakdowns, cache-hit indicators.
Each has to be read, stored and displayed.
A new content type in the request.
Audio, video, documents-as-first-class-inputs.
New validation, new size limits, new storage.
A capability your abstraction has no slot for.
This is the expensive class.
If a new model exposes something your provider-neutral interface cannot express, you either widen the interface for everyone or special-case one provider, and the second option is how abstractions rot.
A parameter that some providers ignore rather than reject.
Silent acceptance is worse than refusal: a fully billed response arrives without the field your code expects.
Refuse unsupported parameters at your own boundary.
The boundaries that decide which Whether a given announcement is a data update or a week of work is decided long before the announcement, by five boundaries.
Boundary Description Model identifiers are data A model string never appears in application code.
It comes from configuration, per environment, and every request records which one was used so the question 'what served this?' is answerable retroactively.
Prices are data with provenance Each price carries the page i