Repository navigation
fix(compression): show a retry when settings fail to load - #15346
Merged
diegosouzapw merged 5 commits intoOct 6, 2026
Merged
diegosouzapw merged 5 commits into
diegosouzapw merged 5 commits into
Conversation
When GET /api/settings/compression fails, CompressionPanel renders its editable controls on DEFAULT_CONFIG. The first switch pressed then PUTs those defaults over the stored row: a one-entry engines map, a one-entry outputStyles list, a default liveZone. CompressionSettingsTab swallows the same failure and reports every compression layer as off. The new cases answer the first settings GET with a 500. They expect an error with a retry in place of the controls, no settings PUT until a GET succeeds, and the stored values once the retry loads. They fail here.
A failed GET /api/settings/compression (a 5xx, or a network error during a server restart) was swallowed, and both compression views rendered their editable controls on defaults. CompressionPanel's confirmed-config ref kept those defaults, so the next output-style toggle or context-budget change overwrote the stored outputStyles or contextBudget, and an engine toggle stored a one-entry engines map that dispatch then followed. CompressionSettingsTab reported every compression layer as off. Both now treat a non-OK response or a fetch error as a failed load and render the error with a Retry button in place of the controls, so no save can go out until a GET succeeds. Retry re-runs the component's loads. The message reuses settings.compressionTitle, common.failedToLoad and settings.retry, which every locale already carries. The tab already imported Button without using it; the retry button uses it now, so the tab's frozen no-unused-vars entry leaves config/quality/eslint-suppressions.json.
The load-failure cases now also run with a fetch that throws. The Retry cases hold the retried GET open and check that loading shows and no control renders until it answers. Two new cases answer a request from the first load only after a retry finished: the panel's mcp-accessibility toggle and the tab's rule list must keep the retried load's values. They fail here, because the load effects have no cleanup.
Both load effects now return a cleanup, so after a retry the answers that arrive for the replaced run are ignored: the panel's mcp-accessibility and combos loads, and the tab's rules load. The derived-pipeline text moves into derivedPreviewText. That takes the decision point the loadFailed return added back out of CompressionPanel, so the complexity ratchet is at its base count again. The load-error text uses text-red-600 dark:text-red-400, which meets the WCAG AA contrast ratio on the card.
This was referenced Oct 5, 2026
diegosouzapw
merged commit Oct 6, 2026
f43c467
into
diegosouzapw:release/v3.8.52
114 of 177 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
GET /api/settings/compressionfails (a 5xx, or a network error during a server restart),CompressionPanel(/dashboard/context/settings) andCompressionSettingsTab(embedded in/dashboard/context/caveman) now show "Prompt Compression: Failed To Load" and a Retry button in place of their controls. Retry shows the loading state, re-runs the component's loads, and the controls come back once a GET succeeds. Both load effects return a cleanup, so answers that arrive for a run a retry replaced are ignored..catch(() => {})swallowed the failure and.finally(() => setLoading(false))rendered the editable controls onDEFAULT_CONFIG(engines: {},outputStyles: [], the defaultcontextBudget), andlastConfirmedRefkept those defaults. The output-style toggles and the context-budget dial are live at once, so the next click overwrote the storedoutputStylesorcontextBudgetwith the defaults plus one change. Turning on the master switch (shown off) unlocked the engine toggles. One engine toggle then PUT a one-entryenginesmap, whichsanitizeEnginesForWrite(src/lib/db/compression.ts) stored withenginesExplicit: true, so dispatch followed that one-entry map. The tab's defaults have compression off, so it hid its editable sections and reported every layer as off.derivedPreviewTexthelper. That keepsCompressionPanelat the complexity cap of 15 that theif (loadFailed)return would otherwise exceed.settings.compressionTitle,common.failedToLoadandsettings.retry, which all 67 locales already carry, so no catalog changes are needed. Its text usestext-red-600 dark:text-red-400, the repo's most common error-text pair. Computed from Tailwind's OKLCH values against the card surface, that is 4.8:1 in the light theme (#ffffff) and 6.0:1 in the dark theme (#161b22), above the WCAG AA minimum of 4.5:1. The previoustext-red-500measures 3.8:1 in the light theme.CompressionSettingsTabalready importedButtonwithout using it. The retry button now uses it, so the tab's frozen@typescript-eslint/no-unused-varsentry comes out ofconfig/quality/eslint-suppressions.json(lint-staged fails on an unused suppression).Related Issues
fix/compression-panel-partial-saveandfix/compression-engines-partial-write(see Reviewer Notes).Validation
{ enabled: true }, engines maps that start one-entry ({ "session-dedup": { enabled: true } }), one-entryoutputStyleslists, andliveZone. Commit 2104355 adds the stale-load cases. On it they fail (the panel's MCP toggle and the tab's rule list take the superseded load's values), and the 17 other cases pass.npx vitest run --config vitest.config.tson the 9 files that render either component passes 50/50, including the caveman page that embeds the tab.npm run lint: ESLint on the 4 changed source and test files (--suppressions-location config/quality/eslint-suppressions.json --pass-on-unpruned-suppressions) is clean. The full lint runs in the CIlintjob.node scripts/check/check-complexity-ratchets.mjs --base-ref 4db3c54ec1: OK, 3 violations in the touched files against 3 at the base.npm run check:dashboard-typecheck: OK, within the frozen baseline.npx prettier --checkon the changed files is clean.release/v3.8.52at 228d72d.git merge-treeagainst the current tip is clean, and none of the files changed here moved on the base.Tests Added Or Updated
tests/unit/ui/compressionPanel.test.tsx, newdescribe("CompressionPanel when the settings GET fails"):{ enabled: false }.tests/unit/ui/compression-settings-tab-partial-save.test.tsx, newdescribe("CompressionSettingsTab when the settings GET fails"):Coverage Notes
.tsxvitest UI tests.ci.yml'stest-vitestjob runs them on this PR (npm run test:vitest:ui). In the CI run on 06fe786, both files ran and passed:compressionPanel.test.tsx(8 tests) andcompression-settings-tab-partial-save.test.tsx(12 tests).Reviewer Notes
Fast Quality Gates, gatecycles: every PR againstrelease/v3.8.52fails it the same way (for example fix(executors): route GHE Copilot GPT-6 models to Responses #15499 and fix(providers): load the ChatGPT web validator only when it is tested #15516), with the same 14 strongly connected components. After fix(ci): make check-cycles honest — real graph walk + cycles ratchet (#15159 G-01/G-02) #15281,ci.ymlrunscheck:cycles:ratchet, butquality.ymlstill runs the plaincheck:cycles, which exits 1 on any cycle. 🔴 Release branch not green: release/v3.8.52 #15306 does not list it.Fast Quality Gates, gatecomplexity-ratchets(second run): it reportsFeatureFlagCard.tsx: 1 → 2, a file this PR does not touch. The gate measures new code fromgithub.event.pull_request.base.sha, which is still this PR's opening base, 4db3c54. The job merges into the current tip, 23a1148, so the gate sweeps in the three base commits that landed after this PR opened, including feat(dashboard): add description display modes to feature-flags cards #12740, whose own run printed the same line. Against 23a1148, this PR's files read 1 → 1 (CompressionPanel.tsx) and 2 → 2 (CompressionSettingsTab.tsx).Integration Tests (2/2)(second run):batch-e2e-rate-limit.test.tsfailed before serving a request, because its dev server hitlisten EADDRINUSEon the free port the test had picked. The test releases that port, and the server binds it 15 to 18 seconds later. This PR touches no server code, integration test or dev script.Build: fork PRs build on the hostedubuntu-latestrunner, which is shut down partway through the Next build ("The runner has received a shutdown signal"). Other fork PRs fail the same way (for example fix(combo): type the custom-model row in the auto pool check #15461, fix(cli): scope the serve port guard to the bind address #15472 and fix(sse): drop a replayed responses event when the sequence is a string #15510), while base pushes build on the self-hosted runner.Vitest (MCP / autoCombo / UI components): every test passes. The UI step exits 1 on unhandledReferenceError: window is not definederrors raised after teardown by other files (comboLiveStudio.test.tsx,flowCanvas.test.tsx,providerCardAudioBadge.test.tsx). The base push on 23a1148 fails the same way.Lint:npm run audit:depsstops on the critical advisory fornext16.2.0 - 16.3.5 (GHSA-vcvr-r3jv-pc5j) before ESLint runs. Base pushes fail the same step.Docs Sync (Strict): translation drift ondocs/architecture/QUALITY_GATES.mdat the base.Merge integrity:check:agent-skills-syncfindsskills/omni-providersstale againstdocs/openapi.yamlat the base.check:changelog-integritypasses.Gate / CIandGate / Qualitysummarize the jobs above.fix/compression-panel-partial-saverewritessave()and the refs above it, andfix/compression-engines-partial-writemerges engines by id and changessetEngine. Both also editCompressionPanel.tsxandcompressionPanel.test.tsx. This PR leavessave(), those refs,setEngineandsetupFetchMockuntouched, and adds its tests in a separatedescribe.git merge-treeagainst the current heads (e3529ed and 42c7027) reports no conflicts. On each trial merge, the compression UI suites pass: 58/58 with the partial-save branch and 53/53 with the engines branch, including itscompressionPanelEnginesPartialWrite.test.tsx.Browser QA
A real-Chromium pass against a local dev server serving 06fe786, with
GET /api/settings/compressionpatched to answer 500:role="alert"card reading "Prompt Compression: Failed To Load" with exactly one Retry button.