Skip to content

fix(providers): stop the Antigravity rename migration re-announcing itself on every boot - #5077

Merged
lidge-jun merged 2 commits into
devfrom
codex/antigravity-rename-migration-loop
Sep 19, 2026
Merged

lidge-jun merged 2 commits into
devfrom
codex/antigravity-rename-migration-loop

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Sep 18, 2026 •

Copy link
Copy Markdown
Owner

Summary

Starting the proxy with a google-antigravity provider printed the same nine
[model-rename-migration] renamed "google-antigravity/gemini-3.x-flash..." lines on every
single boot (#5066). The migration was not failing to persist; it was losing to the second half
of its own boot.

startServer runs runModelRenameStartupMigration and then reconcileOAuthProviders.
ANTIGRAVITY_MODEL_CONTEXT_WINDOWS derives a context window for every compatibility alias, so
the Antigravity OAuth preset carries a modelContextWindows key for all nine retired Flash ids
beside the live ones. The migration deleted those keys and wrote the config;
applyOAuthPresetCatalog then copied the preset's record straight back over them and wrote the
config again; the next boot found them and said so. That is also why the report shows nine
messages from a user who never selected nine models: the ids came from the registry, not from
anything they had chosen.

The fix is one guard in the projection, the mirror of the registrySeedsTarget check already in
that file. A field is skipped only when both of these hold:

  1. the registry's own seed (providerConfigSeed, the row both the OAuth preset and
    enrichProviderFromRegistry contribute) still publishes the retired id in that field, so the
    entry arrives in the config on its own; and
  2. the saved field already carries the supported id, so the rename would only delete a key,
    with no value left to carry forward.

The second condition is what keeps it narrow. A row that saved
modelContextWindows: { "gemini-3.6-flash": 1048576 } and nothing else still gets that value
moved onto gemini-3.7-flash, because dropping it there would blank the record instead of
moving it. The retired registry entries themselves are deliberate and stay put: a request that
still names gemini-3.6-flash routes to 3.7 and needs a window under the id it asked for.

Everything the user owns is unchanged. models, selectedModels, retainModels,
defaultModel and disabledModels are still renamed, and a user who has not started the proxy
since the rename shipped still gets the repair and still sees it reported -- once.

Deliberately not done: no new store, no unconditional silencing of the log, no change to which
aliases are retired, and no change to ANTIGRAVITY_MODEL_CONTEXT_WINDOWS itself (those windows
are pinned by tests/adapters/google/gemini-37-flash-migration.test.ts for a reason).

Closes #5066

Verification

No local suite was run: this checkout is under a no-local-execution rule after an earlier local
run destroyed the operator's real ~/.opencodex. Correctness rests on static tracing plus hosted
CI at the exact head.

  • Traced the loop end to end in source: src/server/index.ts (migration, then reconcile),
    src/providers/model-rename-migration.ts, src/oauth/index.ts (applyOAuthPresetCatalog,
    OAUTH_RECONCILE_FIELDS), src/providers/antigravity-models.ts, src/providers/derive.ts.
    modelContextWindows is the only reconciled field the preset publishes keyed by a retired id,
    which is exactly the nine messages reported.
  • Confirmed enrichProviderFromRegistry is all-or-nothing for modelContextWindows and that
    loadConfig does not enrich at all, so the writer between the two boots is reconciliation.
  • Confirmed the guard is inert for the two Alibaba renames: qwen3.8-max-preview appears nowhere
    in src/ outside the rename table, so [Bug] Registry model renames never reach existing key-auth provider configs (qwen3.8-max-preview persists) #1610 coverage is untouched.
  • Added three tests in tests/providers/model-rename-migration.test.ts (basename already
    registered in scripts/test-layout/layout.json and tests/fixtures/test-layout-expected.json,
    so no layout change is needed):
    • a two-boot fixture against a temp OPENCODEX_HOME: save a synthetic Antigravity config, run
      migrate-then-reconcile, assert reconciliation put the retired keys on disk, then assert the
      second boot renames nothing and prints nothing. Red on dev at that last assertion.
    • the intended asymmetry: a registry-published id stays in metadata while a stale
      selectedModels entry is still repaired and still reported once.
    • the general invariant, table-driven over every shipped rename: a provider row built by
      providerConfigSeed must never be something the migration wants to rewrite. Red on dev for
      all nine Antigravity renames.
  • The first push of this branch had a broader guard; test 4/4 caught that it also skipped a row
    saving only the retired key, which is the case that must still be migrated. That is the second
    condition above, and gemini-37-flash-migration.test.ts:211 is the regression test for it.
  • File-size ratchet: neither changed file is tracked in tests/fixtures/file-size-baseline.json,
    and the test file is 418 lines against the 2000-line threshold for untracked files.
  • Branch is cut from origin/dev at 6044a9a.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed. (No user-facing behavior change beyond a log
    line that stops repeating; nothing in docs-site/ describes it.)
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults. (No auth,
    credential or workflow surface is touched; the change narrows which config fields a startup
    migration rewrites.)

Summary by CodeRabbit

  • Bug Fixes
    • Fixed repeated model metadata migrations after provider reconciliation.
    • Retired model identifiers are now repaired when user-selected, while supported registry-provided metadata remains intact.
    • Prevented migrations from repeatedly reporting changes across application restarts.

…tself

The rename migration and the OAuth preset reconciliation disagreed about
nine retired Antigravity Flash ids, and startServer runs both, in that
order. ANTIGRAVITY_MODEL_CONTEXT_WINDOWS derives a window for every
compatibility alias, so the google-antigravity preset carries a
modelContextWindows key for each retired id. The migration renamed those
keys and persisted, applyOAuthPresetCatalog copied the preset's record
back over them in the same boot, and the next start found them again:
nine [model-rename-migration] lines on every ocx start, for a user who
never selected any of those nine models.

Skip a field the registry's own seed still publishes keyed by the retired
id. Those entries are deliberate (a request naming gemini-3.6-flash routes
to 3.7 and needs a window under the id it asked for), and reconciliation
owns that record anyway, so the migration has nothing to repair there.
Every field the user owns (models, selectedModels, retainModels,
defaultModel, disabledModels) is still renamed and still reported once.

Closes #5066
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 18, 2026 18:05
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-18T18:09:31.769257Z 1dfc1f3 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown
Contributor

✅ Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Sep 18, 2026
@coderabbitai

coderabbitai Bot commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 8794c052-f72c-4770-9378-dee6681aef43

📥 Commits

Reviewing files that changed from the base of the PR and between 6044a9a and 952bac6.

📒 Files selected for processing (2)
  • src/providers/model-rename-migration.ts
  • tests/providers/model-rename-migration.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

The migration now skips registry-seeded retired IDs when the saved field already contains the replacement ID. Regression tests cover repeated startup, user-selected IDs, registry-published metadata, and all shipped renames.

Changes

Model rename migration

Layer / File(s) Summary
Skip registry-seeded metadata
src/providers/model-rename-migration.ts
The migration imports providerConfigSeed, identifies registry-published IDs, and skips residue in MODEL_ID_LISTS and MODEL_KEYED_RECORDS fields. User-selected retired IDs remain eligible for replacement.
Validate startup convergence
tests/providers/model-rename-migration.test.ts
Tests cover migrate-then-reconcile startup order, user-selected model repair, preserved registry metadata, and every shipped model rename. They verify that repeated boots produce no new rename warnings.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 952ba

The migration preserves registry compatibility metadata while continuing to repair user-selected retired IDs, with no remaining actionable risk identified.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.78% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Issue #5066 requires the Antigravity Flash aliases to remap to gemini-3.7-flash and to stop producing migration logs on every startup. src/providers/model-rename-migration.ts adds registrySeed, …
Out of Scope Changes check ✅ Passed The changed source logic directly addresses the reconciliation loop in issue #5066. The added tests exercise the startup sequence, registry residue, user-owned configuration, and the shipped rename ta…
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: preventing the Antigravity model rename migration from logging repeatedly on each boot.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1dfc1f303f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/providers/model-rename-migration.ts Outdated
Comment on lines +17 to +18
// replacement — and only in the fields the registry does not itself republish
// keyed by that retired id (see `registrySeededFields`, issue #5066). Everything

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Update the mapped structure contracts

This changes the startup/config-migration contract for the owned src/providers/ area, but the commit updates none of the documents mapped to that area in structure/INDEX.md (runtime.md, subagents.md, transports/inventory.md, providers-and-adapters.md, and providers/xai-grok.md). Update those documents in this change so the maintained architecture description records which registry-owned fields the rename migration intentionally leaves untouched.

AGENTS.md reference: src/AGENTS.md:L10-L11

Useful? React with 👍 / 👎.

Comment on lines 280 to 282
for (const field of MODEL_KEYED_RECORDS) {
if (registrySeeded.has(field)) continue;
const next = rename.dropReasoningEffortMap && field === "modelReasoningEffortMap"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Limit seed skips to rows that OAuth reconciliation owns

When a saved google-antigravity row has a non-oauth or legacy-absent authMode, reconcileOAuthProviders does not republish modelContextWindows, and enrichProviderFromRegistry only supplies that record when it is missing. Nevertheless, this unconditional skip treats the field as registry-owned merely because the seed contains the retired ID. For a row with defaultModel: "gemini-3.6-flash" and a user override such as modelContextWindows: {"gemini-3.6-flash": 262144}, the migration now changes the default to 3.7 but strands the override under 3.6, so routing falls back to the registry's 3.7 window. Restrict the skip to rows actually eligible for OAuth reconciliation, or distinguish the registry seed shape from user-owned values.

AGENTS.md reference: src/AGENTS.md:L7-L10

Useful? React with 👍 / 👎.

The first cut skipped any field the registry seed published keyed by the
retired id, which also skipped a row that saved only the retired key. That
row needs the value carried onto the supported id, and dropping it blanks
the record instead of moving it (test 4/4 caught it at
gemini-37-flash-migration.test.ts:211).

Require both conditions now: the registry seed still publishes the retired
id in the field, AND the saved field already carries the supported id, so
the rename would only delete a key reconciliation puts straight back. The
reporter's post-reconcile row satisfies both for all nine ids; a row with
just the retired key does not, and is still migrated and still reported.

@abhisheksharma2411 abhisheksharma2411 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diagnosis is the valuable part here and it's exactly right — this was never a persistence failure, it was two boot phases disagreeing. runModelRenameStartupMigration deletes the keys, reconcileOAuthProviders → applyOAuthPresetCatalog copies the preset's record straight back, and the next boot finds them again. A migration that loses to the second half of its own boot is a genuinely hard thing to see from the symptom, and "nine messages from a user who never selected nine models" is the tell that makes it obvious in hindsight.

Traced the root cause to confirm the premise rather than take it on trust, and it holds:

export const ANTIGRAVITY_MODEL_CONTEXT_WINDOWS = {
  "gemini-3.8-flash": …, "gemini-3.7-flash": …, "gemini-3.1-pro": …,
  ...ANTIGRAVITY_WIRE_MODEL_CONTEXT_WINDOWS,
  ...Object.fromEntries(Object.entries(ANTIGRAVITY_MODEL_ALIASES).map(…)),   // <- every alias
};

export const ANTIGRAVITY_MODEL_ALIASES = {
  ...ANTIGRAVITY_VISIBLE_MODEL_ALIASES,
  ...ANTIGRAVITY_COMPATIBILITY_MODEL_ALIASES,   // <- includes the retired ids
};

So the seed publishes a window for every compatibility alias, retired ones included, which is precisely why the delete can never converge.

Worth noting the sibling map does not do this. ANTIGRAVITY_MODEL_INPUT_MODALITIES, twenty lines below, lists live ids explicitly and derives nothing. Two maps describing the same model set, one curated and one derived-over-all-aliases — that asymmetry is the root cause, and it'll produce the next instance of this bug in whatever field gets added next.

I'd still land this rather than chase that, and I think the PR chose correctly: narrowing ANTIGRAVITY_MODEL_CONTEXT_WINDOWS to live ids would strip the window from requests that still use a retired alias, which is a behaviour change on the request path to fix a logging and config-churn problem. Suppressing at the migration is the smaller blast radius. But it's worth a line in the code or the issue saying the derivation is the upstream cause, so the next person doesn't re-derive the whole diagnosis.

On isRegistryResidue itself: requiring both conditions — registry still publishes the retired id, and the saved field already carries the supported id — is the right pair. It also self-heals: the day the registry stops seeding a retired alias, publishes goes false, the migration resumes, and the key finally gets cleaned up without anyone revisiting this function. Worth saying that in the doc comment, because "skip the rename" reads like a permanent exemption and it isn't.

140 lines of test for 55 lines of fix is the right ratio for a boot-path migration.

@lidge-jun
lidge-jun merged commit 735f915 into dev Sep 19, 2026
35 of 38 checks passed
@lidge-jun
lidge-jun deleted the codex/antigravity-rename-migration-loop branch September 19, 2026 02:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants