From 073b87bf6a0f819bb7f92bb5931c9682062b0b50 Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza Date: Tue, 30 Jun 2026 05:48:15 -0300 Subject: [PATCH] fix(release): repair inherited base-red tests from #5480/#5527/#5427/#5521 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fast-path (PR->release/**) does not run the full unit+integration suites, so four merged feature PRs shipped with stale/incorrect tests that only surface on the release PR (PR->main). Repairs (features are correct; align tests to the new behavior — no assertions weakened): - #5480 (gate claude adaptive thinking): adaptive thinking is now injected only for a real Claude Code client (x-app:cli / claude-code UA), not for any bare Claude OAuth token. claude-thinking-tool-choice-guard + base-thinking-budget-5312 now identify as a Claude Code client to exercise the adaptive path (3 tests). - #5527 (T02 inflation guard): the guard reverts a stacked body that did not shrink in tokens. The bail-out/advancement fixtures used growth-appending mock engines; they now carry a droppable padding message the engines empty, so the body realistically shrinks and the marker assertions survive. bailout (5), stacked-async (3), engine-enabled-toggle (2). - #5427 (render onboarding wizard at /providers/new): integration-wiring asserted the old redirect stub; now asserts the route renders ProviderOnboardingWizard. - #5521 (mimocode SOCKS5 per-account proxy): the constructor's default account omitted the proxy field (undefined), breaking the 'all proxies null' backward compat guard. Default it to null, mirroring syncAccountsFromCredentials(). --- open-sse/executors/mimocode.ts | 4 ++ tests/integration/integration-wiring.test.ts | 21 ++++------ .../base-thinking-budget-config-5312.test.ts | 5 +++ .../claude-thinking-tool-choice-guard.test.ts | 5 +++ tests/unit/compression/bailout.test.ts | 42 +++++++++++++------ .../compression/engine-enabled-toggle.test.ts | 13 +++++- tests/unit/compression/stacked-async.test.ts | 26 +++++++++--- 7 files changed, 85 insertions(+), 31 deletions(-) diff --git a/open-sse/executors/mimocode.ts b/open-sse/executors/mimocode.ts index 1c7e66f883..45a061bae3 100644 --- a/open-sse/executors/mimocode.ts +++ b/open-sse/executors/mimocode.ts @@ -219,6 +219,10 @@ export class MimocodeExecutor extends BaseExecutor { expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0, + // #3837/#5521 backward compat: default the per-account proxy to null (not undefined), + // mirroring the syncAccountsFromCredentials() account builder, so an executor with no + // accountProxies config still exposes `acct.proxy === null` on every account. + proxy: null, }); } diff --git a/tests/integration/integration-wiring.test.ts b/tests/integration/integration-wiring.test.ts index acad6b66c6..348b41c057 100644 --- a/tests/integration/integration-wiring.test.ts +++ b/tests/integration/integration-wiring.test.ts @@ -602,18 +602,15 @@ describe("Page Integration — provider test results privacy", () => { }); }); -describe("Page Integration — legacy provider create route retirement", () => { - const legacyProviderNewSrc = readProjectFile( - "src/app/(dashboard)/dashboard/providers/new/page.tsx" - ); +describe("Page Integration — provider create route renders the onboarding wizard (#5427)", () => { + const providerNewSrc = readProjectFile("src/app/(dashboard)/dashboard/providers/new/page.tsx"); - it("should redirect legacy /dashboard/providers/new to the canonical providers flow", () => { - assert.ok( - legacyProviderNewSrc, - "src/app/(dashboard)/dashboard/providers/new/page.tsx should exist" - ); - assert.match(legacyProviderNewSrc, /redirect\("\/dashboard\/providers"\)/); - assert.doesNotMatch(legacyProviderNewSrc, /authMethod:\s*"api_key"/); - assert.doesNotMatch(legacyProviderNewSrc, /displayName/); + it("renders ProviderOnboardingWizard instead of redirecting (#5427)", () => { + // #5427 reversed the earlier redirect-stub retirement: /dashboard/providers/new now + // renders the previously-orphaned ProviderOnboardingWizard directly (auth enforced by + // the (dashboard) layout). The dedicated guard is tests/unit/onboarding-wizard-route-5427. + assert.ok(providerNewSrc, "src/app/(dashboard)/dashboard/providers/new/page.tsx should exist"); + assert.match(providerNewSrc, /ProviderOnboardingWizard/); + assert.doesNotMatch(providerNewSrc, /redirect\("\/dashboard\/providers"\)/); }); }); diff --git a/tests/unit/base-thinking-budget-config-5312.test.ts b/tests/unit/base-thinking-budget-config-5312.test.ts index 92578a1a8c..046a3348de 100644 --- a/tests/unit/base-thinking-budget-config-5312.test.ts +++ b/tests/unit/base-thinking-budget-config-5312.test.ts @@ -52,6 +52,11 @@ async function captureUpstreamBody( body, stream: false, credentials: { accessToken: "sk-ant-oat-test-5312" }, + // #5480: the default adaptive-thinking injection (and the native-Claude-Code wire + // image these #5312 cases exercise) is gated behind a real Claude Code client + // (`x-app: cli` / `claude-code` UA). A bare OAuth token from a generic OpenAI-compat + // client must opt in via x-omniroute-thinking, so identify as a Claude Code client here. + clientHeaders: { "x-app": "cli" }, }); } finally { globalThis.fetch = originalFetch; diff --git a/tests/unit/claude-thinking-tool-choice-guard.test.ts b/tests/unit/claude-thinking-tool-choice-guard.test.ts index 8ef086f937..9cfcb1fd36 100644 --- a/tests/unit/claude-thinking-tool-choice-guard.test.ts +++ b/tests/unit/claude-thinking-tool-choice-guard.test.ts @@ -52,6 +52,11 @@ async function captureUpstreamBody( stream: false, // OAuth token (sk-ant-oat…) with NO apiKey => wire-image path fires. credentials: { accessToken: "sk-ant-oat-test-thinkguard" }, + // #5480: the default adaptive-thinking injection is gated behind a real Claude Code + // client (`x-app: cli` / `claude-code` UA). A bare OAuth token (generic OpenAI-compat + // client) must opt in via x-omniroute-thinking and no longer gets force-injected, so + // these tests now identify as a Claude Code client to exercise the adaptive path. + clientHeaders: { "x-app": "cli" }, }); } finally { globalThis.fetch = originalFetch; diff --git a/tests/unit/compression/bailout.test.ts b/tests/unit/compression/bailout.test.ts index 46b97eca4e..ed46072f66 100644 --- a/tests/unit/compression/bailout.test.ts +++ b/tests/unit/compression/bailout.test.ts @@ -71,8 +71,9 @@ function makeLowGainEngine(id = LOW_GAIN_ENGINE_ID): CompressionEngine { ...makeBaseEngine(id), apply: (body) => { const messages = (body.messages as Array<{ role: string; content: string }>) ?? []; + // Tag the user message; drop any padding (non-user) content so the body shrinks. const next = messages.map((m) => - m.role === "user" ? { ...m, content: m.content + "|low" } : m + m.role === "user" ? { ...m, content: m.content + "|low" } : { ...m, content: "" } ); return { body: { ...body, messages: next }, @@ -97,8 +98,9 @@ const highGainEngine: CompressionEngine = { ...makeBaseEngine(HIGH_GAIN_ENGINE_ID), apply: (body) => { const messages = (body.messages as Array<{ role: string; content: string }>) ?? []; + // Tag the user message; drop any padding (non-user) content so the body shrinks. const next = messages.map((m) => - m.role === "user" ? { ...m, content: m.content + "|high" } : m + m.role === "user" ? { ...m, content: m.content + "|high" } : { ...m, content: "" } ); return { body: { ...body, messages: next }, @@ -146,6 +148,22 @@ function userContent(result: CompressionResult): string { const BAILOUT_ON = { bailout: { enabled: true, minGainPercent: 10 } }; const BAILOUT_OFF = {}; // default — no bailout field +// A fixture body carrying a large droppable padding message. When an engine runs it +// drops that padding (and tags the user message), so the FINAL stacked body genuinely +// shrinks — keeping the #5527 (T02) inflation guard from reverting these advancement +// fixtures. The guard only reverts a pipeline whose final body did NOT shrink in tokens; +// these tests exercise bail-out/advancement, an orthogonal concern, so the body must +// realistically shrink for the marker assertions to survive the guard. +const PADDING = "padding tokens ".repeat(40); +function mkBody(): { messages: Array<{ role: string; content: string }> } { + return { + messages: [ + { role: "user", content: "hello" }, + { role: "assistant", content: PADDING }, + ], + }; +} + // ── suite ──────────────────────────────────────────────────────────────────── describe("TV1 — stacked pipeline bail-out discipline (OPT-IN)", () => { @@ -169,7 +187,7 @@ describe("TV1 — stacked pipeline bail-out discipline (OPT-IN)", () => { describe("sync — applyStackedCompression", () => { it("bail-out ON: throwing engine → step skipped, pipeline does NOT throw", () => { - const body = { messages: [{ role: "user", content: "hello" }] }; + const body = mkBody(); // Must not throw and original body is kept (throw engine was the only step) const result = applyStackedCompression(body, pipeline(THROW_ENGINE_ID), BAILOUT_ON); @@ -186,7 +204,7 @@ describe("TV1 — stacked pipeline bail-out discipline (OPT-IN)", () => { }); it("bail-out ON: throwing engine before a good engine → good engine still runs", () => { - const body = { messages: [{ role: "user", content: "hello" }] }; + const body = mkBody(); // throw engine first, then high-gain engine — the high-gain must still run const result = applyStackedCompression( @@ -201,7 +219,7 @@ describe("TV1 — stacked pipeline bail-out discipline (OPT-IN)", () => { }); it("bail-out ON: low-gain engine (5%) → body NOT advanced (step skipped)", () => { - const body = { messages: [{ role: "user", content: "hello" }] }; + const body = mkBody(); const result = applyStackedCompression(body, pipeline(LOW_GAIN_ENGINE_ID), BAILOUT_ON); @@ -212,7 +230,7 @@ describe("TV1 — stacked pipeline bail-out discipline (OPT-IN)", () => { }); it("bail-out ON: high-gain engine (20%) → body IS advanced normally", () => { - const body = { messages: [{ role: "user", content: "hello" }] }; + const body = mkBody(); const result = applyStackedCompression(body, pipeline(HIGH_GAIN_ENGINE_ID), BAILOUT_ON); @@ -221,7 +239,7 @@ describe("TV1 — stacked pipeline bail-out discipline (OPT-IN)", () => { }); it("bail-out ON: low-gain then high-gain → only high-gain advances body", () => { - const body = { messages: [{ role: "user", content: "hello" }] }; + const body = mkBody(); const result = applyStackedCompression( body, @@ -234,7 +252,7 @@ describe("TV1 — stacked pipeline bail-out discipline (OPT-IN)", () => { }); it("bail-out OFF (default): low-gain engine IS applied (opt-in guard)", () => { - const body = { messages: [{ role: "user", content: "hello" }] }; + const body = mkBody(); // No bailout config at all — original behavior const result = applyStackedCompression(body, pipeline(LOW_GAIN_ENGINE_ID), BAILOUT_OFF); @@ -245,7 +263,7 @@ describe("TV1 — stacked pipeline bail-out discipline (OPT-IN)", () => { }); it("bail-out OFF (default): throwing engine propagates — unchanged existing behavior", () => { - const body = { messages: [{ role: "user", content: "hello" }] }; + const body = mkBody(); // Without bail-out, a throw is NOT caught → pipeline throws assert.throws(() => { @@ -258,7 +276,7 @@ describe("TV1 — stacked pipeline bail-out discipline (OPT-IN)", () => { describe("async — applyStackedCompressionAsync", () => { it("bail-out ON: async throwing engine → step skipped, no throw", async () => { - const body = { messages: [{ role: "user", content: "hello" }] }; + const body = mkBody(); const result = await applyStackedCompressionAsync(body, pipeline(THROW_ASYNC_ID), BAILOUT_ON); @@ -267,7 +285,7 @@ describe("TV1 — stacked pipeline bail-out discipline (OPT-IN)", () => { }); it("bail-out ON: async low-gain engine (5%) → step skipped", async () => { - const body = { messages: [{ role: "user", content: "hello" }] }; + const body = mkBody(); const result = await applyStackedCompressionAsync( body, @@ -280,7 +298,7 @@ describe("TV1 — stacked pipeline bail-out discipline (OPT-IN)", () => { }); it("bail-out OFF (default): async low-gain engine IS applied", async () => { - const body = { messages: [{ role: "user", content: "hello" }] }; + const body = mkBody(); const result = await applyStackedCompressionAsync( body, diff --git a/tests/unit/compression/engine-enabled-toggle.test.ts b/tests/unit/compression/engine-enabled-toggle.test.ts index 958d419e6d..544bb6b753 100644 --- a/tests/unit/compression/engine-enabled-toggle.test.ts +++ b/tests/unit/compression/engine-enabled-toggle.test.ts @@ -53,8 +53,10 @@ function makeTaggingEngine(id: string): CompressionEngine { validateConfig: () => ({ valid: true, errors: [] }), apply: (body) => { const messages = (body.messages as Array<{ role: string; content: string }>) ?? []; + // Tag the user message; drop any padding (non-user) content so the body shrinks + // and the #5527 (T02) inflation guard keeps the tagged output instead of reverting. const next = messages.map((m) => - m.role === "user" ? { ...m, content: m.content + "|tagged" } : m + m.role === "user" ? { ...m, content: m.content + "|tagged" } : { ...m, content: "" } ); return { body: { ...body, messages: next }, @@ -83,7 +85,14 @@ function userContent(result: CompressionResult): string { } function freshBody() { - return { messages: [{ role: "user", content: "hi" }] }; + // Includes a droppable padding message so an engine that runs nets a real token shrink + // (the engine empties non-user content), keeping the #5527 inflation guard from reverting. + return { + messages: [ + { role: "user", content: "hi" }, + { role: "assistant", content: "padding tokens ".repeat(40) }, + ], + }; } describe("registry enabled toggle — stacked loop honors setEngineEnabled", () => { diff --git a/tests/unit/compression/stacked-async.test.ts b/tests/unit/compression/stacked-async.test.ts index 81a864b046..9fb8743467 100644 --- a/tests/unit/compression/stacked-async.test.ts +++ b/tests/unit/compression/stacked-async.test.ts @@ -27,8 +27,10 @@ const FA = "fake-async-engine"; */ function tag(id: string, body: Record): CompressionResult { const messages = (body.messages as Array<{ role: string; content: string }>) ?? []; + // Tag the user message; drop any padding (non-user) content so the stacked body + // genuinely shrinks and the #5527 (T02) inflation guard does not revert it. const next = messages.map((m) => - m.role === "user" ? { ...m, content: `${m.content}|${id}` } : m + m.role === "user" ? { ...m, content: `${m.content}|${id}` } : { ...m, content: "" } ); return { body: { ...body, messages: next }, @@ -87,6 +89,20 @@ function pipeline(...ids: string[]): CompressionPipelineStep[] { return ids.map((engine) => ({ engine })) as unknown as CompressionPipelineStep[]; } +// Fixture body with a large droppable padding message: engines drop it (see `tag`) so the +// final stacked body shrinks and the #5527 (T02) inflation guard keeps the tagged output +// instead of reverting it. These tests assert engine ORDER/advancement, not compression +// ratios, so the body must realistically shrink for the tag assertions to survive the guard. +const PADDING = "padding tokens ".repeat(40); +function mkBody(): { messages: Array<{ role: string; content: string }> } { + return { + messages: [ + { role: "user", content: "hello" }, + { role: "assistant", content: PADDING }, + ], + }; +} + describe("stacked compression — async interface (H10)", () => { before(() => { registerCompressionEngine(makeEngine(FS)); @@ -98,7 +114,7 @@ describe("stacked compression — async interface (H10)", () => { }); it("runs a mixed sync+async pipeline in pipeline order", async () => { - const body = { messages: [{ role: "user", content: "hello" }] }; + const body = mkBody(); const result = await applyStackedCompressionAsync(body, pipeline(FS, FA)); assert.equal(userContent(result), "hello|fake-sync-engine|fake-async-engine"); @@ -111,7 +127,7 @@ describe("stacked compression — async interface (H10)", () => { }); it("preserves order when the async engine runs first", async () => { - const body = { messages: [{ role: "user", content: "hello" }] }; + const body = mkBody(); const result = await applyStackedCompressionAsync(body, pipeline(FA, FS)); assert.equal(userContent(result), "hello|fake-async-engine|fake-sync-engine"); @@ -122,7 +138,7 @@ describe("stacked compression — async interface (H10)", () => { }); it("async path yields the same result as sync path for sync-only engines", async () => { - const body = { messages: [{ role: "user", content: "hello" }] }; + const body = mkBody(); const asyncResult = await applyStackedCompressionAsync(body, pipeline(FS)); const syncResult = applyStackedCompression(body, pipeline(FS)); @@ -131,7 +147,7 @@ describe("stacked compression — async interface (H10)", () => { }); it("legacy sync path gracefully skips async-only work without crashing", () => { - const body = { messages: [{ role: "user", content: "hello" }] }; + const body = mkBody(); const result = applyStackedCompression(body, pipeline(FA)); // The async-only engine's sync apply() is a pass-through: no transform.