fix(codex): preserve routed models in desktop picker - #1244
Conversation
📝 WalkthroughWalkthroughThe PR adds opt-in native OpenAI aliases for combos. It updates validation, CLI and GUI editing, catalog routing and restoration, server visibility, localized documentation, and regression coverage. It also improves asynchronous socket-drain test synchronization. ChangesNative alias compatibility
Native profile socket drain test
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant CLI_or_GUI
participant ComboRoutes
participant CatalogSync
participant CatalogConvergence
participant CodexDesktop
CLI_or_GUI->>ComboRoutes: submit nativeAlias and displayName
ComboRoutes->>CatalogSync: persist normalized combo
CatalogSync->>CatalogConvergence: generate and recover catalog rows
CatalogConvergence->>CodexDesktop: expose routed alias and filtered native rows
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
|
✅ Deterministic PR hygiene checks passed. |
✅ READY
|
|
@codex review Please review this replacement PR against current |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
@coderabbitai review |
|
There was a problem hiding this comment.
Actionable comments posted: 25
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/maintainer-full-verify-1244.yml:
- Around line 3-6: Add a branch-scoped concurrency group to the workflow’s
top-level configuration so pushes to the same branch run serially. Update the
cleanup/removal step to tolerate the workflow already having been successfully
removed by an earlier run, while preserving normal failure reporting for other
errors.
- Around line 33-34: Update the high-severity dependency audit invoked by the
“High severity dependency audit” workflow step to also run `bun audit
--audit-level=high` from the `docs-site` directory, while preserving the
existing root and gui audits.
- Around line 16-21: Replace the mutable action references in the workflow’s
checkout and Bun setup steps with verified full commit SHA references, reusing
the corresponding SHA-pinned versions from the CI workflow while preserving
their existing configuration.
- Around line 8-9: The full verification job grants excessive repository write
access and persists checkout credentials. Change its permissions to contents:
read and configure actions/checkout with persist-credentials: false; move only
the trusted maintainer cleanup into a separate job with contents: write,
ensuring it does not execute repository-provided install, build, audit, or
verification code, and protect the maintainer/supersede-1056-native-alias branch
and its writers.
In `@docs-site/src/content/docs/zh-cn/guides/codex-app-models.md`:
- Around line 85-86: Update the native-alias behavior description in the Chinese
guide to state that shadowed bare native rows are omitted from the Models page
and have no native switch; only unshadowed native rows retain a switch and can
restore native metadata when re-enabled.
In `@gui/tests/combo-native-alias-editor.test.tsx`:
- Around line 86-95: Re-query the `#cwi-edit-display-name` input after
nativeAlias.click() and before calling setInputValue, while retaining the
existing pre-toggle expect(displayName).toBeTruthy() assertion. Use the
refreshed element for the post-toggle input event so the test targets the
current DetailPanel DOM node.
- Around line 96-98: Update ComboWorkspaceDetailPanel’s create and save action
buttons with stable selectors such as the specified IDs or data-testid
attributes, then revise the corresponding test queries around the create and
save clicks to use those selectors instead of rendered textContent.
In `@src/codex/catalog/aggregation.ts`:
- Around line 258-266: Update src/codex/catalog/aggregation.ts lines 258-266 in
the combo visibility logic to use only the canonical combo/<id> selector for
native-alias combos, while retaining the bare alias selector for native-row
visibility. Update src/codex/catalog/provider-fetch.ts lines 1199-1207 so native
target metadata remains available to native-alias combos when that bare alias is
disabled for the native row; add regression coverage for a disabled bare alias
with an openai/<alias> combo target.
In `@src/codex/catalog/metadata.ts`:
- Line 217: Update mergeCatalogEntriesForSync() so preserved native-alias
entries also pass through the exactComboCatalogSlugs() disabled-combo filtering
before or during the final merge. Ensure native aliases whose combo/<id> is in
disabledModels are removed from the transitory saved-route result instead of
remaining visible, while retaining enabled aliases.
In `@src/codex/catalog/sync.ts`:
- Around line 495-520: Update mergeCatalogModelsWithNativeRecovery to create a
fully independent clone of each recovered entry before adding it to merged,
replacing the selective supported_reasoning_levels copy. Use the existing
structured-clone mechanism available in the project so nested fields such as
input_modalities, service_tiers, and metadata cannot remain shared with
nativeRecoverySources.
- Around line 337-344: Update the nativeAliasesBySlug construction in the sync
flow to detect duplicate bare aliases among COMBO_NAMESPACE native aliases
instead of overwriting earlier models. Preserve the first occurrence for each
alias, add subsequent matching combo models to collisionSkipped, and ensure they
are excluded or warned consistently before routed aliases are emitted.
- Around line 662-665: Update the input_modalities filtering logic near the
preserved-entry check to retain bare native aliases whose slug is present in
exactComboSlugs, even when input_modalities is missing or empty. Ensure this
retention is applied consistently with retainedNativeAlias so these rows are not
dropped during disk-loaded catalog filtering.
- Line 976: Update buildCatalogEntries() to exclude suppressedBareNativeSlugs
from nativeEntries before creating account-bound selector/native-slug clones,
preventing disabled desktop-hidden native slugs from being emitted with list
visibility. Ensure clones for slugs removed from suppression are restored before
applyNativeVisibility() runs, while preserving existing behavior for
unsuppressed native entries.
In `@src/codex/convergence.ts`:
- Around line 186-195: Replace the intermediate preservedNativeAliases array
with direct construction of preservedNativeAliasSlugs from active.models,
retaining the existing preservingExistingRouted guard and both predicates. Leave
the independently pushed-row logic unchanged.
In `@src/server/management/combo-routes.ts`:
- Around line 127-138: Update the PUT response in the combo route to return the
persisted `stored` object instead of the pre-strip `normalized` object, while
preserving the existing storage behavior in the normalization block. This keeps
PUT responses consistent with GET responses and ensures both use the same
key-omitting shape.
In `@tests/codex-catalog.test.ts`:
- Line 424: Loosen the warning assertion in the test around the preservation
case so it checks only the stable message portion, such as the preservation
count and context, rather than exact singular wording. Update the expect call
for warning to avoid coupling it to pluralization while still verifying that one
existing routed entry is preserved.
- Around line 769-816: Update the native-alias assertions in the test to derive
context windows, input modalities, reasoning efforts, and default reasoning
efforts from the native snapshot helpers used by completeNativeAliasMembers,
including nativeOpenAiContextWindow, nativeInputModalities, and
nativeReasoningEfforts. Assert that each alias inherits those source values
rather than duplicating literals, while preserving the existing alias-specific
expectations.
- Around line 351-367: Refactor the test setup around mergeCatalogEntriesForSync
so this 15-argument call uses a test-local helper with named options. Ensure
disabledModels, goIds, gatheredProviderNames, and exactComboSlugs are explicitly
assigned to their intended parameters, preserving the gpt-5.6-sol survival
assertion as a disabled-model scenario rather than relying on positional set
ordering.
In `@tests/codex-convergence-contract.test.ts`:
- Around line 234-269: The test fixture does not prove that alias generation or
routed-entry backup handling executes. Update the convergence test around
liveConfig, gatherCodexCatalogCandidate, and commitCodexCatalogCandidate to
assert a generation-only field such as the routed description or distinct
priority, add a case with the active catalog cleared, and verify the published
backup; ensure the fixture exercises bare-slug alias routing and exposes
incorrect catalogHasRoutedEntries behavior.
- Line 274: Strengthen the gpt-5.5 assertion in the recovery test by locating
the matching entry and asserting its display_name equals the bundled fixture
value "GPT-5.5", rather than only checking that an entry exists. Keep the test
focused on metadata recovered through mergeCatalogModelsWithNativeRecovery.
- Line 219: Replace the `as never` cast in the call to
`setBundledCatalogCacheForTests` with the directly typed `bundled` value. If
needed, annotate `bundled` as `RawCatalog & { models: RawEntry[] }` at its
declaration, preserving the existing models data while allowing TypeScript to
validate future signature changes.
In `@tests/combo-management-api.test.ts`:
- Around line 338-357: Rename the test case around comboApi PUT validation to
“PUT rejects a native alias without a displayName,” matching the omitted
displayName and nativeAlias: true inputs. Optionally add a sibling test for a
native alias that omits nativeAlias while preserving the existing no-mutation
assertions.
In `@tests/model-visibility-management-api.test.ts`:
- Around line 283-289: Update the disable-step assertion in the test around put
and loadConfig to compare the complete disabledModels array with toEqual,
including both the preserved bare native key gpt-5.6-sol and the newly disabled
combo/nova entry in the handler’s actual order.
In `@tests/native-alias-maintainer-regressions.test.ts`:
- Around line 45-51: Update the test around mergeCatalogModelsWithNativeRecovery
to locate the recovered row by its expected slug instead of assuming merged[0]
is the target. Assert that the slug-matched row exists before accessing
supported_reasoning_levels, then keep the deep-copy and source-immutability
assertions unchanged.
In `@tests/native-profile-drain-server.test.ts`:
- Around line 290-293: Extract the repeated bounded polling logic into a shared
helper in the test module, preserving the 2,000 ms deadline and Bun.sleep(10)
interval. Replace both loops near the upstream-close checks with calls to that
helper, including the loops around the existing upstream close assertions, while
preserving their current conditions and behavior.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 50ee5be5-27f1-4608-b56a-3c2f1b207cf0
📒 Files selected for processing (58)
.github/workflows/maintainer-full-verify-1244.ymldocs-site/src/content/docs/guides/codex-app-models.mddocs-site/src/content/docs/guides/combos.mddocs-site/src/content/docs/ja/guides/codex-app-models.mddocs-site/src/content/docs/ja/guides/combos.mddocs-site/src/content/docs/ja/reference/configuration/routing.mddocs-site/src/content/docs/ko/guides/codex-app-models.mddocs-site/src/content/docs/ko/guides/combos.mddocs-site/src/content/docs/ko/reference/configuration/routing.mddocs-site/src/content/docs/reference/cli/agents.mddocs-site/src/content/docs/reference/configuration/routing.mddocs-site/src/content/docs/ru/guides/codex-app-models.mddocs-site/src/content/docs/ru/guides/combos.mddocs-site/src/content/docs/ru/reference/configuration/routing.mddocs-site/src/content/docs/zh-cn/guides/codex-app-models.mddocs-site/src/content/docs/zh-cn/guides/combos.mddocs-site/src/content/docs/zh-cn/reference/cli/agents.mddocs-site/src/content/docs/zh-cn/reference/configuration/routing.mdgui/src/combo-workspace-data.tsgui/src/components/combo-workspace-detail-panel.tsxgui/src/i18n/de.tsgui/src/i18n/en.tsgui/src/i18n/ja.tsgui/src/i18n/ko.tsgui/src/i18n/ru.tsgui/src/i18n/zh.tsgui/tests/combo-native-alias-editor.test.tsxgui/tests/combo-workspace-dirty.test.tsxsrc/cli/combo.tssrc/codex/catalog.tssrc/codex/catalog/aggregation.tssrc/codex/catalog/effort.tssrc/codex/catalog/kinds.tssrc/codex/catalog/metadata.tssrc/codex/catalog/native-models.tssrc/codex/catalog/parsing.tssrc/codex/catalog/provider-fetch.tssrc/codex/catalog/sync.tssrc/codex/convergence.tssrc/combos/index.tssrc/combos/types.tssrc/server/index.tssrc/server/management/combo-routes.tssrc/server/management/model-routes.tssrc/server/management/model-rows.tssrc/types.tsstructure/03_catalog-and-subagents.mdtests/cli-headless-parity.test.tstests/codex-catalog-sync-hardening.test.tstests/codex-catalog.test.tstests/codex-convergence-contract.test.tstests/combo-management-api.test.tstests/combo-workspace-data.test.tstests/combos.test.tstests/model-visibility-management-api.test.tstests/native-alias-maintainer-regressions.test.tstests/native-model-toggle.test.tstests/native-profile-drain-server.test.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2402848a83
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/codex/convergence.ts (1)
253-258: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winKeep preserved native aliases without
input_modalities.When routed discovery returns no rows, Lines 241-251 preserve exact native aliases from the active catalog. Lines 253-258 then remove those same rows if
input_modalitiesis absent or empty.A transient discovery failure can therefore delete a valid bare native alias from the converged catalog. Retain
isNativeAliasCatalogEntry(entry)rows whenpreservingExistingRoutedandexact.has(entry.slug)are both true. Add a regression test with an active native-alias row that has noinput_modalities.Proposed fix
if (!hasPhysicalComboProvider) { const exact = exactComboSlugs; - catalog.models = entries.filter(entry => ( - typeof entry.slug !== "string" || !exact.has(entry.slug) - || (Array.isArray(entry.input_modalities) && entry.input_modalities.length > 0) - )); + catalog.models = entries.filter(entry => { + const slug = typeof entry.slug === "string" ? entry.slug : ""; + const retainedNativeAlias = preservingExistingRouted + && isNativeAliasCatalogEntry(entry) + && exact.has(slug); + return retainedNativeAlias + || !exact.has(slug) + || (Array.isArray(entry.input_modalities) && entry.input_modalities.length > 0); + }); }This follows the preserved-alias contract in
src/codex/catalog/sync.tsLines 673-681.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/codex/convergence.ts` around lines 253 - 258, Update the filtering logic in the hasPhysicalComboProvider block of convergence so entries satisfying preservingExistingRouted, exact.has(entry.slug), and isNativeAliasCatalogEntry(entry) are retained even when input_modalities is missing or empty. Preserve the existing filtering behavior for other entries, and add a regression test covering an active bare native-alias catalog row during routed discovery failure.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/codex/convergence.ts`:
- Around line 253-258: Update the filtering logic in the
hasPhysicalComboProvider block of convergence so entries satisfying
preservingExistingRouted, exact.has(entry.slug), and
isNativeAliasCatalogEntry(entry) are retained even when input_modalities is
missing or empty. Preserve the existing filtering behavior for other entries,
and add a regression test covering an active bare native-alias catalog row
during routed discovery failure.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 2c7e602f-d8bc-4de4-a007-f02560c31361
📒 Files selected for processing (13)
docs-site/src/content/docs/zh-cn/guides/codex-app-models.mdgui/src/components/combo-workspace-detail-panel.tsxgui/tests/combo-native-alias-editor.test.tsxsrc/codex/catalog/provider-fetch.tssrc/codex/catalog/sync.tssrc/codex/convergence.tssrc/server/management/combo-routes.tstests/codex-catalog.test.tstests/codex-convergence-contract.test.tstests/combo-management-api.test.tstests/model-visibility-management-api.test.tstests/native-alias-maintainer-regressions.test.tstests/native-profile-drain-server.test.ts
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/codex/convergence.ts (1)
241-252: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
prepareCatalogdrops preserved native aliases that carry noinput_modalities;mergeCatalogEntriesForSynckeeps them.Line 245 preserves an alias row from the active catalog when its slug is in
exactComboSlugs. The filter at Line 253-258 then removes any entry whose slug is inexactComboSlugsunlessinput_modalitiesis a non-empty array. The preserved alias row has no exemption, so a disk row withoutinput_modalitiesis preserved and then discarded in the same function.
src/codex/catalog/sync.tsadded exactly that exemption at Line 673-681 (retainedNativeAlias || !exactComboSlugs.has(slug) || ...). The two catalog paths therefore disagree for the same input.tests/native-alias-maintainer-regressions.test.tsLine 90-104 covers only themergeCatalogEntriesForSyncpath, so the convergence path has no regression test for it.Apply the same retention rule here and add a matching case to
tests/codex-convergence-contract.test.ts.🐛 Proposed fix — mirror the sync.ts retention rule
if (!hasPhysicalComboProvider) { const exact = exactComboSlugs; catalog.models = entries.filter(entry => ( typeof entry.slug !== "string" || !exact.has(entry.slug) + || (preservingExistingRouted && isNativeAliasCatalogEntry(entry)) || (Array.isArray(entry.input_modalities) && entry.input_modalities.length > 0) )); } else {As per path instructions: "A behavior change in src/ should come with a focused regression test near the existing tests for that subsystem."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/codex/convergence.ts` around lines 241 - 252, Update prepareCatalog’s preserved-entry filtering to retain native alias entries in exactComboSlugs when they lack input_modalities, matching the retainedNativeAlias exemption used by mergeCatalogEntriesForSync; preserve existing filtering for other entries. Add a focused regression case to tests/codex-convergence-contract.test.ts covering a disk/active native alias without input_modalities and asserting it remains in the converged catalog.Source: Path instructions
src/codex/catalog/sync.ts (1)
663-681: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winAdd a test for generated exact combo aliases without
inputModalities.
deriveEntrysetspreserveExactInputModalitiesfor exact combo rows, andensureStrictCatalogFieldsonly normalizes to["text"]wheninput_modalitiesis absent if that option is false. Since the later filter keeps exact combo rows only wheninput_modalitiesis a non-empty array, a combo catalog model with noinputModalitiesdrops the generated alias after the existing bare native alias has been suppressed. Add a regression test that exercises a bare exact combo native alias withmodel.inputModalitiesmissing/empty.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/codex/catalog/sync.ts` around lines 663 - 681, Add a regression test covering a bare exact combo native alias where model.inputModalities is missing or empty. Exercise the sync flow through deriveEntry and ensureStrictCatalogFields, verify the existing bare native alias is suppressed, and assert the generated exact combo alias is retained despite lacking input_modalities.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs-site/src/content/docs/guides/combos.md`:
- Around line 101-104: Update the routing explanation around the exact bare slug
to state that only gpt-5.6-sol resolves to combo/nova-sol. Explicitly document
that openai-apikey/gpt-5.6-sol remains a provider-qualified API-key route and
never falls through to the native alias, while preserving the existing
account-qualified route behavior.
In `@docs-site/src/content/docs/reference/configuration/routing.md`:
- Around line 67-68: Update the routing configuration documentation around
nativeAlias to explicitly state that bare gpt-5.6-* aliases use Codex
Pool/Direct credentials, while openai-apikey/gpt-5.6-* uses API keys and never
falls through to the native alias; retain the existing distinction for
account-qualified and provider-qualified routes.
In `@docs-site/src/content/docs/ru/reference/configuration/routing.md`:
- Around line 67-68: Update the routing documentation at
docs-site/src/content/docs/ru/reference/configuration/routing.md lines 67-68 to
state that bare gpt-5.6-* IDs use Codex Pool/Direct credentials, while
openai-apikey/gpt-5.6-* uses API keys and never falls through. Apply the same
authentication and routing distinction at
docs-site/src/content/docs/ru/guides/combos.md lines 266-267, while clarifying
that account-qualified and provider-qualified identities remain unchanged.
In `@gui/src/i18n/de.ts`:
- Around line 1742-1743: Update the German translation value for
cws.field.nativeAliasHint to use the feminine article “diese Combo” instead of
“diesen Combo”, leaving the rest of the hint unchanged.
In `@gui/tests/combo-native-alias-editor.test.tsx`:
- Around line 9-29: Update the global-state setup in beforeEach and cleanup in
afterEach to save each key’s complete property descriptor via
Object.getOwnPropertyDescriptor(globalThis, key). Restore existing descriptors
with Object.defineProperty, and delete keys that had no original descriptor
instead of recreating them with undefined values. Keep the current testWindow
lifecycle and IS_REACT_ACT_ENVIRONMENT handling intact.
---
Outside diff comments:
In `@src/codex/catalog/sync.ts`:
- Around line 663-681: Add a regression test covering a bare exact combo native
alias where model.inputModalities is missing or empty. Exercise the sync flow
through deriveEntry and ensureStrictCatalogFields, verify the existing bare
native alias is suppressed, and assert the generated exact combo alias is
retained despite lacking input_modalities.
In `@src/codex/convergence.ts`:
- Around line 241-252: Update prepareCatalog’s preserved-entry filtering to
retain native alias entries in exactComboSlugs when they lack input_modalities,
matching the retainedNativeAlias exemption used by mergeCatalogEntriesForSync;
preserve existing filtering for other entries. Add a focused regression case to
tests/codex-convergence-contract.test.ts covering a disk/active native alias
without input_modalities and asserting it remains in the converged catalog.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: ca79901d-7cd1-4806-b683-f19110beebda
📒 Files selected for processing (57)
docs-site/src/content/docs/guides/codex-app-models.mddocs-site/src/content/docs/guides/combos.mddocs-site/src/content/docs/ja/guides/codex-app-models.mddocs-site/src/content/docs/ja/guides/combos.mddocs-site/src/content/docs/ja/reference/configuration/routing.mddocs-site/src/content/docs/ko/guides/codex-app-models.mddocs-site/src/content/docs/ko/guides/combos.mddocs-site/src/content/docs/ko/reference/configuration/routing.mddocs-site/src/content/docs/reference/cli/agents.mddocs-site/src/content/docs/reference/configuration/routing.mddocs-site/src/content/docs/ru/guides/codex-app-models.mddocs-site/src/content/docs/ru/guides/combos.mddocs-site/src/content/docs/ru/reference/configuration/routing.mddocs-site/src/content/docs/zh-cn/guides/codex-app-models.mddocs-site/src/content/docs/zh-cn/guides/combos.mddocs-site/src/content/docs/zh-cn/reference/cli/agents.mddocs-site/src/content/docs/zh-cn/reference/configuration/routing.mdgui/src/combo-workspace-data.tsgui/src/components/combo-workspace-detail-panel.tsxgui/src/i18n/de.tsgui/src/i18n/en.tsgui/src/i18n/ja.tsgui/src/i18n/ko.tsgui/src/i18n/ru.tsgui/src/i18n/zh.tsgui/tests/combo-native-alias-editor.test.tsxgui/tests/combo-workspace-dirty.test.tsxsrc/cli/combo.tssrc/codex/catalog.tssrc/codex/catalog/aggregation.tssrc/codex/catalog/effort.tssrc/codex/catalog/kinds.tssrc/codex/catalog/metadata.tssrc/codex/catalog/native-models.tssrc/codex/catalog/parsing.tssrc/codex/catalog/provider-fetch.tssrc/codex/catalog/sync.tssrc/codex/convergence.tssrc/combos/index.tssrc/combos/types.tssrc/server/index.tssrc/server/management/combo-routes.tssrc/server/management/model-routes.tssrc/server/management/model-rows.tssrc/types.tsstructure/03_catalog-and-subagents.mdtests/cli-headless-parity.test.tstests/codex-catalog-sync-hardening.test.tstests/codex-catalog.test.tstests/codex-convergence-contract.test.tstests/combo-management-api.test.tstests/combo-workspace-data.test.tstests/combos.test.tstests/model-visibility-management-api.test.tstests/native-alias-maintainer-regressions.test.tstests/native-model-toggle.test.tstests/native-profile-drain-server.test.ts
| It changes exact routing precedence: requests for `gpt-5.6-sol` resolve to `combo/nova-sol` before | ||
| the canonical OpenAI native-family route. The catalog contains one bare row with the configured | ||
| display label, not duplicate native and combo rows. Account-qualified rows such as | ||
| `main/gpt-5.6-sol` remain genuine OpenAI routes. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Document the provider-qualified routing boundary.
Lines 101-104 state that account-qualified rows remain separate, but omit provider-qualified OpenAI routes. A reader can infer that the alias also captures openai-apikey/gpt-5.6-sol.
State that only the exact bare slug is captured. State that openai-apikey/gpt-5.6-sol remains a provider-qualified API-key route and never falls through to the native alias.
Proposed documentation change
-Account-qualified rows such as
-`main/gpt-5.6-sol` remain genuine OpenAI routes.
+Only the bare `gpt-5.6-sol` slug is captured. Account-qualified rows such as
+`main/gpt-5.6-sol` and provider-qualified rows such as
+`openai-apikey/gpt-5.6-sol` remain distinct OpenAI routes.As per path instructions, native-alias documentation must preserve account-qualified and provider-qualified identity and metadata.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs-site/src/content/docs/guides/combos.md` around lines 101 - 104, Update
the routing explanation around the exact bare slug to state that only
gpt-5.6-sol resolves to combo/nova-sol. Explicitly document that
openai-apikey/gpt-5.6-sol remains a provider-qualified API-key route and never
falls through to the native alias, while preserving the existing
account-qualified route behavior.
Source: Path instructions
| | `nativeAlias?` | `boolean` | `false` | Let a currently supported bare native id take precedence only for that unqualified id. Account-qualified and provider-qualified OpenAI routes remain distinct. | | ||
| | `displayName?` | `string` | — | Display-only catalog label, required and non-empty for a native alias. | |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Document the credential and routing boundary.
State that bare gpt-5.6-* aliases use Codex Pool/Direct credentials. State that openai-apikey/gpt-5.6-* uses API keys and never falls through to the native alias. The current text only says that qualified routes are distinct. That can cause an operator to configure the wrong credential path.
Proposed documentation change
-| `nativeAlias?` | `boolean` | `false` | Let a currently supported bare native id take precedence only for that unqualified id. Account-qualified and provider-qualified OpenAI routes remain distinct. |
+| `nativeAlias?` | `boolean` | `false` | Let a currently supported bare native id take precedence only for that unqualified id. Bare `gpt-5.6-*` ids use Codex Pool/Direct credentials. Account-qualified routes remain distinct. Provider-qualified routes such as `openai-apikey/gpt-5.6-*` use their configured API-key route and never fall through to the native alias. |📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| | `nativeAlias?` | `boolean` | `false` | Let a currently supported bare native id take precedence only for that unqualified id. Account-qualified and provider-qualified OpenAI routes remain distinct. | | |
| | `displayName?` | `string` | — | Display-only catalog label, required and non-empty for a native alias. | | |
| | `nativeAlias?` | `boolean` | `false` | Let a currently supported bare native id take precedence only for that unqualified id. Bare `gpt-5.6-*` ids use Codex Pool/Direct credentials. Account-qualified routes remain distinct. Provider-qualified routes such as `openai-apikey/gpt-5.6-*` use their configured API-key route and never fall through to the native alias. | | |
| | `displayName?` | `string` | — | Display-only catalog label, required and non-empty for a native alias. | |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs-site/src/content/docs/reference/configuration/routing.md` around lines
67 - 68, Update the routing configuration documentation around nativeAlias to
explicitly state that bare gpt-5.6-* aliases use Codex Pool/Direct credentials,
while openai-apikey/gpt-5.6-* uses API keys and never falls through to the
native alias; retain the existing distinction for account-qualified and
provider-qualified routes.
Source: Path instructions
| | `nativeAlias?` | `boolean` | `false` | Даёт поддерживаемому bare native id приоритет только для этого неквалифицированного id. OpenAI-маршруты с квалификатором аккаунта или провайдера остаются отдельными. | | ||
| | `displayName?` | `string` | — | Метка только для catalog; для native alias обязательна и не может быть пустой. | |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Document the qualified OpenAI route boundary consistently.
Both sections distinguish qualified routes from bare native aliases but omit their credential source and no-fallthrough behavior.
docs-site/src/content/docs/ru/reference/configuration/routing.md#L67-L68: state that baregpt-5.6-*IDs use Codex Pool/Direct credentials, whileopenai-apikey/gpt-5.6-*uses API keys and never falls through.docs-site/src/content/docs/ru/guides/combos.md#L266-L267: add the same authentication and routing distinction, and state that account-qualified/provider-qualified identity remains unchanged.
📍 Affects 2 files
docs-site/src/content/docs/ru/reference/configuration/routing.md#L67-L68(this comment)docs-site/src/content/docs/ru/guides/combos.md#L266-L267
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs-site/src/content/docs/ru/reference/configuration/routing.md` around
lines 67 - 68, Update the routing documentation at
docs-site/src/content/docs/ru/reference/configuration/routing.md lines 67-68 to
state that bare gpt-5.6-* IDs use Codex Pool/Direct credentials, while
openai-apikey/gpt-5.6-* uses API keys and never falls through. Apply the same
authentication and routing distinction at
docs-site/src/content/docs/ru/guides/combos.md lines 266-267, while clarifying
that account-qualified and provider-qualified identities remain unchanged.
Source: Path instructions
| "cws.field.nativeAlias": "Natives OpenAI-Alias", | ||
| "cws.field.nativeAliasHint": "Lässt diesen Combo eine unterstützte unqualifizierte native OpenAI-Modell-ID übernehmen. Konto- und providerqualifizierte OpenAI-Routen bleiben getrennt.", |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Correct the German article in cws.field.nativeAliasHint.
Combo is feminine in this catalog. Replace diesen Combo with diese Combo.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@gui/src/i18n/de.ts` around lines 1742 - 1743, Update the German translation
value for cws.field.nativeAliasHint to use the feminine article “diese Combo”
instead of “diesen Combo”, leaving the rest of the hint unchanged.
| const globals = ["document", "window", "navigator", "localStorage", "IS_REACT_ACT_ENVIRONMENT"] as const; | ||
| let previousGlobals: Record<(typeof globals)[number], unknown>; | ||
| let testWindow: Window; | ||
|
|
||
| beforeEach(() => { | ||
| previousGlobals = Object.fromEntries(globals.map(key => [key, Reflect.get(globalThis, key)])) as typeof previousGlobals; | ||
| testWindow = new Window({ url: "http://localhost/" }); | ||
| Object.defineProperty(testWindow.navigator, "language", { configurable: true, value: "en-US" }); | ||
| Object.defineProperties(globalThis, { | ||
| document: { configurable: true, value: testWindow.document }, | ||
| window: { configurable: true, value: testWindow }, | ||
| navigator: { configurable: true, value: testWindow.navigator }, | ||
| localStorage: { configurable: true, value: testWindow.localStorage }, | ||
| }); | ||
| (globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| testWindow.close(); | ||
| for (const key of globals) Object.defineProperty(globalThis, key, { configurable: true, value: previousGlobals[key] }); | ||
| }); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Restore the original global property descriptors.
The cleanup recreates every global property with its previous value. If document, window, or localStorage did not exist before the test, cleanup leaves an own property with value undefined.
This changes feature detection such as "document" in globalThis for later tests. It also fails to restore an original getter or descriptor flags.
Store Object.getOwnPropertyDescriptor(globalThis, key). During cleanup, restore that descriptor when it exists. Otherwise, delete the injected property.
Proposed test-isolation fix
const globals = ["document", "window", "navigator", "localStorage", "IS_REACT_ACT_ENVIRONMENT"] as const;
-let previousGlobals: Record<(typeof globals)[number], unknown>;
+let previousGlobalDescriptors: Record<
+ (typeof globals)[number],
+ PropertyDescriptor | undefined
+>;
beforeEach(() => {
- previousGlobals = Object.fromEntries(globals.map(key => [key, Reflect.get(globalThis, key)])) as typeof previousGlobals;
+ previousGlobalDescriptors = Object.fromEntries(
+ globals.map(key => [key, Object.getOwnPropertyDescriptor(globalThis, key)]),
+ ) as typeof previousGlobalDescriptors;
// ...
});
afterEach(() => {
testWindow.close();
- for (const key of globals) Object.defineProperty(globalThis, key, { configurable: true, value: previousGlobals[key] });
+ for (const key of globals) {
+ const descriptor = previousGlobalDescriptors[key];
+ if (descriptor) Object.defineProperty(globalThis, key, descriptor);
+ else Reflect.deleteProperty(globalThis, key);
+ }
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const globals = ["document", "window", "navigator", "localStorage", "IS_REACT_ACT_ENVIRONMENT"] as const; | |
| let previousGlobals: Record<(typeof globals)[number], unknown>; | |
| let testWindow: Window; | |
| beforeEach(() => { | |
| previousGlobals = Object.fromEntries(globals.map(key => [key, Reflect.get(globalThis, key)])) as typeof previousGlobals; | |
| testWindow = new Window({ url: "http://localhost/" }); | |
| Object.defineProperty(testWindow.navigator, "language", { configurable: true, value: "en-US" }); | |
| Object.defineProperties(globalThis, { | |
| document: { configurable: true, value: testWindow.document }, | |
| window: { configurable: true, value: testWindow }, | |
| navigator: { configurable: true, value: testWindow.navigator }, | |
| localStorage: { configurable: true, value: testWindow.localStorage }, | |
| }); | |
| (globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; | |
| }); | |
| afterEach(() => { | |
| testWindow.close(); | |
| for (const key of globals) Object.defineProperty(globalThis, key, { configurable: true, value: previousGlobals[key] }); | |
| }); | |
| const globals = ["document", "window", "navigator", "localStorage", "IS_REACT_ACT_ENVIRONMENT"] as const; | |
| let previousGlobalDescriptors: Record< | |
| (typeof globals)[number], | |
| PropertyDescriptor | undefined | |
| >; | |
| let testWindow: Window; | |
| beforeEach(() => { | |
| previousGlobalDescriptors = Object.fromEntries( | |
| globals.map(key => [key, Object.getOwnPropertyDescriptor(globalThis, key)]), | |
| ) as typeof previousGlobalDescriptors; | |
| testWindow = new Window({ url: "http://localhost/" }); | |
| Object.defineProperty(testWindow.navigator, "language", { configurable: true, value: "en-US" }); | |
| Object.defineProperties(globalThis, { | |
| document: { configurable: true, value: testWindow.document }, | |
| window: { configurable: true, value: testWindow }, | |
| navigator: { configurable: true, value: testWindow.navigator }, | |
| localStorage: { configurable: true, value: testWindow.localStorage }, | |
| }); | |
| (globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; | |
| }); | |
| afterEach(() => { | |
| testWindow.close(); | |
| for (const key of globals) { | |
| const descriptor = previousGlobalDescriptors[key]; | |
| if (descriptor) Object.defineProperty(globalThis, key, descriptor); | |
| else Reflect.deleteProperty(globalThis, key); | |
| } | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@gui/tests/combo-native-alias-editor.test.tsx` around lines 9 - 29, Update the
global-state setup in beforeEach and cleanup in afterEach to save each key’s
complete property descriptor via Object.getOwnPropertyDescriptor(globalThis,
key). Restore existing descriptors with Object.defineProperty, and delete keys
that had no original descriptor instead of recreating them with undefined
values. Keep the current testWindow lifecycle and IS_REACT_ACT_ENVIRONMENT
handling intact.
Summary
Supersedes #1056, which had diverged 362 commits behind
dev.This maintainer rebuild transplants the original native-alias feature onto current
devwith a true three-way merge, then hardens the resulting catalog/routing behavior against the still-valid bot/reviewer findings and current-dev integration changes.available_modelsfiltering. Bare supported native IDs route through the configured combo; account-qualified/provider-qualified OpenAI routes remain separate.nativeAliasanddisplayNamein the dashboard editor with localized labels and create/edit/save coverage.Maintainer verification so far
dev(9326b851) and verified the branch is 0 commits behind.UI verification
The original implementation was verified in an isolated Codex Desktop instance; the routed native aliases remained in the picker while native OpenAI rows were suppressed as intended. This screenshot is carried forward from #1056 because #1244 preserves that user-facing behavior while rebuilding the implementation on current
dev.Security / integrity review
Manual diff review covers alias validation and namespace boundaries, bare-vs-qualified routing separation, catalog backup/recovery trust, disabled-model migration, live/provider discovery isolation, duplicate/suppressed native rows, metadata mutation, and model-ranking behavior. No new secret-bearing or authentication material is introduced by this feature.
Review readiness
This replacement remains draft until the full repository gate, fresh CI, and all current reviewer/bot findings are clean.
Supersedes #1056.
Summary by CodeRabbit
New Features
Documentation
Tests