diff --git a/changelog.d/fixes/12647-background-degradation-deletions.md b/changelog.d/fixes/12647-background-degradation-deletions.md new file mode 100644 index 0000000000..5339d07594 --- /dev/null +++ b/changelog.d/fixes/12647-background-degradation-deletions.md @@ -0,0 +1 @@ +- **fix(config):** Persist deletions of built-in background-degradation entries — when a stored settings record exists its `degradationMap` is now authoritative instead of being merged under the defaults, so an entry the user removed in the dashboard no longer reappears on the next apply or restart ([#12424](https://github.com/diegosouzapw/OmniRoute/issues/12424)) diff --git a/src/lib/config/runtimeSettings.ts b/src/lib/config/runtimeSettings.ts index 0cb93c8fee..ed5930cbb7 100644 --- a/src/lib/config/runtimeSettings.ts +++ b/src/lib/config/runtimeSettings.ts @@ -323,10 +323,11 @@ async function applyBackgroundDegradationSection(backgroundDegradation: JsonReco setBackgroundDegradationConfig({ enabled: backgroundDegradation.enabled === true, - degradationMap: { - ...getDefaultDegradationMap(), - ...normalizeStringRecord(backgroundDegradation.degradationMap), - }, + // #12424: a present stored record is authoritative for degradationMap — do NOT back-fill + // defaults, or a key the user deleted (absent from the stored map) resurrects on every + // apply/restart. Mirrors detectionPatterns below, which already treats a present stored + // value as authoritative and only falls back to defaults when it is empty. + degradationMap: normalizeStringRecord(backgroundDegradation.degradationMap), detectionPatterns: normalizeStringArray(backgroundDegradation.detectionPatterns).length > 0 ? normalizeStringArray(backgroundDegradation.detectionPatterns) diff --git a/tests/unit/settings/background-degradation-deletions-12424.test.ts b/tests/unit/settings/background-degradation-deletions-12424.test.ts new file mode 100644 index 0000000000..f5b157a723 --- /dev/null +++ b/tests/unit/settings/background-degradation-deletions-12424.test.ts @@ -0,0 +1,57 @@ +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"; + +process.env.DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-bgdeg-12424-")); + +const { applyRuntimeSettings, resetRuntimeSettingsStateForTests } = await import( + "../../../src/lib/config/runtimeSettings.ts" +); +const { + getBackgroundDegradationConfig, + getDefaultDegradationMap, + getDefaultDetectionPatterns, + setBackgroundDegradationConfig, +} = await import("../../../open-sse/services/backgroundTaskDetector.ts"); + +// Issue #12424: deleting a built-in background-degradation entry through the dashboard +// did not persist — the runtime loader merged defaults *under* the stored map, so a key +// the user removed (absent from the stored record) was indistinguishable from one never +// touched and always came back on the next apply/restart. +test("stored degradationMap that omits a default key does not resurrect it (#12424)", async () => { + resetRuntimeSettingsStateForTests(); + setBackgroundDegradationConfig({ + enabled: false, + degradationMap: getDefaultDegradationMap(), + detectionPatterns: getDefaultDetectionPatterns(), + }); + + const defaults = getDefaultDegradationMap(); + const deletedKey = "gpt-5"; + const keptKey = "gpt-4o"; + assert.ok( + defaults[deletedKey] && defaults[keptKey], + "fixture assumes these default keys exist in DEFAULT_DEGRADATION_MAP" + ); + + // The stored map is every default except the one the user deleted. + const stored: Record = { ...defaults }; + delete stored[deletedKey]; + + await applyRuntimeSettings( + { backgroundDegradation: JSON.stringify({ enabled: true, degradationMap: stored }) }, + { force: true, source: "test" } + ); + + const applied = getBackgroundDegradationConfig().degradationMap; + + // The entries the user kept still apply… + assert.equal(applied[keptKey], defaults[keptKey], "a kept default entry still applies"); + // …and the one they deleted stays deleted instead of being back-filled from defaults. + assert.ok( + !(deletedKey in applied), + `deleted default '${deletedKey}' must not be re-added from defaults` + ); +});