fix(web): hide deleted providers with prototype keys - #8337
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthrough
ChangesProvider instance settings
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to This narrowly fixes stale deleted provider entries during settings reconciliation while preserving valid configured names; no actionable merge-blocking risk remains after normal checks and review. Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a narrowly scoped web bug fix that hardens provider settings lookups against inherited prototype keys and adds focused regression tests. Its runtime impact is limited to provider visibility and enablement reconciliation, with no schema, deployment, security, billing, or authentication changes. You can add or adjust custom eligibility rules. Learn more. |
Lucenx9
left a comment
There was a problem hiding this comment.
Review: verified correct ✅
Reviewed the diff locally at bdeb3b5 and traced every production call path. Approving the fix logic; one non-blocking note below.
The bug is real
settings.providerInstances?.[entry.instanceId] resolved inherited keys like Object.prototype.constructor, so a deleted custom instance named after a prototype member stayed visible until the next provider snapshot reconciled it. Same failure class existed on the legacy providers lookup for fork-driver default instances (legacyProviders[entry.driverKind] where driverKind === "constructor").
The fix is right
Object.hasOwncorrectly guards both maps without restricting valid instance slugs — a custom instance genuinely namedconstructorstill resolves its own settings row.- The tightened default branch (
entry.isDefault && legacyProvider ? ... : false) matches the documented invariant: only built-in defaults own a legacyproviders.*entry, so absence there means a stale snapshot and "disabled" is correct, including for fork drivers that exist solely throughproviderInstances. - No regression risk for built-ins: their legacy keys always exist as own properties after schema decode (
withDecodingDefault({})), so the newhasOwncheck always passes for them.
Call-site safety checked
All four production callers pass the full decoded settings object, never a hand-built partial:
ChatView.tsx:2788ChatComposer.tsx:824SettingsPanels.tsx:1878ProjectSettingsPanel.tsx:423
The atom fallback (primaryServerConfigAtom?.settings ?? DEFAULT_SERVER_SETTINGS, state/server.ts:74) guarantees both maps are present at runtime, so Object.hasOwn(undefined, ...) cannot throw.
Non-blocking note
The old ?. tolerated caller-built partials missing the settings fields entirely; the new code would throw on those. The types already forbid this shape and no caller constructs one, so no change needed — just worth knowing if a future caller passes an ad-hoc object.
Verification
vitest run apps/web/src/providerInstances.test.ts→ 34/34 passtsc --noEmit -p apps/web→ clean- Web-only module (
apps/web/src); mobile surface untouched, correctly - CI green: Check, Test ×3, Macroscope, Bugbot
Reviewed with GLM 5.3 Flash (Z.ai) in the opencode harness.
What Changed
Why
Plain object lookups can resolve inherited values such as
Object.prototype.constructor. A deleted provider with that instance ID was therefore treated as configured and could remain visible until the next provider snapshot.Own-property checks match the settings invariant without restricting valid provider slugs.
UI Changes
No visual design changes. This only removes stale deleted provider entries during settings reconciliation.
Checklist
Built with GPT-5.6 Sol in the Codex harness through T3 Code.
Note
Low Risk
Narrow change to client-side settings overlay for provider picker visibility; no auth or server persistence changes.
Overview
Fixes stale provider entries staying visible in the picker when a deleted instance ID collides with inherited object keys (e.g.
constructor,toString).applyProviderInstanceSettingsnow usesObject.hasOwnfor bothproviderInstancesand legacyprovidersbefore reading settings. Removed custom instances (including fork defaults with no legacy row) are forced disabled when absent from settings; legacyproviders.*.enabledapplies only to built-in defaults that actually have an own legacy entry. Explicitly configured instances with prototype-like names still honor their settings.Regression tests cover inherited-key deletion, valid prototype-named instances, fork-driver defaults, and built-in legacy fallback.
Reviewed by Cursor Bugbot for commit bdeb3b5. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix deleted providers with prototype keys in
applyProviderInstanceSettingsapplyProviderInstanceSettingsin providerInstances.ts now usesObject.hasOwnbefore readingproviderInstancesandlegacyProviders, so prototype members likeconstructorortoStringare no longer treated as configured instances or legacy provider entries.providerInstancesandlegacyProviderswill now be disabled rather than kept enabled; reviewers should checkproviderInstances.tsdefaulting logic for any callers relying on the old pass-through behavior.Macroscope summarized bdeb3b5.
Summary by CodeRabbit
constructorortoString.