Welcome back! In the previous chapter, State Migration and Evolution, we learned how to move data from old formats to new ones.
However, moving data isn't always a "one size fits all" operation. Sometimes, a change should only happen for Pro users. Other times, it should only apply to internal employees.
In this chapter, we will learn how to write Gatesβlogic that checks who the user is before applying a migration.
Imagine a high-end nightclub with different rooms:
If the club decides to upgrade the furniture in the VIP Lounge, they shouldn't force everyone on the Main Floor to move.
The Use Case: We want to upgrade users from the model "Sonnet 4.5" to "Sonnet 4.6".
To make these decisions, we check specific "ID Cards" that the application holds.
A "Gate" is simply an if statement at the very top of your migration function. If the condition isn't met, we return immediately (do nothing).
The most common check is ensuring we only modify settings for First Party users.
import { getAPIProvider } from '../utils/model/providers.js'
export function migrateMyFeature() {
// GATE: Check if the user is using our managed service
if (getAPIProvider() !== 'firstParty') {
// If they are using their own keys (3rd party), stop here.
return
}
// ... continue with migration
}
If a feature is exclusive to paid users, we check their subscription status.
import { isProSubscriber } from '../utils/auth.js'
export function upgradeToPremiumModel() {
// GATE: Check if the user pays for a subscription
if (!isProSubscriber()) {
// If they are a free user, stop here.
return
}
// ... upgrade them to the cool new model
}
Here is how the application decides whether to run a specific migration script.
Let's look at how we combine these checks in real files.
migrateSonnet45ToSonnet46.ts)In this file, we want to move users from an old model to a new one. This requires passing two gates.
Gate 1: The Provider Check
// From migrateSonnet45ToSonnet46.ts
export function migrateSonnet45ToSonnet46(): void {
// 1. Must be First Party. We don't touch 3rd party keys.
if (getAPIProvider() !== 'firstParty') {
return
}
// ... continues below
Gate 2: The Subscription Check We need to check if the user is Pro, Max, OR Team. Any of these allow access.
// 2. Must have a premium subscription
if (!isProSubscriber() && !isMaxSubscriber() && !isTeamPremiumSubscriber()) {
return
}
// ... continues to logic
The Logic: Changing the Setting Once past the gates, we proceed with the logic we learned in Chapter 2.
// 3. Only change it if they are currently on the specific old model
const model = getSettingsForSource('userSettings')?.model
if (model === 'claude-sonnet-4-5-20250929') {
updateSettingsForSource('userSettings', { model: 'sonnet' })
}
}
Note: We check the current model to ensure we don't accidentally overwrite a user who manually switched to something else entirely, like "Haiku".
migrateFennecToOpus.ts)Sometimes we have features that only exist for employees ("Ants"). We use environment variables to check this.
// From migrateFennecToOpus.ts
export function migrateFennecToOpus(): void {
// GATE: Only run for internal "Ant" users
if (process.env.USER_TYPE !== 'ant') {
return
}
// ... migrate internal test models to public ones
}
Why? Regular users don't have access to the USER_TYPE variable (or it is undefined), so this code is safely skipped for the public.
FirstParty AND ProSubscriber checks.User Segmentation acts as a safety filter. It ensures that the powerful state transformations we write are applied only to the users who need themβand are allowed to have them.
Now that we have verified the user's identity and updated their settings, we might run into a new problem: What happens if the name of a model changes (e.g., "claude-3-opus" becomes just "opus")?
In the next chapter, we will learn how the system handles these names dynamically.
Next Chapter: Model Alias Resolution
Generated by Code IQ