From 8f51f8c92a1e9cd385af156be932fce69b7266db Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza Date: Tue, 30 Jun 2026 14:45:41 -0300 Subject: [PATCH] fix(compression): derive preserveSystemPromptMode from legacy boolean when no mode row (#5653 back-compat) --- src/lib/db/compression.ts | 23 ++++- .../preserve-system-prompt-mode-db.test.ts | 93 +++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 tests/unit/compression/preserve-system-prompt-mode-db.test.ts diff --git a/src/lib/db/compression.ts b/src/lib/db/compression.ts index 6a19c83fcb..e2806a3406 100644 --- a/src/lib/db/compression.ts +++ b/src/lib/db/compression.ts @@ -28,7 +28,10 @@ import { type RtkConfig, type UltraConfig, } from "@omniroute/open-sse/services/compression/types.ts"; -import { isPreserveSystemPromptMode } from "@omniroute/open-sse/services/compression/preserveSystemPromptMode.ts"; +import { + isPreserveSystemPromptMode, + normalizePreserveSystemPromptMode, +} from "@omniroute/open-sse/services/compression/preserveSystemPromptMode.ts"; import { maybePrewarmUltraSlmOnConfig } from "@omniroute/open-sse/services/compression/ultra.ts"; const NAMESPACE = "compression"; @@ -551,6 +554,11 @@ export async function getCompressionSettings(): Promise { // we derive the engines map from the legacy fields below so behavior is preserved. let storedEngines: Record | null = null; + // Tracks whether an authoritative `preserveSystemPromptMode` row was persisted. When absent + // (legacy install that only stored the `preserveSystemPrompt` boolean) the mode is derived + // from that boolean below so it keeps its old behaviour instead of inheriting the new default. + let sawPreserveSystemPromptModeRow = false; + for (const row of rows) { const record = toRecord(row); const key = typeof record.key === "string" ? record.key : null; @@ -592,6 +600,7 @@ export async function getCompressionSettings(): Promise { // T05/C5 — authoritative intent; ignore unknown tokens (keep the default mode). if (isPreserveSystemPromptMode(parsed)) { config.preserveSystemPromptMode = parsed; + sawPreserveSystemPromptModeRow = true; } break; case "mcpDescriptionCompressionEnabled": @@ -659,6 +668,18 @@ export async function getCompressionSettings(): Promise { } } + // T05/C5 back-compat: a legacy install persisted only the `preserveSystemPrompt` boolean and no + // `preserveSystemPromptMode` row. The DEFAULT spread above seeds the new `always` mode, which would + // otherwise shadow that boolean (an explicit mode wins in normalizePreserveSystemPromptMode) and + // silently flip `preserveSystemPrompt=false` installs from "compress unless cached" to "always + // preserve". When no mode row was stored, derive the authoritative mode from the boolean instead. + if (!sawPreserveSystemPromptModeRow) { + config.preserveSystemPromptMode = normalizePreserveSystemPromptMode({ + preserveSystemPrompt: config.preserveSystemPrompt, + preserveSystemPromptMode: undefined, + }); + } + // Engines map: prefer the stored row; otherwise derive from the legacy fields (migration 102 // backfill on the read path). Always fill EVERY id in ENGINE_IDS so the shape matches // DEFAULT_COMPRESSION_CONFIG. diff --git a/tests/unit/compression/preserve-system-prompt-mode-db.test.ts b/tests/unit/compression/preserve-system-prompt-mode-db.test.ts new file mode 100644 index 0000000000..ab3ae491f7 --- /dev/null +++ b/tests/unit/compression/preserve-system-prompt-mode-db.test.ts @@ -0,0 +1,93 @@ +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"; + +// T05/C5 back-compat regression (#5653) at the DB read path. The new DEFAULT_COMPRESSION_CONFIG +// seeds preserveSystemPromptMode='always'. getCompressionSettings() spreads that default, so a +// legacy install that persisted ONLY the `preserveSystemPrompt` boolean (no mode row) would have +// the default 'always' shadow the boolean — silently flipping `preserveSystemPrompt=false` installs +// from "compress unless cached" (whenNoCache) to "always preserve". The read path must instead +// derive the mode from the boolean when no mode row exists. +// +// core.ts freezes DATA_DIR/SQLITE_FILE into module consts at first import, so the temp DATA_DIR is +// set BEFORE any import and the db file is shared across tests. Each test isolates by wiping the +// `compression` namespace and busting the module-level TTL cache via resetDbInstance() (which hands +// out a NEW db object, so the cache — keyed by db ref — misses). +const TEMP_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-preserve-mode-")); +process.env.DATA_DIR = TEMP_DIR; + +async function freshCompressionDb() { + const { getDbInstance, resetDbInstance } = await import("../../../src/lib/db/core.ts"); + const db = getDbInstance(); // runs migrations on first call + db.prepare("DELETE FROM key_value WHERE namespace = 'compression'").run(); + return { db, resetDbInstance }; +} + +async function readSettings() { + const { getCompressionSettings } = await import("../../../src/lib/db/compression.ts"); + return getCompressionSettings(); +} + +test.after(async () => { + try { + const { resetDbInstance } = await import("../../../src/lib/db/core.ts"); + resetDbInstance(); + } catch { + /* core never loaded */ + } + try { + fs.rmSync(TEMP_DIR, { recursive: true, force: true }); + } catch { + /* best-effort */ + } +}); + +test("legacy preserveSystemPrompt=false (no mode row) derives whenNoCache", async () => { + const { db, resetDbInstance } = await freshCompressionDb(); + db.prepare( + "INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES ('compression','preserveSystemPrompt','false')" + ).run(); + resetDbInstance(); // new db object => TTL cache miss on the next read + + const cfg = await readSettings(); + assert.equal( + cfg.preserveSystemPromptMode, + "whenNoCache", + "legacy preserveSystemPrompt=false must derive whenNoCache, not inherit the 'always' default" + ); + + // End-to-end: without a cacheable prefix, a legacy-off install must still compress the prompt. + const { resolveCacheAwareConfig } = await import( + "../../../open-sse/services/compression/cacheAwareConfig.ts" + ); + assert.equal( + resolveCacheAwareConfig(cfg).preserveSystemPrompt, + false, + "legacy-off install must compress the system prompt when there is no cache" + ); +}); + +test("fresh install (no override rows) defaults to always", async () => { + const { resetDbInstance } = await freshCompressionDb(); // wipes all compression rows + resetDbInstance(); + + const cfg = await readSettings(); + assert.equal(cfg.preserveSystemPromptMode, "always", "fresh default mode is always"); + assert.equal(cfg.preserveSystemPrompt, true, "fresh default boolean is true"); +}); + +test("an explicit mode row wins over the legacy boolean", async () => { + const { db, resetDbInstance } = await freshCompressionDb(); + db.prepare( + "INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES ('compression','preserveSystemPrompt','false')" + ).run(); + db.prepare( + "INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES ('compression','preserveSystemPromptMode','\"never\"')" + ).run(); + resetDbInstance(); + + const cfg = await readSettings(); + assert.equal(cfg.preserveSystemPromptMode, "never", "an explicit stored mode row wins"); +});