{"course":{"slug":"building-with-ai","title":"Building with AI","url":"https://addaly.com/learn/building-with-ai","level":"intermediate","track":"build"},"lesson":{"slug":"deprecations-and-the-pinning-problem","title":"Deprecations and the pinning problem","url":"https://addaly.com/learn/building-with-ai/deprecations-and-the-pinning-problem","position":79,"of":80,"minutes":8,"answer":"An undated model alias changes behaviour silently whenever the provider ships a new version, and dated snapshots retire on a published schedule, so production pins a snapshot, a quarterly check reads the deprecation page.","keyIdea":"An undated model alias changes behaviour silently whenever the provider ships a new version, and dated snapshots retire on a published schedule, so production pins a snapshot, a quarterly check reads the deprecation page, and every upgrade goes through the harness, shadow and canary before the provider's date forces it."},"body":{"format":"markdown","text":"## Models retire\n\nEvery provider retires models. The notice is typically six to twelve months, occasionally less, and on the date the endpoint returns an error. Each provider publishes a page listing what retires when. Almost nobody reads it until the error arrives, usually at an inconvenient hour, in production, on the feature nobody has touched in a year because it was working.\n\n## Aliases and snapshots\n\nProviders offer two kinds of model name. A dated snapshot (something like `model-2026-03-15`) is a fixed set of weights that behaves the same today and next month. An alias (`model-latest`, or an undated name) resolves to whatever the provider currently considers that model, and changes when they ship a new version.\n\nAn alias changes behaviour silently. The new version refuses slightly different things, formats JSON slightly differently, writes longer answers, calls tools with a different style. The harness goes red on a Tuesday with no commit; or, if nobody ran it, the feature degrades quietly and the first sign is a complaint. The shipping lesson made model changes go through the same process as prompt changes; an alias bypasses that process by design.\n\n## Pin in production, upgrade on purpose\n\nProduction uses a dated snapshot. So does the harness, so that a red run means something changed on your side. The upgrade to a newer snapshot is a change: run the harness on the candidate, fix the prompt divergences with per-model overrides, shadow it, canary it, flip the flag. Record the pinned snapshot's retirement date in the same configuration file as its name, so the two are never separated.\n\n## The calendar\n\nOnce a quarter, someone reads the deprecation pages for every provider in use and, for each pinned snapshot, writes down the months remaining. Under three months, the migration starts. That is enough time for the harness to show what broke, for the prompt fixes, for a week of shadow and a week of canary, with slack for the surprise that always turns up.\n\n## The cost of skipping it\n\nThe migration happens anyway, on the provider's date, under pressure. The harness fails on a fifth of cases against the replacement model, the prompt fixes are made in an afternoon without shadow or canary, and the product ships a behaviour change nobody evaluated. Or the migration does not happen, and the endpoint returns an error at two in the morning, and the fallback chain from the last lesson (if it exists) is what the users get for a week.\n\n## Keep prompts portable where it is cheap\n\nSome prompts lean on one model's quirks: a particular tag format it happens to emit, a refusal phrase the code matches by string, an assumption that it always returns a list in a certain shape. Each of these is a migration cost waiting to be paid. Prefer structured output over parsing prose. Show the format with an example rather than assuming the model knows it. Check stop reasons and usage through the abstraction layer's normalised fields rather than provider-specific strings. None of this makes migration free; it makes it a week rather than a month.\n\n## Embedding models retire too, and that is worse\n\nWhen a chat model retires, you change a name and re-run the harness. When an embedding model retires, every vector in the index was produced by it and is incompatible with any replacement. The retrieval module told you to store the model name with each vector and to keep the raw chunk text: this is the day that pays off. The migration is a full re-embed (five million tokens at ten cents on a hosted model, or a few hours on a CPU) followed by a re-run of the retrieval gold set, because recall will have moved. Budget it, and schedule it before the date, not on it.\n\n## Fine-tunes are pinned to their base\n\nA model you fine-tuned sits on a base model, and when the base retires, the fine-tune goes with it. Keep the training data and the recipe in version control, so retraining on the new base is a job rather than an archaeology project.\n\n> Figure: A model retirement, handled on your calendar rather than theirs. Timeline: Announcement, The provider publishes a retirement date for the pinned snapshot, typically six to twelve months out, on a page almost nobody reads; Nine months out, The quarterly check writes the months remaining beside the snapshot name, in the same configuration file, so the two are never separated; Three months out, Migration begins: the harness runs against the candidate snapshot and prints exactly which cases the new weights break; Two months out, Divergences fixed as per-model overrides rather than a forked prompt, then a week of shadow against real traffic; Six weeks out, A week of sticky canary with a stopping rule, then the flag is flipped and the new snapshot's own retirement date is recorded; Retirement day, Nothing happens, because production moved six weeks ago. The same work happens either way. Done on this schedule it is a fortnight of ordinary process; done on the provider's date it is an afternoon of prompt fixes with no shadow, no canary and a behaviour change nobody evaluated.\n\n## Where the list lives\n\nThe one-page feature record from the safety module already lists model versions. Add the retirement date beside each. The quarterly check is then a read of that page against the providers' pages, ten minutes, and the difference between an upgrade you planned and one that was done to you."},"check":{"question":"A feature that has run unchanged for months starts producing longer answers and occasional refusals, with no deployment. The model is configured as an undated alias. What happened?","options":[{"text":"The provider shipped a new version under the same alias, and its behaviour differs from the one the prompts were tuned against.","correct":true},{"text":"The prompt cache expired and the model is now reading the system prompt fresh, which changes its behaviour.","correct":false,"tempting":"A cache miss changes cost and latency, never the content of the response."},{"text":"Accumulated conversation history has grown past the trimming budget and is pushing the system prompt out of context.","correct":false,"tempting":"Trimming keeps the system prompt by rule, and history is per conversation, not something that accumulates across months."},{"text":"The evaluation harness drifted and is now flagging behaviour that was always present.","correct":false,"tempting":"The symptoms were noticed in production output, not in the harness; the behaviour itself changed."}]},"prev":{"slug":"outages-and-switching-providers","title":"Outages, fallbacks and what does not port","url":"https://addaly.com/learn/building-with-ai/outages-and-switching-providers"},"next":{"slug":"one-feature-end-to-end","title":"One feature, end to end, with every number filled in","url":"https://addaly.com/learn/building-with-ai/one-feature-end-to-end"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'Deprecations and the pinning problem', in Building with AI. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/building-with-ai/deprecations-and-the-pinning-problem (Accessed: 13 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"Deprecations and the pinning problem","courseTitle":"Building with AI","module":{"index":8,"slug":"cost-latency-and-running-it","title":"Cost, latency and running it in production"},"answer":null,"keyIdea":"An undated model alias changes behaviour silently whenever the provider ships a new version, and dated snapshots retire on a published schedule, so production pins a snapshot, a quarterly check reads the deprecation page, and every upgrade goes through the harness, shadow and canary before the provider’s date forces it.","hero":{"kind":"figure","figure":{"t":"figure","label":"Figure","figure":{"type":"timeline","title":"A model retirement, handled on your calendar rather than theirs","events":[{"when":"Announcement","what":"The provider publishes a retirement date for the pinned snapshot, typically six to twelve months out, on a page almost nobody reads"},{"when":"Nine months out","what":"The quarterly check writes the months remaining beside the snapshot name, in the same configuration file, so the two are never separated"},{"when":"Three months out","what":"Migration begins: the harness runs against the candidate snapshot and prints exactly which cases the new weights break"},{"when":"Two months out","what":"Divergences fixed as per-model overrides rather than a forked prompt, then a week of shadow against real traffic"},{"when":"Six weeks out","what":"A week of sticky canary with a stopping rule, then the flag is flipped and the new snapshot’s own retirement date is recorded"},{"when":"Retirement day","what":"Nothing happens, because production moved six weeks ago"}],"caption":"The same work happens either way. Done on this schedule it is a fortnight of ordinary process; done on the provider’s date it is an afternoon of prompt fixes with no shadow, no canary and a behaviour change nobody evaluated."},"alt":"Figure: A model retirement, handled on your calendar rather than theirs. Timeline: Announcement, The provider publishes a retirement date for the pinned snapshot, typically six to twelve months out, on a page almost nobody reads; Nine months out, The quarterly check writes the months remaining beside the snapshot name, in the same configuration file, so the two are never separated; Three months out, Migration begins: the harness runs against the candidate snapshot and prints exactly which cases the new weights break; Two months out, Divergences fixed as per-model overrides rather than a forked prompt, then a week of shadow against real traffic; Six weeks out, A week of sticky canary with a stopping rule, then the flag is flipped and the new snapshot’s own retirement date is recorded; Retirement day, Nothing happens, because production moved six weeks ago. The same work happens either way. Done on this schedule it is a fortnight of ordinary process; done on the provider’s date it is an afternoon of prompt fixes with no shadow, no canary and a behaviour change nobody evaluated."}},"blocks":[{"t":"h2","id":"models-retire","runs":[{"text":"Models retire"}]},{"t":"p","runs":[{"text":"Every provider retires models. The notice is typically six to twelve months, occasionally less, and on the date the endpoint returns an error. Each provider publishes a page listing what retires when. Almost nobody reads it until the error arrives, usually at an inconvenient hour, in production, on the feature nobody has touched in a year because it was working."}]},{"t":"h2","id":"aliases-and-snapshots","runs":[{"text":"Aliases and snapshots"}]},{"t":"p","runs":[{"text":"Providers offer two kinds of model name. A dated snapshot (something like "},{"text":"model-2026-03-15","code":true},{"text":") is a fixed set of weights that behaves the same today and next month. An alias ("},{"text":"model-latest","code":true},{"text":", or an undated name) resolves to whatever the provider currently considers that model, and changes when they ship a new version."}]},{"t":"p","runs":[{"text":"An alias changes behaviour silently. The new version refuses slightly different things, formats JSON slightly differently, writes longer answers, calls tools with a different style. The harness goes red on a Tuesday with no commit; or, if nobody ran it, the feature degrades quietly and the first sign is a complaint. The shipping lesson made model changes go through the same process as prompt changes; an alias bypasses that process by design."}]},{"t":"h2","id":"pin-in-production-upgrade-on-purpose","runs":[{"text":"Pin in production, upgrade on purpose"}]},{"t":"p","runs":[{"text":"Production uses a dated snapshot. So does the harness, so that a red run means something changed on your side. The upgrade to a newer snapshot is a change: run the harness on the candidate, fix the prompt divergences with per-model overrides, shadow it, canary it, flip the flag. Record the pinned snapshot’s retirement date in the same configuration file as its name, so the two are never separated."}]},{"t":"h2","id":"the-calendar","runs":[{"text":"The calendar"}]},{"t":"p","runs":[{"text":"Once a quarter, someone reads the deprecation pages for every provider in use and, for each pinned snapshot, writes down the months remaining. Under three months, the migration starts. That is enough time for the harness to show what broke, for the prompt fixes, for a week of shadow and a week of canary, with slack for the surprise that always turns up."}]},{"t":"h2","id":"the-cost-of-skipping-it","runs":[{"text":"The cost of skipping it"}]},{"t":"p","runs":[{"text":"The migration happens anyway, on the provider’s date, under pressure. The harness fails on a fifth of cases against the replacement model, the prompt fixes are made in an afternoon without shadow or canary, and the product ships a behaviour change nobody evaluated. Or the migration does not happen, and the endpoint returns an error at two in the morning, and the fallback chain from the last lesson (if it exists) is what the users get for a week."}]},{"t":"h2","id":"keep-prompts-portable-where-it-is-cheap","runs":[{"text":"Keep prompts portable where it is cheap"}]},{"t":"p","runs":[{"text":"Some prompts lean on one model’s quirks: a particular tag format it happens to emit, a refusal phrase the code matches by string, an assumption that it always returns a list in a certain shape. Each of these is a migration cost waiting to be paid. Prefer structured output over parsing prose. Show the format with an example rather than assuming the model knows it. Check stop reasons and usage through the abstraction layer’s normalised fields rather than provider-specific strings. None of this makes migration free; it makes it a week rather than a month."}]},{"t":"h2","id":"embedding-models-retire-too-and-that-is-worse","runs":[{"text":"Embedding models retire too, and that is worse"}]},{"t":"p","runs":[{"text":"When a chat model retires, you change a name and re-run the harness. When an embedding model retires, every vector in the index was produced by it and is incompatible with any replacement. The retrieval module told you to store the model name with each vector and to keep the raw chunk text: this is the day that pays off. The migration is a full re-embed (five million tokens at ten cents on a hosted model, or a few hours on a CPU) followed by a re-run of the retrieval gold set, because recall will have moved. Budget it, and schedule it before the date, not on it."}]},{"t":"h2","id":"fine-tunes-are-pinned-to-their-base","runs":[{"text":"Fine-tunes are pinned to their base"}]},{"t":"p","runs":[{"text":"A model you fine-tuned sits on a base model, and when the base retires, the fine-tune goes with it. Keep the training data and the recipe in version control, so retraining on the new base is a job rather than an archaeology project."}]},{"t":"h2","id":"where-the-list-lives","runs":[{"text":"Where the list lives"}]},{"t":"p","runs":[{"text":"The one-page feature record from the safety module already lists model versions. Add the retirement date beside each. The quarterly check is then a read of that page against the providers’ pages, ten minutes, and the difference between an upgrade you planned and one that was done to you."}]}],"check":{"question":[{"text":"A feature that has run unchanged for months starts producing longer answers and occasional refusals, with no deployment. The model is configured as an undated alias. What happened?"}],"options":[{"text":[{"text":"The provider shipped a new version under the same alias, and its behaviour differs from the one the prompts were tuned against."}],"correct":true,"tempting":null},{"text":[{"text":"The prompt cache expired and the model is now reading the system prompt fresh, which changes its behaviour."}],"correct":false,"tempting":[{"text":"A cache miss changes cost and latency, never the content of the response."}]},{"text":[{"text":"Accumulated conversation history has grown past the trimming budget and is pushing the system prompt out of context."}],"correct":false,"tempting":[{"text":"Trimming keeps the system prompt by rule, and history is per conversation, not something that accumulates across months."}]},{"text":[{"text":"The evaluation harness drifted and is now flagging behaviour that was always present."}],"correct":false,"tempting":[{"text":"The symptoms were noticed in production output, not in the harness; the behaviour itself changed."}]}],"order":[2,1,3,0],"why":null},"prev":{"slug":"outages-and-switching-providers","title":"Outages, fallbacks and what does not port","minutes":9},"next":{"slug":"one-feature-end-to-end","title":"One feature, end to end, with every number filled in","minutes":12}}}