From 824ceda46fd439ed00dfb58b3235fc4109453112 Mon Sep 17 00:00:00 2001 From: Lance Woodson <65194841+woodsonl@users.noreply.github.com> Date: Tue, 22 Sep 2026 14:46:13 -0500 Subject: [PATCH 1/2] test(compression): make output-style checks able to fail #13383 moved the output-style instruction out of messages[0]. On an OpenAI-shaped body with no system turn, placeSystemInstruction now appends a trailing system message. #14423 repointed the five assertions that failed after that change. Five tests still carried checks that could not fail: - output-styles-backcompat golden: it read messages[0] from both injectors' results, which is the untouched user turn. Once strip() drops the first line, both sides are "", so it passed even when the two instruction texts diverged. - "caveman output mode skipped when compression is globally disabled": it checked that messages[0] is the user turn, which still holds with the config.enabled gate removed, because the instruction lands at the end of the array. - The #6240 compression:off test: its messages[0] assertion can no longer fail for the same reason, and its marker scan read only message text. - The two compression-combo tests: they pinned the global language default to pt-BR, so they passed even when chatCore ignored the combo's language packs. The golden test now reads each injector's system message, checks that it starts with its own marker, and compares the text below the marker. It also covers a bypass turn, "Explain this security vulnerability in detail." With Auto-Clarity off, both injectors apply the same text. With Auto-Clarity on, both skip the turn as security_warning. The disabled-compression and compression:off tests deep-equal the untouched messages and assert that the [OmniRoute Output Styles] marker appears nowhere in the upstream body. The disabled-compression test moves to test-model-compression-off-6240.test.ts and runs through that file's runChatCore helper, which keeps chatcore-compression-integration.test.ts under its 1,214-line freeze. Its explicit-any suppression count in config/quality/eslint-suppressions.json drops from 9 to 8 with it. The 6240 file's storage reset now waits up to 30 seconds for the previous test's background call-log save and fails if it does not land, so the #2101 test's save cannot race the moved test's reset. Its teardown closes the call-log writer, so the file exits on its own, and its temporary data directory now comes from the shared createTempDataDir helper in tests/_setup/tempDataDir.ts. The combo tests set the global default to English, so pt-BR output has to come from the combo. tests/unit/compression/output-styles-anthropic-placement.test.ts is new. It sends Claude Code-style /v1/messages requests through chatCore with three system shapes: a string, content blocks, and none. The upstream system field must carry the full instruction exactly once, in blocks whose text is a string, next to the client's own prompt, and messages[] must keep the client's turns. The two shapes with a system prompt also carry a later system turn, which must stay in messages[]. That shows chatCore took the mid-conversation-system path and did not hoist every system turn. The file takes its temporary data directory from the shared createTempDataDir helper. Each test waits up to 30 seconds for the call-log writer to finish before the next one resets storage, and fails if it does not. The file closes the writer at the end, so it exits on its own. It lives with the unit tests so the unit shards that gate pull requests into release branches run it. --- config/quality/eslint-suppressions.json | 2 +- .../chatcore-compression-integration.test.ts | 88 +------- .../test-model-compression-off-6240.test.ts | 72 ++++-- .../output-styles-anthropic-placement.test.ts | 211 ++++++++++++++++++ .../output-styles-backcompat.test.ts | 65 ++++-- 5 files changed, 324 insertions(+), 114 deletions(-) create mode 100644 tests/unit/compression/output-styles-anthropic-placement.test.ts diff --git a/config/quality/eslint-suppressions.json b/config/quality/eslint-suppressions.json index 7cd73e1edb34..ba0f152d7993 100644 --- a/config/quality/eslint-suppressions.json +++ b/config/quality/eslint-suppressions.json @@ -2063,7 +2063,7 @@ }, "tests/integration/chatcore-compression-integration.test.ts": { "@typescript-eslint/no-explicit-any": { - "count": 9 + "count": 8 }, "@typescript-eslint/no-unused-vars": { "count": 4 diff --git a/tests/integration/chatcore-compression-integration.test.ts b/tests/integration/chatcore-compression-integration.test.ts index 832b45b59be1..a05b27fe33ef 100644 --- a/tests/integration/chatcore-compression-integration.test.ts +++ b/tests/integration/chatcore-compression-integration.test.ts @@ -612,11 +612,12 @@ test("chatCore integration: assigned compression combo applies language packs an }, languageConfig: { enabled: true, - // autoDetect would read the (English) user turn and resolve back to "en", - // so the pack under test has to be pinned explicitly. + // autoDetect finds no pt-BR hint word in this short Portuguese turn and resolves to + // "en", so it stays off. The global default is English too, so pt-BR output can only + // come from the combo's language packs. autoDetect: false, - defaultLanguage: "pt-BR", - enabledPacks: ["pt-BR"], + defaultLanguage: "en", + enabledPacks: ["en"], }, }); @@ -724,11 +725,12 @@ test("chatCore integration: default stacked compression combo applies for unassi }, languageConfig: { enabled: true, - // autoDetect would read the (English) user turn and resolve back to "en", - // so the pack under test has to be pinned explicitly. + // autoDetect finds no pt-BR hint word in this short Portuguese turn and resolves to + // "en", so it stays off. The global default is English too, so pt-BR output can only + // come from the combo's language packs. autoDetect: false, - defaultLanguage: "pt-BR", - enabledPacks: ["pt-BR"], + defaultLanguage: "en", + enabledPacks: ["en"], }, }); @@ -983,76 +985,6 @@ test("chatCore integration: modular compression records analytics row best-effor } }); -test("chatCore integration: caveman output mode skipped when compression is globally disabled", async () => { - const provider = "openai"; - const model = "gpt-4"; - - await compressionDb.updateCompressionSettings({ - enabled: false, - defaultMode: "off", - autoTriggerTokens: 0, - cavemanOutputMode: { - enabled: true, - intensity: "full", - autoClarity: true, - }, - }); - - const connection = await providersDb.createProviderConnection({ - provider, - apiKey: "test-key", - isActive: true, - }); - - let capturedBody: any = null; - globalThis.fetch = async (_url: string | URL | Request, init?: RequestInit) => { - if (init?.body) { - capturedBody = JSON.parse(init.body as string); - } - return new Response( - JSON.stringify({ - choices: [{ message: { role: "assistant", content: "ok" } }], - usage: { prompt_tokens: 20, completion_tokens: 4, total_tokens: 24 }, - }), - { - status: 200, - headers: { "content-type": "application/json" }, - } - ); - }; - - try { - const result = await handleChatCore({ - body: { - model, - stream: false, - messages: [{ role: "user", content: "Summarize this implementation." }], - }, - modelInfo: { provider, model }, - credentials: { apiKey: "test-key" }, - log: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} }, - clientRawRequest: { endpoint: "/v1/chat/completions", headers: new Map() }, - connectionId: connection.id, - onCredentialsRefreshed: () => {}, - onRequestSuccess: () => {}, - onStreamFailure: () => {}, - onDisconnect: () => {}, - userAgent: "test-agent", - comboName: null, - }); - - assert.ok(result.success, "Request should succeed"); - assert.equal( - capturedBody.messages[0].role, - "user", - "No system message should be injected when compression is disabled" - ); - assert.doesNotMatch(capturedBody.messages[0].content ?? "", /Output Styles/); - } finally { - globalThis.fetch = originalFetch; - } -}); - test("chatCore integration: caveman output mode injected when both compression and output mode are enabled", async () => { const provider = "openai"; const model = "gpt-4"; diff --git a/tests/integration/test-model-compression-off-6240.test.ts b/tests/integration/test-model-compression-off-6240.test.ts index d0ac6c3ebb89..98fc0efff494 100644 --- a/tests/integration/test-model-compression-off-6240.test.ts +++ b/tests/integration/test-model-compression-off-6240.test.ts @@ -14,11 +14,9 @@ import test from "node:test"; import assert from "node:assert/strict"; import fs from "node:fs"; -import os from "node:os"; -import path from "node:path"; +import { createTempDataDir } from "../_setup/tempDataDir.ts"; -const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-testmodel-compression-")); -process.env.DATA_DIR = TEST_DATA_DIR; +const { dir: TEST_DATA_DIR, cleanup } = createTempDataDir("omniroute-testmodel-compression-"); process.env.REQUIRE_API_KEY = "false"; process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "test-testmodel-compression-secret"; @@ -28,6 +26,9 @@ const readCacheDb = await import("../../src/lib/db/readCache.ts"); const compressionDb = await import("../../src/lib/db/compression.ts"); const { handleChatCore } = await import("../../open-sse/handlers/chatCore.ts"); const { resetAllCircuitBreakers } = await import("../../src/shared/utils/circuitBreaker.ts"); +const { OUTPUT_STYLE_MARKER } = + await import("../../open-sse/services/compression/outputStyles/apply.ts"); +const { waitForCallLogSaves, closeCallLogSaves } = await import("../../src/lib/usage/callLogs.ts"); const originalFetch = globalThis.fetch; @@ -36,6 +37,8 @@ async function resetStorage() { resetAllCircuitBreakers(); readCacheDb.invalidateDbCache(); await new Promise((resolve) => setTimeout(resolve, 20)); + // The previous test's call log is saved in the background; it must land before the reset. + assert.ok(await waitForCallLogSaves(30_000), "the previous test's call-log saves should finish"); core.resetDbInstance(); fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); @@ -47,12 +50,9 @@ test.beforeEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; - core.closeDbInstance(); - try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); - } catch { - // best-effort cleanup - } + // Stops the call-log writer too, which otherwise keeps the process alive for its idle timeout. + await closeCallLogSaves(2_000); + await cleanup(); }); async function runChatCore(opts: { @@ -146,18 +146,15 @@ test("chatCore: x-omniroute-compression: off suppresses Output Styles injection connectionId: connection.id, headers: new Headers({ "x-omniroute-compression": "off" }), }); - const testModelFirstMessage = testModelBody.capturedBody?.messages?.[0]; - assert.ok( - !testModelFirstMessage || testModelFirstMessage.role !== "system", - "Test-model request (compression:off) must not receive an injected Output Styles system message" - ); - const anyMessageHasMarker = (testModelBody.capturedBody?.messages ?? []).some((m) => - (m?.content ?? "").includes("OmniRoute Output Styles") + assert.deepEqual( + testModelBody.capturedBody?.messages, + [{ role: "user", content: "ping" }], + "Test-model request (compression:off) must reach upstream with its messages untouched" ); assert.equal( - anyMessageHasMarker, + JSON.stringify(testModelBody.capturedBody).includes(OUTPUT_STYLE_MARKER), false, - "No message in the compression:off request should carry the Output Styles marker" + "No part of the compression:off request should carry the Output Styles marker" ); }); @@ -217,3 +214,40 @@ test("chatCore: a per-key opt-out wins over request headers and Output Styles (# assert.deepEqual(disabled.capturedBody?.messages, [{ role: "user", content: originalContent }]); assert.equal(disabled.response.headers.get("x-omniroute-compression"), "off; source=off"); }); + +test("chatCore: caveman output mode skipped when compression is globally disabled", async () => { + await compressionDb.updateCompressionSettings({ + enabled: false, + defaultMode: "off", + autoTriggerTokens: 0, + cavemanOutputMode: { + enabled: true, + intensity: "full", + autoClarity: true, + }, + }); + + const connection = await providersDb.createProviderConnection({ + provider: "openai", + apiKey: "test-key", + isActive: true, + }); + + const { capturedBody } = await runChatCore({ + provider: "openai", + model: "gpt-4", + connectionId: connection.id, + headers: new Headers(), + messageContent: "Summarize this implementation.", + }); + assert.deepEqual( + capturedBody?.messages, + [{ role: "user", content: "Summarize this implementation." }], + "The messages should reach upstream untouched when compression is disabled" + ); + assert.equal( + JSON.stringify(capturedBody).includes(OUTPUT_STYLE_MARKER), + false, + "No output-style instruction should reach upstream when compression is disabled" + ); +}); diff --git a/tests/unit/compression/output-styles-anthropic-placement.test.ts b/tests/unit/compression/output-styles-anthropic-placement.test.ts new file mode 100644 index 000000000000..e78204772fad --- /dev/null +++ b/tests/unit/compression/output-styles-anthropic-placement.test.ts @@ -0,0 +1,211 @@ +// #12584: on an Anthropic-shaped body the output-style instruction must reach upstream in the +// top-level system field, never as a system turn in messages[]. Each body carries a tool, so the +// two shapes with a system prompt take the mid-conversation-system path, where only a leading +// run of system turns is hoisted out of messages[]. Those two shapes also carry a later system +// turn, which that path keeps in messages[] and the default Claude path would hoist. +import test from "node:test"; +import assert from "node:assert/strict"; +import fs from "node:fs"; +import { createTempDataDir } from "../../_setup/tempDataDir.ts"; + +const { dir: TEST_DATA_DIR, cleanup } = createTempDataDir("omniroute-style-placement-"); +process.env.REQUIRE_API_KEY = "false"; +process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "test-style-placement-secret"; + +const core = await import("../../../src/lib/db/core.ts"); +const readCacheDb = await import("../../../src/lib/db/readCache.ts"); +const compressionDb = await import("../../../src/lib/db/compression.ts"); +const { handleChatCore } = await import("../../../open-sse/handlers/chatCore.ts"); +const { isClaudeCodeSemanticPassthroughRequest } = + await import("../../../open-sse/handlers/chatCore/passthroughHelpers.ts"); +const { shouldUseMidConversationSystem } = + await import("../../../open-sse/executors/claudeIdentity.ts"); +const { FORMATS } = await import("../../../open-sse/translator/formats.ts"); +const { resetAllCircuitBreakers } = await import("../../../src/shared/utils/circuitBreaker.ts"); +const { CAVEMAN_INSTRUCTION_BY_LANGUAGE } = + await import("../../../open-sse/services/compression/outputMode.ts"); +const { OUTPUT_STYLE_MARKER } = + await import("../../../open-sse/services/compression/outputStyles/apply.ts"); +const { waitForCallLogSaves, closeCallLogSaves } = + await import("../../../src/lib/usage/callLogs.ts"); + +const originalFetch = globalThis.fetch; +const USER_AGENT = "claude-code/2.1.154"; +const LATER_SYSTEM_TURN = "Answer in one short paragraph."; + +// The Anthropic `system` field is a string or an array of text blocks; anything else fails. +function systemText(system: unknown): string { + if (typeof system === "string") return system; + assert.ok(Array.isArray(system), "the upstream system field should be a string or block array"); + return system + .map((block: { type?: string; text?: string }) => { + assert.equal(block?.type, "text", "every upstream system block should be a text block"); + assert.ok( + typeof block.text === "string", + "every upstream system block should carry string text" + ); + return block.text; + }) + .join("\n"); +} + +test.beforeEach(async () => { + globalThis.fetch = originalFetch; + resetAllCircuitBreakers(); + readCacheDb.invalidateDbCache(); + // Each request saves a call log in the background; it must land before the DB is reset. + assert.ok(await waitForCallLogSaves(30_000), "the previous test's call-log saves should finish"); + core.resetDbInstance(); + fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); +}); + +test.after(async () => { + globalThis.fetch = originalFetch; + // Stops the call-log writer too, which otherwise keeps the process alive for its idle timeout. + await closeCallLogSaves(2_000); + await cleanup(); +}); + +for (const [shape, system] of [ + ["a string system", "You are Claude."], + ["a content-block system", [{ type: "text", text: "You are Claude." }]], + ["no system", undefined], +] as const) { + test(`chatCore: output style lands in the top-level system field on an Anthropic body with ${shape} (#12584)`, async () => { + await compressionDb.updateCompressionSettings({ + enabled: true, + defaultMode: "off", + autoTriggerTokens: 0, + cavemanOutputMode: { + enabled: true, + intensity: "full", + autoClarity: true, + }, + }); + + let capturedBody = null as { + system?: unknown; + messages?: Array<{ role?: string; content?: unknown }>; + } | null; + globalThis.fetch = async (url: string | URL | Request, init?: RequestInit) => { + if (String(url).includes("/v1/messages") && init?.body) { + capturedBody = JSON.parse(init.body as string); + } + return Response.json({ + id: "msg_test", + type: "message", + role: "assistant", + model: "claude-opus-5", + content: [{ type: "text", text: "OK" }], + usage: { input_tokens: 4, output_tokens: 1 }, + }); + }; + + const body = { + model: "claude-opus-5", + max_tokens: 64, + stream: false, + ...(system === undefined ? {} : { system }), + tools: [ + { + name: "Read", + description: "Read a file", + input_schema: { type: "object", properties: {} }, + }, + ], + messages: [ + { role: "user", content: "Summarize this implementation." }, + ...(system === undefined + ? [] + : [ + { role: "assistant", content: "Which file?" }, + { role: "system", content: LATER_SYSTEM_TURN }, + { role: "user", content: "src/app.ts" }, + ]), + ], + }; + const headers = new Headers({ + accept: "application/json", + "content-type": "application/json", + "user-agent": USER_AGENT, + }); + + // The fixture must keep taking the routing these assertions depend on. + assert.equal( + isClaudeCodeSemanticPassthroughRequest({ + provider: "claude", + sourceFormat: FORMATS.CLAUDE, + targetFormat: FORMATS.CLAUDE, + headers, + userAgent: USER_AGENT, + }), + true, + "the fixture should take the Claude Code semantic passthrough" + ); + assert.equal( + shouldUseMidConversationSystem(body, body.model), + system !== undefined, + "only the shapes with a system prompt should take the mid-conversation-system path" + ); + + try { + const result = await handleChatCore({ + body: structuredClone(body), + modelInfo: { provider: "claude", model: "claude-opus-5", extendedContext: false }, + credentials: { apiKey: "test-claude-key", providerSpecificData: {} }, + log: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} }, + clientRawRequest: { endpoint: "/v1/messages", body: structuredClone(body), headers }, + connectionId: null, + onCredentialsRefreshed: () => {}, + onRequestSuccess: () => {}, + onStreamFailure: () => {}, + onDisconnect: () => {}, + userAgent: USER_AGENT, + comboName: null, + }); + + assert.ok(result.success, "Request should succeed"); + assert.ok(capturedBody, "the upstream request should be captured"); + const upstreamSystem = systemText(capturedBody.system); + assert.ok( + upstreamSystem.includes( + `${OUTPUT_STYLE_MARKER}\n${CAVEMAN_INSTRUCTION_BY_LANGUAGE.en.full}` + ), + "the full output-style instruction should land in the top-level system field" + ); + assert.equal( + JSON.stringify(capturedBody).split(OUTPUT_STYLE_MARKER).length - 1, + 1, + "the instruction should reach upstream exactly once" + ); + const upstreamMessages = capturedBody.messages ?? []; + assert.deepEqual( + upstreamMessages.map((message) => message.role), + body.messages.map((message) => message.role), + "messages[] should carry the client's turns and nothing else" + ); + assert.ok( + JSON.stringify(upstreamMessages[0]).includes("Summarize this implementation."), + "the user's text should survive" + ); + if (system !== undefined) { + assert.ok( + upstreamSystem.includes("You are Claude."), + "the client's own system prompt should survive" + ); + assert.ok( + JSON.stringify(upstreamMessages[2]).includes(LATER_SYSTEM_TURN), + "the later system turn should stay in messages[] on the mid-conversation-system path" + ); + assert.equal( + upstreamSystem.includes(LATER_SYSTEM_TURN), + false, + "the later system turn should not be hoisted into the top-level system field" + ); + } + } finally { + globalThis.fetch = originalFetch; + } + }); +} diff --git a/tests/unit/compression/output-styles-backcompat.test.ts b/tests/unit/compression/output-styles-backcompat.test.ts index 195e58152271..0c70881bac1c 100644 --- a/tests/unit/compression/output-styles-backcompat.test.ts +++ b/tests/unit/compression/output-styles-backcompat.test.ts @@ -1,7 +1,10 @@ import { test } from "node:test"; import assert from "node:assert/strict"; import { resolveOutputStyleSelection } from "../../../open-sse/services/compression/outputStyles/backCompat.ts"; -import { applyOutputStyles } from "../../../open-sse/services/compression/outputStyles/apply.ts"; +import { + applyOutputStyles, + OUTPUT_STYLE_MARKER, +} from "../../../open-sse/services/compression/outputStyles/apply.ts"; import { applyCavemanOutputMode } from "../../../open-sse/services/compression/outputMode.ts"; test("explicit outputStyles win when present", () => { @@ -29,21 +32,51 @@ test("disabled legacy mode and no styles → empty selection", () => { assert.deepEqual(resolveOutputStyleSelection({}), []); }); -test("golden: legacy config injects the same prose instruction as the old injector", () => { - const body = { messages: [{ role: "user", content: "Summarize this API response." }] }; - const legacy = applyCavemanOutputMode(structuredClone(body), { - enabled: true, - intensity: "full", - autoClarity: true, - }); - const sel = resolveOutputStyleSelection({ - cavemanOutputMode: { enabled: true, intensity: "full", autoClarity: true }, - }); - const next = applyOutputStyles(structuredClone(body), sel); +const LEGACY_MARKER = "[OmniRoute Caveman Output Mode]"; + +// Runs one user turn through the legacy injector and the unified one with the same config. +function injectBoth(content: string, autoClarity: boolean) { + const body = { messages: [{ role: "user", content }] }; + const config = { enabled: true, intensity: "full" as const, autoClarity }; + const legacy = applyCavemanOutputMode(structuredClone(body), config); + const next = applyOutputStyles( + structuredClone(body), + resolveOutputStyleSelection({ cavemanOutputMode: config }), + "en", + { autoClarity } + ); + return { body, legacy, next }; +} - const legacyInstr = String(legacy.body.messages?.[0]?.content); - const nextInstr = String(next.body.messages?.[0]?.content); +// The instruction text below the marker line. With no system turn in the body, both injectors +// append it as a trailing system message (#13383), so it is found by role, not at messages[0]. +function instructionText( + result: { body: { messages?: Array<{ role?: string; content?: unknown }> } }, + marker: string +) { + const injected = result.body.messages?.find((message) => message.role === "system"); + assert.ok(injected, "the injector added a system message"); + const text = String(injected.content); + assert.ok(text.startsWith(`${marker}\n`), `the instruction starts with ${marker}`); + return text.slice(marker.length + 1); +} + +test("golden: legacy config injects the same prose instruction as the old injector", () => { + const { legacy, next } = injectBoth("Summarize this API response.", true); // The prose instruction text (minus the marker line) must be byte-identical. - const strip = (s: string) => s.split("\n").slice(1).join("\n"); - assert.equal(strip(nextInstr), strip(legacyInstr)); + assert.equal(instructionText(next, OUTPUT_STYLE_MARKER), instructionText(legacy, LEGACY_MARKER)); +}); + +test("golden: with Auto-Clarity off, both injectors apply the same instruction on a bypass turn", () => { + const { legacy, next } = injectBoth("Explain this security vulnerability in detail.", false); + assert.equal(instructionText(next, OUTPUT_STYLE_MARKER), instructionText(legacy, LEGACY_MARKER)); +}); + +test("golden: with Auto-Clarity on, both injectors skip a bypass turn as security_warning", () => { + const { body, legacy, next } = injectBoth("Explain this security vulnerability in detail.", true); + for (const result of [legacy, next]) { + assert.equal(result.applied, false); + assert.equal(result.skippedReason, "security_warning"); + assert.deepEqual(result.body, body); + } }); From c84434577a6caad898a2a69a622b23d90ba0632e Mon Sep 17 00:00:00 2001 From: Lance Woodson <65194841+woodsonl@users.noreply.github.com> Date: Mon, 5 Oct 2026 20:59:24 -0500 Subject: [PATCH 2/2] test(compression): drain call-log saves on the paths the placement commit missed The pass-2 review of 824ceda46f (five specialist lenses, adversarial pass, red-team sweep, independent refuter votes) upheld nine advisory findings; this applies the in-scope ones with the drain pattern that commit already established in its two sibling files: - chatcore-compression-integration.test.ts now uses the shared createTempDataDir helper, asserts waitForCallLogSaves before every resetDbInstance, and drains + closes the call-log writer in test.after. Every green run of the two tests this diff edits logged 'The database connection is not open' (measured twice per run by the review); the file also kept the racy teardown the moved test was fixed for. - test-model-compression-off-6240.test.ts and output-styles-anthropic-placement.test.ts drain the last test's save before closeCallLogSaves, so the final in-flight save lands instead of erroring during close (1 and 3 residual lines per green run, now 0). - the two pt-BR combo-test comments stated as present fact what the autoDetect detector 'finds' while the fixture sets autoDetect: false; they now state the actual mechanism (detector off, global default 'en'). - the golden back-compat and placement tests pin their scope: the legacy-vs-unified identity and placement contracts are asserted for the English instruction only. - file-size-baseline.json: the chatcore freeze tracked the pre-split size (1214); the file gate-counts 1145 now, so the entry is tightened to the measured size per the baseline's exact-LOC convention. - eslint-suppressions.json: drop six entries whose violations no longer occur on this tree (stale-enforcement fails a cold-cache lint run). Verification: all four changed test files pass with zero residual call-log error lines (chatcore 13, 6240 3, placement 3, backcompat 6); npm run lint, Prettier and check:file-size are clean. The 20 production mutations banked on the parent commit all remain caught: no assertion changed, only teardown, comments and scope notes. --- config/quality/eslint-suppressions.json | 30 ------------------- config/quality/file-size-baseline.json | 2 +- .../chatcore-compression-integration.test.ts | 27 ++++++++--------- .../test-model-compression-off-6240.test.ts | 2 ++ .../output-styles-anthropic-placement.test.ts | 5 ++++ .../output-styles-backcompat.test.ts | 2 ++ 6 files changed, 23 insertions(+), 45 deletions(-) diff --git a/config/quality/eslint-suppressions.json b/config/quality/eslint-suppressions.json index ba0f152d7993..e457f9f727a4 100644 --- a/config/quality/eslint-suppressions.json +++ b/config/quality/eslint-suppressions.json @@ -625,11 +625,6 @@ "count": 1 } }, - "open-sse/translator/request/openai-to-cursor.ts": { - "@typescript-eslint/no-unused-vars": { - "count": 3 - } - }, "open-sse/translator/request/openai-to-gemini.ts": { "@typescript-eslint/no-unused-vars": { "count": 5 @@ -945,11 +940,6 @@ "count": 1 } }, - "src/app/(dashboard)/dashboard/settings/components/SystemStorageTab.tsx": { - "@typescript-eslint/no-unused-vars": { - "count": 1 - } - }, "src/app/(dashboard)/dashboard/tools/agent-bridge/components/AgentList.tsx": { "no-restricted-syntax": { "count": 3 @@ -1228,11 +1218,6 @@ "count": 1 } }, - "src/app/api/v1/vscode/[token]/combos/route.ts": { - "@typescript-eslint/no-unused-vars": { - "count": 1 - } - }, "src/app/api/v1/vscode/[token]/models/route.ts": { "no-restricted-syntax": { "count": 1 @@ -1243,11 +1228,6 @@ "count": 1 } }, - "src/app/api/v1/vscode/raw/[token]/combos/route.ts": { - "@typescript-eslint/no-unused-vars": { - "count": 1 - } - }, "src/app/login/page.tsx": { "@typescript-eslint/no-unused-vars": { "count": 3 @@ -1546,11 +1526,6 @@ "count": 1 } }, - "src/lib/oauth/providers/ghe-copilot.ts": { - "@typescript-eslint/no-unused-vars": { - "count": 1 - } - }, "src/lib/oauth/providers/kiro.ts": { "@typescript-eslint/no-unused-vars": { "count": 3 @@ -3352,11 +3327,6 @@ "count": 4 } }, - "tests/unit/cursor-agent-session.test.ts": { - "@typescript-eslint/no-unused-vars": { - "count": 1 - } - }, "tests/unit/cursor-usage-fetcher.test.ts": { "@typescript-eslint/no-explicit-any": { "count": 1 diff --git a/config/quality/file-size-baseline.json b/config/quality/file-size-baseline.json index 2e16ef3f9520..5cdcd6771813 100644 --- a/config/quality/file-size-baseline.json +++ b/config/quality/file-size-baseline.json @@ -287,7 +287,7 @@ "_rebaseline_2026_09_04_12737_codex_ws_premature_close_tests": "PR #12737 own test growth: executor-codex.test.ts 1465->1620 (+155, entirely this PR's diff — regression coverage for the premature WebSocket close fix: emits terminal response.failed with code upstream_websocket_closed when the socket closes before any terminal event, and proves no second terminal event fires after a normal post-response.completed close).", "_rebaseline_pr4613_compatible_provider_groups": "Reconcile #4613 already-merged growth: providers-page-utils.test.ts 1004->1052 (+48, buildCompatibleProviderGroups partition unit test). Fast-gate PR->release does not run check:file-size, so this surfaced post-merge.", "tests/integration/chat-pipeline.test.ts": 1756, - "tests/integration/chatcore-compression-integration.test.ts": 1214, + "tests/integration/chatcore-compression-integration.test.ts": 1145, "tests/unit/account-fallback-service.test.ts": 2086, "tests/unit/batch_api.test.ts": 1353, "tests/unit/cc-compatible-provider.test.ts": 1225, diff --git a/tests/integration/chatcore-compression-integration.test.ts b/tests/integration/chatcore-compression-integration.test.ts index a05b27fe33ef..ba64bbedef01 100644 --- a/tests/integration/chatcore-compression-integration.test.ts +++ b/tests/integration/chatcore-compression-integration.test.ts @@ -1,11 +1,9 @@ import test from "node:test"; import assert from "node:assert/strict"; import fs from "node:fs"; -import os from "node:os"; -import path from "node:path"; +import { createTempDataDir } from "../_setup/tempDataDir.ts"; -const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-compression-")); -process.env.DATA_DIR = TEST_DATA_DIR; +const { dir: TEST_DATA_DIR, cleanup } = createTempDataDir("omniroute-compression-"); process.env.REQUIRE_API_KEY = "false"; process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "test-compression-secret"; @@ -19,6 +17,7 @@ const compressionAnalyticsDb = await import("../../src/lib/db/compressionAnalyti const { handleChatCore } = await import("../../open-sse/handlers/chatCore.ts"); const { estimateTokens, getTokenLimit } = await import("../../open-sse/services/contextManager.ts"); const { resetAllCircuitBreakers } = await import("../../src/shared/utils/circuitBreaker.ts"); +const { waitForCallLogSaves, closeCallLogSaves } = await import("../../src/lib/usage/callLogs.ts"); const originalFetch = globalThis.fetch; @@ -27,6 +26,8 @@ async function resetStorage() { resetAllCircuitBreakers(); readCacheDb.invalidateDbCache(); await new Promise((resolve) => setTimeout(resolve, 20)); + // The previous test's call log is saved in the background; it must land before the reset. + assert.ok(await waitForCallLogSaves(30_000), "the previous test's call-log saves should finish"); core.resetDbInstance(); fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); @@ -38,10 +39,10 @@ test.beforeEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; - core.closeDbInstance(); - try { - fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); - } catch {} + // Drain the last test's in-flight save, then stop the writer before the database closes. + assert.ok(await waitForCallLogSaves(30_000), "the last test's call-log save should finish"); + await closeCallLogSaves(2_000); + await cleanup(); }); test("chatCore integration: compressContext called proactively when context exceeds 85% threshold", async () => { @@ -612,9 +613,8 @@ test("chatCore integration: assigned compression combo applies language packs an }, languageConfig: { enabled: true, - // autoDetect finds no pt-BR hint word in this short Portuguese turn and resolves to - // "en", so it stays off. The global default is English too, so pt-BR output can only - // come from the combo's language packs. + // autoDetect is disabled here, so the detector never runs. With the global default + // language "en", pt-BR output can only come from the combo's language packs. autoDetect: false, defaultLanguage: "en", enabledPacks: ["en"], @@ -725,9 +725,8 @@ test("chatCore integration: default stacked compression combo applies for unassi }, languageConfig: { enabled: true, - // autoDetect finds no pt-BR hint word in this short Portuguese turn and resolves to - // "en", so it stays off. The global default is English too, so pt-BR output can only - // come from the combo's language packs. + // autoDetect is disabled here, so the detector never runs. With the global default + // language "en", pt-BR output can only come from the combo's language packs. autoDetect: false, defaultLanguage: "en", enabledPacks: ["en"], diff --git a/tests/integration/test-model-compression-off-6240.test.ts b/tests/integration/test-model-compression-off-6240.test.ts index 98fc0efff494..b03c1df90cf1 100644 --- a/tests/integration/test-model-compression-off-6240.test.ts +++ b/tests/integration/test-model-compression-off-6240.test.ts @@ -50,6 +50,8 @@ test.beforeEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; + // Drain the last test's in-flight save before closing, so it lands instead of erroring. + assert.ok(await waitForCallLogSaves(30_000), "the last test's call-log save should finish"); // Stops the call-log writer too, which otherwise keeps the process alive for its idle timeout. await closeCallLogSaves(2_000); await cleanup(); diff --git a/tests/unit/compression/output-styles-anthropic-placement.test.ts b/tests/unit/compression/output-styles-anthropic-placement.test.ts index e78204772fad..631433f5d133 100644 --- a/tests/unit/compression/output-styles-anthropic-placement.test.ts +++ b/tests/unit/compression/output-styles-anthropic-placement.test.ts @@ -3,6 +3,9 @@ // two shapes with a system prompt take the mid-conversation-system path, where only a leading // run of system turns is hoisted out of messages[]. Those two shapes also carry a later system // turn, which that path keeps in messages[] and the default Claude path would hoist. +// +// Scope: the placement contract is asserted for the English ("en") instruction only; the +// localized instruction texts are not covered here. import test from "node:test"; import assert from "node:assert/strict"; import fs from "node:fs"; @@ -62,6 +65,8 @@ test.beforeEach(async () => { test.after(async () => { globalThis.fetch = originalFetch; + // Drain the last test's in-flight save before closing, so it lands instead of erroring. + assert.ok(await waitForCallLogSaves(30_000), "the last test's call-log save should finish"); // Stops the call-log writer too, which otherwise keeps the process alive for its idle timeout. await closeCallLogSaves(2_000); await cleanup(); diff --git a/tests/unit/compression/output-styles-backcompat.test.ts b/tests/unit/compression/output-styles-backcompat.test.ts index 0c70881bac1c..95c8794511b4 100644 --- a/tests/unit/compression/output-styles-backcompat.test.ts +++ b/tests/unit/compression/output-styles-backcompat.test.ts @@ -35,6 +35,8 @@ test("disabled legacy mode and no styles → empty selection", () => { const LEGACY_MARKER = "[OmniRoute Caveman Output Mode]"; // Runs one user turn through the legacy injector and the unified one with the same config. +// Language scope: "en" only — the legacy-vs-unified identity contracts below are not asserted +// for the localized (hu/ja/zh) instruction texts. function injectBoth(content: string, autoClarity: boolean) { const body = { messages: [{ role: "user", content }] }; const config = { enabled: true, intensity: "full" as const, autoClarity };