From 5c4bc584c7e96efe347c329e550b552f0c351cb7 Mon Sep 17 00:00:00 2001 From: OpenCode Builder Date: Fri, 17 Jul 2026 10:23:16 +0800 Subject: [PATCH] test(claude-app): lock in routable discovery default for #1535 The hardcoded CLAUDE_APP_FALLBACK_MODEL ("claude-sonnet-4-5") that issue #1535 reported was already removed in 7b0e203 ("Refine Claude app model discovery and fallback routing"), so GET /v1/models no longer surfaces the unroutable bare fallback as the first/default model, and the model registry now resolves a bare "claude-sonnet-4-5" to its configured provider. Add a regression test using the issue's exact three-provider config that asserts both invariants: the discovered default round-trips through the request rewrite path to a provider-prefixed selector, and a bare fallback id resolves to a provider rather than falling into model-chain fallback. Fixes #1535 --- .../agents/claude-app-gateway-models.test.mjs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/packages/core/test/unit/agents/claude-app-gateway-models.test.mjs b/packages/core/test/unit/agents/claude-app-gateway-models.test.mjs index 8e1dc6c4..2df7fa87 100644 --- a/packages/core/test/unit/agents/claude-app-gateway-models.test.mjs +++ b/packages/core/test/unit/agents/claude-app-gateway-models.test.mjs @@ -65,6 +65,43 @@ test("issue 1535 Claude App discovery defaults to the first configured provider assertPublishedRoutesResolveUniquely(config); }); +test("issue 1535 the discovered default is routable and the bare fallback resolves to a provider", () => { + const config = createConfig({ + providers: [ + { models: ["AED"], name: "provider-1" }, + { models: ["claude-sonnet-4-5"], name: "provider-2" }, + { models: ["deepseek-v4-flash"], name: "provider-3" } + ] + }); + const response = createClaudeModelsResponse(config); + + assert.equal( + response.data.some((model) => model.id === "claude-sonnet-4-5"), + false, + "the unroutable bare fallback must never be published by GET /v1/models" + ); + assert.ok(response.first_id, "discovery must publish a routable default model"); + + const rewritten = prepareClaudeAppDiscoveredModelRequest( + config, + "POST", + "/v1/messages", + Buffer.from(JSON.stringify({ messages: [], model: response.first_id })) + ); + assert.equal( + rewritten?.routedModel, + "provider-1/AED", + "the discovered default must round-trip to a provider-prefixed selector instead of model-chain fallback" + ); + + const registry = new ModelRegistry(config); + assert.equal( + registry.resolve("claude-sonnet-4-5")?.canonicalSelector, + "provider-2/claude-sonnet-4-5", + "a bare fallback model id must resolve to a provider rather than going unroutable" + ); +}); + test("issue 1535 Claude App discovery canonicalizes a uniquely configured bare profile model", () => { const config = createConfig({ profileModel: "claude-sonnet-4-5",