…b.js (#4161)
Migrations 032 -> 058 -> 153 -> 206 are four hand-copies of the same
"bump one seeded Claude provider tier" shell: exact-match the prior seeded
models list, rewrite it, swap every retired id wherever it appears, repair an
orphan tier pointer, skip anything customized. Only the data differs.
`makeSeededProviderTierMigration({ targets, tierLabel })` is that shell, so the
next bump is a small data table (prior models list + retired-id -> replacement
map per provider) rather than another ~200-line clone.
`runSeededProviderTierMigrationTests` in _testHelpers.js is its companion
runner, deriving every fixture from the migration's own targets table the way
`runPromptMigrationTests` does for the prompt-replace family.
The four shipped migrations are NOT rewritten to consume the factory - a
migration is the historical record of what it did to an install, and an applied
one must keep behaving exactly as documented. Instead 153 and 206 are re-expressed
as targets tables in a differential suite that runs each shipped migration
head-to-head against its factory-built equivalent over the same fixtures and
requires a byte-identical data/providers.json. The factory pays off starting
with the migration after 206.
Also extracts the data/providers.json read -> parse -> shape-guard preamble
that the provider-seed family already repeated into a shared `readProvidersDoc`,
with each family keeping its own log copy and result shape.
Summary
scripts/migrations/206-claude-default-opus-5.jswas the fourth hand-copy of the same "bump one seeded Claude provider tier" shell (032 → 058 → 153 → 206). All four exact-match the prior seededmodelslist, rewrite it, swap every retired model id wherever it appears (the list plus any of the four tier pointers), repair an orphan pointer left at a now-absent id, and skip anything the user curated. Only the data differs.makeSeededProviderTierMigration({ targets, tierLabel })inscripts/migrations/_lib.jsis that shell. A future bump becomes a small data table — per provider, the exact prior seededmodelsarray plus a retired-id → replacement map — instead of another ~200-line clone. Bedrock entries list the plain and[1m]ids separately so a long-context pin maps like-for-like rather than silently dropping a context tier. Resolves to{ ok, reason, touched, alreadyCurrent, customized }.runSeededProviderTierMigrationTests({ migration, targets, prefix })inscripts/migrations/_testHelpers.jsis its companion runner, mirroringrunPromptMigrationTests. Every fixture is derived from the migration's owntargetstable, so a bump's test file collapses to adescribe+ one call and still asserts the whole conservative contract (exact-match-only rewrites, like-for-like mapping of each retired id, still-current pointers preserved, orphan pointers repaired, byte-for-byte no-op on customized/current/absent/unparseable input).Migrations 032/058/153/206 are deliberately NOT rewritten to consume the factory. A migration is the historical record of what it did to an install, and an applied one must keep behaving exactly as documented. Instead, 153 and 206 are re-expressed as
targetstables inside a differential suite that runs each shipped migration head-to-head against its factory-built equivalent over the same fixtures and requires a byte-identicaldata/providers.json. That is what proves the factory reproduces their behavior without touching them. The factoring pays off starting with the migration after 206.Also folded in while there: the
data/providers.jsonread → parse → shape-guard preamble was duplicated between the existing provider-seed family and the new one, so it is now a shared privatereadProvidersDoc. Each family keeps its own log copy and result shape, so the six provider-seed migrations (149/152/185/195/201/231) are behaviorally unchanged — their existing suite asserts every reason path.Test plan
cd server && NODE_ENV=test npx vitest run ../scripts/— 247 files / 1802 tests pass.cd server && NODE_ENV=test npm test— full server suite green (1395 files, 29225 tests; the 26 DB-backed suites skip against the non-test database as designed)._lib.jsand reverted. Breaking the like-for-like pointer map failed 10 tests (including both Bedrock[1m]differential fixtures); making the factory silently decline to write failed 30. The differential test additionally asserts that the mutating fixtures really did change on disk and that the three no-op fixtures really did not, so "both migrations wrote nothing" can never pass as a match.Closes #4161