feat(compression-ui): unified compression config UI — per-engine pages + combos editor + menu + WS default-on - #3860
Conversation
Add getPerEngineAnalytics() to compressionAnalytics.ts (mirrors byEngine GROUP BY COALESCE pattern, calls ensureCompressionAnalyticsColumns) and GET /api/context/analytics/engine?engineId=&days= route with management auth. 9 TDD tests covering aggregation, time window, COALESCE fallback, 400 on missing engineId, and days param forwarding.
… pipeline - Fix #1: expand normalizePipeline allowlist to include headroom, session-dedup, ccr, llmlingua so new engine IDs are no longer silently stripped when reading from DB - Fix #2 + setEngineInDefaultCombo: new exported function that enables/disables a single engine in the default compression combo, sorts by stackPriority, and uses a direct UPDATE to allow empty pipeline (bypassing buildComboPayload's non-empty fallback) - New route GET/PUT /api/context/combos/default: mirrors existing combos auth pattern (requireManagementAuth + Zod validation), delegates to setEngineInDefaultCombo - Tests: 6 DB unit tests (normalizePipeline regression + enable/disable/config/empty pipeline) and 4 route tests (GET, PUT enable, PUT 400 bad input, PUT 400 bad JSON)
…anitization, route auth, save state, docs
…ix cross-file isolation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Code Review
This pull request introduces per-engine configuration pages and analytics for compression engines (CCR, Headroom, LLMLingua, and Session Dedup), along with supporting API endpoints, database functions, and comprehensive tests. Feedback on the changes highlights a potential usability issue where users could lose configuration changes if they click save while an engine is disabled, and suggests disabling the save button in this state. Additionally, the API should distinguish between an invalid engine ID (400) and a missing default combo (404). Finally, inline Zod schemas in the route files should be moved to src/shared/validation/schemas.ts to comply with the repository style guide.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| <button | ||
| onClick={handleSave} | ||
| disabled={saving} | ||
| className="px-4 py-1.5 rounded bg-primary text-primary-foreground text-sm font-medium disabled:opacity-50" | ||
| > | ||
| {saving ? "Salvando…" : "Salvar"} | ||
| </button> |
There was a problem hiding this comment.
Since the database only stores configuration for engines that are active in the pipeline (via compression_combos), saving the configuration while the engine is disabled (enabled === false) will result in the configuration being silently discarded on the backend.
To prevent users from losing their configuration changes, we should disable the Salvar button when the engine is not enabled, or prompt them to enable the engine first.
Here is a suggestion to disable the button and add a descriptive tooltip when the engine is disabled:
| <button | |
| onClick={handleSave} | |
| disabled={saving} | |
| className="px-4 py-1.5 rounded bg-primary text-primary-foreground text-sm font-medium disabled:opacity-50" | |
| > | |
| {saving ? "Salvando…" : "Salvar"} | |
| </button> | |
| <button | |
| onClick={handleSave} | |
| disabled={saving || !enabled} | |
| className="px-4 py-1.5 rounded bg-primary text-primary-foreground text-sm font-medium disabled:opacity-50" | |
| title={!enabled ? "Ative a camada para salvar a configuração" : undefined} | |
| > | |
| {saving ? "Salvando…" : "Salvar"} | |
| </button> |
| if (!combo) { | ||
| return NextResponse.json({ error: "No default compression combo found" }, { status: 404 }); | ||
| } | ||
| return NextResponse.json(combo); |
There was a problem hiding this comment.
The setEngineInDefaultCombo function returns null if either the engineId is invalid (not in KNOWN_ENGINE_IDS) or if the default compression combo is not found in the database.
Currently, if an invalid engineId is provided, the API misleadingly responds with a 404 status and the message "No default compression combo found".
We should distinguish between these two cases so that an invalid engine ID correctly returns a 400 Bad Request error.
const combo = setEngineInDefaultCombo(engineId, enabled, config);
if (!combo) {
if (!getDefaultCompressionCombo()) {
return NextResponse.json({ error: "No default compression combo found" }, { status: 404 });
}
return NextResponse.json({ error: "Invalid engine ID" }, { status: 400 });
}
return NextResponse.json(combo);| const engineToggleSchema = z | ||
| .object({ | ||
| engineId: z.string().trim().min(1).max(64), | ||
| enabled: z.boolean(), | ||
| config: z.record(z.string(), z.unknown()).optional(), | ||
| }) | ||
| .strict(); |
There was a problem hiding this comment.
According to the repository style guide, all input validation Zod schemas should be defined in src/shared/validation/schemas.ts rather than inline in the route files. Please move engineToggleSchema to src/shared/validation/schemas.ts and import it here.
References
- Always validate inputs with Zod schemas from src/shared/validation/schemas.ts (link)
| }) | ||
| ) | ||
| .min(1), | ||
| mode: z.enum(["off", "lite", "standard", "aggressive", "ultra", "rtk", "stacked"]), | ||
| mode: z | ||
| .enum(["off", "lite", "standard", "aggressive", "ultra", "rtk", "stacked"]) | ||
| .optional() | ||
| .default("stacked"), | ||
| engineId: z.string().optional(), | ||
| config: PreviewCompressionConfigSchema.optional(), | ||
| }); |
There was a problem hiding this comment.
According to the repository style guide, all input validation Zod schemas should be defined in src/shared/validation/schemas.ts rather than inline in the route files. Please move PreviewRequestSchema to src/shared/validation/schemas.ts and import it here.
References
- Always validate inputs with Zod schemas from src/shared/validation/schemas.ts (link)
…eader strict-resolves i18nKey; missing key froze page hydration)
…equential→Promise.all)
…) — hydration regression The redesigned CompressionCombosPageClient failed to hydrate on the production build (useEffect never ran, React buttons inert, engineCatalog stayed empty so engine names rendered as ids and the add-engine buttons never appeared). Restore the previous working combos editor and remove the now-unused pipeline reducer. Engine activation still works via the per-engine config pages. The ordered-layer combos redesign will return in a dedicated follow-up with local hydration testing.
…ine pages
Make the Combos screen a single control center for compression and complete the
per-engine page coverage.
Compression Hub (top of the Combos screen):
- Master switch (Token Saver) + mode selector with a clear status callout: the
layered pipeline runs only when Token Saver is on AND mode = Stacked, with
one-click fixes ("Ligar Token Saver" / "Usar modo Stacked"). No auto-stacked magic.
- Collapsible "Como funciona?" explainer (master → mode → ordered layers → config →
named combos).
- Ordered, reorderable list of all 9 layers: on/off toggle, live description, beta
badge, stackPriority, and a gear link to each engine's dedicated page.
- Toggle routes through /api/context/combos/default (handles the empty pipeline and
inserts at the stackPriority position).
- Reorder persists via /api/context/combos/[id] (preserves custom order; the route's
pipeline.min(1) guard is always satisfied since reorder needs >= 2 steps).
New engine pages (generic EngineConfigPage): Lite, Aggressive, Ultra — completing the
6 existing pages to all 9 engines (one menu item each).
Hydration: the Hub and the rewritten Combos page deliberately use no useTranslations
(hardcoded pt-BR, like EngineConfigPage which hydrates cleanly) — the earlier combos
redesign failed to hydrate on the production build and a page-level useTranslations was
the only structural difference. New sidebar items get contextLite/contextAggressive/
contextUltra keys across all 42 locales so the Header's strict i18n resolve never
freezes their pages.
Tests: render tests for the Hub + the 3 new engine pages (createRoot + act); updated
the sidebar-visibility membership assertions (were stale vs the engine items added
earlier in this branch). typecheck/cycles/any-budget/ESLint clean; backend route tests
and 60 sidebar tests green.
sidebarVisibility.ts 1006->1100 (Compression Hub menu + per-engine pages) and chatCore.ts 5812->5815 (compression UI config wiring). Cohesive feature growth; restores Fast Quality Gates on the PR.
tests/unit/ws/ is not in any runner's collection glob, so the new live-ws-default test never ran (check:test-discovery orphan). Moved to tests/unit/runtime/ (collected, same depth → import path unchanged). 7/7 pass.
…ributors Audited every commit since v3.8.24 and filled the gaps the [3.8.25] section was missing: a New Features section (compression engines + Compression Studios #3848, compression UI #3860, injection-guard #3857, kiro discovery #3836, Veo #3839, mimocode proxy #3837, Arena ELO flag #3821), 9 more Fixed entries (#3811/#3807/#3759/#3849/#3838/#3835/#3814/#3820/#3819), a Security section (CCR IDOR #3859, supply-chain #3824), and an Internal/Quality section. Every contributor and issue reporter is now credited.
* chore(release): continue v3.8.25 development cycle after main code-sync (r5) main fast-forwarded to release/v3.8.25 (#3863): unblocked Build+Docker via #3864, plus #3837 (mimocode proxy) and #3862 (trivy bump). This marker re-opens the umbrella PR for further v3.8.25 work. No version bump. * fix(db): persist the Keep-latest-backups retention setting (#3834) (#3867) * fix(oauth): clear GitLab Duo setup message instead of 500 (#3861) (#3868) * test(oauth): prove refresh_token preserved on real gemini-cli/antigravity dispatch (#3850) (#3869) * feat(compression-ui): unified compression config UI — per-engine pages + combos editor + menu + WS default-on (#3860) Integrated into release/v3.8.25 — feat(compression-ui): unified compression configuration UI (Compression Hub + per-engine Lite/Aggressive/Ultra pages + combos editor + sidebar entry + live-WS default-on). File-size re-baselined for sidebarVisibility.ts/chatCore.ts growth; orphan ws test relocated to a collected path. * docs(changelog): complete the v3.8.25 release notes + credit all contributors Audited every commit since v3.8.24 and filled the gaps the [3.8.25] section was missing: a New Features section (compression engines + Compression Studios #3848, compression UI #3860, injection-guard #3857, kiro discovery #3836, Veo #3839, mimocode proxy #3837, Arena ELO flag #3821), 9 more Fixed entries (#3811/#3807/#3759/#3849/#3838/#3835/#3814/#3820/#3819), a Security section (CCR IDOR #3859, supply-chain #3824), and an Internal/Quality section. Every contributor and issue reporter is now credited. * docs(changelog): restore + complete the v3.8.25 release notes Re-adds CHANGELOG.md (a prior server-side commit accidentally dropped it) with the complete, audited [3.8.25] section: New Features, the full Fixed list, Security & Hardening, and Internal/Quality — every contributor and issue reporter credited. * chore(release): finalize v3.8.25 — reconcile CHANGELOG + i18n mirrors, document OMNIROUTE_MAX_PENDING_MIGRATIONS, green the unit suite Release-gate reconciliation for v3.8.25: - CHANGELOG: dated 2026-06-14, linked #3826, rolled up file-size re-baselines (#3823/#3833), recorded the test-greening; re-synced all 41 i18n CHANGELOG mirrors. - Documented OMNIROUTE_MAX_PENDING_MIGRATIONS (#3416) in .env.example + ENVIRONMENT.md. - Greened the unit suite (was merged red on 4 CI shards): aligned 10 stale tests to this cycle's intended behavior (#3838/#3822/#3501/SOCKS5/Vertex-Express/Antigravity) and the same-provider 503 fall-through test; de-flaked the compression benchmark reproducibility and ServiceSupervisor crash tests. No production code changed. * ci(security): clear OpenSSF Scorecard code-scanning noise + harden workflow token permissions The Security tab held 155 open alerts, ALL from the advisory OpenSSF Scorecard tool (#3824) — supply-chain/posture scores, not code vulnerabilities — which drowned out real CodeQL findings. - scorecard.yml: stop uploading SARIF to the code-scanning tab (drop the upload-sarif step + the now-unused security-events: write). The run still produces the OpenSSF badge (publish_results) and a downloadable SARIF artifact. - TokenPermissions hardening (the high-severity, genuinely-valuable subset): set each workflow's top-level token to read-only and grant the exact writes at the job level that needs them — npm-publish (id-token/packages on publish jobs), docker-publish (packages on build), electron-release (contents on build/release, id-token/packages on publish-npm), build-fork (packages on build), claude (empty top-level; job grants its own). The 155 existing alerts were dismissed. Not adopting repo-wide SHA-pinning (143 PinnedDependencies advisories) — declined. * test(integration): align stale wiring/socks5 integration tests to this cycle's behavior These were red on the CI Integration job (pre-existing). No production code changed: - integration-wiring: the combos page no longer renders a per-page EmailPrivacyToggle (#3822 consolidated it into Settings → Appearance); the provider-detail test-result masking and upstream-proxy copy moved to decomposed components (#3501 BatchTestResultsModal / UpstreamProxyCard) — assertions now read the owning files. - api-routes-critical: SOCKS5 is now enabled by default (opt-out), so the disabled- rejection test must set ENABLE_SOCKS5_PROXY=false explicitly (an unset env now means enabled). (The ~32 live-Gemini integration tests are gated on OMNIROUTE_API_KEY and skip in CI; they only 'fail' locally when that key is present without a running server.)
* chore(release): continue v3.8.25 development cycle after main code-sync (r5) main fast-forwarded to release/v3.8.25 (diegosouzapw#3863): unblocked Build+Docker via diegosouzapw#3864, plus diegosouzapw#3837 (mimocode proxy) and diegosouzapw#3862 (trivy bump). This marker re-opens the umbrella PR for further v3.8.25 work. No version bump. * fix(db): persist the Keep-latest-backups retention setting (diegosouzapw#3834) (diegosouzapw#3867) * fix(oauth): clear GitLab Duo setup message instead of 500 (diegosouzapw#3861) (diegosouzapw#3868) * test(oauth): prove refresh_token preserved on real gemini-cli/antigravity dispatch (diegosouzapw#3850) (diegosouzapw#3869) * feat(compression-ui): unified compression config UI — per-engine pages + combos editor + menu + WS default-on (diegosouzapw#3860) Integrated into release/v3.8.25 — feat(compression-ui): unified compression configuration UI (Compression Hub + per-engine Lite/Aggressive/Ultra pages + combos editor + sidebar entry + live-WS default-on). File-size re-baselined for sidebarVisibility.ts/chatCore.ts growth; orphan ws test relocated to a collected path. * docs(changelog): complete the v3.8.25 release notes + credit all contributors Audited every commit since v3.8.24 and filled the gaps the [3.8.25] section was missing: a New Features section (compression engines + Compression Studios diegosouzapw#3848, compression UI diegosouzapw#3860, injection-guard diegosouzapw#3857, kiro discovery diegosouzapw#3836, Veo diegosouzapw#3839, mimocode proxy diegosouzapw#3837, Arena ELO flag diegosouzapw#3821), 9 more Fixed entries (diegosouzapw#3811/diegosouzapw#3807/diegosouzapw#3759/diegosouzapw#3849/diegosouzapw#3838/diegosouzapw#3835/diegosouzapw#3814/diegosouzapw#3820/diegosouzapw#3819), a Security section (CCR IDOR diegosouzapw#3859, supply-chain diegosouzapw#3824), and an Internal/Quality section. Every contributor and issue reporter is now credited. * docs(changelog): restore + complete the v3.8.25 release notes Re-adds CHANGELOG.md (a prior server-side commit accidentally dropped it) with the complete, audited [3.8.25] section: New Features, the full Fixed list, Security & Hardening, and Internal/Quality — every contributor and issue reporter credited. * chore(release): finalize v3.8.25 — reconcile CHANGELOG + i18n mirrors, document OMNIROUTE_MAX_PENDING_MIGRATIONS, green the unit suite Release-gate reconciliation for v3.8.25: - CHANGELOG: dated 2026-06-14, linked diegosouzapw#3826, rolled up file-size re-baselines (diegosouzapw#3823/diegosouzapw#3833), recorded the test-greening; re-synced all 41 i18n CHANGELOG mirrors. - Documented OMNIROUTE_MAX_PENDING_MIGRATIONS (diegosouzapw#3416) in .env.example + ENVIRONMENT.md. - Greened the unit suite (was merged red on 4 CI shards): aligned 10 stale tests to this cycle's intended behavior (diegosouzapw#3838/diegosouzapw#3822/diegosouzapw#3501/SOCKS5/Vertex-Express/Antigravity) and the same-provider 503 fall-through test; de-flaked the compression benchmark reproducibility and ServiceSupervisor crash tests. No production code changed. * ci(security): clear OpenSSF Scorecard code-scanning noise + harden workflow token permissions The Security tab held 155 open alerts, ALL from the advisory OpenSSF Scorecard tool (diegosouzapw#3824) — supply-chain/posture scores, not code vulnerabilities — which drowned out real CodeQL findings. - scorecard.yml: stop uploading SARIF to the code-scanning tab (drop the upload-sarif step + the now-unused security-events: write). The run still produces the OpenSSF badge (publish_results) and a downloadable SARIF artifact. - TokenPermissions hardening (the high-severity, genuinely-valuable subset): set each workflow's top-level token to read-only and grant the exact writes at the job level that needs them — npm-publish (id-token/packages on publish jobs), docker-publish (packages on build), electron-release (contents on build/release, id-token/packages on publish-npm), build-fork (packages on build), claude (empty top-level; job grants its own). The 155 existing alerts were dismissed. Not adopting repo-wide SHA-pinning (143 PinnedDependencies advisories) — declined. * test(integration): align stale wiring/socks5 integration tests to this cycle's behavior These were red on the CI Integration job (pre-existing). No production code changed: - integration-wiring: the combos page no longer renders a per-page EmailPrivacyToggle (diegosouzapw#3822 consolidated it into Settings → Appearance); the provider-detail test-result masking and upstream-proxy copy moved to decomposed components (diegosouzapw#3501 BatchTestResultsModal / UpstreamProxyCard) — assertions now read the owning files. - api-routes-critical: SOCKS5 is now enabled by default (opt-out), so the disabled- rejection test must set ENABLE_SOCKS5_PROXY=false explicitly (an unset env now means enabled). (The ~32 live-Gemini integration tests are gated on OMNIROUTE_API_KEY and skip in CI; they only 'fail' locally when that key is present without a running server.)
* chore(release): continue v3.8.25 development cycle after main code-sync (r5) main fast-forwarded to release/v3.8.25 (diegosouzapw#3863): unblocked Build+Docker via diegosouzapw#3864, plus diegosouzapw#3837 (mimocode proxy) and diegosouzapw#3862 (trivy bump). This marker re-opens the umbrella PR for further v3.8.25 work. No version bump. * fix(db): persist the Keep-latest-backups retention setting (diegosouzapw#3834) (diegosouzapw#3867) * fix(oauth): clear GitLab Duo setup message instead of 500 (diegosouzapw#3861) (diegosouzapw#3868) * test(oauth): prove refresh_token preserved on real gemini-cli/antigravity dispatch (diegosouzapw#3850) (diegosouzapw#3869) * feat(compression-ui): unified compression config UI — per-engine pages + combos editor + menu + WS default-on (diegosouzapw#3860) Integrated into release/v3.8.25 — feat(compression-ui): unified compression configuration UI (Compression Hub + per-engine Lite/Aggressive/Ultra pages + combos editor + sidebar entry + live-WS default-on). File-size re-baselined for sidebarVisibility.ts/chatCore.ts growth; orphan ws test relocated to a collected path. * docs(changelog): complete the v3.8.25 release notes + credit all contributors Audited every commit since v3.8.24 and filled the gaps the [3.8.25] section was missing: a New Features section (compression engines + Compression Studios diegosouzapw#3848, compression UI diegosouzapw#3860, injection-guard diegosouzapw#3857, kiro discovery diegosouzapw#3836, Veo diegosouzapw#3839, mimocode proxy diegosouzapw#3837, Arena ELO flag diegosouzapw#3821), 9 more Fixed entries (diegosouzapw#3811/diegosouzapw#3807/diegosouzapw#3759/diegosouzapw#3849/diegosouzapw#3838/diegosouzapw#3835/diegosouzapw#3814/diegosouzapw#3820/diegosouzapw#3819), a Security section (CCR IDOR diegosouzapw#3859, supply-chain diegosouzapw#3824), and an Internal/Quality section. Every contributor and issue reporter is now credited. * docs(changelog): restore + complete the v3.8.25 release notes Re-adds CHANGELOG.md (a prior server-side commit accidentally dropped it) with the complete, audited [3.8.25] section: New Features, the full Fixed list, Security & Hardening, and Internal/Quality — every contributor and issue reporter credited. * chore(release): finalize v3.8.25 — reconcile CHANGELOG + i18n mirrors, document OMNIROUTE_MAX_PENDING_MIGRATIONS, green the unit suite Release-gate reconciliation for v3.8.25: - CHANGELOG: dated 2026-06-14, linked diegosouzapw#3826, rolled up file-size re-baselines (diegosouzapw#3823/diegosouzapw#3833), recorded the test-greening; re-synced all 41 i18n CHANGELOG mirrors. - Documented OMNIROUTE_MAX_PENDING_MIGRATIONS (diegosouzapw#3416) in .env.example + ENVIRONMENT.md. - Greened the unit suite (was merged red on 4 CI shards): aligned 10 stale tests to this cycle's intended behavior (diegosouzapw#3838/diegosouzapw#3822/diegosouzapw#3501/SOCKS5/Vertex-Express/Antigravity) and the same-provider 503 fall-through test; de-flaked the compression benchmark reproducibility and ServiceSupervisor crash tests. No production code changed. * ci(security): clear OpenSSF Scorecard code-scanning noise + harden workflow token permissions The Security tab held 155 open alerts, ALL from the advisory OpenSSF Scorecard tool (diegosouzapw#3824) — supply-chain/posture scores, not code vulnerabilities — which drowned out real CodeQL findings. - scorecard.yml: stop uploading SARIF to the code-scanning tab (drop the upload-sarif step + the now-unused security-events: write). The run still produces the OpenSSF badge (publish_results) and a downloadable SARIF artifact. - TokenPermissions hardening (the high-severity, genuinely-valuable subset): set each workflow's top-level token to read-only and grant the exact writes at the job level that needs them — npm-publish (id-token/packages on publish jobs), docker-publish (packages on build), electron-release (contents on build/release, id-token/packages on publish-npm), build-fork (packages on build), claude (empty top-level; job grants its own). The 155 existing alerts were dismissed. Not adopting repo-wide SHA-pinning (143 PinnedDependencies advisories) — declined. * test(integration): align stale wiring/socks5 integration tests to this cycle's behavior These were red on the CI Integration job (pre-existing). No production code changed: - integration-wiring: the combos page no longer renders a per-page EmailPrivacyToggle (diegosouzapw#3822 consolidated it into Settings → Appearance); the provider-detail test-result masking and upstream-proxy copy moved to decomposed components (diegosouzapw#3501 BatchTestResultsModal / UpstreamProxyCard) — assertions now read the owning files. - api-routes-critical: SOCKS5 is now enabled by default (opt-out), so the disabled- rejection test must set ENABLE_SOCKS5_PROXY=false explicitly (an unset env now means enabled). (The ~32 live-Gemini integration tests are gated on OMNIROUTE_API_KEY and skip in CI; they only 'fail' locally when that key is present without a running server.)
…s + combos editor + menu + WS default-on (diegosouzapw#3860) Integrated into release/v3.8.25 — feat(compression-ui): unified compression configuration UI (Compression Hub + per-engine Lite/Aggressive/Ultra pages + combos editor + sidebar entry + live-WS default-on). File-size re-baselined for sidebarVisibility.ts/chatCore.ts growth; orphan ws test relocated to a collected path.
…ributors Audited every commit since v3.8.24 and filled the gaps the [3.8.25] section was missing: a New Features section (compression engines + Compression Studios diegosouzapw#3848, compression UI diegosouzapw#3860, injection-guard diegosouzapw#3857, kiro discovery diegosouzapw#3836, Veo diegosouzapw#3839, mimocode proxy diegosouzapw#3837, Arena ELO flag diegosouzapw#3821), 9 more Fixed entries (diegosouzapw#3811/diegosouzapw#3807/diegosouzapw#3759/diegosouzapw#3849/diegosouzapw#3838/diegosouzapw#3835/diegosouzapw#3814/diegosouzapw#3820/diegosouzapw#3819), a Security section (CCR IDOR diegosouzapw#3859, supply-chain diegosouzapw#3824), and an Internal/Quality section. Every contributor and issue reporter is now credited.
* chore(release): continue v3.8.25 development cycle after main code-sync (r5) main fast-forwarded to release/v3.8.25 (diegosouzapw#3863): unblocked Build+Docker via diegosouzapw#3864, plus diegosouzapw#3837 (mimocode proxy) and diegosouzapw#3862 (trivy bump). This marker re-opens the umbrella PR for further v3.8.25 work. No version bump. * fix(db): persist the Keep-latest-backups retention setting (diegosouzapw#3834) (diegosouzapw#3867) * fix(oauth): clear GitLab Duo setup message instead of 500 (diegosouzapw#3861) (diegosouzapw#3868) * test(oauth): prove refresh_token preserved on real gemini-cli/antigravity dispatch (diegosouzapw#3850) (diegosouzapw#3869) * feat(compression-ui): unified compression config UI — per-engine pages + combos editor + menu + WS default-on (diegosouzapw#3860) Integrated into release/v3.8.25 — feat(compression-ui): unified compression configuration UI (Compression Hub + per-engine Lite/Aggressive/Ultra pages + combos editor + sidebar entry + live-WS default-on). File-size re-baselined for sidebarVisibility.ts/chatCore.ts growth; orphan ws test relocated to a collected path. * docs(changelog): complete the v3.8.25 release notes + credit all contributors Audited every commit since v3.8.24 and filled the gaps the [3.8.25] section was missing: a New Features section (compression engines + Compression Studios diegosouzapw#3848, compression UI diegosouzapw#3860, injection-guard diegosouzapw#3857, kiro discovery diegosouzapw#3836, Veo diegosouzapw#3839, mimocode proxy diegosouzapw#3837, Arena ELO flag diegosouzapw#3821), 9 more Fixed entries (diegosouzapw#3811/diegosouzapw#3807/diegosouzapw#3759/diegosouzapw#3849/diegosouzapw#3838/diegosouzapw#3835/diegosouzapw#3814/diegosouzapw#3820/diegosouzapw#3819), a Security section (CCR IDOR diegosouzapw#3859, supply-chain diegosouzapw#3824), and an Internal/Quality section. Every contributor and issue reporter is now credited. * docs(changelog): restore + complete the v3.8.25 release notes Re-adds CHANGELOG.md (a prior server-side commit accidentally dropped it) with the complete, audited [3.8.25] section: New Features, the full Fixed list, Security & Hardening, and Internal/Quality — every contributor and issue reporter credited. * chore(release): finalize v3.8.25 — reconcile CHANGELOG + i18n mirrors, document OMNIROUTE_MAX_PENDING_MIGRATIONS, green the unit suite Release-gate reconciliation for v3.8.25: - CHANGELOG: dated 2026-06-14, linked diegosouzapw#3826, rolled up file-size re-baselines (diegosouzapw#3823/diegosouzapw#3833), recorded the test-greening; re-synced all 41 i18n CHANGELOG mirrors. - Documented OMNIROUTE_MAX_PENDING_MIGRATIONS (diegosouzapw#3416) in .env.example + ENVIRONMENT.md. - Greened the unit suite (was merged red on 4 CI shards): aligned 10 stale tests to this cycle's intended behavior (diegosouzapw#3838/diegosouzapw#3822/diegosouzapw#3501/SOCKS5/Vertex-Express/Antigravity) and the same-provider 503 fall-through test; de-flaked the compression benchmark reproducibility and ServiceSupervisor crash tests. No production code changed. * ci(security): clear OpenSSF Scorecard code-scanning noise + harden workflow token permissions The Security tab held 155 open alerts, ALL from the advisory OpenSSF Scorecard tool (diegosouzapw#3824) — supply-chain/posture scores, not code vulnerabilities — which drowned out real CodeQL findings. - scorecard.yml: stop uploading SARIF to the code-scanning tab (drop the upload-sarif step + the now-unused security-events: write). The run still produces the OpenSSF badge (publish_results) and a downloadable SARIF artifact. - TokenPermissions hardening (the high-severity, genuinely-valuable subset): set each workflow's top-level token to read-only and grant the exact writes at the job level that needs them — npm-publish (id-token/packages on publish jobs), docker-publish (packages on build), electron-release (contents on build/release, id-token/packages on publish-npm), build-fork (packages on build), claude (empty top-level; job grants its own). The 155 existing alerts were dismissed. Not adopting repo-wide SHA-pinning (143 PinnedDependencies advisories) — declined. * test(integration): align stale wiring/socks5 integration tests to this cycle's behavior These were red on the CI Integration job (pre-existing). No production code changed: - integration-wiring: the combos page no longer renders a per-page EmailPrivacyToggle (diegosouzapw#3822 consolidated it into Settings → Appearance); the provider-detail test-result masking and upstream-proxy copy moved to decomposed components (diegosouzapw#3501 BatchTestResultsModal / UpstreamProxyCard) — assertions now read the owning files. - api-routes-critical: SOCKS5 is now enabled by default (opt-out), so the disabled- rejection test must set ENABLE_SOCKS5_PROXY=false explicitly (an unset env now means enabled). (The ~32 live-Gemini integration tests are gated on OMNIROUTE_API_KEY and skip in CI; they only 'fail' locally when that key is present without a running server.)
Unified Compression Config UI
Makes every compression engine configurable and activatable from the dashboard, so compression actually runs on normal calls — not just the WS visualization. Follow-up to #3848 (engines + 2 Studios).
Built via brainstorming → spec → implementation plan → subagent-driven TDD, then deployed to the VPS and validated end-to-end via Chrome. Planning docs live in
docs/research/compression/(git-ignored, not committed).What ships (validated live on the VPS)
Per-engine config pages (rich layout: explainer + enable toggle + config form + live preview + 7-day analytics), one per technology — reusing the engines' own
getConfigSchema():minRows+ Salvar + Preview + analytics).Activation model (no new schema) — enabling an engine on its page edits the default compression combo's pipeline (
setEngineInDefaultCombo), inserting at thestackPriority-ordered position. The stacked pipeline runs that combo on real calls.[rtk,caveman]→[rtk,headroom,caveman](sorted by stackPriority) with config{minRows:5}persisted; disabling removed it. ThenormalizePipelineallowlist fix lets the new engines survive the write→read round-trip.pipeline.length > 1(dropped a one-engine combo) → changed to>= 1.stacked; the engine pages show a notice pointing to Compression Settings.Unified compression menu group — flat list under "Compression Context": Settings · Caveman · RTK · Headroom · Session-Dedup · CCR · LLMLingua · Combos · Compression Studio + a Combo Studio item. ✅ Menu validated.
Compression Settings surfaced in the group (mounts the existing
CompressionSettingsTab).Live dashboard WebSocket default-ON (loopback-bound).
DEFAULT_HOSTstays127.0.0.1; build/test never auto-start; LAN exposure remains opt-in viaLIVE_WS_HOST=0.0.0.0+LIVE_WS_ALLOWED_ORIGINS.Backend
GET /api/compression/engines— engine catalog + eachgetConfigSchema()(management-auth gated).POST /api/compression/preview— gains anengineIdbranch (single-engine stacked preview, async/fail-open).GET /api/context/analytics/engine?engineId=&days=— per-engine aggregation over theenginecolumn (mirrors the existingbyEnginequery; no new column/migration).GET|PUT /api/context/combos/default— read default combo / toggle one engine.Deferred to a follow-up
Combos ordered-layer editor (Task 8/9) was reverted (
a49b407ae). The redesignedCompressionCombosPageClientdid not hydrate on the production build (useEffect never ran, React buttons inert). During validation the previous combos editor showed the same non-hydration symptom, which points to a pre-existing combos-page hydration issue (the Headroom page and the rest of the dashboard hydrate fine) rather than a regression introduced here. The revert keeps the combos page at parity with production (the old editor degrades gracefully) and removes the now-unused pipeline reducer. The ordered-layer redesign — plus root-causing the combos hydration with a localnpm run devsession (production suppresses hydration error detail) — returns in a dedicated follow-up.Bugs found + fixed during live validation
6a4b33c3a): the Header strict-resolves each sidebar item'si18nKey; the new menu items had no message key, so a missing-message error froze hydration on every new page. Added the 7 keys across all 42 locales. Verified the pages load after.587928544): EngineConfigPage's three reads were sequential (~6-9s on the VPS) → parallelized withPromise.all.9f4abc482): Hard Rule fix(ui): fix Select dropdown dark theme inconsistency #12 sanitized preview error · single-engine guard · engines-route auth + error body ·handleSaveno longer force-enables a disabled engine ·engineIdallowlist validation ·ENVIRONMENT.mddefault corrected.Tests & gates
typecheck:core0 ·check:cycles0 ·check:any-budgetPASS · ESLint 0 errors on changed files ·test:vitest(MCP) 171/171.docs-syncis red branch-wide on pre-existing stale i18n CHANGELOG translations (refreshed at release time) — unrelated to this PR.