Repository navigation
feat(deploy): Kubernetes support for k3s and k8s - #12400
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The provisioning plan’s input validation and command rendering have correctness issues that can generate broken commands or reject valid Kubernetes quantity/context inputs.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds first-class Kubernetes deployment support to OmniRoute by introducing committed Kustomize manifests (base + k3s/k8s overlays), a Helm chart, and a new omniroute deploy k8s CLI generator/provision-plan, plus an ops guide and unit tests that pin the single-writer + SSE/probe invariants.
Changes:
- Add
deploy/kubernetes/(Kustomize base + k3s/k8s overlays) anddeploy/helm/omniroute/(Helm chart) that encode single-replica + RWO + Recreate + SSE/probe guardrails. - Add pure TS deploy-spec validation + manifest generator + provisioning plan under
src/lib/deploy/kubernetes/, surfaced viaomniroute deploy k8sCLI command. - Add docs (
docs/ops/KUBERNETES_DEPLOYMENT_GUIDE.md) and tests to prevent drift/regressions; adjust CLI stdout handling sodeployoutput is pipe-safe.
Validation / Coverage (custom)
- Commands run (reviewer): not run in this review (see PR description for author-run results).
- Tests added/updated:
tests/unit/k8s-deploy-manifests.test.ts,tests/unit/deploy/kubernetes-*.test.ts(3 files). - Coverage result (custom): not measured in this review.
File summaries
| File | Description |
|---|---|
| tests/unit/k8s-deploy-manifests.test.ts | Pins invariants across committed Kustomize + Helm artifacts (replicas/strategy/RWO/probes/SSE/secret hygiene). |
| tests/unit/deploy/kubernetes-provision-plan.test.ts | Verifies provision-plan output and deploy-spec guardrails (TLS SAN, kubeconfig rewrite, input safety). |
| tests/unit/deploy/kubernetes-manifest-generator.test.ts | Validates manifest generation invariants + parity vs deploy/kubernetes/base. |
| tests/unit/deploy/kubernetes-cli-command.test.ts | End-to-end CLI tests for stdout/data contract and deploy-spec validation errors. |
| src/lib/deploy/kubernetes/types.ts | Zod schema for deploy spec + memory-limit parsing helper used for guardrails. |
| src/lib/deploy/kubernetes/provisionPlan.ts | Pure “print-only” k3s provisioning plan builder + input validators. |
| src/lib/deploy/kubernetes/manifestGenerator.ts | Pure manifest object builder + YAML renderer + target-specific defaults. |
| docs/ops/meta.json | Registers the new Kubernetes ops guide in ops docs metadata. |
| docs/ops/KUBERNETES_DEPLOYMENT_GUIDE.md | End-to-end Kubernetes deployment guide (k3s + k8s), covering SSE/Ingress and probes. |
| docs/guides/DOCKER_GUIDE.md | Cross-links to Kubernetes deployment guide from the Docker guide. |
| deploy/kubernetes/base/namespace.yaml | Adds base Namespace manifest. |
| deploy/kubernetes/base/configmap.yaml | Adds base ConfigMap (non-secret runtime config) with API_PORT explicitly unset. |
| deploy/kubernetes/base/pvc.yaml | Adds base PVC pinned to ReadWriteOnce. |
| deploy/kubernetes/base/deployment.yaml | Adds base Deployment pinned to replicas=1 and strategy=Recreate, with probe/lifecycle defaults. |
| deploy/kubernetes/base/service.yaml | Adds base Service exposing http + live-ws ports with explicit TCP protocols. |
| deploy/kubernetes/base/secret.example.yaml | Adds Secret template with placeholders only (not referenced by kustomization). |
| deploy/kubernetes/base/kustomization.yaml | Adds base kustomization wiring (intentionally excludes secret.example.yaml). |
| deploy/kubernetes/overlays/k3s/kustomization.yaml | k3s overlay resources + patches (storageClass + resources trim). |
| deploy/kubernetes/overlays/k3s/ingress.yaml | Traefik ingress overlay with streaming caveats documented. |
| deploy/kubernetes/overlays/k3s/pvc-storageclass.yaml | k3s overlay pinning StorageClass to local-path. |
| deploy/kubernetes/overlays/k3s/resources.yaml | k3s overlay resource sizing patch. |
| deploy/kubernetes/overlays/k8s/kustomization.yaml | Generic k8s overlay resources + PVC patch. |
| deploy/kubernetes/overlays/k8s/ingress.yaml | ingress-nginx ingress overlay with buffering/timeouts configured for SSE. |
| deploy/kubernetes/overlays/k8s/pvc-storageclass.yaml | Generic k8s PVC patch leaving storageClassName unset (bind default). |
| deploy/kubernetes/overlays/k8s/liveness-tcp.yaml | Optional TCP liveness patch for event-loop stall resilience. |
| deploy/helm/omniroute/Chart.yaml | Introduces the Helm chart definition. |
| deploy/helm/omniroute/values.yaml | Chart values encoding single-writer constraints and runtime config knobs. |
| deploy/helm/omniroute/.helmignore | Adds Helm ignore rules. |
| deploy/helm/omniroute/templates/_helpers.tpl | Adds chart guardrails + common naming/label helpers. |
| deploy/helm/omniroute/templates/deployment.yaml | Adds Deployment template mirroring k8s invariants and probes. |
| deploy/helm/omniroute/templates/service.yaml | Adds Service template exposing http + live-ws. |
| deploy/helm/omniroute/templates/configmap.yaml | Adds ConfigMap template (non-secret env) matching runtime expectations. |
| deploy/helm/omniroute/templates/secret.yaml | Adds optional Secret template with guardrails to avoid conflicting secret configs. |
| deploy/helm/omniroute/templates/pvc.yaml | Adds PVC template with helm.sh/resource-policy: keep. |
| deploy/helm/omniroute/templates/ingress.yaml | Adds Ingress template controlled by values. |
| deploy/helm/omniroute/templates/serviceaccount.yaml | Adds ServiceAccount template with automount disabled. |
| deploy/helm/omniroute/templates/NOTES.txt | Adds post-install notes highlighting outage semantics and key settings. |
| changelog.d/features/kubernetes-deploy-manifests.md | Adds changelog entry describing Kubernetes support artifacts. |
| bin/omniroute.mjs | Treats deploy as a “stdout is data” mode (redirects logs to stderr). |
| bin/cli/commands/registry.mjs | Registers the new deploy command in the CLI registry. |
| bin/cli/commands/deploy.mjs | Implements omniroute deploy k8s + provision command surface and spec validation. |
| .prettierignore | Excludes Helm templates from Prettier YAML parsing. |
Review details
Suppressed comments (1)
src/lib/deploy/kubernetes/types.ts:146
parseMemoryToMib()mirrors the sameKvskissue (it parsesKbut notk). If a user supplies a validk-suffixed quantity forlimitsMemory, the heap-vs-cgroup validation will silently skip (match fails) or miscompute. Parse lowercasekinstead.
- Files reviewed: 39/42 changed files
- Comments generated: 4
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Notes from a production deployment running exactly this topology (single replica, Recreate, RWO PVC on Longhorn, ingress-nginx) — three things that bit us and may be worth folding in:
Also, for the storage section: PVC sizing currently has to budget for unbounded telemetry growth ( |
|
Thanks — this is the kind of feedback that only comes from actually running it. Items 1, 2 and 4 are in as of
The Ingress split is now Telemetry sizing now says the PVC is sized by retention window, citing #12453 and your ~190 MB/day figure. On item 3, I think the behaviour changed under you. On function resolveLegacyCountCap(): number {
const raw = process.env.OMNIROUTE_CHAT_MAX_HEAVY_IN_FLIGHT;
if (raw === undefined || raw.trim() === "") return Number.MAX_SAFE_INTEGER;
return CHAT_MAX_HEAVY_IN_FLIGHT;
}Left unset, the legacy count cap resolves to unlimited and the auto-derived ingest byte budget is what gates — the source comment says as much ("the default on every deployment that produced the multi-subagent 503 storm ... resolves to effectively unlimited"). So I documented both knobs in the sizing section with that caveat, since the variable name reads like a ceiling you raise. If |
|
Confirmed: we're on 3.8.50, where the bundle still reads |
insoln
left a comment
There was a problem hiding this comment.
Ran this exact topology in production today (generic k8s, ingress-nginx, Longhorn, ~1 GB storage.sqlite, agentic load) and hit the failure the liveness comment hints at — hard enough that I think two defaults should flip. Sequence: HTTP liveness (3 s timeout) killed the pod mid-startup-VACUUM → each restart grew the WAL (it reached 999 MB) → every checkpoint then stalled the event loop for ~a minute → readiness flapped → nginx 503s. tcpSocket liveness plus a bigger startup budget broke the loop. Three inline suggestions with the numbers.
Sweep-reds babysit (round 5 Fase B)No push. HEAD remains Remaining reds are inherited — not this PR's fault
Not merging. Needs the base-red drain, not a k8s rewrite. |
|
Both defaults flipped, plus a third that fell out of testing. Pushed as I went looking for the mechanism in the repo before changing anything, and it is there in two places: Liveness is now Startup budget 150s → 10 min, for the reason you give: the failure is self-amplifying, and readiness holds traffic back for exactly as long as it takes, so the budget costs nothing.
A third one, found by running it. On a real cluster the startup probe logged Verified on k3s v1.36.4+k3s1, not just rendered: pod The tests pin each default to the source fact it derives from rather than to the number: one greps the VACUUM call out of Credited you as co-author on the commit; the tcpSocket rationale is yours. (For anyone tracking CI here: HEAD moved from |
|
This is an exceptionally well-executed PR — the self-review notes (the silently-discarded |
Adds the infrastructure-as-code path for running OmniRoute on Kubernetes, alongside the existing docker-compose.yml and fly.toml, plus a CLI that generates the same manifests from a running instance's settings. Artifacts: - deploy/kubernetes: Kustomize base with k3s (Traefik + local-path) and generic k8s (ingress-nginx) overlays. - deploy/helm/omniroute: equivalent chart, values-driven. - `omniroute deploy k8s`: prints manifests on stdout, so it composes — `omniroute deploy k8s --target local | kubectl apply -f -`. - `omniroute deploy k8s provision`: prints the commands for standing up a k3s cluster locally or on a VPS. - docs/ops/KUBERNETES_DEPLOYMENT_GUIDE.md: deploy, ingress/SSE, probes, upgrades, storage/backups, sizing, troubleshooting. The single-SQLite-writer topology is encoded rather than left to a comment: replicas pinned to 1, Recreate strategy, ReadWriteOnce volume. The chart and the spec schema refuse — with an explanatory message — a configuration that fails at runtime: replicaCount > 1, a non-RWO access mode, a heap ceiling at or above the memory limit (OOMKilled instead of a recoverable heap error), a shutdown budget larger than the drain window (SSE cut rather than drained). Replica count, update strategy and access mode are not CLI flags. Ingress defaults keep SSE working: response buffering off on ingress-nginx, where buffering withholds the stream until the provider turn ends, and the Traefik entrypoint idle-timeout caveat documented for k3s. Probes follow MONITORING_GUIDE.md — /healthz for startup and readiness, /livez for liveness, never /api/monitoring/health. Provisioning is deliberately advisory: OmniRoute prints the k3s commands and never runs them or connects to a server, since doing it directly would mean shipping an SSH client and holding a private key. This mirrors how contrib/vps documents a VPS install. The VPS plan covers the two steps easiest to get wrong by hand — `--tls-san`, without which a remote kubectl fails TLS verification, and rewriting the 127.0.0.1 server address in the kubeconfig k3s writes. Values rendered into those commands are constrained to hostname, version, username and context shapes, so a printed command cannot mean something other than it looks like. Validated on a live single-node k3s cluster (v1.36.4+k3s1), not just a dry run: the PVC binds on local-path, the pod reaches Ready, the rollout completes, /healthz and /livez answer 200 through the Service, and no probe failure or restart is recorded. That run corrected two documentation errors a client-side dry run cannot catch — the health check used `wget`, which the image does not ship (nor curl; node is the only HTTP client in it), and an Ingress naming an IngressClass the cluster does not run is accepted by the API server and then silently routes nothing. Two fixes to the manifests themselves, both found by the test that pins the generator against deploy/kubernetes/base: - Drop API_PORT from the base ConfigMap. Setting it moves the API to a separate port (src/lib/runtime/ports.ts) that neither the container nor the Service exposes, leaving that listener unreachable. - Make the container port protocol explicit so both sources agree. `deploy` also joins `--mcp` in reserving stdout for data. Startup notices there made the YAML unparseable, breaking the pipe the command exists for.
Four findings from the automated review on cheaper-inference#12400, all real: - `isSafeServerAddress` accepted `:` and a trailing `]`, so `example.com:123` or a bare IPv6 literal passed and then rendered as `https://host:123:6443`. The plan does not add brackets and appends its own port, so the input is now restricted to a hostname or a validated IPv4 literal. An all-numeric final label is rejected too — `1.2.3.4.5` is a malformed address, not a host. - `isSafeContextName` rejected `:` and `/`, which excluded the ARN-shaped contexts managed clusters produce (`arn:aws:eks:…:cluster/prod`). Widened; the leading-alphanumeric requirement still prevents a value being read as an option, and nothing here reaches a shell. - The fetch-kubeconfig step interpolated the context into a temp path. With `/` now allowed that would write outside the intended location, so the filename is fixed and the context is used only for the kubeconfig rename. - The quantity pattern accepted `K` but rejected `k`, which is how Kubernetes spells the decimal thousand — `512k` was refused. Both are accepted now, and the pattern gained the missing `P`/`E`/`Pi`/`Ei` suffixes, with matching factors in `parseMemoryToMib`. Each is covered by a regression case; the provisioning suite goes from 14 to 19.
Two Fast Quality Gates failures on cheaper-inference#12400. `check:test-discovery` reported all three new suites as orphans: the unit runner's subdirectory glob is an explicit allowlist (`tests/unit/{api,auth,authz,...}/**`) and `deploy` is not in it, so nothing under `tests/unit/deploy/` was ever collected. The suites passed locally and in no CI job — the exact failure mode that gate was added for after the 2026-06-09 audit found ~135 orphaned tests, one of them a Hard Rules cheaper-inference#15/cheaper-inference#17 check whose asserts were already failing unnoticed. Moved the three files to `tests/unit/` rather than widening the allowlist: adding a directory there changes the runner for every contributor, which is not this PR's business. Import depths adjusted; the fourth suite was already at the collected level. `check:complexity-ratchets` flagged `buildDeployment` at 83 lines against a limit of 80. The pod template is almost entirely the container object, so that object moved to `buildContainer`. No behaviour change — the generator's output is byte-identical, which the parity test against deploy/kubernetes/base pins. Both gates verified locally: test-discovery OK, complexityNewCode=0.
…split Three items from production-deployment feedback on cheaper-inference#12400. `proxy-body-size` was 32m while the application's own cap (OMNIROUTE_CHAT_HARD_MAX_BODY_BYTES, src/shared/middleware/chatBodyAdmission.ts) defaults to 50 MB. nginx therefore returned 413 for bodies the app would have accepted, and the app's own 413 — which tells the client to compact and retry — never ran. Raised to 50m in the overlay and in the generator, with a test that reads the real default out of the source rather than restating it, so raising either side alone fails. The single Ingress puts the dashboard on the same host and behind the same authentication as /v1, which on a reachable cluster means it is protected only by INITIAL_PASSWORD — defaulted to CHANGEME in the published image. That split cannot be expressed in one Ingress resource, so overlays/k8s/ingress-split-example.yaml shows it: /v1 and /api/v1 on an API host with REQUIRE_API_KEY, the dashboard on its own host behind an external identity provider. Not wired into the kustomization, same as the liveness-tcp patch. Storage sizing now says the volume is sized by telemetry growth, not by the control plane: conversation_turn_nodes and agentic_conversations have no retention path yet (cheaper-inference#12453), and a reported ~190 MB/day under agentic load makes the 10Gi/20Gi defaults a starting point rather than a recommendation. Also documented the two chat-admission knobs an operator is most likely to reach for, including the one whose behaviour inverts expectations: OMNIROUTE_CHAT_MAX_HEAVY_IN_FLIGHT is a legacy count cap that binds ONLY when explicitly set (resolveLegacyCountCap returns MAX_SAFE_INTEGER when unset), so setting it enables the cap rather than relaxing it.
Production feedback on the PR reported a self-amplifying crashloop on this
exact topology: an HTTP liveness probe timed out while the pod was running the
cold-start VACUUM, the kubelet killed it mid-write, the interrupted write left
a larger WAL, the next boot was slower, and it got killed again.
The cause is in this repository, not in the manifests' author's imagination:
better-sqlite3 is synchronous, so `db.exec("VACUUM")` in
src/lib/db/cleanup.ts and `wal_checkpoint(TRUNCATE)` in src/lib/db/core.ts
block the event loop for as long as they run. Every HTTP handler stops
answering meanwhile, /livez included — it shares the loop.
Three defaults follow from that:
- liveness is now tcpSocket, not `GET /livez`. The asymmetry decides it: a
wrong HTTP liveness restarts the pod mid-write and grows the data file; a
wrong TCP liveness lets a hung-but-listening process survive until someone
looks. Readiness stays on HTTP and is what removes a stalled pod from the
Service. overlays/k8s/liveness-tcp.yaml is inverted into liveness-http.yaml,
an opt-in for small databases on fast local storage.
- the startup budget goes 150s -> 10 min, and gains an explicit 3s timeout.
Cold start is migrations plus WAL replay plus the cleanup VACUUM, and a kill
mid-VACUUM is what creates the oversized WAL that makes the next boot slower.
Readiness holds traffic back for exactly as long as it takes, so it is free.
- terminationGracePeriodSeconds goes 90 -> 300. SHUTDOWN_TIMEOUT_MS bounds only
the request drain; gracefulShutdown.ts then runs closeDbInstance(), whose WAL
checkpoint has no timeout of its own. It is a ceiling, not a delay.
Verified on a real k3s cluster (v1.36.4+k3s1): pod 1/1 Running with 0 restarts,
/healthz and /livez 200 through the Service, and a deleted pod terminating in
25s against the 300s grace period. The kubelet's default 1s probe timeout was
exceeded by /healthz even on a trivial boot, which is what motivated the
explicit timeoutSeconds.
Tests pin each default to the source fact it derives from — the VACUUM call in
cleanup.ts, and the drain-then-cleanup order in gracefulShutdown.ts — so
raising one side alone fails. Verified by mutation: each of the five reverts
fails at least one test.
Co-authored-by: insoln <11380274+insoln@users.noreply.github.com>
e3e4960 to
5b6e50c
Compare
The startup-budget guard pinned its rationale to `db.exec("VACUUM")` inside
`startCleanupScheduler`. cheaper-inference#12821 — filed from this PR's own review thread —
replaced that with bounded incremental reclamation, so the pin stopped
matching on the current release tip and the test went red on rebase. That is
the pin doing its job: the manifest's reason moved, so the manifest has to be
re-argued, not the assertion relaxed.
Re-derived against the facts that hold on this base:
- Cold start still blocks. Opening the database runs the legacy call-log
offload, which checkpoints the WAL and then rebuilds the file with a full
VACUUM (src/lib/db/core.ts), and the startup cleanup pass 30s later reclaims
freed pages on the same synchronous connection. The 10-minute startup budget
is now pinned to both.
- The blocking full VACUUM still runs on a live, healthy process — from
vacuumScheduler at the configured hour, including the request cleanup now
defers there on an auto_vacuum=NONE database. That is what the tcpSocket
liveness default exists for, so the liveness guard pins it there instead.
Manifest, chart, generator and guide comments that cited the cleanup VACUUM as
the cold-start cost now name the offload and the reclamation pass. No manifest
value changes: replicas, strategy, access mode, probe targets, budgets and
annotations are all untouched.
Rebased onto the current release/v3.8.51 tip (964 commits). 57/57 tests pass,
typecheck:core clean, check:complexity-ratchets green in absolute mode
(complexity 2910 vs baseline 3218, cognitive 1322 vs 1437).
…equires `source.config.ts` compiles every Markdown file under docs/ with fumadocs-mdx, and `check:docs-frontmatter` fails the Docs Gates job for any compiled doc without a `title`. The guide predates that gate on this base, so the rebase turned it red — the only failure in that job that belongs to this PR. Fields follow the sibling ops guides (MONITORING_GUIDE.md, TUNNELS_GUIDE.md): title, plus version pinned to the release this lands in.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
…er it The k3s overlay drops the container limit to 2Gi so the pod fits a 2-core box, but the heap ceiling lives in the base ConfigMap and stayed at 3072 MB. The rendered overlay therefore shipped the one combination the deploy spec refuses: a V8 ceiling above the cgroup, where the kernel OOM-kills the pod instead of Node raising a recoverable heap error (cheaper-inference#7849) — the process dies with every in-flight stream and writes no useful log. Neither file is wrong on its own, which is why this survived. The chart guards it in a template `fail`, and the generator guards it in the spec schema, but the Kustomize path had no guard at all: the base test read the base pair and the overlay test read the overlay patch, and nothing read the pair the overlay actually renders. So the guard is the point, not the number. The new test resolves the effective heap/limit pair per overlay — inheriting whichever half the overlay does not patch — and walks every directory under overlays/, so a future overlay that trims one side without the other fails on arrival rather than at 3am. Verified red first: removing heap.yaml turns exactly that one test red, naming the 3072 MiB ceiling against the 2048 MiB limit. Found while deploying this branch to a real 2-core arm64 k3s node.
|
Re-homed to |
Concrete event-loop stall relevant to the TCP-liveness defaultFiled separately as #16039: clicking USD cost on a provider card calls This is an application defect, not introduced by this deployment PR, and is separate from #16036/#16037. Linking it here because it makes the recovery tradeoff in this PR concrete:
I checked the current head Suggested follow-up for the deployment policy:
The primary fix belongs in the analytics algorithm (#16039); probes only determine what happens when such a defect slips through. This comment intentionally contains only public-code analysis and synthetic evidence, no production logs or private deployment details. |
|
Hi @PauloFH — closing this pull request to clear the open queue. The branch |
|
Hi @PauloFH — reopening this pull request. The close was a mistake, and it is back in the merge queue. The branch |
|
Re-homed to |
Resolve the .prettierignore conflict by keeping both the Helm templates block and the ui-kit entry. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
8572495
into
cheaper-inference:release/v3.8.53
… Kit (#14) * test(perplexity-web): use a mapped model in the stream boundary delayed-hook case (#18232) Use a mapped model in the stream boundary delayed-hook case. Evidence: focused tests (no test files in diff); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(compression): report RTK's real truncation count and cut on line boundaries (#18139) Report RTK's real truncation count and cut on line boundaries. Evidence: focused tests (tests/unit/compression/rtk-smart-truncate.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(responses): keep replayed web search call ids on generic executors (#18127) Keep replayed web search call ids on generic executors. Evidence: focused tests (tests/unit/responses-input-sanitizer-websearch-id.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(sse): purge releasable failure entries past held lockouts (#18126) Purge releasable failure entries past held lockouts. Evidence: focused tests (tests/unit/account-fallback-lockout-eviction.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(sse): keep explicit thinking type over connection default (#18114) Keep explicit thinking type over connection default. Evidence: focused tests (tests/unit/glm-thinking-type-explicit.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(combo): clear stale LKGP pin on quality-rejected 200 (#18113) Clear stale LKGP pin on quality-rejected 200. Evidence: focused tests (tests/unit/combo/execute-target-attempt.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(translator): deferred OpenAI→Claude finish replays the pending choice, duplicating the last tool-arg fragment (#18193) Deferred OpenAI→Claude finish replays the pending choice, duplicating the last tool-arg fragment. Evidence: focused tests (tests/unit/openai-to-claude-trailing-usage-deferred-finish.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(bootstrap): strip inline comments from unquoted env values (#18116) Strip inline comments from unquoted env values. Evidence: focused tests (tests/unit/bootstrap-env-inline-comment.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(sse): enforce UTF-8 byte caps for captured stream chunks (#18187) Enforce UTF-8 byte caps for captured stream chunks. Evidence: focused tests (tests/unit/request-logger-stream-byte-cap.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(opencode): scope a retired-model 410 to the model, not the connection (#17827) Scope a retired-model 410 to the model, not the connection. Evidence: focused tests (tests/unit/opencode-410-model-scope.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(models): bound retained catalog response caches (#18188) Bound retained catalog response caches. Evidence: focused tests (tests/unit/catalog-cache-bounds.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(api): expose provider-wildcard combos in model catalog (#18182) Expose provider-wildcard combos in model catalog. Evidence: focused tests (tests/unit/models-catalog-provider-wildcard.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 Fixes #18033 * fix(usage): include Kimi Coding monthly quota (#18234) Include Kimi Coding monthly quota. Evidence: focused tests (tests/unit/kimi-monthly-membership-quota.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(pool): reclaim dead sessions on acquire instead of returning null (#18115) Reclaim dead sessions on acquire instead of returning null. Evidence: focused tests (tests/unit/session-pool-dead-reclaim.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(embeddings): preserve Gemini native token usage (#18244) (#18246) Preserve Gemini native token usage. Evidence: focused tests (tests/unit/embeddings-multimodal-7956.test.ts, tests/unit/gemini-embedding-2-multimodal.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 Closes #18244. * fix(combo): apply the global per-target expansion cap when a combo sets none (#18130) Apply the global per-target expansion cap when a combo sets none. Evidence: focused tests (tests/unit/combo/connection-aware-expansion.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(translator): keep OpenAI prompt_cache_breakpoint on content parts for openai/openrouter (#18255) Keep OpenAI prompt_cache_breakpoint on content parts for openai/openrouter. Evidence: focused tests (tests/unit/translator-openai-prompt-cache-breakpoint-18254.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 Closes #18254 * fix(sse): preserve complexity hints in primary auto routing (#18104) Preserve complexity hints in primary auto routing. Evidence: focused tests (tests/unit/auto-combo-primary-complexity.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(build): bundle locale catalogs as text in webpack builds (#18183) Bundle locale catalogs as text in webpack builds. Evidence: focused tests (tests/unit/build/webpack-locale-messages-source.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(compression): let an idle pool worker stop holding the process open (#18136) Let an idle pool worker stop holding the process open. Evidence: focused tests (tests/unit/compression/compression-worker-pool-exit.test.ts, tests/unit/compression/compression-worker-pool-jam.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(firefly): avoid false stale detection for non-underscore Forter timestamps (#18099) Avoid false stale detection for non-underscore Forter timestamps. Evidence: focused tests (tests/unit/adobe-firefly-browser-login.test.ts, tests/unit/adobe-forter-session-timestamp.test.ts, tests/unit/adobe-forter-timestamp-extraction.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(tls): cancel response bodies when requests are aborted (#18228) Cancel response bodies when requests are aborted. Evidence: focused tests (tests/unit/http-backed-chat-response-lifetime.test.ts, tests/unit/tls-client-abort-lifetime.test.ts, tests/unit/tls-proxy-context.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(sse): honor pii-masker opt-out in streaming pipeline (#18121) Honor pii-masker opt-out in streaming pipeline. Evidence: focused tests (tests/unit/chatcore-streaming-pipeline.test.ts, tests/unit/streaming-pii-optout-gate.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(nvidia): replace retired Nemotron 3 Super with Nemotron 3.5 Super VL (#17928) Replace retired Nemotron 3 Super with Nemotron 3.5 Super VL. Evidence: focused tests (tests/unit/antigravity-bridge-routing.test.ts, tests/unit/catalog-updates-v3x.test.ts, tests/unit/nvidia-eol-catalog.test.ts, tests/unit/nvidia-nim-registry-6108.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(services): harden embedded Bifrost runtime (#17976) Harden embedded Bifrost runtime. Evidence: focused tests (tests/unit/authz/route-guard-version-get-exemption.test.ts, tests/unit/route-guard-local-only-sweep.test.ts, tests/unit/services/installers/bifrost.test.ts, tests/unit/services/internal-health-fetch.test.ts, tests/unit/services/service-status-route-guard.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(oauth): accept permission-based Cursor user API keys (#17905) Accept permission-based Cursor user API keys. Evidence: focused tests (tests/unit/cursor-agent-image.test.ts, tests/unit/cursor-api-key-auth.test.ts, tests/unit/cursor-api-models-discovery.test.ts, tests/unit/cursor-apikey-provider.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(mcp): validate Origin on /api/mcp/* to block DNS rebinding (#17273) Validate Origin on /api/mcp/* to block DNS rebinding. Evidence: focused tests (tests/integration/mcp-origin-host-e2e.test.ts, tests/unit/mcp-origin-validation.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * test(authz): fail when a host-config, process-control or data-export route can be anonymous (#18293) Fail when a host-config, process-control or data-export route can be anonymous. Evidence: focused tests (tests/unit/management-capability-routes-protected.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * refactor(api): move the per-request keepalive frame into a helper (#17825) (#18281) Move the per-request keepalive frame into a helper. Evidence: focused tests (tests/unit/responses-route-early-keepalive-wiring.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * test(ui): repair the vitest UI base-red on release/v3.8.53 (#18306) Repair the vitest UI base-red on release/v3.8.53. Evidence: focused tests (tests/unit/ui/api-key-access-editor.test.tsx); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * fix(sse): type empty or typeless array items in Gemini tool schemas (#18289) Type empty or typeless array items in Gemini tool schemas. Evidence: focused tests (tests/unit/gemini-array-items.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * fix(auth): fail closed when the logout revocation cannot be saved (#18323) Fail closed when the logout revocation cannot be saved. Evidence: focused tests (tests/unit/dashboard-session-invalidation.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * fix(cursor): harden the HTTP/2 proxy tunnel and fail closed on unresolvable pinned proxies (#18324) Harden the HTTP/2 proxy tunnel and fail closed on unresolvable pinned proxies. Evidence: focused tests (tests/unit/cursor-h2-proxy-connect-hardening.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * fix(antigravity): accept the bare gemini-4-argon id and list Gemini 4 Argon on Vertex (#18285) Accept the bare gemini-4-argon id and list Gemini 4 Argon on Vertex. Evidence: focused tests (tests/unit/gemini-4-argon-bare-alias-vertex.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * feat(providers): add Kimi K3.1 Pro to the Command Code static catalog (#18292) Add Kimi K3.1 Pro to the Command Code static catalog. Evidence: focused tests (tests/unit/command-code-executor.test.ts, tests/unit/command-code-kimi-k3-1-pro-5172.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * fix(api): report an unreachable upstream as 502 in provider model discovery (#18294) Report an unreachable upstream as 502 in provider model discovery. Evidence: focused tests (tests/unit/provider-models-upstream-unreachable-4843.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * fix(db): revoke a deleted combo's name from API key allowed_combos (#18297) Revoke a deleted combo's name from API key allowed_combos. Evidence: focused tests (tests/unit/combo-delete-revokes-key-grants.test.ts); combined board B5 (5 PRs) on origin/release/v3.8.53: 63/63 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. ⚠️ base-red inherited: #17219 * feat(providers): add Kimi K3.1 Pro to OpenCode Go (#18295) Add Kimi K3.1 Pro to OpenCode Go. Evidence: focused tests (tests/unit/opencode-go-kimi-k3.1-pro-5147.test.ts); combined board B5 (5 PRs) on origin/release/v3.8.53: 63/63 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. ⚠️ base-red inherited: #17219 * feat(compression): add RTK filter for PHPUnit test output (#18317) Add RTK filter for PHPUnit test output. Evidence: focused tests (tests/unit/compression/rtk-phpunit-filter.test.ts); combined board B5 (5 PRs) on origin/release/v3.8.53: 63/63 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. ⚠️ base-red inherited: #17219 * fix(translator): honor explicit client max_tokens on Claude/Gemini/Antigravity -> OpenAI (#18300) Honor explicit client max_tokens on Claude/Gemini/Antigravity -> OpenAI. Evidence: focused tests (tests/unit/openai-to-claude-explicit-max-tokens-cap.test.ts, tests/unit/translator-antigravity-to-openai.test.ts, tests/unit/translator-explicit-max-tokens-cap-5180.test.ts, tests/unit/translator-gemini-to-openai.test.ts); combined board B5 (5 PRs) on origin/release/v3.8.53: 63/63 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. ⚠️ base-red inherited: #17219 * fix(api): honor OMNIROUTE_NO_UPDATE_NOTIFIER in the dashboard version check (#18316) Honor OMNIROUTE_NO_UPDATE_NOTIFIER in the dashboard version check. Evidence: focused tests (tests/unit/system-version-update-optout.test.ts); combined board B5 (5 PRs) on origin/release/v3.8.53: 63/63 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. ⚠️ base-red inherited: #17219 * fix(docs): refresh the live counts and the design-system palette note on release/v3.8.53 (#18339) * i18n(ui): translate the cursor-api onboarding description in 38 locales (#18351) * fix(discovery): show why a model discovery fell back to the built-in catalog (#17342) * feat(dashboard): account-availability quota overview with per-pool rows and reorderable providers (#17026) * fix(dashboard): show the configured model and the full account in the Combo Control Center (#17393) (#17774) Co-authored-by: vincent <webmaster@palmit.com.au> * refactor(routing): share combo attempt failure facts (#17956) * fix(claude): forward max reasoning effort on the Responses path for max-capable models (#18064) Co-authored-by: Davy Massoneto <davy.m.massoneto@gmail.com> * feat(proxy): accept selector-only subscriptions with no feed URL (#16165) * fix(translator): bridge Claude Code WebSearch to Codex native web_search (#16365) Co-authored-by: wray-lee <wray-lee@outlook.com> * feat(routing): enrich routing events with apiKeyId and stream cost (#14736) Co-authored-by: Safeer Ahmad <asafeer1994@gmail.com> * fix(providers): surface failed Codex client-version refreshes instead of swallowing them (#17855) * feat(api): add per-key Claude Code discovery alias control (#17979) Co-authored-by: Sean P. Ford <sean@seanford.com> * docs(readme): hero in the Cheaper Inference UI Kit typography (#18261) * docs(readme): four above-the-fold diagrams in the UI Kit typography (#18308) * docs(readme): tier cascade, strategies grid, resilience layers and comparison table in the UI Kit typography (#18309) * docs(readme): privacy ledger, CLI terminal and compression pipeline in the UI Kit typography (#18310) * docs(readme): one regenerate command for the twelve README diagrams + design-system docs (#18337) * docs(i18n): re-sync 6 drifted docs across 66 locales (wave 1027) (#18371) * fix(i18n): use the canonical zh provider term in the providerStats and discovery keys (#18372) * feat: add Gemini prompt cache accounting (#12775) * fix(sse): distinguish generic buffered error frames from identified Responses failures (#18370) * fix: repair inherited release test reds (SSE bare-error frames, catalog fixtures, Codex fixture) (#17550) Co-authored-by: KiaroSama <Kiaro.Sama.Dev@gmail.com> * fix(providers): keep the ChatGPT Web browser launch under local and operator control (#18358) Validation of chatgpt-web-codex ignored allowLocalSpawn, so a remote management request could make the host launch a browser, and both ChatGPT Web browser providers used a connection's stored chromeExecutablePath as the executable whenever the path existed. Honour allowLocalSpawn before any launch, and let the stored path only select a browser the operator configured (CHROME_PATH / CHATGPT_WEB_*_CHROME_PATH) or a known install location. Co-authored-by: AiCaptain357 <345568968+AiCaptain357@users.noreply.github.com> * fix(dashboard): quota UIs fall back to /api/providers and show an auth-required state on 401 (#17262) (#18194) * deps(security): raise the qs override to ^6.16.1 (#18381) Raise the qs override to ^6.16.1 (the lock resolves 6.17.0), picking up the upstream fix for qs.stringify with arrayFormat comma throwing an uncaught TypeError. Lockfile-only. * fix(providers): honour allowLocalSpawn in Auggie validation (#18380) The Auggie validator took no options and always ran `auggie --version`, so remote-reachable routes that pass allowLocalSpawn=false for non-loopback callers still made the host start the CLI. Return a local-validation-only result for those callers before any spawn; internal and local callers keep the CLI probe. Co-authored-by: AiCaptain357 <345568968+AiCaptain357@users.noreply.github.com> * ci: let own-origin PR unit and vitest jobs opt in to the omni-ci slots (USE_VPS_TEST_RUNNER) (#18338) The hosted pool is the CI bottleneck (org-wide hosted concurrency; PR runs queued for hours). test-unit and test-vitest of own-origin pull requests can now opt in to three dedicated self-hosted omni-ci slots (omniroute-113-3/-4/-8, 12G/16G and 4 CPUs each) through vars.USE_VPS_TEST_RUNNER, default off. Forks, merge_group and push stay hosted, and USE_VPS_RUNNER still never governs a test job; the gap-19 guard pins the new switch. * docs(i18n): refresh 8 docs in 66 locales and fix the README version-table provider count (#18253) * fix(i18n): fall back to the next model and re-split when a chunk fails validation (#18422) * ci(i18n): make docs-mirror drift advisory on pull requests and the merge train (#18420) * Support custom compatible gateways behind an access proxy (#17136) * fix(release): drain the deterministic unit and vitest reds of release/v3.8.53 (#18426) * feat(release): bun-pack — bun-first global installs (build stays on Node) (#12801) * fix(streams): let a target's declared budget raise the 21-minute stream cap (#18002) * feat(providers): add Kimi (Moonshot) as a web search provider (#14292) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * feat(deploy): Kubernetes support for k3s and k8s (#12400) Co-authored-by: Paulo Holanda <paulorfholanda@gmail.com> Co-authored-by: Paulo Roberto Fernandes Holanda <paulorfholanda@gmail.com> Co-authored-by: insoln <11380274+insoln@users.noreply.github.com> * feat(cli-agents): add WhyCodes as a first-class CLI Agent (#14107) * feat(teams): billing cost centers, soft budgets and dashboard (#10409) Co-authored-by: Markus Hartung <mail@hartmark.se> Co-authored-by: dongsjoa <dongsjoa@Xiaoyaner-Mac-Studio.local> * test(log-export): deflake the child-runner timing tests on loaded runners (#18440) * feat(logs): add an OTLP/HTTP traces log-export destination (#16664) * fix(providers): honour allowLocalSpawn in Qoder PAT validation (#18424) Qoder Personal Access Token validation now honours allowLocalSpawn: for remote callers it returns a "validate locally" result instead of running the local qodercli. Covered by tests/unit/qoder-pat-validation-local-spawn.test.ts (direct call, dispatcher for qoder and the if alias, local control). (no public reference) Co-authored-by: AiCaptain357 <345568968+AiCaptain357@users.noreply.github.com> * feat(i18n): structure-safe Google Translate engine for the docs pipeline + ENVIRONMENT re-sync (#18429) * chore(ci): keep promptfoo, fumadocs-mdx, @playwright/test and bun out of dependabot groups (#18369) The development group #17197 cannot land as is: five of its bumps (four packages) break a contract or need a coordinated migration, and they keep the 21 routine updates riding along with them red. - promptfoo: exact pin mirrored by nightly-llm-security.yml and enforced by llm-security-nightly-promptfoo-pin.test.ts (0.124.1 is a known-broken release, promptfoo/promptfoo#10866). - fumadocs-mdx >=15.4.7: imports embedSource, which the fumadocs-core on this branch does not export; Build fails loading next.config.mjs. - @playwright/test: must equal the runtime playwright exact pin (playwright-runner-args.test.ts); runtime lives in the production group. - bun / @types/bun: exact pin documented in AGENTS.md and BUILD_WARNINGS.md, bumped by hand after byte-identical validation of the Bun scripts. No other dependabot rule changes. * fix(providers): announce direct Poolside inference shutdown (#17331) Announce the direct Poolside inference shutdown (2026-10-31) in the provider notes, FREE_TIERS and the generated provider reference. Evidence: reconciled with origin/release/v3.8.53 (0 commits behind); poolside-sunset-notice-17318 2/2 and poolside-registry-models-9085 4/4; check:docs-all, ESLint, typecheck:core, file-size and changelog integrity green. ⚠️ base-red inherited: #17219 Fixes #17318 * test: move late top-level imports above the first test() in three unit files (#18439) * fix(docs): keep the routing-strategy identifiers verbatim in the Bosnian AGENTS.md mirror (#18382) * fix(sse): replay an empty upstream turn on the direct streaming path (#17280) * fix(providers): register DeepSeek Flash aliases for vision requests (#17180) (#17243) * chore(dashboard): sync the vendored CI UI Kit to 0.0.66 (#18434) packages/ui-kit moves from upstream f0986a6 (0.0.48) to 3b6ba89 (0.0.66) through scripts/dev/sync-ui-kit.sh; the workspace version and its lockfile entry follow. The kit now self-hosts Switzer for every role (ci-tokens.css imports ci-fonts.css with local woff2 files), so src/app/globals.css drops the @fontsource Inter / Instrument Serif / IBM Plex Mono imports nothing references any more (the packages stay for the README diagram generator). The bridge and snapshot-gate tests follow the new contract, and DESIGN_SYSTEM.md describes Switzer. Validated on the local VPS (.15) before merge. Red CI checks are inherited from the base (#17219) and touch none of these files. * test(security): match the codex fallback version without a hand-escaped regex (CodeQL #1187) (#18419) The refresh-warning assertion uses String.includes instead of a RegExp that escaped only the dots of DEFAULT_CODEX_CLIENT_VERSION (CodeQL js/incomplete-sanitization #1187). Test-only; 9/9. * ci: add the CodeRabbit review configuration (#18431) Adds .coderabbit.yaml (validated against the CodeRabbit schema v2): auto review on non-draft PRs to release/vX.Y.Z and main, path filters for translated mirrors, lockfiles and generated files, per-area instructions from the AGENTS.md hard rules, pre-merge checks in warning mode for calibration. Takes effect once the CodeRabbit GitHub App is installed on the organization. * ci: drop the duplicate unit/vitest fast-path and skip lcov/Codecov on PR coverage (#18336) Quality Gates no longer runs fast-unit (4 shards of test:unit:ci:shard) and fast-vitest, which duplicated ci.yml test-unit/test-vitest on every PR since #14420 (~62 runner-minutes and 5 hosted jobs per PR); admission policy, check-test-discovery anchor and tests updated. On pull_request the Coverage job skips the lcov reporter and the informational Codecov upload; the 60% gate and summaries are unchanged. * ci: run the heavy CI lanes in the merge queue, not on every PR push (#18342) E2E, Electron smoke, Bun SQLite, integration, package artifact, ecosystem and protocol-client lanes run on push, workflow_dispatch, merge_group and the Mergify queue candidate (admission conditions full-code/full-code-e2e), not on every push to an ordinary PR. Merge through the Mergify queue (label queue) or run gh workflow run ci.yml --ref <branch> before a manual merge. * docs(i18n): refresh 6 drifted docs in 66 locales with the Google engine (#18462) * feat(discovery): remember the last discovery outcome per connection (#17346) * fix(sse): report a buffered stream cut before its terminal signal as truncated, not stop (#18460) * fix(release): bring the open-sse → src boundary back to 774 on release/v3.8.53 (#18467) Refs #17219 * docs(i18n): re-sync DESIGN_SYSTEM mirrors with the Google engine (66 locales) (#18469) * docs(ci): record the Team plan, the janitor ceiling of 8 and the hosted-only test lane in RUNNER_BOX (#18456) Records the 2026-10-28 state of the runner box in docs/ops/RUNNER_BOX.md: Team plan (60 hosted jobs), janitor ceiling 8, five OmniRoute listeners (113-7 also carries omni-build, 113-3/-4/-8 deleted), and the vars.USE_VPS_TEST_RUNNER rule (same-repo pull_request only, off) with the measurement that turned it off. The 66 mirrors and .i18n-state.json come from scripts/i18n/run-translation.mjs (record/replay against a local backend). * feat(i18n): Google fallback and quota circuit breaker for every translation entry point (#18461) * fix(docs): sync the migration and provider counts to the live tree (base-red #17219) (#18476) * feat(providers): extend expiry-first account routing (#16352) * feat(api): serve Gemini-native /v1beta routes on the API-only port (#16745) Co-authored-by: Muhammad Usama <55662931+MuhammadUsamaMX@users.noreply.github.com> * feat(dashboard): per-step Test button in the combo create/edit modal (#16748) Co-authored-by: Erwan Novianto <smserwan@gmail.com> * feat(dashboard): hide/show models across providers from the Models catalog (#16749) Co-authored-by: Muhammad Usama <55662931+MuhammadUsamaMX@users.noreply.github.com> * fix(usage): enforce pending-request byte ceiling on all mutation paths (#17282) Co-authored-by: turbolego <turbolego@gmail.com> * perf: settings/combo read caches, async fs routes, bounded limiter settings (#17304) Co-authored-by: Mayank Jaiswal <mayankjaiswal1707@gmail.com> * fix(providers): align chatplayground with the current web chat API (#17312) * fix(release): list the three covering tests in stryker tap.testFiles (#18485) Refs #17219 * fix(release): open-sse typecheck and README diagram counts (377) on release/v3.8.53 (#18472) Refs #17219 * feat(search): support Exa 3.0 lite pricing and field set (#17394) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * fix(catalog): keep operator-defined custom models on curated providers (#18018) * fix(sse): preserve harness tool history in Codex app-server (#18105) Co-authored-by: Anton Shilin <coder.root@gmail.com> * fix(sse): strip learned-only effort suffix back to the base model (#18131) * fix(combo): keep durable exhaustion across set retries (#18133) * fix(antigravity): stop three retry layers from hammering Cloud Code with a refused request (#18140) Co-authored-by: Wital <witalo_rocha@hotmail.com> * fix(build): skip the webpack persistent cache in production builds (#18141) * fix(sse): copy-on-write in the JSON-schema fallbacks and skip non-JSON response_format (#18241) * fix(i18n): protect inline HTML in the Google engine and guard HTML structure in the output check (#18486) * ci(i18n): scheduled post-merge mirror refresh (LLM first, Google last resort) (#18489) * fix(sse): withhold tool calls cut mid-arguments in a truncated buffered stream (#18482) * feat(search): price Exa extra results and summaries like Exa bills them (#17396) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * fix(usage): bound pending request retention (#17405) Co-authored-by: Hummern <hummernkloa@gmail.com> * fix(combo): fail over from a target whose buffered stream was cut before its terminal signal (#18490) * feat(search): record Tavily advanced search at 2 credits (#17902) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * feat(search): record Linkup deep search at $0.05 (#17903) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * feat(search): record Firecrawl search per block of 10 results (#17904) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * fix(release): clear the 10-28 typecheck, boundary, stryker, route-map and i18n reds on release/v3.8.53 (#18515) Refs #17219 * fix(i18n): open the LLM circuit after three consecutive failures, not only on quota (#18474) * fix(dashboard): monospace code text and a non-Latin script fallback after the kit 0.0.66 bump (#18477) * fix(dashboard): bring the team costs, combo step test and catalog toggle onto the kit components (#18487) * fix(api): let operators limit the Telegram bot to allowlisted senders (#18475) A valid Telegram signature (webhook secret_token or Mini App initData) proves an update came from Telegram, not that its sender may use this instance. TELEGRAM_USER_ALLOWLIST_ENABLED=true now serves only the numeric user ids in TELEGRAM_ALLOWED_USER_IDS: unlisted Mini App users get 403 and webhook messages from unlisted senders are acknowledged and dropped. The check uses the sender (message.from.id), so group chats are covered; an empty list serves nobody; misconfiguration is logged once without echoing ids. Off by default. Co-authored-by: HouMinXi <19586012+HouMinXi@users.noreply.github.com> * fix(api): stop keyless cross-origin reads on the client API and inference WebSockets (#18512) HTTP: on a keyless install (REQUIRE_API_KEY=false) any Authorization, x-api-key or x-goog-api-key header, valid or not, made client-API routes echo the request Origin while serving the request as anonymous. The allow path now relaxes CLIENT_API CORS only for a non-anonymous subject; route-level 401s that refuse a presented key still echo Origin (Vary: Origin, no credentials header) so browser clients can read them (#5242). WebSocket: browsers do not apply CORS to WebSockets and the /v1/responses, /v1/ws and /api/v1/ws handshakes never read Origin. They now admit no-Origin clients, CORS-allowlisted origins, the gateway's own public origin and handshakes with a valid API key; everything else, null included, gets 403 ws_origin_forbidden. The bridge upgrades only when the route answers originChecked: true. /v1/responses now enforces REQUIRE_API_KEY. The service worker also bypasses the client-API aliases. CORS and PWA guide mirrors refreshed. Co-authored-by: HouMinXi <19586012+HouMinXi@users.noreply.github.com> * fix(release): clear the remaining release/v3.8.53 base-reds — namespaced combo lookup, curated imported rows, build-scope ceiling (#18516) * fix(sse): resolve client-namespaced combos through the cached name lookup #17304 replaced the exact-name combo lookups in getCombo() with getCachedComboByName and dropped the getComboByName import, but missed the third call site in getComboByClientNamespacedName (#16493). Any model id with a "/" that is not a provider pin or catalog id then threw "ReferenceError: getComboByName is not defined" inside getComboForModel, which broke reasoning routing for unknown models and the client-namespace combo resolution. Fixes reasoning-routing-decision-guards ("an unknown model with no rules is also a clean pass-through") and 5 cases of combo-prefixed-name-resolve. * fix(models): keep sync-imported custom rows off curated-only providers #18018 made custom models listable on curated-only providers so a model added through "Add Custom Model" can be routed. Its stated scope is the operator's own rows ("Discovery behaviour is unchanged ... only the operator's own rows are kept"), but the three read paths kept every custom row, including rows whose source is imported/api-sync/auto-sync. On a provider with no upstream catalog such a row is a stale leftover of a retired discovery path: #8451 removed exactly those obsolete Z.ai Web ids (they 404 upstream), and zai-web-models-discovery-7678 pins that. The provider listing merge, GET /api/providers/[id]/models and /v1/models now drop discovery-imported custom rows on curated providers through one helper (isDiscoveryImportedCustomSource); operator rows keep flowing. zai-web-models-discovery-7678 now also expects the manual row, which #18018 made listable on purpose. New cases pin the imported-row exclusion in the listing merge and in /v1/models. * chore(changelog): drop the duplicate namespaced-combo fragment (#18514 carries it) The client-namespaced combo lookup fix is the same one-line change as #18514, which already ships its changelog fragment. Refs #17219 * chore(quality): raise the build-scope ceiling to 13500 in-scope files The release branch reached 12267 in-scope .ts/.tsx/.js/.jsx files through legitimate test growth (tests/ went 7841 -> 8296 files since 10-21), so check:build-scope failed on every PR although nothing was leaking. A leaked worktree or vendored checkout adds roughly a full tree (~12k files), which 13500 still catches. Refs #17219 * chore(dashboard): sync the CI UI Kit to 0.0.79 and keep tracking the newest release (#18504) * docs(i18n): refresh the changed ENVIRONMENT sections in 66 locales (#18524) * feat(antigravity): add Gemini 3.8 Flash tiers and update client fallbacks (#12499) Co-authored-by: Abhishek Chhetri <abhishekchhetri@example.com> * feat(oauth): GitHub Copilot capability-driven account integrationClaude/GitHub copilot integration 748ebe (#12833) * feat(dashboard): size dialogs to 70% of the viewport (#14091) Co-authored-by: Felipe Almeman <felipe@aireset.com.br> * feat(opencode): sanitize the OpenCode PR 4145 fingerprint (#14142) * feat(resilience): recover queued quota-failed sessions (#14981) (#14982) * feat(providers): wire claude-haiku-5-5 across catalogs, pricing, and fallbacks (#16159) Co-authored-by: Tuan Dinh <tuan.dinh.truong@sap.com> * feat(models-health): report whether reasoning_effort none was honored per model (#16253) * feat(providers): bounded-turn tool-call support for the ChatGPT Web clean-room adapter (#14948) Co-authored-by: Arash <arash.ashrafi@gmail.com> * feat(oauth): add Freebuff browser login to the freebuff provider (#15336) (#15343) * feat(muse-code): consolidate open Muse Code PRs (#15234, #14138, #13634, #14267, #12687) (#15521) Co-authored-by: mdc2122 <mdc2122@users.noreply.github.com> Co-authored-by: SIGTERM-015 <SIGTERM-015@users.noreply.github.com> Co-authored-by: KSonny4 <KSonny4@users.noreply.github.com> Co-authored-by: caniko <caniko@users.noreply.github.com> Co-authored-by: Chewji9875 <Chewji9875@users.noreply.github.com> * feat(dashboard): show which combos use a model on the provider detail page (#16307) Co-authored-by: Farshad <asadpoor.f@gmail.com> * feat(pii): GDPR + POPIA PII patterns with validators (#16461) Co-authored-by: Wayne <wayne@local> * feat(affinity): optional Redis store for shared session-to-account affinity (#16569) * feat(oauth): opt-in passive token refresh for Codex replicas (#16577) * feat: improve adaptive routing and model health monitoring (#16746) * feat(providers): allow manual vision overrides for synced models (#16794) * fix(mcp): ignore client _meta scopes for stdio callers (#17112) * fix(xai): flatten Codex namespace tools for /v1/responses; no account cooldown on 422 shape errors (#17134) Co-authored-by: özcan Yaman <ozc.yaman@gmail.com> * perf(provider-stats): bound provider-stats history to a 7-day window and cache the payload (#17227) * fix(dashboard): decode percent-encoded combo route params for auto/* control center (#17271) (#17272) * fix(desktop): publish and verify indexed optional runtime packs (#17338) * refactor(a2a): share agent discovery metadata (#17357) Co-authored-by: Jan Leon <jan@leoncode.de> * fix: require reasoning_content presence for DeepSeek and align Grok 4.7 context and effort tiers (#17388) Co-authored-by: Felipe Fidelix <felipe@fdx.is> * fix(providers): isolate agy/antigravity hiddenModelGate and clear compat overrides on model reset (#17398) (#17400) * fix(providers): rotate the deprecated OpenCode Zen mimo-v2.5-free id to v2.6 flash (#17472) (#17788) Co-authored-by: vincent <webmaster@palmit.com.au> * feat(sse): follow the published OpenCode endpoint and client headers for keyed requests (#17864) * fix(tls): follow the newest wreq-js browser profile in the web providers (#17869) * fix(sse): match the native Antigravity CLI wire image (#17913) * fix(docker): pin node 26.12.1 / bun 1.4.4 so images reject the compromised eMudhra CAs (security) (#17927) Co-authored-by: Markus Hartung <mail@hartmark.se> * feat(db): maintain configurable SQLite planner statistics (#17936) * fix(translator): ensure all assistant tool_calls are answered in fixMissingToolResponses (#17946) (#17947) Co-authored-by: Felipe Fidelix <felipe@fdx.is> * fix(dev): avoid the macOS dev-startup EBADF and keep reasoning out of combo test output (#17955) * feat(combo): global outputLimitAdvisory setting and a per target context window check (#17958) * fix(docker): split clientless CLI runtime from Docker tooling (#17972) Co-authored-by: Sean P. Ford <sean@seanford.com> * fix(providers): preserve Gemini function tools with native web search (#18020) * fix(db): preserve utilization bucket timezone (#18083) * fix(stream): preserve queued chunks on 6 abortStreamFailure sites (#18094) * fix(sse): refuse non-JSON data lines in stream readiness and content checks (#18095) * fix(db): don't skip half-applied proxy timing migration 194 (#18096) * fix(sse): fold camel-case reasoning effort into the canonical field (#18117) * fix(providers): preserve Codex reasoning controls and expose Muse subscription metadata (#18124) Co-authored-by: Aldo <github@aldo.pw> * fix(sse): local backends answer 499 while draining instead of 502 (#18134) Co-authored-by: roomhackerfrom100 <megamen932@gmai.com> * fix(compression): keep the tail of a truncated lite tool result (#18138) * fix(zcode): stream native Anthropic responses to clients (#18190) Co-authored-by: roomhackerfrom100 <megamen932@gmai.com> * fix(quota): recognize international Kimi Coding usage endpoints (#18180) (#18224) Co-authored-by: Nabi Bukhsh <nabibuksh.baloch01@gmail.com> * feat(dashboard): assign catalog models and combos to API keys (#14890) Co-authored-by: Fouad Salkini <fouad@wecansync.com> * feat(ci): validate protection domains for admission jobs (#16142) * feat(dashboard): add inline toggle and bulk disable/enable for no-auth providers (#16553) * feat(cli-tools): add OpenClaude setup guide card (#16844) Co-authored-by: Nguyen Thanh Dat <ntdat812@gmail.com> * feat(api): opt-in "expose combos only" setting for /v1/models (#16846) Co-authored-by: snower <sujian199@gmail.com> * feat(mcp): add a deep research tool that is off by default (#17317) * fix(opencode): map custom-provider catalog identities to public prefixes (#17369) * feat(oauth): import Antigravity Manager account exports (#15746) * feat(logs): distinguish generation rate from end-to-end throughput (#17847) * feat(api): CLIProxyAPI management usage compatibility endpoints (#17999) Co-authored-by: Rahul Bansal <rtrrahulbansal@gmail.com> * feat(antigravity): add Gemini 4 Argon weekly quota, dual-resolver preflight, and 404 short-circuit (#18026) * fix(zcode): preserve exact native Coding Plan quota refusals (#18118) Co-authored-by: roomhackerfrom100 <megamen932@gmai.com> * feat(opencode-plugin-v2): publish one catalog branch with prefix wildcard and hide every combo (#18135) * fix(combo): test all model health targets without a cumulative deadline (#18231) (#18238) * fix(codex): distinguish transient capacity 429 from quota cooldown (#18221) (#18239) * feat(oauth): route Grok Build image, video and audio (#15305) * feat(codebuddy-cn): sync authenticated live model catalog (#17916) * feat(providers): add MiniMax M3.1 Flash model (#18110) * fix(build): select webpack automatically on low-memory builders (#18184) (#18242) * fix(resilience): keep combos routable after transient credential probe errors (#18037) (#18243) * fix(claude): keep model-credit 429 cooldown scoped to the affected model (#18058) (#18245) * feat(providers): add Token Harbor API-key provider (#16315) Co-authored-by: GitHub Actions <github-actions@github.com> * feat(cli-tools): add current Pi setup flow (#16381) Co-authored-by: Arash <arash.ashrafi@gmail.com> * feat(api): configurable unpriced-usage budget policy + admin notice (#14604) (#14608) * fix(i18n): escape the Maltese apostrophe in providers.usedInComboTooltip (base-red) (#18545) * fix(usage): release terminal pending attempts when completion bookkeeping fails (#18217) Co-authored-by: AiCapitan357 <ai-capitan-357@proton.me> * feat(providers): add Runcrate (#18061) * i18n: complete feature-flag definitions for all 66 locales, fix zh-CN/zh-TW mistranslations (#17960) * feat(i18n): wire hardcoded dashboard strings into message catalogs (#17987) * feat(providers): add Gisoo (OpenAI-compatible) (#18112) Co-authored-by: Nirupam Bhowmick <48842933+heydryft@users.noreply.github.com> * feat(providers): dashboard control for the advertised CLI client version (#14817) Co-authored-by: Abhishek Divekar <adivekar@utexas.edu> * feat(ui): add remove error models button in combo test results, default autoHideFailed, and fix db import crash (#14944) * revert(kea): drop the stale-model badge and preferred-connections kit guards (#18250) * revert(kea): drop the kit e2e spec filter and settings-toggles realignment (#18247) * revert(kea): drop the post-migration follow-ups A on the kit (#18202) * revert(kea): drop the kit chart token palettes (#18144) * revert(kea): drop the UI kit line from the repository map (#18080) * revert(kea): drop the Keak CI UI Kit dashboard migration (#17951) Removes packages/ui-kit and the dashboard/UI-kit surface from the merged upstream state; the fork keeps its own dashboard. The kit workspace, its snapshot scripts and the vendored sources are deleted with it. * revert(dashboard): drop the team-costs/catalog kit port and the leftover kit scripts c0a7b86272 moved the team costs screens onto @omniroute/ui-kit, which the fork no longer vendors. Reverting it restores SearchableSelect and the legacy team components. Also drops the kit-only updater script and its two tests, and removes the ui-kit workspace entry from package.json / package-lock.json. * fix(dashboard): finish the kit removal on the two stragglers ModelCatalogTable came back from the pre-kit tree (it was still importing @omniroute/ui-kit table primitives); DiscoveryDegradedNotice swaps the kit Icon for the Material glyph the rest of the legacy UI uses. Restores the material-symbols dependency the restored globals.css imports. * chore(ci): keep only the fork workflows (bun.yml + release.yml) * docs(env): drop the UI kit upstream token now that the kit is not vendored * chore(compression): keep the release branch wording in lite.ts --------- Co-authored-by: Bob.Hou <houminxi@gmail.com> Co-authored-by: Dizzle <112548150+maxmad64bis@users.noreply.github.com> Co-authored-by: 量子跃迁 <42333314+starxjys@users.noreply.github.com> Co-authored-by: Ai Captain 357 <ai-capitan-357@proton.me> Co-authored-by: Adrián Cancio <49328080+adrian-cancio@users.noreply.github.com> Co-authored-by: trespassmk <123762858+trespassmk@users.noreply.github.com> Co-authored-by: Fabio Junior Gruchovski <122614728+fabioKoruja00@users.noreply.github.com> Co-authored-by: Cristhian Hernandez <ayalachristian555@gmail.com> Co-authored-by: xc0derx <11428624+xc0derx@users.noreply.github.com> Co-authored-by: AbdullahPesteli <121692116+AbdullahPesteli@users.noreply.github.com> Co-authored-by: DeadY2J <jorgelamelas@hotmail.com> Co-authored-by: Sean Ford <sean@seanford.com> Co-authored-by: stanley <gstanleytejakusuma@gmail.com> Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: 小妍儿 ✨ <258399167+xiaoyaner0201@users.noreply.github.com> Co-authored-by: skygunner <skygunner@users.noreply.github.com> Co-authored-by: vincent <webmaster@palmit.com.au> Co-authored-by: MumuTW <42820974+MumuTW@users.noreply.github.com> Co-authored-by: Davy Massoneto <davy.massoneto@yahoo.com> Co-authored-by: Davy Massoneto <davy.m.massoneto@gmail.com> Co-authored-by: Wray <i@wray7.top> Co-authored-by: wray-lee <wray-lee@outlook.com> Co-authored-by: kenny000666 <kennyhomeautomation@googlemail.com> Co-authored-by: Safeer Ahmad <asafeer1994@gmail.com> Co-authored-by: Junior-HJ <sjaradj@ucvvirtual.edu.pe> Co-authored-by: jbovard2016 <jon.bovard@gmail.com> Co-authored-by: Kiaro-Sama <106400900+KiaroSama@users.noreply.github.com> Co-authored-by: KiaroSama <Kiaro.Sama.Dev@gmail.com> Co-authored-by: AiCaptain357 <345568968+AiCaptain357@users.noreply.github.com> Co-authored-by: Guan Gui <guiguan@gmail.com> Co-authored-by: opensource-elearning <159253500+opensource-elearning@users.noreply.github.com> Co-authored-by: Praveen K Palaniswamy <praveen.palaniswamy@gmail.com> Co-authored-by: Paulo Holanda <paulorfholanda@gmail.com> Co-authored-by: insoln <11380274+insoln@users.noreply.github.com> Co-authored-by: Mr. Nasıl <leidizayn@gmail.com> Co-authored-by: Markus Hartung <mail@hartmark.se> Co-authored-by: dongsjoa <dongsjoa@Xiaoyaner-Mac-Studio.local> Co-authored-by: Prince <162042308+PrinceThummar011@users.noreply.github.com> Co-authored-by: Muhammad Usama <55662931+MuhammadUsamaMX@users.noreply.github.com> Co-authored-by: Erwan Novianto <smserwan@gmail.com> Co-authored-by: hummern <hummernkloa@gmail.com> Co-authored-by: turbolego <turbolego@gmail.com> Co-authored-by: Mayank Jaiswal <mayankjaiswal1707@gmail.com> Co-authored-by: James Martinez <james-martinez@users.noreply.github.com> Co-authored-by: Anton Shilin <coder.root@gmail.com> Co-authored-by: WITALO ROCHA <witalo_rocha@hotmail.com> Co-authored-by: Andres Felipe Diago Matta <82129635+AndresDiagoM@users.noreply.github.com> Co-authored-by: HouMinXi <19586012+HouMinXi@users.noreply.github.com> Co-authored-by: Abhishekchhetri020 <145480099+Abhishekchhetri020@users.noreply.github.com> Co-authored-by: Abhishek Chhetri <abhishekchhetri@example.com> Co-authored-by: ScottyAmr <scott.kanowski@gmail.com> Co-authored-by: Felipe Almeman <4226997+zhiru@users.noreply.github.com> Co-authored-by: Felipe Almeman <felipe@aireset.com.br> Co-authored-by: Rafa Martins <146174365+rafacpti23@users.noreply.github.com> Co-authored-by: Dongwook <dongwook.chan@gmail.com> Co-authored-by: Tuan Dinh <tuan.dinh.truong@sap.com> Co-authored-by: arashashrafii <arash.ashrafi@gmail.com> Co-authored-by: Pranav Deshpande <134182346+PranavD2905@users.noreply.github.com> Co-authored-by: kalpakprod <beta_virus123@proton.me> Co-authored-by: mdc2122 <mdc2122@users.noreply.github.com> Co-authored-by: SIGTERM-015 <SIGTERM-015@users.noreply.github.com> Co-authored-by: KSonny4 <KSonny4@users.noreply.github.com> Co-authored-by: caniko <caniko@users.noreply.github.com> Co-authored-by: Chewji9875 <Chewji9875@users.noreply.github.com> Co-authored-by: Farshad Asadpour <asadpoor.f@gmail.com> Co-authored-by: Wayne Fourie <31033564+zerotraceio@users.noreply.github.com> Co-authored-by: Wayne <wayne@local> Co-authored-by: Thành Long <102373535+Longvt1164@users.noreply.github.com> Co-authored-by: özcan Yaman <ozc.yaman@gmail.com> Co-authored-by: Afonso Dutra Nogueira Filho <afonsoft@gmail.com> Co-authored-by: Jan Leon <jan@leoncode.de> Co-authored-by: Felipe Fidelix <309092+fidelix@users.noreply.github.com> Co-authored-by: Felipe Fidelix <felipe@fdx.is> Co-authored-by: openclaw-bot <balance.devdart@gmail.com> Co-authored-by: ahmed shahin <ahmedgo17390@gmail.com> Co-authored-by: lorenzozane <wyz0707@proton.me> Co-authored-by: Kevin Lin <levinkin07@gmail.com> Co-authored-by: Bl0ck <36800583+Bl0ck154@users.noreply.github.com> Co-authored-by: Aldo <github@aldo.pw> Co-authored-by: Bezrabotnyi <megamen932@gmail.com> Co-authored-by: roomhackerfrom100 <megamen932@gmai.com> Co-authored-by: Nabi Bukhsh <133964972+NabiBukhsh-AI@users.noreply.github.com> Co-authored-by: Nabi Bukhsh <nabibuksh.baloch01@gmail.com> Co-authored-by: Fouad Salkini <fouad@wecansync.com> Co-authored-by: Nguyen Thanh Dat <ntdat812@gmail.com> Co-authored-by: snower <sujian199@gmail.com> Co-authored-by: mertcandrks <mertcanbakir34@gmail.com> Co-authored-by: Rahul Bansal <42.rahulbansal@gmail.com> Co-authored-by: Rahul Bansal <rtrrahulbansal@gmail.com> Co-authored-by: MrSiB <a@aq2.ru> Co-authored-by: Kizuno18 <110933270+Kizuno18@users.noreply.github.com> Co-authored-by: AStupidBear <luyaocns@gmail.com> Co-authored-by: Octopus <jellyjellysoo127@gmail.com> Co-authored-by: GitHub Actions <github-actions@github.com> Co-authored-by: Nirupam Bhowmick <48842933+heydryft@users.noreply.github.com> Co-authored-by: NetArz | نِت اَرز <aaramin92@gmail.com> Co-authored-by: Abhishek Divekar <adivekar@utexas.edu> Co-authored-by: skymanbj <liubohn69@gmail.com>
… Kit (#15) * test(perplexity-web): use a mapped model in the stream boundary delayed-hook case (#18232) Use a mapped model in the stream boundary delayed-hook case. Evidence: focused tests (no test files in diff); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(compression): report RTK's real truncation count and cut on line boundaries (#18139) Report RTK's real truncation count and cut on line boundaries. Evidence: focused tests (tests/unit/compression/rtk-smart-truncate.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(responses): keep replayed web search call ids on generic executors (#18127) Keep replayed web search call ids on generic executors. Evidence: focused tests (tests/unit/responses-input-sanitizer-websearch-id.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(sse): purge releasable failure entries past held lockouts (#18126) Purge releasable failure entries past held lockouts. Evidence: focused tests (tests/unit/account-fallback-lockout-eviction.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(sse): keep explicit thinking type over connection default (#18114) Keep explicit thinking type over connection default. Evidence: focused tests (tests/unit/glm-thinking-type-explicit.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(combo): clear stale LKGP pin on quality-rejected 200 (#18113) Clear stale LKGP pin on quality-rejected 200. Evidence: focused tests (tests/unit/combo/execute-target-attempt.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(translator): deferred OpenAI→Claude finish replays the pending choice, duplicating the last tool-arg fragment (#18193) Deferred OpenAI→Claude finish replays the pending choice, duplicating the last tool-arg fragment. Evidence: focused tests (tests/unit/openai-to-claude-trailing-usage-deferred-finish.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(bootstrap): strip inline comments from unquoted env values (#18116) Strip inline comments from unquoted env values. Evidence: focused tests (tests/unit/bootstrap-env-inline-comment.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(sse): enforce UTF-8 byte caps for captured stream chunks (#18187) Enforce UTF-8 byte caps for captured stream chunks. Evidence: focused tests (tests/unit/request-logger-stream-byte-cap.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(opencode): scope a retired-model 410 to the model, not the connection (#17827) Scope a retired-model 410 to the model, not the connection. Evidence: focused tests (tests/unit/opencode-410-model-scope.test.ts); validated in a combined board (B1) of non-overlapping PRs on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(models): bound retained catalog response caches (#18188) Bound retained catalog response caches. Evidence: focused tests (tests/unit/catalog-cache-bounds.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(api): expose provider-wildcard combos in model catalog (#18182) Expose provider-wildcard combos in model catalog. Evidence: focused tests (tests/unit/models-catalog-provider-wildcard.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 Fixes #18033 * fix(usage): include Kimi Coding monthly quota (#18234) Include Kimi Coding monthly quota. Evidence: focused tests (tests/unit/kimi-monthly-membership-quota.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(pool): reclaim dead sessions on acquire instead of returning null (#18115) Reclaim dead sessions on acquire instead of returning null. Evidence: focused tests (tests/unit/session-pool-dead-reclaim.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(embeddings): preserve Gemini native token usage (#18244) (#18246) Preserve Gemini native token usage. Evidence: focused tests (tests/unit/embeddings-multimodal-7956.test.ts, tests/unit/gemini-embedding-2-multimodal.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 Closes #18244. * fix(combo): apply the global per-target expansion cap when a combo sets none (#18130) Apply the global per-target expansion cap when a combo sets none. Evidence: focused tests (tests/unit/combo/connection-aware-expansion.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(translator): keep OpenAI prompt_cache_breakpoint on content parts for openai/openrouter (#18255) Keep OpenAI prompt_cache_breakpoint on content parts for openai/openrouter. Evidence: focused tests (tests/unit/translator-openai-prompt-cache-breakpoint-18254.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 Closes #18254 * fix(sse): preserve complexity hints in primary auto routing (#18104) Preserve complexity hints in primary auto routing. Evidence: focused tests (tests/unit/auto-combo-primary-complexity.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(build): bundle locale catalogs as text in webpack builds (#18183) Bundle locale catalogs as text in webpack builds. Evidence: focused tests (tests/unit/build/webpack-locale-messages-source.test.ts); validated in a combined board (B2) of non-overlapping PRs on origin/release/v3.8.53: 110/110 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(compression): let an idle pool worker stop holding the process open (#18136) Let an idle pool worker stop holding the process open. Evidence: focused tests (tests/unit/compression/compression-worker-pool-exit.test.ts, tests/unit/compression/compression-worker-pool-jam.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(firefly): avoid false stale detection for non-underscore Forter timestamps (#18099) Avoid false stale detection for non-underscore Forter timestamps. Evidence: focused tests (tests/unit/adobe-firefly-browser-login.test.ts, tests/unit/adobe-forter-session-timestamp.test.ts, tests/unit/adobe-forter-timestamp-extraction.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(tls): cancel response bodies when requests are aborted (#18228) Cancel response bodies when requests are aborted. Evidence: focused tests (tests/unit/http-backed-chat-response-lifetime.test.ts, tests/unit/tls-client-abort-lifetime.test.ts, tests/unit/tls-proxy-context.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(sse): honor pii-masker opt-out in streaming pipeline (#18121) Honor pii-masker opt-out in streaming pipeline. Evidence: focused tests (tests/unit/chatcore-streaming-pipeline.test.ts, tests/unit/streaming-pii-optout-gate.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(nvidia): replace retired Nemotron 3 Super with Nemotron 3.5 Super VL (#17928) Replace retired Nemotron 3 Super with Nemotron 3.5 Super VL. Evidence: focused tests (tests/unit/antigravity-bridge-routing.test.ts, tests/unit/catalog-updates-v3x.test.ts, tests/unit/nvidia-eol-catalog.test.ts, tests/unit/nvidia-nim-registry-6108.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(services): harden embedded Bifrost runtime (#17976) Harden embedded Bifrost runtime. Evidence: focused tests (tests/unit/authz/route-guard-version-get-exemption.test.ts, tests/unit/route-guard-local-only-sweep.test.ts, tests/unit/services/installers/bifrost.test.ts, tests/unit/services/internal-health-fetch.test.ts, tests/unit/services/service-status-route-guard.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(oauth): accept permission-based Cursor user API keys (#17905) Accept permission-based Cursor user API keys. Evidence: focused tests (tests/unit/cursor-agent-image.test.ts, tests/unit/cursor-api-key-auth.test.ts, tests/unit/cursor-api-models-discovery.test.ts, tests/unit/cursor-apikey-provider.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(mcp): validate Origin on /api/mcp/* to block DNS rebinding (#17273) Validate Origin on /api/mcp/* to block DNS rebinding. Evidence: focused tests (tests/integration/mcp-origin-host-e2e.test.ts, tests/unit/mcp-origin-validation.test.ts); validated in a combined board (B3) of non-overlapping PRs on origin/release/v3.8.53: 413/419 (the 6 failures: 1 from #18140, ejected; 4 in tests/integration/mcp-origin-host-e2e.test.ts from a Turbopack cache panic in the board worktree — the file passes 4/4 on #17273 alone and paired with every other PR of the board; 1 compression worker-pool timing flake that passes isolated) focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * test(authz): fail when a host-config, process-control or data-export route can be anonymous (#18293) Fail when a host-config, process-control or data-export route can be anonymous. Evidence: focused tests (tests/unit/management-capability-routes-protected.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * refactor(api): move the per-request keepalive frame into a helper (#17825) (#18281) Move the per-request keepalive frame into a helper. Evidence: focused tests (tests/unit/responses-route-early-keepalive-wiring.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * test(ui): repair the vitest UI base-red on release/v3.8.53 (#18306) Repair the vitest UI base-red on release/v3.8.53. Evidence: focused tests (tests/unit/ui/api-key-access-editor.test.tsx); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * fix(sse): type empty or typeless array items in Gemini tool schemas (#18289) Type empty or typeless array items in Gemini tool schemas. Evidence: focused tests (tests/unit/gemini-array-items.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * fix(auth): fail closed when the logout revocation cannot be saved (#18323) Fail closed when the logout revocation cannot be saved. Evidence: focused tests (tests/unit/dashboard-session-invalidation.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * fix(cursor): harden the HTTP/2 proxy tunnel and fail closed on unresolvable pinned proxies (#18324) Harden the HTTP/2 proxy tunnel and fail closed on unresolvable pinned proxies. Evidence: focused tests (tests/unit/cursor-h2-proxy-connect-hardening.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * fix(antigravity): accept the bare gemini-4-argon id and list Gemini 4 Argon on Vertex (#18285) Accept the bare gemini-4-argon id and list Gemini 4 Argon on Vertex. Evidence: focused tests (tests/unit/gemini-4-argon-bare-alias-vertex.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * feat(providers): add Kimi K3.1 Pro to the Command Code static catalog (#18292) Add Kimi K3.1 Pro to the Command Code static catalog. Evidence: focused tests (tests/unit/command-code-executor.test.ts, tests/unit/command-code-kimi-k3-1-pro-5172.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * fix(api): report an unreachable upstream as 502 in provider model discovery (#18294) Report an unreachable upstream as 502 in provider model discovery. Evidence: focused tests (tests/unit/provider-models-upstream-unreachable-4843.test.ts); combined board B4 (9 PRs) on origin/release/v3.8.53: 77/77 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. tests/unit/ui/api-key-access-editor.test.tsx keeps one inherited failure ('shows the model selection cap inline', also failing on the pure tip). ⚠️ base-red inherited: #17219 * fix(db): revoke a deleted combo's name from API key allowed_combos (#18297) Revoke a deleted combo's name from API key allowed_combos. Evidence: focused tests (tests/unit/combo-delete-revokes-key-grants.test.ts); combined board B5 (5 PRs) on origin/release/v3.8.53: 63/63 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. ⚠️ base-red inherited: #17219 * feat(providers): add Kimi K3.1 Pro to OpenCode Go (#18295) Add Kimi K3.1 Pro to OpenCode Go. Evidence: focused tests (tests/unit/opencode-go-kimi-k3.1-pro-5147.test.ts); combined board B5 (5 PRs) on origin/release/v3.8.53: 63/63 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. ⚠️ base-red inherited: #17219 * feat(compression): add RTK filter for PHPUnit test output (#18317) Add RTK filter for PHPUnit test output. Evidence: focused tests (tests/unit/compression/rtk-phpunit-filter.test.ts); combined board B5 (5 PRs) on origin/release/v3.8.53: 63/63 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. ⚠️ base-red inherited: #17219 * fix(translator): honor explicit client max_tokens on Claude/Gemini/Antigravity -> OpenAI (#18300) Honor explicit client max_tokens on Claude/Gemini/Antigravity -> OpenAI. Evidence: focused tests (tests/unit/openai-to-claude-explicit-max-tokens-cap.test.ts, tests/unit/translator-antigravity-to-openai.test.ts, tests/unit/translator-explicit-max-tokens-cap-5180.test.ts, tests/unit/translator-gemini-to-openai.test.ts); combined board B5 (5 PRs) on origin/release/v3.8.53: 63/63 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. ⚠️ base-red inherited: #17219 * fix(api): honor OMNIROUTE_NO_UPDATE_NOTIFIER in the dashboard version check (#18316) Honor OMNIROUTE_NO_UPDATE_NOTIFIER in the dashboard version check. Evidence: focused tests (tests/unit/system-version-update-optout.test.ts); combined board B5 (5 PRs) on origin/release/v3.8.53: 63/63 focused tests; ESLint, typecheck:core, check:open-sse-typecheck, API-route typecheck and check-deps clean; file-size OK; changelog integrity OK. ⚠️ base-red inherited: #17219 * fix(docs): refresh the live counts and the design-system palette note on release/v3.8.53 (#18339) * i18n(ui): translate the cursor-api onboarding description in 38 locales (#18351) * fix(discovery): show why a model discovery fell back to the built-in catalog (#17342) * feat(dashboard): account-availability quota overview with per-pool rows and reorderable providers (#17026) * fix(dashboard): show the configured model and the full account in the Combo Control Center (#17393) (#17774) Co-authored-by: vincent <webmaster@palmit.com.au> * refactor(routing): share combo attempt failure facts (#17956) * fix(claude): forward max reasoning effort on the Responses path for max-capable models (#18064) Co-authored-by: Davy Massoneto <davy.m.massoneto@gmail.com> * feat(proxy): accept selector-only subscriptions with no feed URL (#16165) * fix(translator): bridge Claude Code WebSearch to Codex native web_search (#16365) Co-authored-by: wray-lee <wray-lee@outlook.com> * feat(routing): enrich routing events with apiKeyId and stream cost (#14736) Co-authored-by: Safeer Ahmad <asafeer1994@gmail.com> * fix(providers): surface failed Codex client-version refreshes instead of swallowing them (#17855) * feat(api): add per-key Claude Code discovery alias control (#17979) Co-authored-by: Sean P. Ford <sean@seanford.com> * docs(readme): hero in the Cheaper Inference UI Kit typography (#18261) * docs(readme): four above-the-fold diagrams in the UI Kit typography (#18308) * docs(readme): tier cascade, strategies grid, resilience layers and comparison table in the UI Kit typography (#18309) * docs(readme): privacy ledger, CLI terminal and compression pipeline in the UI Kit typography (#18310) * docs(readme): one regenerate command for the twelve README diagrams + design-system docs (#18337) * docs(i18n): re-sync 6 drifted docs across 66 locales (wave 1027) (#18371) * fix(i18n): use the canonical zh provider term in the providerStats and discovery keys (#18372) * feat: add Gemini prompt cache accounting (#12775) * fix(sse): distinguish generic buffered error frames from identified Responses failures (#18370) * fix: repair inherited release test reds (SSE bare-error frames, catalog fixtures, Codex fixture) (#17550) Co-authored-by: KiaroSama <Kiaro.Sama.Dev@gmail.com> * fix(providers): keep the ChatGPT Web browser launch under local and operator control (#18358) Validation of chatgpt-web-codex ignored allowLocalSpawn, so a remote management request could make the host launch a browser, and both ChatGPT Web browser providers used a connection's stored chromeExecutablePath as the executable whenever the path existed. Honour allowLocalSpawn before any launch, and let the stored path only select a browser the operator configured (CHROME_PATH / CHATGPT_WEB_*_CHROME_PATH) or a known install location. Co-authored-by: AiCaptain357 <345568968+AiCaptain357@users.noreply.github.com> * fix(dashboard): quota UIs fall back to /api/providers and show an auth-required state on 401 (#17262) (#18194) * deps(security): raise the qs override to ^6.16.1 (#18381) Raise the qs override to ^6.16.1 (the lock resolves 6.17.0), picking up the upstream fix for qs.stringify with arrayFormat comma throwing an uncaught TypeError. Lockfile-only. * fix(providers): honour allowLocalSpawn in Auggie validation (#18380) The Auggie validator took no options and always ran `auggie --version`, so remote-reachable routes that pass allowLocalSpawn=false for non-loopback callers still made the host start the CLI. Return a local-validation-only result for those callers before any spawn; internal and local callers keep the CLI probe. Co-authored-by: AiCaptain357 <345568968+AiCaptain357@users.noreply.github.com> * ci: let own-origin PR unit and vitest jobs opt in to the omni-ci slots (USE_VPS_TEST_RUNNER) (#18338) The hosted pool is the CI bottleneck (org-wide hosted concurrency; PR runs queued for hours). test-unit and test-vitest of own-origin pull requests can now opt in to three dedicated self-hosted omni-ci slots (omniroute-113-3/-4/-8, 12G/16G and 4 CPUs each) through vars.USE_VPS_TEST_RUNNER, default off. Forks, merge_group and push stay hosted, and USE_VPS_RUNNER still never governs a test job; the gap-19 guard pins the new switch. * docs(i18n): refresh 8 docs in 66 locales and fix the README version-table provider count (#18253) * fix(i18n): fall back to the next model and re-split when a chunk fails validation (#18422) * ci(i18n): make docs-mirror drift advisory on pull requests and the merge train (#18420) * Support custom compatible gateways behind an access proxy (#17136) * fix(release): drain the deterministic unit and vitest reds of release/v3.8.53 (#18426) * feat(release): bun-pack — bun-first global installs (build stays on Node) (#12801) * fix(streams): let a target's declared budget raise the 21-minute stream cap (#18002) * feat(providers): add Kimi (Moonshot) as a web search provider (#14292) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * feat(deploy): Kubernetes support for k3s and k8s (#12400) Co-authored-by: Paulo Holanda <paulorfholanda@gmail.com> Co-authored-by: Paulo Roberto Fernandes Holanda <paulorfholanda@gmail.com> Co-authored-by: insoln <11380274+insoln@users.noreply.github.com> * feat(cli-agents): add WhyCodes as a first-class CLI Agent (#14107) * feat(teams): billing cost centers, soft budgets and dashboard (#10409) Co-authored-by: Markus Hartung <mail@hartmark.se> Co-authored-by: dongsjoa <dongsjoa@Xiaoyaner-Mac-Studio.local> * test(log-export): deflake the child-runner timing tests on loaded runners (#18440) * feat(logs): add an OTLP/HTTP traces log-export destination (#16664) * fix(providers): honour allowLocalSpawn in Qoder PAT validation (#18424) Qoder Personal Access Token validation now honours allowLocalSpawn: for remote callers it returns a "validate locally" result instead of running the local qodercli. Covered by tests/unit/qoder-pat-validation-local-spawn.test.ts (direct call, dispatcher for qoder and the if alias, local control). (no public reference) Co-authored-by: AiCaptain357 <345568968+AiCaptain357@users.noreply.github.com> * feat(i18n): structure-safe Google Translate engine for the docs pipeline + ENVIRONMENT re-sync (#18429) * chore(ci): keep promptfoo, fumadocs-mdx, @playwright/test and bun out of dependabot groups (#18369) The development group #17197 cannot land as is: five of its bumps (four packages) break a contract or need a coordinated migration, and they keep the 21 routine updates riding along with them red. - promptfoo: exact pin mirrored by nightly-llm-security.yml and enforced by llm-security-nightly-promptfoo-pin.test.ts (0.124.1 is a known-broken release, promptfoo/promptfoo#10866). - fumadocs-mdx >=15.4.7: imports embedSource, which the fumadocs-core on this branch does not export; Build fails loading next.config.mjs. - @playwright/test: must equal the runtime playwright exact pin (playwright-runner-args.test.ts); runtime lives in the production group. - bun / @types/bun: exact pin documented in AGENTS.md and BUILD_WARNINGS.md, bumped by hand after byte-identical validation of the Bun scripts. No other dependabot rule changes. * fix(providers): announce direct Poolside inference shutdown (#17331) Announce the direct Poolside inference shutdown (2026-10-31) in the provider notes, FREE_TIERS and the generated provider reference. Evidence: reconciled with origin/release/v3.8.53 (0 commits behind); poolside-sunset-notice-17318 2/2 and poolside-registry-models-9085 4/4; check:docs-all, ESLint, typecheck:core, file-size and changelog integrity green. ⚠️ base-red inherited: #17219 Fixes #17318 * test: move late top-level imports above the first test() in three unit files (#18439) * fix(docs): keep the routing-strategy identifiers verbatim in the Bosnian AGENTS.md mirror (#18382) * fix(sse): replay an empty upstream turn on the direct streaming path (#17280) * fix(providers): register DeepSeek Flash aliases for vision requests (#17180) (#17243) * chore(dashboard): sync the vendored CI UI Kit to 0.0.66 (#18434) packages/ui-kit moves from upstream f0986a6 (0.0.48) to 3b6ba89 (0.0.66) through scripts/dev/sync-ui-kit.sh; the workspace version and its lockfile entry follow. The kit now self-hosts Switzer for every role (ci-tokens.css imports ci-fonts.css with local woff2 files), so src/app/globals.css drops the @fontsource Inter / Instrument Serif / IBM Plex Mono imports nothing references any more (the packages stay for the README diagram generator). The bridge and snapshot-gate tests follow the new contract, and DESIGN_SYSTEM.md describes Switzer. Validated on the local VPS (.15) before merge. Red CI checks are inherited from the base (#17219) and touch none of these files. * test(security): match the codex fallback version without a hand-escaped regex (CodeQL #1187) (#18419) The refresh-warning assertion uses String.includes instead of a RegExp that escaped only the dots of DEFAULT_CODEX_CLIENT_VERSION (CodeQL js/incomplete-sanitization #1187). Test-only; 9/9. * ci: add the CodeRabbit review configuration (#18431) Adds .coderabbit.yaml (validated against the CodeRabbit schema v2): auto review on non-draft PRs to release/vX.Y.Z and main, path filters for translated mirrors, lockfiles and generated files, per-area instructions from the AGENTS.md hard rules, pre-merge checks in warning mode for calibration. Takes effect once the CodeRabbit GitHub App is installed on the organization. * ci: drop the duplicate unit/vitest fast-path and skip lcov/Codecov on PR coverage (#18336) Quality Gates no longer runs fast-unit (4 shards of test:unit:ci:shard) and fast-vitest, which duplicated ci.yml test-unit/test-vitest on every PR since #14420 (~62 runner-minutes and 5 hosted jobs per PR); admission policy, check-test-discovery anchor and tests updated. On pull_request the Coverage job skips the lcov reporter and the informational Codecov upload; the 60% gate and summaries are unchanged. * ci: run the heavy CI lanes in the merge queue, not on every PR push (#18342) E2E, Electron smoke, Bun SQLite, integration, package artifact, ecosystem and protocol-client lanes run on push, workflow_dispatch, merge_group and the Mergify queue candidate (admission conditions full-code/full-code-e2e), not on every push to an ordinary PR. Merge through the Mergify queue (label queue) or run gh workflow run ci.yml --ref <branch> before a manual merge. * docs(i18n): refresh 6 drifted docs in 66 locales with the Google engine (#18462) * feat(discovery): remember the last discovery outcome per connection (#17346) * fix(sse): report a buffered stream cut before its terminal signal as truncated, not stop (#18460) * fix(release): bring the open-sse → src boundary back to 774 on release/v3.8.53 (#18467) Refs #17219 * docs(i18n): re-sync DESIGN_SYSTEM mirrors with the Google engine (66 locales) (#18469) * docs(ci): record the Team plan, the janitor ceiling of 8 and the hosted-only test lane in RUNNER_BOX (#18456) Records the 2026-10-28 state of the runner box in docs/ops/RUNNER_BOX.md: Team plan (60 hosted jobs), janitor ceiling 8, five OmniRoute listeners (113-7 also carries omni-build, 113-3/-4/-8 deleted), and the vars.USE_VPS_TEST_RUNNER rule (same-repo pull_request only, off) with the measurement that turned it off. The 66 mirrors and .i18n-state.json come from scripts/i18n/run-translation.mjs (record/replay against a local backend). * feat(i18n): Google fallback and quota circuit breaker for every translation entry point (#18461) * fix(docs): sync the migration and provider counts to the live tree (base-red #17219) (#18476) * feat(providers): extend expiry-first account routing (#16352) * feat(api): serve Gemini-native /v1beta routes on the API-only port (#16745) Co-authored-by: Muhammad Usama <55662931+MuhammadUsamaMX@users.noreply.github.com> * feat(dashboard): per-step Test button in the combo create/edit modal (#16748) Co-authored-by: Erwan Novianto <smserwan@gmail.com> * feat(dashboard): hide/show models across providers from the Models catalog (#16749) Co-authored-by: Muhammad Usama <55662931+MuhammadUsamaMX@users.noreply.github.com> * fix(usage): enforce pending-request byte ceiling on all mutation paths (#17282) Co-authored-by: turbolego <turbolego@gmail.com> * perf: settings/combo read caches, async fs routes, bounded limiter settings (#17304) Co-authored-by: Mayank Jaiswal <mayankjaiswal1707@gmail.com> * fix(providers): align chatplayground with the current web chat API (#17312) * fix(release): list the three covering tests in stryker tap.testFiles (#18485) Refs #17219 * fix(release): open-sse typecheck and README diagram counts (377) on release/v3.8.53 (#18472) Refs #17219 * feat(search): support Exa 3.0 lite pricing and field set (#17394) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * fix(catalog): keep operator-defined custom models on curated providers (#18018) * fix(sse): preserve harness tool history in Codex app-server (#18105) Co-authored-by: Anton Shilin <coder.root@gmail.com> * fix(sse): strip learned-only effort suffix back to the base model (#18131) * fix(combo): keep durable exhaustion across set retries (#18133) * fix(antigravity): stop three retry layers from hammering Cloud Code with a refused request (#18140) Co-authored-by: Wital <witalo_rocha@hotmail.com> * fix(build): skip the webpack persistent cache in production builds (#18141) * fix(sse): copy-on-write in the JSON-schema fallbacks and skip non-JSON response_format (#18241) * fix(i18n): protect inline HTML in the Google engine and guard HTML structure in the output check (#18486) * ci(i18n): scheduled post-merge mirror refresh (LLM first, Google last resort) (#18489) * fix(sse): withhold tool calls cut mid-arguments in a truncated buffered stream (#18482) * feat(search): price Exa extra results and summaries like Exa bills them (#17396) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * fix(usage): bound pending request retention (#17405) Co-authored-by: Hummern <hummernkloa@gmail.com> * fix(combo): fail over from a target whose buffered stream was cut before its terminal signal (#18490) * feat(search): record Tavily advanced search at 2 credits (#17902) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * feat(search): record Linkup deep search at $0.05 (#17903) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * feat(search): record Firecrawl search per block of 10 results (#17904) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * fix(release): clear the 10-28 typecheck, boundary, stryker, route-map and i18n reds on release/v3.8.53 (#18515) Refs #17219 * fix(i18n): open the LLM circuit after three consecutive failures, not only on quota (#18474) * fix(dashboard): monospace code text and a non-Latin script fallback after the kit 0.0.66 bump (#18477) * fix(dashboard): bring the team costs, combo step test and catalog toggle onto the kit components (#18487) * fix(api): let operators limit the Telegram bot to allowlisted senders (#18475) A valid Telegram signature (webhook secret_token or Mini App initData) proves an update came from Telegram, not that its sender may use this instance. TELEGRAM_USER_ALLOWLIST_ENABLED=true now serves only the numeric user ids in TELEGRAM_ALLOWED_USER_IDS: unlisted Mini App users get 403 and webhook messages from unlisted senders are acknowledged and dropped. The check uses the sender (message.from.id), so group chats are covered; an empty list serves nobody; misconfiguration is logged once without echoing ids. Off by default. Co-authored-by: HouMinXi <19586012+HouMinXi@users.noreply.github.com> * fix(api): stop keyless cross-origin reads on the client API and inference WebSockets (#18512) HTTP: on a keyless install (REQUIRE_API_KEY=false) any Authorization, x-api-key or x-goog-api-key header, valid or not, made client-API routes echo the request Origin while serving the request as anonymous. The allow path now relaxes CLIENT_API CORS only for a non-anonymous subject; route-level 401s that refuse a presented key still echo Origin (Vary: Origin, no credentials header) so browser clients can read them (#5242). WebSocket: browsers do not apply CORS to WebSockets and the /v1/responses, /v1/ws and /api/v1/ws handshakes never read Origin. They now admit no-Origin clients, CORS-allowlisted origins, the gateway's own public origin and handshakes with a valid API key; everything else, null included, gets 403 ws_origin_forbidden. The bridge upgrades only when the route answers originChecked: true. /v1/responses now enforces REQUIRE_API_KEY. The service worker also bypasses the client-API aliases. CORS and PWA guide mirrors refreshed. Co-authored-by: HouMinXi <19586012+HouMinXi@users.noreply.github.com> * fix(release): clear the remaining release/v3.8.53 base-reds — namespaced combo lookup, curated imported rows, build-scope ceiling (#18516) * fix(sse): resolve client-namespaced combos through the cached name lookup #17304 replaced the exact-name combo lookups in getCombo() with getCachedComboByName and dropped the getComboByName import, but missed the third call site in getComboByClientNamespacedName (#16493). Any model id with a "/" that is not a provider pin or catalog id then threw "ReferenceError: getComboByName is not defined" inside getComboForModel, which broke reasoning routing for unknown models and the client-namespace combo resolution. Fixes reasoning-routing-decision-guards ("an unknown model with no rules is also a clean pass-through") and 5 cases of combo-prefixed-name-resolve. * fix(models): keep sync-imported custom rows off curated-only providers #18018 made custom models listable on curated-only providers so a model added through "Add Custom Model" can be routed. Its stated scope is the operator's own rows ("Discovery behaviour is unchanged ... only the operator's own rows are kept"), but the three read paths kept every custom row, including rows whose source is imported/api-sync/auto-sync. On a provider with no upstream catalog such a row is a stale leftover of a retired discovery path: #8451 removed exactly those obsolete Z.ai Web ids (they 404 upstream), and zai-web-models-discovery-7678 pins that. The provider listing merge, GET /api/providers/[id]/models and /v1/models now drop discovery-imported custom rows on curated providers through one helper (isDiscoveryImportedCustomSource); operator rows keep flowing. zai-web-models-discovery-7678 now also expects the manual row, which #18018 made listable on purpose. New cases pin the imported-row exclusion in the listing merge and in /v1/models. * chore(changelog): drop the duplicate namespaced-combo fragment (#18514 carries it) The client-namespaced combo lookup fix is the same one-line change as #18514, which already ships its changelog fragment. Refs #17219 * chore(quality): raise the build-scope ceiling to 13500 in-scope files The release branch reached 12267 in-scope .ts/.tsx/.js/.jsx files through legitimate test growth (tests/ went 7841 -> 8296 files since 10-21), so check:build-scope failed on every PR although nothing was leaking. A leaked worktree or vendored checkout adds roughly a full tree (~12k files), which 13500 still catches. Refs #17219 * chore(dashboard): sync the CI UI Kit to 0.0.79 and keep tracking the newest release (#18504) * docs(i18n): refresh the changed ENVIRONMENT sections in 66 locales (#18524) * feat(antigravity): add Gemini 3.8 Flash tiers and update client fallbacks (#12499) Co-authored-by: Abhishek Chhetri <abhishekchhetri@example.com> * feat(oauth): GitHub Copilot capability-driven account integrationClaude/GitHub copilot integration 748ebe (#12833) * feat(dashboard): size dialogs to 70% of the viewport (#14091) Co-authored-by: Felipe Almeman <felipe@aireset.com.br> * feat(opencode): sanitize the OpenCode PR 4145 fingerprint (#14142) * feat(resilience): recover queued quota-failed sessions (#14981) (#14982) * feat(providers): wire claude-haiku-5-5 across catalogs, pricing, and fallbacks (#16159) Co-authored-by: Tuan Dinh <tuan.dinh.truong@sap.com> * feat(models-health): report whether reasoning_effort none was honored per model (#16253) * feat(providers): bounded-turn tool-call support for the ChatGPT Web clean-room adapter (#14948) Co-authored-by: Arash <arash.ashrafi@gmail.com> * feat(oauth): add Freebuff browser login to the freebuff provider (#15336) (#15343) * feat(muse-code): consolidate open Muse Code PRs (#15234, #14138, #13634, #14267, #12687) (#15521) Co-authored-by: mdc2122 <mdc2122@users.noreply.github.com> Co-authored-by: SIGTERM-015 <SIGTERM-015@users.noreply.github.com> Co-authored-by: KSonny4 <KSonny4@users.noreply.github.com> Co-authored-by: caniko <caniko@users.noreply.github.com> Co-authored-by: Chewji9875 <Chewji9875@users.noreply.github.com> * feat(dashboard): show which combos use a model on the provider detail page (#16307) Co-authored-by: Farshad <asadpoor.f@gmail.com> * feat(pii): GDPR + POPIA PII patterns with validators (#16461) Co-authored-by: Wayne <wayne@local> * feat(affinity): optional Redis store for shared session-to-account affinity (#16569) * feat(oauth): opt-in passive token refresh for Codex replicas (#16577) * feat: improve adaptive routing and model health monitoring (#16746) * feat(providers): allow manual vision overrides for synced models (#16794) * fix(mcp): ignore client _meta scopes for stdio callers (#17112) * fix(xai): flatten Codex namespace tools for /v1/responses; no account cooldown on 422 shape errors (#17134) Co-authored-by: özcan Yaman <ozc.yaman@gmail.com> * perf(provider-stats): bound provider-stats history to a 7-day window and cache the payload (#17227) * fix(dashboard): decode percent-encoded combo route params for auto/* control center (#17271) (#17272) * fix(desktop): publish and verify indexed optional runtime packs (#17338) * refactor(a2a): share agent discovery metadata (#17357) Co-authored-by: Jan Leon <jan@leoncode.de> * fix: require reasoning_content presence for DeepSeek and align Grok 4.7 context and effort tiers (#17388) Co-authored-by: Felipe Fidelix <felipe@fdx.is> * fix(providers): isolate agy/antigravity hiddenModelGate and clear compat overrides on model reset (#17398) (#17400) * fix(providers): rotate the deprecated OpenCode Zen mimo-v2.5-free id to v2.6 flash (#17472) (#17788) Co-authored-by: vincent <webmaster@palmit.com.au> * feat(sse): follow the published OpenCode endpoint and client headers for keyed requests (#17864) * fix(tls): follow the newest wreq-js browser profile in the web providers (#17869) * fix(sse): match the native Antigravity CLI wire image (#17913) * fix(docker): pin node 26.12.1 / bun 1.4.4 so images reject the compromised eMudhra CAs (security) (#17927) Co-authored-by: Markus Hartung <mail@hartmark.se> * feat(db): maintain configurable SQLite planner statistics (#17936) * fix(translator): ensure all assistant tool_calls are answered in fixMissingToolResponses (#17946) (#17947) Co-authored-by: Felipe Fidelix <felipe@fdx.is> * fix(dev): avoid the macOS dev-startup EBADF and keep reasoning out of combo test output (#17955) * feat(combo): global outputLimitAdvisory setting and a per target context window check (#17958) * fix(docker): split clientless CLI runtime from Docker tooling (#17972) Co-authored-by: Sean P. Ford <sean@seanford.com> * fix(providers): preserve Gemini function tools with native web search (#18020) * fix(db): preserve utilization bucket timezone (#18083) * fix(stream): preserve queued chunks on 6 abortStreamFailure sites (#18094) * fix(sse): refuse non-JSON data lines in stream readiness and content checks (#18095) * fix(db): don't skip half-applied proxy timing migration 194 (#18096) * fix(sse): fold camel-case reasoning effort into the canonical field (#18117) * fix(providers): preserve Codex reasoning controls and expose Muse subscription metadata (#18124) Co-authored-by: Aldo <github@aldo.pw> * fix(sse): local backends answer 499 while draining instead of 502 (#18134) Co-authored-by: roomhackerfrom100 <megamen932@gmai.com> * fix(compression): keep the tail of a truncated lite tool result (#18138) * fix(zcode): stream native Anthropic responses to clients (#18190) Co-authored-by: roomhackerfrom100 <megamen932@gmai.com> * fix(quota): recognize international Kimi Coding usage endpoints (#18180) (#18224) Co-authored-by: Nabi Bukhsh <nabibuksh.baloch01@gmail.com> * feat(dashboard): assign catalog models and combos to API keys (#14890) Co-authored-by: Fouad Salkini <fouad@wecansync.com> * feat(ci): validate protection domains for admission jobs (#16142) * feat(dashboard): add inline toggle and bulk disable/enable for no-auth providers (#16553) * feat(cli-tools): add OpenClaude setup guide card (#16844) Co-authored-by: Nguyen Thanh Dat <ntdat812@gmail.com> * feat(api): opt-in "expose combos only" setting for /v1/models (#16846) Co-authored-by: snower <sujian199@gmail.com> * feat(mcp): add a deep research tool that is off by default (#17317) * fix(opencode): map custom-provider catalog identities to public prefixes (#17369) * feat(oauth): import Antigravity Manager account exports (#15746) * feat(logs): distinguish generation rate from end-to-end throughput (#17847) * feat(api): CLIProxyAPI management usage compatibility endpoints (#17999) Co-authored-by: Rahul Bansal <rtrrahulbansal@gmail.com> * feat(antigravity): add Gemini 4 Argon weekly quota, dual-resolver preflight, and 404 short-circuit (#18026) * fix(zcode): preserve exact native Coding Plan quota refusals (#18118) Co-authored-by: roomhackerfrom100 <megamen932@gmai.com> * feat(opencode-plugin-v2): publish one catalog branch with prefix wildcard and hide every combo (#18135) * fix(combo): test all model health targets without a cumulative deadline (#18231) (#18238) * fix(codex): distinguish transient capacity 429 from quota cooldown (#18221) (#18239) * feat(oauth): route Grok Build image, video and audio (#15305) * feat(codebuddy-cn): sync authenticated live model catalog (#17916) * feat(providers): add MiniMax M3.1 Flash model (#18110) * fix(build): select webpack automatically on low-memory builders (#18184) (#18242) * fix(resilience): keep combos routable after transient credential probe errors (#18037) (#18243) * fix(claude): keep model-credit 429 cooldown scoped to the affected model (#18058) (#18245) * feat(providers): add Token Harbor API-key provider (#16315) Co-authored-by: GitHub Actions <github-actions@github.com> * feat(cli-tools): add current Pi setup flow (#16381) Co-authored-by: Arash <arash.ashrafi@gmail.com> * feat(api): configurable unpriced-usage budget policy + admin notice (#14604) (#14608) * fix(i18n): escape the Maltese apostrophe in providers.usedInComboTooltip (base-red) (#18545) * fix(usage): release terminal pending attempts when completion bookkeeping fails (#18217) Co-authored-by: AiCapitan357 <ai-capitan-357@proton.me> * feat(providers): add Runcrate (#18061) * i18n: complete feature-flag definitions for all 66 locales, fix zh-CN/zh-TW mistranslations (#17960) * feat(i18n): wire hardcoded dashboard strings into message catalogs (#17987) * feat(providers): add Gisoo (OpenAI-compatible) (#18112) Co-authored-by: Nirupam Bhowmick <48842933+heydryft@users.noreply.github.com> * feat(providers): dashboard control for the advertised CLI client version (#14817) Co-authored-by: Abhishek Divekar <adivekar@utexas.edu> * feat(ui): add remove error models button in combo test results, default autoHideFailed, and fix db import crash (#14944) * revert(kea): drop the stale-model badge and preferred-connections kit guards (#18250) * revert(kea): drop the kit e2e spec filter and settings-toggles realignment (#18247) * revert(kea): drop the post-migration follow-ups A on the kit (#18202) * revert(kea): drop the kit chart token palettes (#18144) * revert(kea): drop the UI kit line from the repository map (#18080) * revert(kea): drop the Keak CI UI Kit dashboard migration (#17951) Removes packages/ui-kit and the dashboard/UI-kit surface from the merged upstream state; the fork keeps its own dashboard. The kit workspace, its snapshot scripts and the vendored sources are deleted with it. * revert(dashboard): drop the team-costs/catalog kit port and the leftover kit scripts c0a7b86272 moved the team costs screens onto @omniroute/ui-kit, which the fork no longer vendors. Reverting it restores SearchableSelect and the legacy team components. Also drops the kit-only updater script and its two tests, and removes the ui-kit workspace entry from package.json / package-lock.json. * fix(dashboard): finish the kit removal on the two stragglers ModelCatalogTable came back from the pre-kit tree (it was still importing @omniroute/ui-kit table primitives); DiscoveryDegradedNotice swaps the kit Icon for the Material glyph the rest of the legacy UI uses. Restores the material-symbols dependency the restored globals.css imports. * chore(ci): keep only the fork workflows (bun.yml + release.yml) * docs(env): drop the UI kit upstream token now that the kit is not vendored * chore(compression): keep the release branch wording in lite.ts * chore(deps): resync the lockfile after the merge (fontsource, material-symbols, no ui-kit) * chore(kea): drop the leftover 0.0.66 UI kit changelog fragment --------- Co-authored-by: Bob.Hou <houminxi@gmail.com> Co-authored-by: Dizzle <112548150+maxmad64bis@users.noreply.github.com> Co-authored-by: 量子跃迁 <42333314+starxjys@users.noreply.github.com> Co-authored-by: Ai Captain 357 <ai-capitan-357@proton.me> Co-authored-by: Adrián Cancio <49328080+adrian-cancio@users.noreply.github.com> Co-authored-by: trespassmk <123762858+trespassmk@users.noreply.github.com> Co-authored-by: Fabio Junior Gruchovski <122614728+fabioKoruja00@users.noreply.github.com> Co-authored-by: Cristhian Hernandez <ayalachristian555@gmail.com> Co-authored-by: xc0derx <11428624+xc0derx@users.noreply.github.com> Co-authored-by: AbdullahPesteli <121692116+AbdullahPesteli@users.noreply.github.com> Co-authored-by: DeadY2J <jorgelamelas@hotmail.com> Co-authored-by: Sean Ford <sean@seanford.com> Co-authored-by: stanley <gstanleytejakusuma@gmail.com> Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: 小妍儿 ✨ <258399167+xiaoyaner0201@users.noreply.github.com> Co-authored-by: skygunner <skygunner@users.noreply.github.com> Co-authored-by: vincent <webmaster@palmit.com.au> Co-authored-by: MumuTW <42820974+MumuTW@users.noreply.github.com> Co-authored-by: Davy Massoneto <davy.massoneto@yahoo.com> Co-authored-by: Davy Massoneto <davy.m.massoneto@gmail.com> Co-authored-by: Wray <i@wray7.top> Co-authored-by: wray-lee <wray-lee@outlook.com> Co-authored-by: kenny000666 <kennyhomeautomation@googlemail.com> Co-authored-by: Safeer Ahmad <asafeer1994@gmail.com> Co-authored-by: Junior-HJ <sjaradj@ucvvirtual.edu.pe> Co-authored-by: jbovard2016 <jon.bovard@gmail.com> Co-authored-by: Kiaro-Sama <106400900+KiaroSama@users.noreply.github.com> Co-authored-by: KiaroSama <Kiaro.Sama.Dev@gmail.com> Co-authored-by: AiCaptain357 <345568968+AiCaptain357@users.noreply.github.com> Co-authored-by: Guan Gui <guiguan@gmail.com> Co-authored-by: opensource-elearning <159253500+opensource-elearning@users.noreply.github.com> Co-authored-by: Praveen K Palaniswamy <praveen.palaniswamy@gmail.com> Co-authored-by: Paulo Holanda <paulorfholanda@gmail.com> Co-authored-by: insoln <11380274+insoln@users.noreply.github.com> Co-authored-by: Mr. Nasıl <leidizayn@gmail.com> Co-authored-by: Markus Hartung <mail@hartmark.se> Co-authored-by: dongsjoa <dongsjoa@Xiaoyaner-Mac-Studio.local> Co-authored-by: Prince <162042308+PrinceThummar011@users.noreply.github.com> Co-authored-by: Muhammad Usama <55662931+MuhammadUsamaMX@users.noreply.github.com> Co-authored-by: Erwan Novianto <smserwan@gmail.com> Co-authored-by: hummern <hummernkloa@gmail.com> Co-authored-by: turbolego <turbolego@gmail.com> Co-authored-by: Mayank Jaiswal <mayankjaiswal1707@gmail.com> Co-authored-by: James Martinez <james-martinez@users.noreply.github.com> Co-authored-by: Anton Shilin <coder.root@gmail.com> Co-authored-by: WITALO ROCHA <witalo_rocha@hotmail.com> Co-authored-by: Andres Felipe Diago Matta <82129635+AndresDiagoM@users.noreply.github.com> Co-authored-by: HouMinXi <19586012+HouMinXi@users.noreply.github.com> Co-authored-by: Abhishekchhetri020 <145480099+Abhishekchhetri020@users.noreply.github.com> Co-authored-by: Abhishek Chhetri <abhishekchhetri@example.com> Co-authored-by: ScottyAmr <scott.kanowski@gmail.com> Co-authored-by: Felipe Almeman <4226997+zhiru@users.noreply.github.com> Co-authored-by: Felipe Almeman <felipe@aireset.com.br> Co-authored-by: Rafa Martins <146174365+rafacpti23@users.noreply.github.com> Co-authored-by: Dongwook <dongwook.chan@gmail.com> Co-authored-by: Tuan Dinh <tuan.dinh.truong@sap.com> Co-authored-by: arashashrafii <arash.ashrafi@gmail.com> Co-authored-by: Pranav Deshpande <134182346+PranavD2905@users.noreply.github.com> Co-authored-by: kalpakprod <beta_virus123@proton.me> Co-authored-by: mdc2122 <mdc2122@users.noreply.github.com> Co-authored-by: SIGTERM-015 <SIGTERM-015@users.noreply.github.com> Co-authored-by: KSonny4 <KSonny4@users.noreply.github.com> Co-authored-by: caniko <caniko@users.noreply.github.com> Co-authored-by: Chewji9875 <Chewji9875@users.noreply.github.com> Co-authored-by: Farshad Asadpour <asadpoor.f@gmail.com> Co-authored-by: Wayne Fourie <31033564+zerotraceio@users.noreply.github.com> Co-authored-by: Wayne <wayne@local> Co-authored-by: Thành Long <102373535+Longvt1164@users.noreply.github.com> Co-authored-by: özcan Yaman <ozc.yaman@gmail.com> Co-authored-by: Afonso Dutra Nogueira Filho <afonsoft@gmail.com> Co-authored-by: Jan Leon <jan@leoncode.de> Co-authored-by: Felipe Fidelix <309092+fidelix@users.noreply.github.com> Co-authored-by: Felipe Fidelix <felipe@fdx.is> Co-authored-by: openclaw-bot <balance.devdart@gmail.com> Co-authored-by: ahmed shahin <ahmedgo17390@gmail.com> Co-authored-by: lorenzozane <wyz0707@proton.me> Co-authored-by: Kevin Lin <levinkin07@gmail.com> Co-authored-by: Bl0ck <36800583+Bl0ck154@users.noreply.github.com> Co-authored-by: Aldo <github@aldo.pw> Co-authored-by: Bezrabotnyi <megamen932@gmail.com> Co-authored-by: roomhackerfrom100 <megamen932@gmai.com> Co-authored-by: Nabi Bukhsh <133964972+NabiBukhsh-AI@users.noreply.github.com> Co-authored-by: Nabi Bukhsh <nabibuksh.baloch01@gmail.com> Co-authored-by: Fouad Salkini <fouad@wecansync.com> Co-authored-by: Nguyen Thanh Dat <ntdat812@gmail.com> Co-authored-by: snower <sujian199@gmail.com> Co-authored-by: mertcandrks <mertcanbakir34@gmail.com> Co-authored-by: Rahul Bansal <42.rahulbansal@gmail.com> Co-authored-by: Rahul Bansal <rtrrahulbansal@gmail.com> Co-authored-by: MrSiB <a@aq2.ru> Co-authored-by: Kizuno18 <110933270+Kizuno18@users.noreply.github.com> Co-authored-by: AStupidBear <luyaocns@gmail.com> Co-authored-by: Octopus <jellyjellysoo127@gmail.com> Co-authored-by: GitHub Actions <github-actions@github.com> Co-authored-by: Nirupam Bhowmick <48842933+heydryft@users.noreply.github.com> Co-authored-by: NetArz | نِت اَرز <aaramin92@gmail.com> Co-authored-by: Abhishek Divekar <adivekar@utexas.edu> Co-authored-by: skymanbj <liubohn69@gmail.com>
Summary
The repo ships
docker-compose.ymlandfly.toml, andDOCKER_GUIDE.mdalready warns that "stock Docker / Kubernetes OmniRoute is one Node process + one SQLite writer" — but there are no manifests. Anyone running this on k3s or k8s writes them from scratch, against a topology whose constraints are invisible until they bite:/api/monitoring/healthdoes real DB work on every kubelet tick and restarts the only pod under load.So the topology is encoded, not documented.
replicas: 1,RecreateandReadWriteOnceare fixed in the base, in the chart and in the generator — not exposed as options anywhere. And the chart and the spec schema refuse to render a configuration that fails at runtime, naming the field rather than emitting something that breaks later:replicaCount > 1ReadWriteOnceshutdownTimeoutMs≥ grace − preStopFour artifacts, one topology:
deploy/kubernetes/— Kustomize base plus k3s (Traefik +local-path) and generic k8s (ingress-nginx) overlays.deploy/helm/omniroute/— the same topology, values-driven.omniroute deploy k8s— prints manifests built from a running instance's settings, so ports, origins and flags are not transcribed by hand. It writes to stdout and touches nothing, so it composes:omniroute deploy k8s --target local | kubectl apply -f -.docs/ops/KUBERNETES_DEPLOYMENT_GUIDE.md— 416 lines covering deploy, ingress/SSE, probes, upgrades, storage/backups, sizing and troubleshooting.localandvpsdiffer only in defaults.localassumes k3s on the same machine.vpsassumes a hostname in front of a cluster other people can reach, so TLS is on,REQUIRE_API_KEY=true, the cluster's default StorageClass binds, andLIVE_WS_ALLOWED_ORIGINSis derived from the host — without that, the dashboard's live view is rejected by the origin check on the very host it is served from.Probes follow
docs/ops/MONITORING_GUIDE.md("Kubernetes probe recommendations", merged in #10297):/healthzfor startup and readiness,/livezfor liveness, never/api/monitoring/health. The nginx overlay disables response buffering; the Traefik idle-timeout caveat is documented for k3s, since that one is an entrypoint setting and not an Ingress annotation.Provisioning is advisory on purpose.
omniroute deploy k8s provisionprints the k3s commands and never runs them or connects to a server. Doing it directly would mean shipping an SSH client and holding a private key — a standing surface for a one-off task — so it follows the shapecontrib/vpsalready uses for a VPS install. The VPS plan covers the two steps easiest to get wrong by hand:--tls-san, without which the cluster is only reachable as127.0.0.1and a remotekubectlfails TLS verification, and rewriting the127.0.0.1server address in the kubeconfig k3s writes. Values rendered into those commands are constrained to hostname, version, username and context shapes, so a printed command cannot mean something other than what it looks like.No new API route and no new dashboard surface. An earlier draft put this behind
/api/deploy/*with a UI tab; it was dropped before landing. Applying manifests by clicking is at odds with GitOps — the desired state should be versioned, not produced by a form — and the routes existed only to serve the button, spawningkubectlwith the host kubeconfig, which is a full cluster credential. The CLI reaches the same result without that surface, sorouteGuard.tsis untouched.Two fixes to the manifests themselves, both surfaced by the test that pins the generator against
deploy/kubernetes/base:API_PORTfrom the base ConfigMap. Setting it moves the API to a separate port (src/lib/runtime/ports.ts:27) that neither the container nor the Service exposes, leaving that listener unreachable. Unset, the API and dashboard sharePORT— which is what the manifests actually expose.deployalso joins--mcpin reserving stdout for data (bin/omniroute.mjs). Env-loading notices there made the YAML unparseable —control characters are not allowed— which broke the pipe the command exists for.Related Issues
Validation
npm run lintApplied to a live cluster, not just a dry run. Single-node k3s v1.36.4+k3s1:
local-pathBound, 10Gi, RWO1/1 Running, 0 restartsAvailable=True/healthzand/livezthrough the Service/v1/models--dry-run=serverThat run corrected two documentation errors a client-side dry run cannot catch: the health check used
wget, and the published image ships neitherwgetnorcurl(nodeis the only HTTP client in it); and an Ingress naming an IngressClass the cluster does not run is accepted by the API server and then silently routes nothing. Both are now in the guide, the second as a troubleshooting row.Red first, per invariant: each manifest guard was verified to fail under a deliberate mutation of the file it protects — flipping
replicasto 2, the access mode to RWX,proxy-bufferingtoon, liveness to/api/monitoring/health, or the shutdown budget past the grace period each turns exactly one test red, and only one. The generator/CLI suites found three real defects while being written: afailplaced at the top level of a_*.tplfile (Helm parses and discards it, so the replica guard was a silent no-op), context-name validation that rejected legitimate EKS contexts, and the stdout pollution above.The automated review then found four more, fixed in the second commit: an address pattern that accepted a port or a bare IPv6 literal and rendered
https://host:123:6443; a context pattern that rejected the ARN-shaped contexts managed clusters produce; the context being interpolated into a temp path, which the previous item would have turned into a directory traversal; and a quantity pattern that acceptedKwhile rejectingk, the lowercase decimal thousand Kubernetes actually uses, so512kwas refused. Each has a regression case.Rebased onto
release/v3.8.51and the full set rerun there: 54 tests passing,npm run typecheck:coreclean, both overlays render with zero kustomize warnings,helm lintclean,check:docs-all/check:tracked-artifacts/check:cli-i18npassing, andomniroute deploy k8s | kubectl apply --dry-run=client -f -still creates all six objects.npm run lintreports zero errors but exits 2, on this branch and on an untouched checkout of the base alike —suppressions left that do not occur anymore, unrelated to any file here.Tests Added Or Updated
tests/unit/k8s-deploy-manifests.test.ts— 12 cases over the committed manifests: single replica, Recreate, RWO, probe targets, drain budget, unbuffered SSE, secret hygiene, and that the chart's replica guard is actually reachable rather than discarded.tests/unit/deploy/kubernetes-manifest-generator.test.ts— 13 cases: generation invariants, target profiles, storage-class semantics, and parity between the generator anddeploy/kubernetes/base.tests/unit/deploy/kubernetes-provision-plan.test.ts— 19 cases: the provisioning plan's correctness (including--tls-sanand the kubeconfig rewrite), the deploy-spec guard rails, and the five review findings below.tests/unit/deploy/kubernetes-cli-command.test.ts— 10 cases driving the real binary: the stdout contract, exit codes, and argument rejection.Coverage Notes
New production code is
src/lib/deploy/kubernetes/(three pure modules, 830 lines) andbin/cli/commands/deploy.mjs(250 lines).The generator and the spec schema are pure — no cluster, no filesystem, no clock — and are covered directly by the two unit suites. The CLI is covered end to end by a suite that executes
bin/omniroute.mjsand parses its stdout, which is what pinned the stdout-pollution bug; a mocked test would not have caught it.bin/omniroute.mjsgains one condition, exercised by that same suite.Nothing existing loses coverage. Beyond the new files, the only changes are the two ConfigMap/protocol fixes, that one condition, a
.prettierignoreentry for Helm's Go templates (which Prettier's YAML parser cannot read), and two doc cross-references.Reviewer Notes
definethatdeployment.yamlincludes. Helm parses and then discards top-level code in a_*.tplfile, so a barefailthere is a silent no-op — the first version of this had exactly that bug, andreplicaCount=2rendered happily. A test now pins theinclude.storageClassNameis omitted, never set to"". An empty string disables dynamic provisioning entirely; omitting the key binds the cluster default. The two look interchangeable, so a test covers the distinction.--disable=traefikhas no such IngressClass, and the API server accepts the Ingress anyway — it is created and routes nothing. Documented in troubleshooting rather than worked around, since the fix is to name the class the cluster actually runs.:and/. Managed clusters produce them (an EKS context isarn:aws:eks:<region>:<account>:cluster/<name>). Safe because nothing here goes through a shell, the leading-alphanumeric requirement prevents a value being read as an option, and — the part that had to change for this to hold — the temp filename in the fetch-kubeconfig step is fixed rather than derived from the context, so a/cannot turn it into a path.502. That is the SQLite topology, not a probe misconfiguration, and the guide says so where an operator will hit it.--tls-sanstep matters more than it looks: omit it and the cluster works perfectly from the VPS itself while every remotekubectlfails TLS verification, which is a confusing way to lose an afternoon.Status update — 2026-09-24 (head
d905e453b)The pre-merge question is answered
npm run lint's "zero errors but exit 2" is pre-existing, not introduced here. Verified on an untouched checkout of the base tip30f7088c7— not one commit of this branch applied: exit 2, zero errors, byte-identical message (There are suppressions left that do not occur anymore).Every red on this PR is inherited, and Fast Quality Gates now proves it
release/v3.8.51alone (8feaafcf, run 35967005359)deps file-size mutation-test-coverage complexity-ratchets dead-code open-sse-typecheck typecheck:core ts7-diagnostics-ratchetd905e453b, run 35980453742)deps file-size mutation-test-coverage open-sse-typecheck typecheck:coreThe PR's five are a strict subset of the base's eight. The branch additionally passes
complexity-ratchets,dead-codeandts7-diagnostics-ratchet, which the base fails — new-code mode scores only what this diff adds.file-sizejoined the list once the base was merged in: the drift it reports is the base's ownchat.ts, which is why the same gate fails on the base alone.The other jobs trace to #14547 / #14496 the same way:
API Route Typecheckisauggie.ts+projectCombo.ts, the fourUnit Tests fast-pathshards are the provider-catalog drift (reproduced locally:provider-node-reserved-prefixasserts415against an expected414), andDocs Gatesis the stale migration count inREADME.md/AGENTS.md/llm.txt— the exact hard failure #14547 was opened for. None is fixed here: a base-red fix is its own freeze-gated PR.What changed in this branch since the review
Probe budgets re-derived (
5b6e50c4f). The startup-budget guard pinned its rationale todb.exec("VACUUM")insidestartCleanupScheduler. #12821 — filed from this PR's own review thread — replaced that with bounded incremental reclamation, so the pin stopped matching and the test went red on rebase. That is the pin working: the manifest's reason moved, so the manifest was re-argued rather than the assertion relaxed.Cold start still blocks, for reasons that hold on this base: opening the database runs the legacy call-log offload, which checkpoints the WAL and then rebuilds the file with a full
VACUUM(src/lib/db/core.ts), and the startup cleanup pass reclaims freed pages on the same synchronous connection. The blocking fullVACUUMalso still runs on a live, healthy process fromvacuumSchedulerat the configured hour — which is what thetcpSocketliveness default exists for, so the liveness guard pins it there now. Manifest, chart, generator and guide comments were updated to name the offload and the reclamation pass instead of the cleanup VACUUM. No manifest value changed: replicas, strategy, access mode, probe targets, budgets and annotations are untouched.Docs frontmatter (
0f6bfb1ba).source.config.tsnow compiles every Markdown file underdocs/with fumadocs-mdx, andcheck:docs-frontmatterfails Docs Gates for any compiled doc without atitle. The guide predates that gate on this base — this was the one Docs Gates failure that belonged to this PR, and it is fixed.Verified at
5b6e50c4fagainst the then-current base30f7088c7: 57/57 tests across the four suites,typecheck:coreclean,check:complexity-ratchetsgreen in absolute mode (complexity 2910 vs baseline 3218; cognitive 1322 vs 1437).The base was merged into this branch at
d905e453b(60 commits), so the branch is level withrelease/v3.8.51and carries its reds directly. That is why the gate count moved from four to five between runs — nothing in this diff changed.