fix(providers): hidden models leak into GET /v1/models (#11300) - #11309
Conversation
The visibility toggle on a provider's dashboard page (PATCH /api/provider-models) persists the hidden-model override under whatever key the page's [id] route param happened to be — an alias (cc/gh/cx/ag/xao), a canonical provider id, a compatible-provider node UUID, or its configured prefix. catalog.ts's isModelHiddenBulk() only ever did a single-key lookup, so a hidden model stayed listed in GET /v1/models whenever the write key and the loop's read key diverged. Make isModelHiddenBulk multi-key aware: given a provider key and an optional already-resolved canonical id, it now checks the raw key, its canonical provider id, that canonical id's alias, and the compatible-provider-node prefix for either — covering every key the dashboard could plausibly have written under. Updated every catalog loop call site (static PROVIDER_MODELS, Codex-native-unprefixed, synced-discovery, custom models, alias-backed models, managed-fallback) to pass along whichever raw/canonical pair it already has in scope.
|
Independent fix for #11300 over in #11308 — same root-cause diagnosis and an overlapping catalog change, so flagging two functional differences before these collide on the 1. 2. Connection-family aliases aren't resolved here. Everything else in this PR — explicit Happy to rebase #11308 onto this branch — keeping this PR's catalog shape and its integration-style test, adding the db-layer piece and family-alias coverage on top — or fold those two pieces into this PR directly if that's easier on your side. The two test suites compose fine: |
…11300) (diegosouzapw#11309) Merging --admin: only fails are ESLint warnings ratchet drift (inherited) and dast-smoke (advisory, isRequired:null). Zero overlap with this PR's file scope (src/app/api/v1/models/catalog.ts).
Summary
PATCH /api/provider-models?provider=<key>&modelId=<id>(the eye-toggle on aprovider's dashboard page) persists the
isHiddenoverride under whateverkey the page's
[id]route param happened to be — an alias (cc/gh/cx/ag/xao), a canonical provider id, a compatible-provider node UUID, or itsconfigured prefix.
catalog.ts'sisModelHiddenBulk()only did a single-key lookup, so ahidden model stayed listed in
GET /v1/modelswhenever the write key and agiven catalog loop's read key diverged (static
PROVIDER_MODELSloop onlychecked
canonicalProviderId; the Codex-native-unprefixed loop only checked"codex"; the synced-discovery loop only checked the raw connectionproviderId, missing a hide keyed by the node's configured prefix).isModelHiddenBulkis now multi-key aware: given a provider key and anoptional already-resolved canonical id, it checks the raw key, its resolved
canonical provider id, that canonical id's alias, and the
compatible-provider-node prefix for either. Updated every catalog loop call
site to pass along whichever raw/canonical pair it already has in scope.
Closes #11300
Test plan
TDD (Hard Rule #18) —
tests/unit/hidden-models-leak-v1-models-11300.test.ts,3 cases, each independently confirmed RED against the pre-fix code and GREEN
after the fix:
cc) stays excluded under bothcc/andclaude/idsopenaiprovider pageexcludes the bare model id
excludes
prefix/<model>synced-model-hide-persist-3782,model-catalog-policy-invalidation-8728,specialty-model-hidden-openrouter-9293,8327-models-owned-by-prefix,8958-alias-backed-node-prefix,9034-alias-backed-prefix-id-repro(18/18), plus a 104-file catalog/hidden/alias sibling batch (604/605 —
the one failure,
9147-catalog-eventloop-yield, is a pre-existingdevbox-load timing flake reproduced identically on the unmodified base
code under the same contention, not a regression from this change)
npm run typecheck:corecleaneslint(with the project's suppressions) clean on both changed files