From 67c2cfddf49475cdce5e897d2ec7f4c8718c6740 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 21 Feb 2026 02:22:45 +0900 Subject: [PATCH] fix(migration): remove non-existent gpt-5.3-codex from MODEL_VERSION_MAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #1804, fixes #1962 The migration entry 'gpt-5.2-codex → gpt-5.3-codex' caused the plugin to silently overwrite user configs on every startup with a model that doesn't exist in the OpenAI API. Users explicitly setting gpt-5.2-codex (the correct current model) were forced to revert their config manually every session. --- src/shared/migration.test.ts | 76 +++++++++++++------------- src/shared/migration/model-versions.ts | 1 - 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/src/shared/migration.test.ts b/src/shared/migration.test.ts index 42ebd2028..7846cc725 100644 --- a/src/shared/migration.test.ts +++ b/src/shared/migration.test.ts @@ -441,7 +441,7 @@ describe("migrateConfigFile", () => { expect(rawConfig.disabled_hooks).toContain("anthropic-context-window-limit-recovery") }) - test("migrates model versions in agents", () => { + test("does not migrate gpt-5.2-codex model versions in agents", () => { // given: Config with old model version in agents const rawConfig: Record = { agents: { @@ -452,10 +452,10 @@ describe("migrateConfigFile", () => { // when: Migrate config file const needsWrite = migrateConfigFile(testConfigPath, rawConfig) - // then: Model version should be migrated - expect(needsWrite).toBe(true) + // then: Model version should remain unchanged + expect(needsWrite).toBe(false) const agents = rawConfig.agents as Record> - expect(agents["sisyphus"].model).toBe("openai/gpt-5.3-codex") + expect(agents["sisyphus"].model).toBe("openai/gpt-5.2-codex") }) test("migrates model versions in categories", () => { @@ -479,7 +479,7 @@ describe("migrateConfigFile", () => { // given: Config with current model versions const rawConfig: Record = { agents: { - sisyphus: { model: "openai/gpt-5.3-codex" }, + sisyphus: { model: "openai/gpt-5.2-codex" }, }, categories: { "my-category": { model: "anthropic/claude-opus-4-6" }, @@ -514,10 +514,10 @@ describe("migration maps", () => { }) describe("MODEL_VERSION_MAP", () => { - test("maps openai/gpt-5.2-codex to openai/gpt-5.3-codex", () => { + test("does not include openai/gpt-5.2-codex migration", () => { // given/when: Check MODEL_VERSION_MAP - // then: Should contain correct mapping - expect(MODEL_VERSION_MAP["openai/gpt-5.2-codex"]).toBe("openai/gpt-5.3-codex") + // then: openai/gpt-5.2-codex should not be migrated + expect(MODEL_VERSION_MAP["openai/gpt-5.2-codex"]).toBeUndefined() }) test("maps anthropic/claude-opus-4-5 to anthropic/claude-opus-4-6", () => { @@ -528,8 +528,8 @@ describe("MODEL_VERSION_MAP", () => { }) describe("migrateModelVersions", () => { - test("replaces old model string in agent config", () => { - // given: Agent config with old model version + test("#given a config with gpt-5.2-codex model #when migrating model versions #then does not overwrite with non-existent gpt-5.3-codex", () => { + // given: Agent config with gpt-5.2-codex model const agents = { sisyphus: { model: "openai/gpt-5.2-codex", temperature: 0.1 }, } @@ -537,10 +537,10 @@ describe("migrateModelVersions", () => { // when: Migrate model versions const { migrated, changed } = migrateModelVersions(agents) - // then: Model should be updated, other fields preserved - expect(changed).toBe(true) + // then: Model should remain unchanged + expect(changed).toBe(false) const sisyphus = migrated["sisyphus"] as Record - expect(sisyphus.model).toBe("openai/gpt-5.3-codex") + expect(sisyphus.model).toBe("openai/gpt-5.2-codex") expect(sisyphus.temperature).toBe(0.1) }) @@ -615,7 +615,7 @@ describe("migrateModelVersions", () => { // then: Only mapped models should be updated expect(changed).toBe(true) - expect((migrated["sisyphus"] as Record).model).toBe("openai/gpt-5.3-codex") + expect((migrated["sisyphus"] as Record).model).toBe("openai/gpt-5.2-codex") expect((migrated["prometheus"] as Record).model).toBe("anthropic/claude-opus-4-6") expect((migrated["oracle"] as Record).model).toBe("openai/gpt-5.2") }) @@ -658,11 +658,11 @@ describe("migrateModelVersions", () => { // when: Migrate without applied migrations const { migrated, changed, newMigrations } = migrateModelVersions(agents) - // then: Migration applied and recorded - expect(changed).toBe(true) - expect(newMigrations).toEqual(["model-version:openai/gpt-5.2-codex->openai/gpt-5.3-codex"]) + // then: No migration should be applied for gpt-5.2-codex + expect(changed).toBe(false) + expect(newMigrations).toEqual([]) const sisyphus = migrated["sisyphus"] as Record - expect(sisyphus.model).toBe("openai/gpt-5.3-codex") + expect(sisyphus.model).toBe("openai/gpt-5.2-codex") }) test("handles mixed: some applied, some new", () => { @@ -692,10 +692,10 @@ describe("migrateModelVersions", () => { // when: Migrate without the param (backward compat) const { migrated, changed, newMigrations } = migrateModelVersions(agents) - // then: Should still migrate normally - expect(changed).toBe(true) - expect(newMigrations).toHaveLength(1) - expect((migrated["sisyphus"] as Record).model).toBe("openai/gpt-5.3-codex") + // then: Should keep gpt-5.2-codex unchanged + expect(changed).toBe(false) + expect(newMigrations).toHaveLength(0) + expect((migrated["sisyphus"] as Record).model).toBe("openai/gpt-5.2-codex") }) }) @@ -713,9 +713,9 @@ describe("migrateConfigFile _migrations tracking", () => { // when: Migrate config file const result = migrateConfigFile(configPath, rawConfig) - // then: _migrations should be recorded - expect(result).toBe(true) - expect(rawConfig._migrations).toEqual(["model-version:openai/gpt-5.2-codex->openai/gpt-5.3-codex"]) + // then: gpt-5.2-codex should not produce migrations + expect(result).toBe(false) + expect(rawConfig._migrations).toBeUndefined() // cleanup fs.rmSync(tmpDir, { recursive: true }) @@ -1163,10 +1163,10 @@ describe("migrateModelVersions with applied migrations", () => { // when: Migrate model versions const { migrated, changed, newMigrations } = migrateModelVersions(configs, appliedMigrations) - // then: Migration should be applied - expect(changed).toBe(true) - expect(newMigrations).toEqual(["model-version:openai/gpt-5.2-codex->openai/gpt-5.3-codex"]) - expect((migrated.sisyphus as Record).model).toBe("openai/gpt-5.3-codex") + // then: gpt-5.2-codex should not be migrated + expect(changed).toBe(false) + expect(newMigrations).toEqual([]) + expect((migrated.sisyphus as Record).model).toBe("openai/gpt-5.2-codex") }) test("handles mixed: skip applied, apply new", () => { @@ -1196,16 +1196,16 @@ describe("migrateModelVersions with applied migrations", () => { // when: Migrate model versions (without appliedMigrations) const { migrated, changed, newMigrations } = migrateModelVersions(configs) - // then: Migration should be applied (backward compatible) - expect(changed).toBe(true) - expect(newMigrations).toEqual(["model-version:openai/gpt-5.2-codex->openai/gpt-5.3-codex"]) - expect((migrated.sisyphus as Record).model).toBe("openai/gpt-5.3-codex") + // then: gpt-5.2-codex remains unchanged + expect(changed).toBe(false) + expect(newMigrations).toEqual([]) + expect((migrated.sisyphus as Record).model).toBe("openai/gpt-5.2-codex") }) test("returns empty newMigrations when no migrations applied", () => { // given: Config with no old models const configs = { - sisyphus: { model: "openai/gpt-5.3-codex" }, + sisyphus: { model: "openai/gpt-5.2-codex" }, } // when: Migrate model versions @@ -1244,10 +1244,10 @@ describe("migrateConfigFile with _migrations tracking", () => { // when: Migrate config file const needsWrite = migrateConfigFile(testConfigPath, rawConfig) - // then: _migrations field should be added - expect(needsWrite).toBe(true) - expect(rawConfig._migrations).toEqual(["model-version:openai/gpt-5.2-codex->openai/gpt-5.3-codex"]) - expect((rawConfig.agents as Record>).sisyphus.model).toBe("openai/gpt-5.3-codex") + // then: gpt-5.2-codex should not create migration history + expect(needsWrite).toBe(false) + expect(rawConfig._migrations).toBeUndefined() + expect((rawConfig.agents as Record>).sisyphus.model).toBe("openai/gpt-5.2-codex") }) test("skips re-applying already-recorded migrations", () => { diff --git a/src/shared/migration/model-versions.ts b/src/shared/migration/model-versions.ts index 7f24b6983..b3df8cdd2 100644 --- a/src/shared/migration/model-versions.ts +++ b/src/shared/migration/model-versions.ts @@ -6,7 +6,6 @@ * Keys are full "provider/model" strings. Only openai and anthropic entries needed. */ export const MODEL_VERSION_MAP: Record = { - "openai/gpt-5.2-codex": "openai/gpt-5.3-codex", "anthropic/claude-opus-4-5": "anthropic/claude-opus-4-6", "anthropic/claude-sonnet-4-5": "anthropic/claude-sonnet-4-6", }