A model-pinning policy is the one page that stops a production automation from changing behavior because a vendor changed what a name points to. Two of our recent pieces each documented one way that goes wrong: on August 19, 2026, OpenRouter listed ~z-ai/glm-latest
, a floating alias that always redirects to the newest GLM model and currently resolves to z-ai/glm-5.3
; on July 24, 2026, DeepSeek retired its deepseek-chat
and deepseek-reasoner
legacy names outright. Different symptoms, same root cause.
The root cause is a config string that is not actually an identity. A floating alias resolves to whatever the vendor considers newest, with no call-time signal. A legacy alias resolves to a fixed target until a published date, then stops resolving at all. In both cases the automation that reads the string has no opinion about what it is calling — and the person who tuned its prompts did, months ago, against a model that may no longer be what answers.
This piece does not re-explain either incident; it links to them and builds the policy that generalizes across both. It lines up five vendors — Anthropic, OpenAI, Google, DeepSeek and OpenRouter — on naming scheme, auto-update behavior, published notice period and whether the response tells you which model actually served the request. Then it delivers the policy itself as a literal block you can copy, plus the retirement runbook that goes with it.
- 01Drift and retirement are the same bug with opposite symptoms.A floating alias changes target silently; a retired alias stops resolving on schedule. Both come from a model name in a config string that was never a fixed identity. One policy covers both.
- 02Published notice periods range from two weeks to six months.Anthropic states at least 60 days. OpenAI tiers it: at least 6 months for GA models, 3 months for specialized variants, as short as 2 weeks for previews. Google gives 2 weeks for previews and -latest breaking changes. DeepSeek gave 91 days for its July 24 retirement, without a standing policy. OpenRouter publishes none for concrete slugs.
- 03OpenRouter’s own docs say pin for reproducibility.The Latest Model Resolution page states that versions can change at any time and that applications needing a fixed version should use the concrete slug. The pin-in-production recommendation is the vendor’s, not ours.
- 04Log-and-diff is not a universal detector.OpenRouter’s response model field and OpenAI’s reports name the concrete model that served. One developer report says Gemini’s -latest alias echoes the alias name instead, in the Vertex AI Python SDK. Where the resolved ID is not returned, only a canary prompt detects a swap.
- 05The production answer is pin plus a monitored fallback plus a re-eval gate.Pinning solves reproducibility and creates retirement exposure; floating solves retirement exposure and creates drift. Neither alone is a policy. Pin the primary, name a fallback you have evaluated, and move only through a gate you control.
01 — Two Failure ModesTwo failures, one root cause. #
We have already written both halves of this story in full. The drift half is the glm-latest floating alias: OpenRouter’s own description is that the alias “always redirects to the latest GLM model from Z.ai,” its record’s alias_target
currently names z-ai/glm-5.3
, and its expiration field holds the platform’s no-expiry placeholder rather than any promise. The retirement half is DeepSeek’s July 24 alias retirement: the two legacy names had resolved to deepseek-v4-flash
for backward compatibility, and the fix was a literal string rename to the current family names everywhere the alias appeared. Read together, they describe a single design flaw with two presentations. The flaw is treating a model name as if it were an identity when it is actually a pointer. Pointers can be repointed (drift) or nulled (retirement), and a production automation that holds only the pointer cannot tell either has happened until its output changes or its calls start failing.
Silent drift
A name like ~z-ai/glm-latest, which OpenRouter says always redirects to the newest GLM model, or gemini-flash-latest, which Google describes as hot-swapped on each release. Prompts tuned against one target start hitting another. Nothing fails; behavior just changes.
Scheduled retirement
A name that used to resolve stops resolving on a date the vendor announced in advance. Loud, but only if someone read the changelog. DeepSeek’s July 24 retirement had 91 days of notice; OpenAI’s preview tier can be as short as two weeks.
The policy below exists because the obvious fix for one mode makes the other worse. Pin everything to concrete IDs and you eliminate drift but now own every retirement deadline personally. Float everything and retirements stop hurting but you can no longer reproduce last month’s output. The grid in section 03 is what makes the trade-off concrete per vendor; the policy in section 06 is what resolves it.
02 — Published Notice PeriodsWhat the vendors actually promise, verbatim. #
Notice periods are the one input to this policy that you do not get to choose. They are vendor-published, they differ by a factor of roughly thirteen between the shortest and longest stated figures, and several of the five vendors publish no fixed number for at least one tier. Each figure below is quoted from the vendor’s own page.
Anthropic — at least 60 days
The model deprecations page states: “Anthropic notifies customers with active deployments for models with upcoming retirements, providing at least 60 days’ notice before model retirement for publicly released models.” Notification is by email and documentation. The page’s own deprecation history is consistent with the figure — Claude Opus 4.1 was notified June 5, 2026 and retired August 5, 2026, a gap of 61 days; Claude Sonnet 4 and Opus 4 were notified April 14, 2026 and retired June 15, 2026, a gap of 62 days.
OpenAI — tiered by model class
OpenAI’s deprecations page gives generally available models “at least 6 months”; specialized variants — chat variants such as gpt-5.1-chat-latest
, Codex variants such as gpt-5.3-codex
, deep-research variants such as o3-deep-research
— “at least 3 months”; and preview models “may be retired with much shorter notice, such as 2 weeks.” A safety clause sits above all three: “If safety or compliance concerns require us to retire a model sooner, we will provide as much notice as reasonably possible.”
Google Gemini — two weeks, where a number is stated
The Gemini models page describes four status tiers. Stable models “usually don’t change” and are the production recommendation. Preview models “may be retired with at least 2 weeks notice.” The -latest
aliases, such as gemini-flash-latest
, are hot-swapped on each new release, and “for breaking changes, a 2-week notice will be provided through email before the version behind latest is changed.” For stable models, the separate deprecations page publishes no fixed period: “The shutdown dates listed in the table indicate the earliest possible dates on which a model might be retired. We will communicate the exact shutdown date to users with advance notice to ensure a smooth transition to a replacement model.”
DeepSeek — three months, for this retirement
DeepSeek’s API change log entry dated April 24, 2026 states: “The two legacy API model names, deepseek-chat
and deepseek-reasoner
, will be discontinued in three months (2026-07-24).” April 24 to July 24 is 91 days — thirteen weeks exactly. That is DeepSeek’s number for this specific retirement, not a blanket policy for future ones; we found no standing notice-period commitment on its pages.
OpenRouter — not published for concrete slugs
OpenRouter’s Latest Model Resolution page contains no general retirement-notice policy for concrete model slugs; its only behavioral guarantee concerns how the ~latest
router itself resolves. For the alias tier the honest figure is zero: “Versions can change at any time.”
Published minimum notice before a model name stops resolving · by vendor and tier
Source: each vendor’s own deprecation or model documentation; bar length approximates the stated minimum in days, taking a month as ~30 daysno fixed numberbehind them. Google commits to “advance notice” and an emailed exact date, with the shutdown table giving earliest-possible dates only. DeepSeek published 91 days for the July 24 retirement but no standing commitment covering the next one. OpenRouter’s resolution docs carry no retirement policy for concrete slugs at all — and its
~latest
tier is a different cell again, publishing an explicit zero rather than a gap. Any policy that assumes a uniform runway across vendors is wrong on day one; the grid below carries the gaps as gaps.## 03 — The GridFive vendors, four axes, one table.
Every “pin your model” piece we found argues one vendor’s mechanism in isolation. The policy needs all five lined up on the same axes: how the name is built, whether it updates under you, how much notice the vendor has published, and whether the response names the model that actually served. The last column is where the surprises are.
| Vendor · tier | Naming scheme | Auto-update behavior | Published notice period | Resolved ID in response? |
|---|---|---|---|---|
| Anthropic | ||||
| Claude 4.6 and later — dateless ID (claude-sonnet-4-6) | Dateless ID that maps to a single fixed snapshot; an updated version ships under a new ID | Never in place — weights and config are not updated under an existing ID (serving infrastructure can still change) | “At least 60 days” before retirement, publicly released models | Not applicable — the ID you call is the snapshot that serves |
| Pre-4.6 — dated snapshot plus convenience alias (claude-sonnet-4-5 → claude-sonnet-4-5-20250929) | Dated snapshot IDs, with a separate alias per minor version | The alias resolves to the newest dated snapshot for that minor version — a floating pointer | Same “at least 60 days” policy | Yes — the response names the resolved dated snapshot (long-standing documented behavior) |
| OpenAI | ||||
| Generally available models | Stable model IDs; legacy aliases point at dated snapshots | An alias can be retargeted to a newer snapshot under the same name | “At least 6 months” | Yes — the response model field names the resolved dated snapshot (long-standing documented behavior) |
| Specialized variants (gpt-5.1-chat-latest, gpt-5.3-codex, o3-deep-research) | Variant IDs — note the literal -latest suffix on the chat variant | Not stated on the deprecations page — the -latest suffix matches the floating naming pattern, but no auto-update behavior is documented there | “At least 3 months” | Yes — same mechanism as above |
| Preview models | Preview-labeled IDs | May be retired rather than updated | “Much shorter notice, such as 2 weeks”; safety clause can shorten any tier | Not separately documented |
| Google Gemini | ||||
| Stable | Stable IDs — “usually don’t change,” recommended for production | Not hot-swapped | Not published as a fixed period — shutdown table lists “earliest possible dates”; exact date emailed with “advance notice” | Not established by the docs we read |
| Preview | Preview-labeled IDs | May be retired | “At least 2 weeks notice” | Not established by the docs we read |
| -latest alias (gemini-flash-latest) | Floating alias, family-level | “Hot-swapped” on each new release, by design | “2-week notice… through email” for breaking changes only | Reported no — one developer report on the Vertex AI Python SDK says the response echoes the alias name, not the resolved model; unresolved, not confirmed by Google |
| DeepSeek | ||||
| Current family names (deepseek-v4-flash, deepseek-v4-pro) | Concrete family names; the legacy deepseek-chat / deepseek-reasoner aliases were retired July 24, 2026 | No floating-alias construct currently in production — legacy names were retired outright, not redirected | No standing policy found; 91 days given for the July 24 retirement (announced April 24) | Not applicable — nothing floats to resolve |
| OpenRouter | ||||
| Concrete slug (z-ai/glm-5.3) | author/model slug | Fixed — the slug you call is the model that serves; strict parameter validation | Not published for concrete slugs on the resolution docs | Yes — response model field plus the per-account activity log |
| ~latest alias (~z-ai/glm-latest) | ~author/family-latest router; expiry field holds the platform’s no-expiry placeholder | Repoints silently when a newer target is rolled in; unsupported reasoning parameters silently remapped instead of returning 400 | None — “Versions can change at any time” | Yes — “reports the concrete model that served the request” |
Three things fall out of the grid. First, the word “latest” appears as a literal substring in at least three vendors’ naming — OpenRouter’s tilde alias, Google’s -latest
suffix and OpenAI’s gpt-5.1-chat-latest
variant — with three different contracts behind it: no notice, two weeks’ notice for breaking changes, and a three-month retirement umbrella respectively. The string tells you nothing; the vendor page does.
Second, Anthropic’s 4.6-and-later scheme is the only one in the grid that is pin-by-default at the naming layer. Its model IDs page addresses the misreading head-on: “A common misconception is that dateless model IDs such as claude-sonnet-4-6
behave as evergreen pointers that route to the latest or best-performing version. That is not the case.” The dateless ID maps to a single fixed snapshot, and an updated version ships under a new ID — which is the exact floating-alias pattern the pre-4.6 convenience aliases exhibited, retired by design.
Third, and most consequential for the policy: the “resolved ID in response” column is not uniformly yes. That is the subject of the next section. For the broader question of how a floating reference fits into versioning contracts generally, see our API-versioning decision matrix; a model alias is a specific instance of the same problem.
04 — DetectionWhere log-and-diff stops working. #
The simplest drift detector is to log the model identifier the vendor returns on every response and alert when it changes. That works wherever the response names the concrete model that served. OpenRouter documents exactly this: the response’s model
field “reports the concrete model that served the request… so you can always tell which version answered any given call,” and the per-account activity log records the resolved slug as a second surface. OpenAI’s responses have long named the resolved dated snapshot rather than the alias requested, and Anthropic’s pre-4.6 convenience aliases behave the same way — both are long-standing, documented API behavior rather than a recent change.
Google’s -latest
alias is where the detector has a reported hole. A developer filed googleapis/python-genai issue #2271 against the Vertex AI Python SDK, reporting that models.get()
on gemini-flash-latest
returns a version of “default” with no resolved ID, and that the response’s model_version
simply returns the alias name rather than the model that served. The reporter also showed gemini-flash-latest
producing byte-different output from both gemini-2.5-flash
and gemini-3-flash-preview
on identical prompts — evidence that something is rotating even though the API will not say what.
single developer report, unresolved when we read it, scoped to the Vertex AI Python SDK, with no maintainer response visible and no independent check against the direct Gemini API endpoint. It is not a Google statement and not an acknowledged bug. The reporter’s own framing of the consequence: “This makes it impossible to: 1. Know which model you’re actually calling in production 2. Pin to a specific version before an alias rotates 3. Debug behavioral differences between alias and named models.” Treat it as a reason to make the policy’s detection step conditional, not as a settled fact about Gemini.
The operational consequence is that “log the model field” cannot be a universal instruction. The policy therefore has a conditional detection step: where the response names the resolved model, log it and diff it; where it does not — or where you cannot confirm that it does — run a canary prompt on a schedule and diff the output against a stored baseline. A canary is a fixed prompt with a deterministic expected shape, sent at low temperature on a timer, whose output you hash and compare. It detects swaps the response header will not admit to, at the cost of a few tokens a day.
A canary also covers a second silent vector the glm-latest piece documented: on OpenRouter’s ~latest
slugs, unsupported reasoning parameters are silently remapped to the nearest supported value where a concrete slug returns a strict 400. A caller that disabled reasoning keeps receiving 200s with reasoning silently re-enabled after a repoint to a mandatory-reasoning target — GLM-5.3 mandates reasoning with three effort rungs and no medium. The resolved-ID log catches the repoint; only a canary catches the changed output shape.
05 — The TensionPin, float, or both. #
OpenRouter’s documentation and OpenRouter’s blog recommend opposite things, and both are right about the problem they are solving. The resolution docs are unambiguous about reproducibility:
"Versions can change at any time... If your application requires a fixed version for reproducibility (for example in regression tests), use the concrete model slug instead."— OpenRouter documentation, Latest Model Resolution
The platform’s June 15, 2026 blog post, Keep Your Agent Running When Models Disappear, argues the other side. It states that, by OpenRouter’s own count, more than 70 models have been pulled or deprecated by providers in the last few years — an OpenRouter-stated figure we have not independently audited — and warns that “Hard-coding a model slug pins your choice inside every service that uses it. When that model goes away, the only fix is to edit the code and redeploy each service.” Its recommendation is routing through presets with fallback chains, including pointing a fallback at a self-updating alias of the ~anthropic/claude-opus-latest
form, which always resolves to the newest model in that family.
That is not a contradiction so much as two halves of a policy written on two pages. Pinning solves reproducibility and creates retirement exposure. Floating solves retirement exposure and creates drift. Neither is a production answer alone. The production answer is a pinned primary, a fallback chain whose members you have actually evaluated, and a re-evaluation gate that is the only path by which the primary changes. The matrix below maps that onto the automations people actually run.
Lead scoring, extraction, classification, routing
Output is compared against a baseline or feeds a downstream rule. Any target change invalidates the baseline. Pin the concrete ID, log the resolved model, run a daily canary, and change targets only through the re-eval gate.
Chat surfaces that want upgrades
No regression baseline; newer is usually better; a behavior change is tolerable if noticed. Floating is defensible here — but only with the resolved-ID log or a canary, so that “noticed” is not a customer complaint.
Scheduled jobs that must not silently stop
Pin the primary to a concrete ID. Name one evaluated fallback. Make the fallback a concrete ID too, unless you have accepted that its drift is preferable to an outage — and write that acceptance down.
Regression suites and prompt tuning
This is the case OpenRouter’s own docs name. A floating target here makes every historical score non-comparable. Pin, and treat an alias repoint as a new experiment with its own row.
If the production automation in question runs through Claude Code routines or an n8n-style workflow, the same policy applies to the model string in that workflow’s config — our comparison of production automation cost comparisons covers the surrounding cost model, and the policy here covers the string inside it. When we build or take over an automation under our CRM automation practice, the model-string inventory in Rule 2 is the first artifact we produce, because it is the one that every later decision depends on.
06 — The ArtifactThe one-page policy, ready to paste. #
Everything above reduces to the block below. It is written to be copied into an internal wiki as-is, with the vendor grid from section 03 attached. It rests on the five vendor documents cited in this piece; we found no standards-body guidance on pinning inference-time model IDs, and the policy does not pretend to one.
Model-Pinning Policy for Production Automations
v1 · one page · paste into your wikiScope
Applies to every model identifier read by a production automation from any config surface: application code, environment variables, gateway and router configs, scheduled jobs, and evaluation harnesses. “Production” means any automation whose output a person or a downstream system relies on without re-checking.
Rules
Pin the primary. Production automations call a concrete model ID — a dated snapshot or a pin-by-default ID — never a floating alias (any name containing latest, a tilde router, or a vendor convenience alias that resolves to the newest snapshot).One inventory, one owner. Every model string in scope is listed in a single inventory with its vendor, tier, published notice period from the vendor grid, the surface it lives in, and a named owner. A string not in the inventory is a defect.Detect, conditionally. Where the vendor’s response names the resolved model, log that field on every call and alert on any change. Where the resolved ID is not returned, or you cannot confirm it is, run a scheduled canary prompt and alert on any change to its hashed output.Name an evaluated fallback. Each primary has one fallback that has passed the same evaluation. The fallback is concrete by default; a floating fallback is permitted only with a written acceptance that drift is preferable to an outage for that automation.Change only through the gate. A primary changes only when the owner re-runs the evaluation against the candidate ID, records the result, and updates the inventory. Alias repoints, retirements, and vendor emails are inputs to the gate; none of them changes a primary on their own.
Retirement runway
Assume only what the vendor has published: Anthropic at least 60 days; OpenAI at least 6 months (GA), 3 months (specialized variants), as short as 2 weeks (preview); Google 2 weeks for previews and for breaking changes behind a -latest alias, no fixed period for stable models; DeepSeek no standing policy (91 days given at its last retirement); OpenRouter none published for concrete slugs. Where no period is published, plan for two weeks.
Review
The inventory is reviewed against each vendor’s deprecations page monthly, and on receipt of any vendor deprecation email. Each review records the date, the reviewer, and any retirement date entered into the runbook.
Two design notes. Rule 1 bans floating aliases for primaries but Rule 4 permits them for fallbacks with a written acceptance — because that is the one place OpenRouter’s blog argument is sound, and a written acceptance is what turns “we floated by accident” into “we floated on purpose.” Rule 3 is conditional on purpose: the Gemini report in section 04 is unconfirmed, and a policy that only works when the response is honest is not a policy.
07 — RunbookThe retirement runbook, keyed to real runway. #
A notice period is only useful if the runbook is sized to it. The three observed figures below are the only actual runways we could observe — two from Anthropic’s own deprecation history, one from DeepSeek’s change log. They are not a range to plan against: Google’s two-week floor sits below all three and OpenAI’s six-month floor sits above all three. Size each runbook to the vendor’s own published figure, and read these three only as evidence that, in the cases we could check, the published figure was close to the runway that actually arrived.
Notified Jun 5 → retired Aug 5, 2026
Consistent with the stated “at least 60 days.” The published floor was the actual runway, plus one day. Size the runbook to the floor, not to the hope of more.
Notified Apr 14 → retired Jun 15, 2026
Second precedent, same pattern: two days over the floor. Two data points are not a trend, but both sit where the policy says they will.
Announced Apr 24 → retired Jul 24, 2026
Exactly three months, as the change log promised. The longest observed runway in our set — but DeepSeek publishes no standing notice policy, so there is nothing here to carry forward as an assumption.
On receipt of a deprecation notice
Day 0 — inventory match. Find every inventory row whose model string matches the retiring ID or alias. Enter the vendor’s retirement date. If the vendor gave no date, enter notice-plus-two-weeks and mark it provisional.First week — candidate and evaluation. Pick the successor concrete ID, run the automation’s evaluation against it, and record the result. Where the vendor retired a name that was only ever a redirect — DeepSeek’s case — the successor is the concrete name the alias already resolved to, and the evaluation should confirm no behavior change.Half-way point — re-pin everywhere. Update the string in every surface the inventory lists, not only application code: env vars, gateway configs, scheduled jobs and eval harnesses are the surfaces a rename has to reach. Deploy, confirm the resolved-ID log or canary reflects the new target.Retirement day — verify the failure. Send one request to the retired name from a non-production key and confirm it errors. If it still resolves, the vendor’s date slipped; keep the runbook open.After — keep the rollback path. Re-pinning the previous concrete ID is a rollback. Keep the previous ID in the inventory as the documented rollback target until the next review, followingthe rollback and checkpoint patternswe use for agent changes generally.
Model pinning is one line item in a much longer reliability audit. If you want the fuller list this sits inside, our agentic workflow resilience checklist is the place it lives.
08 — Honest LimitsWhat a pin cannot promise. #
A pinned concrete ID eliminates the largest and most abrupt source of behavior change — the model itself being swapped. It does not make the call hermetic, and no vendor in the grid claims it does. Anthropic’s own documentation states the caveat plainly: “Model weights are fixed for a given ID, but the serving infrastructure around the model can change over time” — the request router, safety classifiers, sampling logic — and such changes can “occasionally produce minor differences in observable behavior even when the model ID and weights have not changed.”
minor by design, but “minor” is a vendor’s word for a change you did not measure. The scheduled canary in Rule 3 is cheap enough to leave running on pinned primaries too, which turns “the vendor says nothing changed” into “we checked.”
The grid also exposes a design choice vendors make about incompatibility, and it is worth naming because it shapes how loud your failures will be. Anthropic’s deprecations page records that the temperature
, top_p
and top_k
parameters are deprecated on Claude Opus 4.7 and later, and that passing a non-default value now returns a 400 error — a hard error, not a silent remap. OpenRouter’s ~latest
alias layer made the opposite choice for unsupported reasoning parameters: silent remapping, so that a repoint never breaks an existing caller. Hard-error-on-incompatibility is achievable platform design; where a vendor has chosen silence instead, your canary is the only thing that will shout.
Looking forward, our read is that the naming layer is converging on Anthropic’s pin-by-default pattern faster than the notice layer is converging on anything. Three vendors already ship a literal “latest” construct with three different contracts, and the spread between a two-week and a six-month floor is unlikely to close soon because it reflects genuinely different release cadences. A policy that assumes vendors will harmonize is a policy that will need rewriting; one that carries each vendor’s published figure as a cell in a grid only needs the cell updated. Cross-vendor routing decisions — which vendor’s contract a given automation should live under in the first place — are the kind of comparative evaluation our AI transformation engagements start with.
09 — ConclusionThe string is a pointer. Treat it like one. #
Pin the primary, name a fallback you have evaluated, and change only through a gate you own.
Floating aliases and retired aliases are one defect with two faces: a model name that was never an identity. The glm-latest listing and DeepSeek’s July 24 retirement showed each face within weeks of each other, and the vendor grid shows that the rules around them — naming, auto-update, notice, and what the response admits — differ on every axis across five vendors.
The policy that survives that variation is short. Pin concrete IDs for anything with a baseline. Keep one inventory with an owner per string. Detect by resolved-ID log where the response is honest and by canary where it is not, or where you cannot tell. Name an evaluated fallback. Move the primary only through a re-evaluation gate. Size every retirement runbook to the vendor’s published floor — 60 days, 6 months, 2 weeks, or none — and never to the hope of more.
None of this requires a platform decision. It requires one page, a table that is kept current, and an owner who reads vendor emails. That is a small price for an automation whose behavior you can still explain a year from now.