diff --git a/backend/apps/settings/store.py b/backend/apps/settings/store.py index 29a5976e..c918a24b 100644 --- a/backend/apps/settings/store.py +++ b/backend/apps/settings/store.py @@ -84,6 +84,9 @@ def migrate_legacy_fields(raw: dict) -> dict: if raw.get("connection_mode") == "free-trial": raw["connection_mode"] = "own_key" raw.pop("free_trial_token", None) + # The free lane's forced Haiku default must not outlive the lane (ENG-343): dropping the field lets the real default take over. + if raw.get("default_model") == "haiku": + raw.pop("default_model", None) return raw diff --git a/frontend/src/app/Main.tsx b/frontend/src/app/Main.tsx index 68511b0c..ef3dd910 100644 --- a/frontend/src/app/Main.tsx +++ b/frontend/src/app/Main.tsx @@ -376,6 +376,9 @@ const DefaultModelGuard: React.FC<{ children: React.ReactNode }> = ({ children } const currentExists = flat.some((m) => m.value === settings.default_model); if (currentExists) return; + // Nothing real connected means the synthesized free row is the whole list; persisting it would brand haiku as the user's default forever (ENG-343). + if (!flat.some((m) => m.billing_kind !== 'free')) return; + const fallback = pickFallbackModel(byProvider); if (!fallback || fallback.value === settings.default_model) return;