Skip to content

feat(compression): compression engines + async pipeline + Combo/Compression Studios - #3848

Merged
diegosouzapw merged 27 commits into
release/v3.8.25from
feat/compression-studios
Jun 14, 2026
Merged

diegosouzapw merged 27 commits into
release/v3.8.25from
feat/compression-studios

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Compression engines + Studios — engine layer, async pipeline, two ReactFlow dashboards

Implements the coherent "compression engines (stackable into combos) + the two real-time
Studios" track, end to end, in 20 TDD commits. Every item was built RED→GREEN, audited
(diff + scope + re-run + anti-masking) before acceptance, and closed with a 2-round deep
code-review cycle that converged clean
.

What's here

Foundation

  • applyAsync? on CompressionEngine + applyStackedCompressionAsync/applyCompressionAsync
    (H10) — async-capable stacked pipeline; chatCore awaits it. Sync-only pipelines stay
    byte-identical.
  • Shared FlowCanvas/edgeStyles/StatusDot extracted from ProviderTopology (behaviour-
    preserving), reused by both Studios.
  • API-free eval/benchmark harness: token ratio + semantic retention (reuses preservation.ts),
    tokens-per-task gate (N4), transcript replay.

Deterministic engines (opt-in, stackable)

  • Real JS/TS comment removal via the TypeScript parser (string/template/regex safe, bails on JSX).
  • Matched-filter preserve.errorPatterns/summaryPatterns propagated into smartTruncate.
  • RTK grouping strategy. session-dedup (content-addressed cross-turn dedup, SHA-256 keyed,
    reversible). headroom/SmartCrusher (lossless columnar compaction of homogeneous JSON arrays,
    ≥30%, dependency-free).

Advanced

  • ccr retrieve engine + omniroute_ccr_retrieve MCP tool (scope read:compression).
  • llmlingua async engine — pluggable backend, fail-open in 3 layers, never touches code
    (real ONNX backend is a documented VPS follow-up).
  • Reproducible A/B benchmark over the engines + N4 gate.

Studios

  • Compression Studio (Tela A): compression WS channel + fire-and-forget emit at the
    chokepoint; pure compressionFlowModel + replay; EngineNode/IoNode/CompressionCockpit/
    WaterfallInspector + useLiveCompression/useCompressionReplay.
  • Combo/Routing Studio (Tela B) (backend-zero — events already exist): comboFlowModel +
    fleetAggregation; Request/Strategy/ProviderCascade/Response nodes + ComboLiveStudio
    (Single⇄Fleet, graceful disconnect banner).

Gates

  • Opt-in bail-out discipline (failure-aware + skip-if-gain<10%, default-off byte-identical).
  • RTK filter learn/discover (mine history → suggest filters). MCP tool-manifest cardinality.

Deep review (F5) — converged in 2 rounds

A 3-agent battery (correctness + silent-failure + type-design) over the full diff found and the
fixes resolved (all with tests): HIGH ReDoS in discover.ts (~54s → ~150ms), HIGH djb2
32-bit→SHA-256 hash with an equality guard in session-dedup, MEDIUM bail-out telemetry that
silently dropped a crashing engine, plus clamps/logs/docstring/fleet-clock fixes. Round 2 verified
all fixes correct with no new issues. (Earlier, per-item trust-but-verify also caught a headroom
mixed-column data-loss bug and a build-breaking NodeTypes-from-react import.)

Test gate (20 commits)

compression unit suite 577/577 · test:vitest (MCP) 171/171 · new UI render tests
50/50 · typecheck:core clean · check:cycles 0 · check:any-budget OK · no new npm deps.

Deliberately deferred (env-gated)

  • App/e2e: dashboard tab/nav wiring for the two Studios (left untouched on purpose),
    U6 step-streaming, Playwright e2e of the live WS flow.
  • VPS: Anthropic context-management delegated header, the real LLMLingua-2 ONNX backend,
    Qdrant int8 recall, real A/B benchmark numbers.

Acknowledged by-design (not bugs)

session-dedup/headroom are opt-in lossy engines (NOT in the default pipeline), like
caveman/ultra — their markers/tables are the compressed payload; reconstruct* is for
replay/verification, not the wire. Combo "exhausted" needs a producer terminal event. CCR's
in-memory store has a documented LRU/TTL follow-up.

Note: if release/v3.8.25 advanced chatCore.ts/events/types.ts/strategySelector.ts since
this branch was cut, a rebase may be needed before merge.

Adds an optional CompressionEngine.applyAsync() and an async sibling
applyStackedCompressionAsync()/applyCompressionAsync() that awaits engines
exposing applyAsync (e.g. a future worker-thread LLMLingua-2) while running
sync engines inline. Behaviour is identical for sync-only pipelines (same
order, telemetry and stats), and the legacy sync path gracefully skips
async-only work. chatCore now awaits applyCompressionAsync at the chokepoint.

Shared pure helpers (mergeStackStep/finalizeStackedResult) keep the sync and
async loops from diverging. TDD: tests/unit/compression/stacked-async.test.ts.
Pulls the proven ReactFlow wrapper, edge palette and pulse indicator out of
ProviderTopology into src/shared/components/flow/ so the Combo Studio (Tela B)
and Compression Studio (Tela A) can reuse them. ProviderTopology now consumes
FlowCanvas + edgeStyle + StatusDot with no behavioural change (same buildLayout,
same single sized container, identical ReactFlow flags and palette values).

TDD: tests/unit/ui/edgeStyles.test.ts (pure palette/precedence) +
tests/unit/ui/flowCanvas.test.tsx (render: Controls present, attribution hidden,
className applied). Home visual regression remains covered by the Playwright
home spec at the phase gate.
…0.3)

API-free, CI-safe harness under open-sse/services/compression/harness/:
- measure.ts: token ratio + semantic retention (reuses preservation.ts entity
  extractors + the canonical compression token estimator).
- runner.ts: offline eval over a corpus; awaits sync OR async compress fns (H10).
- budgetGate.ts (N4): tokens-per-task ratchet — fails when compressed cost/task
  rises above a frozen baseline beyond tolerance.
- replay.ts (TV3): replay real transcripts (per-turn ratio + retention).

TDD: tests/unit/compression/harness.test.ts (known degraded pair drops
retention + names the lost entity; gate FAILS when cost/task rises).
…1.1)

codeStripper read removeComments but never applied it (effective no-op). Now
stripCode removes JS/TS comments using the TypeScript parser (ts.createSourceFile),
so string/template/regex literals are never mistaken for comments — the raw
scanner cannot tell a regex from a division without parser context. Bails out on
JSX so {/* */} expression-container comments are preserved. No ts-morph needed:
typescript is already a dependency.

Default flips to false (preserve) to keep the historical effective behaviour and
the existing rtk-code-stripper test green; callers opt in with removeComments:true.

TDD: tests/unit/compression/rtk-comments.test.ts (removal + URL/regex/template/JSX
preservation + default-preserve + non-JS untouched).
…tTruncate (R2 / F1.2)

A matched RTK filter declares preserve.errorPatterns/summaryPatterns, but the
second smartTruncate in processRtkText used a hardcoded priorityPatterns list,
so a filter's own summary/error line could be truncated away. Now the matched
filter's patterns are compiled (try/catch-guarded) and unioned with the defaults,
so those lines become retention-priority.

TDD: tests/unit/compression/rtk-truncate-preserve.test.ts — make filter's
'linking'/'***' patterns (which do NOT match the hardcoded defaults) survive
truncation when placed mid-output.
…5 / F1.3)

New grouper.ts collapses consecutive lines that normalise equal (after stripping
volatile bits: digits, hex ids, timestamps, versions) into one representative +
a [rtk:grouped xN] marker. Opt-in via RtkConfig.enableGrouping (default OFF, so
existing RTK output is unchanged) with an optional groupingThreshold (default 3).
Runs after dedup, before truncation; emits rtk-grouping technique.

TDD: tests/unit/compression/rtk-grouping.test.ts (grouping by number/hex/timestamp,
threshold behaviour, unique lines preserved, default-off, shorter output).
…n dedup (R11/N2/TO1 / F1.4)

New stackable engine session-dedup replaces multi-line blocks that recur
verbatim across turns with a short [dedup:ref sha=<8hex>] marker, keeping the
first occurrence intact. Two-pass suffix-block algorithm (djb2 hash, zero deps),
conservative guards (system prompt untouched, multipart text-only, min 80 chars
+ 3 lines). reconstructSessionDedup reverses it for round-trip fidelity (reverse
map stored non-enumerable so it never reaches the wire). Registered in the engine
registry; CompressionEngineId extended (no exhaustive switch to break).

Opt-in only (not in any default pipeline). TDD:
tests/unit/compression/session-dedup.test.ts (dedup + round-trip deep-equal +
no false positives + system-safe + multipart-safe + schema/validation).
… F1.5)

New stackable engine 'headroom' compacts homogeneous JSON arrays of objects in
message content (and ```json fenced blocks) into a dependency-free columnar
block (shared header + value rows + explicit [N rows] marker, fenced as
omni-tabular), achieving >=30% lossless compression on >=8-row arrays. Reversible
via reconstructHeadroom. No npm dependency (TOON noted as a future drop-in encoder).

Trust-but-verify fix folded in: the original detectHomogeneous only checked key-set
equality, but the decoder applies one kind per column (from row 0) — a nullable or
mixed number/string column would silently corrupt the round-trip (data loss).
detectHomogeneous now also requires per-column TYPE uniformity; mixed-type columns
are left untouched. Regression tests assert the losslessness invariant on nullable
and mixed-type columns.

TDD: tests/unit/compression/headroom-smartcrusher.test.ts (encoder round-trip incl.
commas/quotes/newlines/nested; >=30% savings; reversible; heterogeneous/tiny/system/
non-array untouched; mixed-type-column losslessness regression).
New stackable engine 'ccr' replaces large (>=600 char) message blocks with a
content-addressed marker [CCR retrieve hash=<24hex> chars=N] and stores the
verbatim block keyed by SHA-256 prefix. The original is retrievable via the new
omniroute_ccr_retrieve MCP tool (scope read:compression, sticky-on) or
reconstructCcr(). Retrieval-rate feedback (recordRetrieval/shouldSkipCompression,
threshold 3) marks frequently-retrieved blocks do-not-compress. Opt-in only.

Scope notes (documented follow-ups, not blocking the DoD): the store is an
in-module Map (a SQLite-backed ccrEntries.ts + migration is the production
persistence follow-up) — it is unbounded, so a future LRU/TTL bound is a
review-phase item; the body.tools sticky-injection in chatCore is deferred (the
MCP tool is statically registered = always available). No npm deps.

TDD: tests/unit/compression/ccr-marker-retrieve.test.ts (13: marker, verbatim
retrieve, round-trip deep-equal, small/system untouched, feedback threshold,
multipart, MCP handler hit/miss).
…L3 / F2.1)

New async (H10 applyAsync) stackable engine 'llmlingua' for semantic prose
pruning. Pluggable backend (LlmlinguaBackend, injectable via setLlmlinguaBackend
for tests); production backend is a worker-thread stub in worker.ts that
fail-opens — the real vendored @atjsh/llmlingua-2 (MobileBERT ONNX) is a
documented VPS-validated follow-up (Hard Rule #18), deliberately NOT installed
(no ONNX download / supply-chain in this PR).

Code is inviolable: extractPreservedBlocks tombstones fenced code (and URLs/
identifiers/etc.) so only prose segments ever reach the backend; preserved blocks
are re-stitched verbatim. Fail-open in 3 layers (per-segment, per-message, outer)
— any backend error returns the original body unchanged. Sync apply() is a
pass-through. stackPriority 35.

TDD: tests/unit/compression/llmlingua-failopen.test.ts (prose compresses;
throwing backend → original body deep-equal, no throw; code block byte-identical
+ backend never receives code; system never compressed; sync pass-through).
…V1 / F4.2)

Adds a transversal, OPT-IN bail-out to both stacked loops: when
StackOptions.bailout.enabled is set, a step that throws is silently skipped
(verbatim kept, pipeline continues) and a step whose gain < minGainPercent
(default 10) is skipped (currentBody not advanced). Default-off path is
byte-identical to before (the else branch is the original loop verbatim), so
stacked-async/pipeline-integration stay green unchanged. Shared pure decideStep
helper keeps sync/async in sync.

Review-phase follow-up (documented, not blocking DoD): bailout is reachable via
the stacked-function options but not yet plumbed from applyCompressionAsync/config,
so it is inert in production until a deliberate activation step wires it through.

TDD: tests/unit/compression/bailout.test.ts (throw->skip no-throw; <10% gain
skipped; >=10% applied; default-off applies <10% engine = behaviour unchanged;
sync + async).
…ation)

Tela A testable foundation. Adds a 'compression' live-WS channel: new
compression.completed event + CompressionCompletedPayload in src/lib/events/types.ts,
mapped in CHANNEL_EVENTS (auto-routed by liveServer via getChannelForEvent — no
liveServer edit). chatCore emits it fire-and-forget at the compression chokepoint
(guarded by result.compressed && result.stats, try/catch, never awaited/thrown
into the hot path; engineBreakdown carried for the per-engine cascade).

Pure compressionFlowModel reducer (no React): compressionEventToModel,
compressionRunToFlow (Input -> N engine-step nodes -> Output, N+2 nodes + edges,
@xyflow/react types) and buildReplayFrames (progressive snapshots so the UI
animates a sub-ms run as a replay cascade).

Deferred (visible layer): the ReactFlow canvas/cockpit components + Playwright
e2e -> F5/app. TDD: tests/unit/events/compressionChannel.test.ts +
tests/unit/ui/compressionFlowModel.test.ts (19).
Backend-zero testable core of the Combo/Routing Studio (the events
combo.target.attempt|failed|succeeded already exist). Pure, no-React modules:
- comboFlowModel.ts: reduceComboEvent (attempt/failed/succeeded -> ComboRunModel,
  targets ordered by targetIndex, strategy from the attempt payload, cross-combo
  events ignored), classifyFailKind (circuit>rate>cooldown>other heuristic),
  comboRunToFlow (request -> strategy -> N target nodes -> response, edges styled
  via the shared U0 edgeStyle palette by target state).
- fleetAggregation.ts: aggregateComboEventsToSets(events, windowMs, now) -> active/
  error/last sets (now passed in, no Date.now() — pure/testable).

Deferred (visible layer): the ReactFlow nodes/canvas components + Playwright e2e
-> F5/app. TDD: tests/unit/ui/{comboFlowModel,fleetAggregation}.test.ts (39:
attempt->fail(429)->fail(circuit)->succeed sequence, failKinds, flow node/edge
count + colors, fleet windowing).
… (R6/R7/N7 / F4.1)

Pure, I/O-free filter mining (call_logs DB wiring deferred — functions take
samples as a parameter so they are fully unit-testable):
- discover.ts: discoverRepeatedNoise(samples) normalizes volatile bits (numbers,
  paths, pkg@version, error codes, unit suffixes — extends grouper's normalizer)
  and surfaces line templates recurring across >1 sample as DROP candidates
  (single-occurrence lines excluded).
- learn.ts: suggestFilter(command, samples) -> SuggestedFilter (mirrors the
  RtkFilterPack JSON shape) with a command match pattern, dropPatterns above a
  50% recurrence threshold, and preserve.errorPatterns/summaryPatterns from
  error/summary heuristics. Conflict guard removes any drop pattern that would
  match a preserved error/summary line (never drop an important signal).

Purely additive, no deps. TDD: tests/unit/compression/rtk-learn.test.ts (12:
deprecated-warning template surfaced, unique line not dropped, dropPatterns cover
the noise, preserve covers ERR!/summary, drop never matches a preserved line).
Pure utility toolCardinality.ts: reduceToolManifest(manifest, profile) returns a
smaller tool manifest per profile (allowScopes with trailing-* wildcard matching
scopeEnforcement, allowTools/denyTools with deny>allow, deterministic maxTools cap,
no-filter => full manifest), preserving input shape and never mutating it.
estimateManifestTokens reuses estimateCompressionTokens so callers can measure the
saving. This is compression 'layer 5' — fewer tools announced = cheaper manifest.

Live MCP server registration is UNCHANGED (pure utility; wiring it into startup is
a follow-up). Purely additive, no deps. TDD: tests/unit/mcp/tool-cardinality.test.ts
(17: scope/tool/deny/maxTools filtering, full-passthrough, no-mutation, smaller tokens).
…L2 / F2.4)

benchmark.ts runs compression engines through the C1 harness and applies the N4
tokens-per-task gate so a default can be chosen from real numbers:
- engineToCompressFn(id): wraps text -> body -> engine.apply/applyAsync -> extract,
  fail-open on non-string/error.
- benchmarkEngines / compareReports (sorted savings desc, retention tiebreak) /
  runBenchmarkGate (per-engine N4) + a reproducible BENCHMARK_CORPUS fixture.

Honest sandbox result: ccr ~36.5% savings (retention 0.6 — drops entities), the
other deterministic engines pass-through on this corpus. Two documented
review-phase refinements (framework is correct; these improve the SIGNAL): (1) the
adapter calls apply WITHOUT an activating config, so config-driven engines (rtk/
caveman) need their enabling config passed for a meaningful A/B; (2) llmlingua's
real-model A/B is a VPS follow-up (its sync apply is pass-through in sandbox).
Enrich via real transcripts (replayTranscripts) for production decisions.

Purely additive, no deps. TDD: tests/unit/compression/benchmark.test.ts (12:
adapter, per-engine report ranges, compare sort, N4 gate flag/pass, determinism).
… (F3.2 UI)

React/ReactFlow components consuming the already-tested cores (compressionFlowModel,
FlowCanvas, the compression WS channel):
- nodes/EngineNode + IoNode: custom ReactFlow nodes (per-engine tokens in->out,
  savings %, techniques, layer pills; I/O boundary nodes).
- CompressionCockpit: canvas of the engine cascade via compressionRunToFlow +
  FlowCanvas, header (mode/comboId/savings), replay controls (play/pause/reset +
  0.3x/1x/3x) via useCompressionReplay, graceful empty state.
- WaterfallInspector: Langfuse-style per-engine savings-bar list.
- useLiveCompression hook (subscribes the compression channel, accumulates runs via
  the pure accumulateRun reducer) + useCompressionReplay (useReducer-driven frames).

Trust-but-verify fix folded in: CompressionCockpit imported NodeTypes from 'react'
instead of '@xyflow/react' — a build-breaking type error that esbuild/vitest strip
past; caught by a scoped tsc and fixed (now scoped-tsc clean).

Deferred to app phase: dashboard tab/route wiring (avoid touching nav blind) and
Playwright e2e (live WS flow, flowing-dot animation). 21 vitest render tests
(createRoot+act, ResizeObserver polyfill — no @testing-library/react).
… UI)

React/ReactFlow components consuming the already-tested cores (comboFlowModel,
fleetAggregation, FlowCanvas):
- nodes/{Request,Strategy,ProviderCascade,Response}Node — custom ReactFlow nodes;
  ProviderCascadeNode colors by target state (idle/attempting+pulse/failed/succeeded)
  with a failKind badge (rate-limit/circuit-open/cooldown). Node type keys match
  comboRunToFlow's emitted strings exactly (request/strategy/target/response).
- ComboLiveStudio: combo selector, folds events via reduceComboEvent -> comboRunToFlow
  -> FlowCanvas; Single<->Fleet toggle (aggregateComboEventsToSets radial overview);
  graceful empty state + 'Live disabled' banner when disconnected. Accepts a static
  run? prop for unit-testability.

NodeTypes/NodeProps/Handle/Position imported from @xyflow/react (the prior build-break
class avoided; scoped-tsc verified 0). Deferred to app phase: dashboard tab wiring,
live WS data flow, fleet now-clock refresh, Playwright e2e. 27 vitest render tests
(createRoot+act, no @testing-library/react).
Deep-review battery (code-reviewer + silent-failure-hunter + type-design) over the
18-commit branch surfaced these; fixed with tests:

- HIGH ReDoS (CLAUDE.md regex rule): discover.ts package@version regex had
  unbounded [\w][\w.-]*@ catastrophic backtracking (54s on 200k chars) → bounded
  quantifiers {0,128}/{0,64} + a perf-guard test.
- HIGH session-dedup hash: 32-bit djb2 could collide → reconstruct wrong block.
  Widened to SHA-256 24-hex (like CCR) AND verify owner.block === block before
  substituting (collision can no longer corrupt). Test regex updated to {24}.
- MEDIUM bail-out silent telemetry: a thrown engine under bail-out vanished with
  no trace → now records validationErrors + fallbackApplied (visible in stats);
  test asserts it. + clamp minGainPercent >= 0 (negative meant 'always advance').
- toolCardinality: negative maxTools silently tail-dropped via slice(0,-n) → treat
  max<0 as no-cap + test.
- chatCore compression.completed emit: bare catch now logs like its sibling
  fire-and-forget blocks (still never propagates to the hot path).
- CompressionCockpit docstring corrected (it's controlled, no useLiveCompression
  fallback). FleetOverview 'now' was frozen at mount → low-freq interval so the
  60s rolling window actually rolls.

Compression suite 577/577, vitest render green, typecheck/scoped-tsc/lint clean.

Disposition (by-design, documented — not bugs): session-dedup/headroom are OPT-IN
lossy engines (like caveman/ultra) NOT in the default pipeline; their markers/
tables ARE the compressed payload sent to the model, and reconstruct* is for
replay/verification, not the wire (reconstructing would undo compression). Combo
'exhausted' needs a producer terminal event (combo.ts, out of Tela B's backend-
zero scope). CCR unbounded store: documented LRU/TTL follow-up.
Round-2 review caught a stale prop-level JSDoc line still claiming a
useLiveCompression fallback that does not exist (the component is controlled).
Aligns it with the corrected component docstring. Comment-only.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a modular compression pipeline featuring several new engines: CCR (Content-Compression-Retrieve), Headroom SmartCrusher (tabular compaction of homogeneous JSON arrays), session-dedup (cross-turn deduplication), and LLMLingua (async semantic pruning). It also adds a comprehensive offline evaluation and benchmarking harness, integrates these engines into the async stacked pipeline with TV1 bailout capabilities, and implements live visualization dashboards for both routing cascades and compression steps. The review comments highlight several valuable improvement opportunities, including addressing a potential O(N^2) complexity issue in suffix block extraction, improving deduplication efficiency by removing a premature loop break, handling out-of-order or missed WebSocket events defensively in the cascade flow model, and adding defensive null/undefined checks across various engine entry points.

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.

Comment on lines +81 to +82
for (let start = 0; start < n; start++) {
const block = lines.slice(start).join("\n");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The findSuffixBlocks function has $O(N^2)$ complexity on the number of lines because it slices and joins the remaining lines in a loop. For extremely large inputs (e.g., large log files), this can block the event loop or cause out-of-memory crashes. Consider adding a defensive limit to the maximum number of lines processed to guard against this.

Suggested change
for (let start = 0; start < n; start++) {
const block = lines.slice(start).join("\n");
const limit = Math.min(n, 1000); // Guard against O(N^2) complexity on huge inputs
for (let start = 0; start < limit; start++) {
const block = lines.slice(start).join("\n");

changed = true;
replaced.add(block);
// Only replace once per block per message pass.
break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The break; statement here stops the loop after the first duplicate block replacement in a message. This prevents other non-overlapping duplicate blocks in the same message from being replaced, which unnecessarily reduces compression efficiency. Since there is already an overlap guard ([...replaced].some(...)), this break; can be safely removed to allow multiple distinct duplicate blocks to be replaced.

Suggested change
break;
// Continue to allow replacing other non-overlapping duplicate blocks

Comment on lines +164 to +174
const updatedTargets = run.targets.map((t) =>
t.targetIndex === ev.targetIndex
? {
...t,
state: "failed" as TargetState,
latencyMs: ev.latencyMs,
error: ev.error,
failKind: classifyFailKind(ev.error),
}
: t
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the attempt event for a target was missed or arrived out of order, the target will be silently ignored because run.targets.map only updates existing targets. To make the cascade flow robust against out-of-order or missed WebSocket events, handle this defensively by appending the target if it does not exist in run.targets.

      const targetExists = run.targets.some((t) => t.targetIndex === ev.targetIndex);
      const updatedTargets = targetExists
        ? run.targets.map((t) =>
            t.targetIndex === ev.targetIndex
              ? {
                  ...t,
                  state: "failed" as TargetState,
                  latencyMs: ev.latencyMs,
                  error: ev.error,
                  failKind: classifyFailKind(ev.error),
                }
              : t
          )
        : [
            ...run.targets,
            {
              targetIndex: ev.targetIndex,
              provider: ev.provider,
              model: ev.model,
              state: "failed" as TargetState,
              latencyMs: ev.latencyMs,
              error: ev.error,
              failKind: classifyFailKind(ev.error),
            },
          ].sort((a, b) => a.targetIndex - b.targetIndex);

Comment on lines +200 to +208

const updatedTargets = run.targets.map((t) =>
t.targetIndex === ev.targetIndex
? {
...t,
state: "succeeded" as TargetState,
latencyMs: ev.latencyMs,
}
: t

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similarly to the failed case, if the attempt event was missed or arrived out of order, the succeeded target will be silently ignored. Handle this defensively by appending the target if it does not exist in run.targets.

      const targetExists = run.targets.some((t) => t.targetIndex === ev.targetIndex);
      const updatedTargets = targetExists
        ? run.targets.map((t) =>
            t.targetIndex === ev.targetIndex
              ? {
                  ...t,
                  state: "succeeded" as TargetState,
                  latencyMs: ev.latencyMs,
                }
              : t
          )
        : [
            ...run.targets,
            {
              targetIndex: ev.targetIndex,
              provider: ev.provider,
              model: ev.model,
              state: "succeeded" as TargetState,
              latencyMs: ev.latencyMs,
            },
          ].sort((a, b) => a.targetIndex - b.targetIndex);

Comment on lines +112 to +113
export function handleCcrRetrieve(args: { hash: string }): { content: string } | { error: string } {
if (!args.hash || typeof args.hash !== "string") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To prevent potential runtime crashes if args is null or undefined, add a defensive check for args itself before accessing args.hash.

Suggested change
export function handleCcrRetrieve(args: { hash: string }): { content: string } | { error: string } {
if (!args.hash || typeof args.hash !== "string") {
export function handleCcrRetrieve(args: { hash: string }): { content: string } | { error: string } {
if (!args || !args.hash || typeof args.hash !== "string") {

Comment on lines +113 to +114
export function discoverRepeatedNoise(samples: CommandSample[]): NoiseCandidate[] {
if (samples.length === 0) return [];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Add a defensive check to ensure samples is a valid array before accessing samples.length to prevent potential runtime errors if the function is called with null or undefined.

Suggested change
export function discoverRepeatedNoise(samples: CommandSample[]): NoiseCandidate[] {
if (samples.length === 0) return [];
export function discoverRepeatedNoise(samples: CommandSample[]): NoiseCandidate[] {
if (!samples || !Array.isArray(samples) || samples.length === 0) return [];

Comment on lines +391 to +392
export function reconstructSessionDedup(body: Record<string, unknown>): Record<string, unknown> {
// The reverse map is stored as a non-enumerable property so it doesn't appear

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Add a defensive check to ensure body is not null or undefined before attempting to read its property descriptors, preventing potential runtime crashes.

Suggested change
export function reconstructSessionDedup(body: Record<string, unknown>): Record<string, unknown> {
// The reverse map is stored as a non-enumerable property so it doesn't appear
export function reconstructSessionDedup(body: Record<string, unknown>): Record<string, unknown> {
if (!body) return body;
// The reverse map is stored as a non-enumerable property so it doesn't appear

Comment on lines +259 to +261
function validateLlmlinguaConfig(config: Record<string, unknown>): EngineValidationResult {
const errors: string[] = [];
if (config["enabled"] !== undefined && typeof config["enabled"] !== "boolean") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Add a defensive check to ensure config is not null or undefined before accessing its properties, preventing potential runtime crashes.

function validateLlmlinguaConfig(config: Record<string, unknown>): EngineValidationResult {
  const errors: string[] = [];
  if (!config) {
    return { valid: false, errors: ["config is required"] };
  }
  if (config["enabled"] !== undefined && typeof config["enabled"] !== "boolean") {

…ents

Mounts the two Studios as reachable routes (non-invasive — new page.tsx files,
no existing route touched):
- /dashboard/compression/studio → CompressionCockpit fed by useLiveCompression.
- /dashboard/combos/live → ComboLiveStudio fed by useLiveComboStatus
  (LiveComboEvent is structurally compatible with the studio's ComboEventInput).
Both degrade gracefully (empty state / 'Live disabled' banner) when the WS feed
is off, so they render even without OMNIROUTE_ENABLE_LIVE_WS.

Also carries the routing  on LiveComboEvent (attempt payload) so the
Combo Studio shows the strategy pill.

Sidebar nav links deferred: items require an i18nKey across 42 locales + a
HideableSidebarItemId union entry (strict count-guard) — a separate i18n chore;
the routes are URL-reachable meanwhile. TDD: tests/unit/ui/studio-pages.test.tsx
(both pages mount + render their state offline).
Adds 5 entries in the existing Acknowledgments pattern (verified repos): TOON
(toon-format/toon) for the headroom tabular compaction; LLMLingua (microsoft) +
the llmlingua-2-js ONNX port (atjsh) for the llmlingua engine; ts-morph (dsherret)
for parser-based comment removal; React Flow/xyflow for the Studios; LangGraph
(langchain-ai) for the live workflow-graph visualization concept.
@diegosouzapw

Copy link
Copy Markdown
Owner Author

Studio routes are now wired (URL-reachable) for the VPS/Chrome validation:

  • Compression Studio (Tela A): /dashboard/compression/studio
  • Combo/Routing Studio (Tela B): /dashboard/combos/live

Both are new non-invasive route pages (no existing route touched). They degrade gracefully (empty state / 'Live disabled' banner) when the WS feed is off, so to see live data the instance must run with OMNIROUTE_ENABLE_LIVE_WS=1 and process a request that triggers compression / a combo.

Discoverable Sidebar nav links are deferred (each item needs an i18nKey across 42 locales + a HideableSidebarItemId union entry under the strict count-guard — a separate i18n chore). Also added README Acknowledgments for TOON, LLMLingua/llmlingua-2-js, ts-morph, React Flow/xyflow and LangGraph.

The user noted headroom (the SmartCrusher source) was missing. Adds the projects
whose code/blueprints OmniRoute actually drew on this round, with web-verified
repos: chopratejas/headroom (headroom engine + ccr retrieve), blackwell-systems/gcf
(columnar tabular, alongside TOON), ooples/token-optimizer-mcp (session-dedup
content-delta), Mibayy/token-savior (bail-out + MCP cardinality).
…3848)

chatCore.ts 5808→5811 (+3 compression pipeline hooks, own). Carries release
drift models/route.ts 2487→2489. Merge release/v3.8.25 into the branch.
#3838 added a 3-line comment to usage.ts that shifted getMiniMaxUsage's TS
fn-param-type FP from L543 to L546, leaving the KNOWN_LITERAL_CREDS allowlist
stale (release-wide). Re-pin to the new line; still the same audited FP.
…3848)

tests/unit/events/ is not in the runner's collected subdir glob, so the test
never ran (check:test-discovery orphan). Moved to tests/unit/compression/
(same depth → relative imports unchanged); 4/4 pass.
@diegosouzapw
diegosouzapw merged commit 4ffc55c into release/v3.8.25 Jun 14, 2026
2 checks passed
diegosouzapw added a commit that referenced this pull request Jun 15, 2026
…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.
@diegosouzapw diegosouzapw mentioned this pull request Jun 15, 2026
@diegosouzapw
diegosouzapw deleted the feat/compression-studios branch June 15, 2026 02:35
diegosouzapw added a commit that referenced this pull request Jun 15, 2026
* 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.)
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
* 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.)
Poid-ZA pushed a commit to Poid-ZA/OmniRoute that referenced this pull request Aug 5, 2026
Poid-ZA pushed a commit to Poid-ZA/OmniRoute that referenced this pull request Aug 5, 2026
* 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.)
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…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.
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
* 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.)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant