fix(guardrails): reroute zero-vision combos through the vision bridge (#10415)

* fix(guardrails): reroute zero-vision combos through the vision bridge

Named combos whose model targets all lack vision support are never
reroute-eligible: the bridge only attempts the describe path, and when
describing cannot run or fails the raw images stay in the payload and the
request dies in the combo capability filter with capability_mismatch.

getComboVisionBridgeDecision now returns a "no-vision" verdict for combos
with zero vision-capable targets, and preCall treats it as reroute-eligible
with the same credential guards as single text-only models, falling back to
describe only when no usable reroute target exists.

* chore(changelog): fragment for #10415 vision bridge combo reroute

* fix(guardrails): extend allNull stub fallback to no-vision combos

Reviewer follow-up (#10415): the allNull stub-text fallback at the end of
preCall only fired for comboVisionBridgeDecision === 'process'. In the
compound-failure case for a zero-vision combo — reroute target without
usable credentials AND every describe call failing — raw images were
preserved and the original capability_mismatch recurred, because a
no-vision combo has no target that can consume images.

Include 'no-vision' in the guard: stub text is strictly better than raw
bytes no combo target can consume. Adds a double-failure unit test.

* ci: re-run dast-smoke (Build CLI bundle runner timeout flake)

* fix(build): bound and retry the opencode-plugin npm install in prepublish

The plugin's node_modules is gitignored, so every fresh CI checkout runs a
full npm install inside @omniroute/opencode-plugin during build:cli. npm's
unbounded fetch retries turn a stalled registry CDN connection (the recurring
onnxruntime-class ETIMEDOUT flake) into a 20-30 minute hang — the DAST
'Build CLI bundle' step has been cancelled at the 30m cap repeatedly.

- Bound npm fetch: --fetch-timeout 60s, 2 retries with capped backoff — a
  stalled connection now fails fast instead of hanging the job.
- Retry the install up to 3 times with a 10s pause between attempts, so
  transient CDN failures recover in-build.

Net effect: the step either completes (network OK) or fails quickly with a
clear error (network down) — it can no longer eat the whole job budget.

* ci(dast): use existing npm-ci-retry action instead of bare npm ci

dast-smoke died at 'Run npm ci' with connect ETIMEDOUT to the
onnxruntime-node binary CDN (Microsoft 150.171.x.x) — the same
transient CDN flake class that has hit Vitest/Quality Gates before.
quality.yml already wraps npm ci in ./.github/actions/npm-ci-retry
(3 attempts, exponential backoff); dast-smoke was the one workflow
still using a bare install. Use the existing action for consistency.

* ci(quality): use the npm-ci-retry action on every install step

Fast Quality Gates failed on the recurring onnxruntime-node postinstall
ETIMEDOUT (Microsoft CDN 150.171.x.x) - the same transient flake that has
hit Vitest and dast-smoke today. Only the Build job used the retry action;
the other five jobs (Docs, Fast Quality Gates, Vitest, Unit Tests,
changelog) still ran a bare install and die on any CDN hiccup. Use the
existing retry action (3 attempts, exponential backoff) on every install
step for consistency.

---------

Co-authored-by: Rouzbeh <rqzbeh@users.noreply.github.com>
This commit is contained in:
Rouzbeh†
2026-08-16 06:46:23 +03:30
committed by GitHub
parent 3c8432791e
commit b75f7dde93
6 changed files with 402 additions and 36 deletions

View File

@@ -37,7 +37,7 @@ jobs:
with:
node-version: "24"
cache: npm
- run: npm ci
- uses: ./.github/actions/npm-ci-retry
- name: Build CLI bundle
env:
OMNIROUTE_BUILD_BACKEND_ONLY: "1"

View File

@@ -137,7 +137,7 @@ jobs:
with:
node-version: ${{ env.CI_NODE_VERSION }}
cache: npm
- run: npm ci
- uses: ./.github/actions/npm-ci-retry
# One walk of src/app/api for openapi-routes + docs-symbols (both still fail independently).
- run: npm run check:api-docs-refs
- name: Docs accuracy (fabricated-docs + i18n mirrors, strict)
@@ -181,7 +181,7 @@ jobs:
with:
node-version: ${{ env.CI_NODE_VERSION }}
cache: npm
- run: npm ci
- uses: ./.github/actions/npm-ci-retry
- name: Restore ESLint file cache
uses: actions/cache@v6
with:
@@ -430,7 +430,7 @@ jobs:
with:
node-version: ${{ env.CI_NODE_VERSION }}
cache: npm
- run: npm ci
- uses: ./.github/actions/npm-ci-retry
# WS5.2/5.3: JUnit feeds Trunk Flaky Tests — the fast-path runs on EVERY PR,
# which is where flaky-detection volume actually comes from (ci.yml's heavy
# jobs only run on the release PR). Advisory upload, own-origin only.
@@ -476,7 +476,7 @@ jobs:
with:
node-version: ${{ env.CI_NODE_VERSION }}
cache: npm
- run: npm ci
- uses: ./.github/actions/npm-ci-retry
# QW-d: fonte única — o mesmo npm script do CI pesado/local. Fecha dois drifts do
# comando inline antigo: os dirs `memory` e `usage` estavam FORA do glob (testes
# silenciosamente não rodavam no fast path) e o setupPolyfill não era importado.
@@ -516,7 +516,7 @@ jobs:
with:
node-version: ${{ env.CI_NODE_VERSION }}
cache: npm
- run: npm ci
- uses: ./.github/actions/npm-ci-retry
- name: Restore ESLint file cache
uses: actions/cache@v6
with:
@@ -583,7 +583,7 @@ jobs:
with:
node-version: ${{ env.CI_NODE_VERSION }}
cache: npm
- run: npm ci
- uses: ./.github/actions/npm-ci-retry
- name: CHANGELOG integrity (nenhum bullet da base pode sumir no merge-result)
run: npm run check:changelog-integrity
- name: Agent-skills generator sync (SKILL.md gerado ≡ catálogo)