Skip to content

fix(providers): backfill combo context limit from snapshot after cold start (#13000) - #13759

Merged
diegosouzapw merged 3 commits into
release/v3.8.51from
fix/13000-combo-context-limits-fallback-cold
Sep 16, 2026
Merged

diegosouzapw merged 3 commits into
release/v3.8.51from
fix/13000-combo-context-limits-fallback-cold

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Closes #13000

Root cause (short)

Two gaps in @omniroute/opencode-plugin (client library), both surfacing as the combo
context limit downgrading from the correct server-computed value (245000) to a raw
Math.min(member context_length) lower bound (163840) after a restart:

  1. buildStaticProviderEntry (the static-catalog builder used by
    createOmniRouteConfigHook, which is what actually publishes the combo's limit.context
    on this path) computed the combo limit purely as Math.min(member context_length) and
    never consulted combo.computed_context_length at all — unlike the dynamic hook's
    mapComboToModelV2, which already had a "prefer computed_context_length" branch. This is
    a gap the original plan-file's root-cause analysis didn't catch (it assumed
    buildStaticProviderEntry already respected the field); confirmed by reproducing the bug
    against createOmniRouteConfigHook and finding the backfill alone had zero effect until
    this was also fixed.
  2. Even where computed_context_length is consulted, a background refresh
    (doRefresh()) whose live /api/combos response comes back without the field (e.g. right
    after a restart, before the server finishes recomputing it) had no fallback to the
    last-known-good disk snapshot already sitting in scope (warmSnapshot) — so it silently
    overwrote a correct value with the degraded one.

Fix

  • buildStaticProviderEntry's combo-limit computation now prefers
    combo.computed_context_length the same way mapComboToModelV2 does, falling back to
    Math.min(member context_length) only when the field is absent/0.
  • doRefresh() backfills a combo's missing/zero computed_context_length from
    warmSnapshot.rawCombos (matched by combo id) before caching, publishing, and persisting
    the refreshed block — scoped strictly to that one derived field; no other combo field
    (models/name/etc.) is ever overwritten with stale snapshot data.

Regression test

@omniroute/opencode-plugin/tests/issue-13000-cold-start-combo-limit.test.ts (added to the
package's test script in package.json so opencode-plugin-ci.yml actually runs it —
that workflow lists test files explicitly).

RED (against unfixed code):

✖ issue #13000: warm combo limit (245000) survives a degraded post-restart refresh instead of downgrading to Math.min(member) (1249.699751ms)
  AssertionError [ERR_ASSERTION]: expected the combo limit to stay at the known-good 245000, but got 163840
  163840 !== 245000

GREEN (after both fixes):

✔ issue #13000: warm combo limit (245000) survives a degraded post-restart refresh instead of downgrading to Math.min(member) (431.796312ms)
✔ issue #13000 (control): no warm snapshot exists — Math.min(member) fallback is still used (expected, documented behavior) (25.188027ms)
ℹ tests 2
ℹ pass 2
ℹ fail 0

A second control test asserts the documented, non-regressive behavior for a pure cold start
with no prior disk snapshot: the Math.min(member) fallback is still used (nothing to
backfill from).

Gates run

  • npx eslint --suppressions-location config/quality/eslint-suppressions.json <changed files> → clean, no output.
  • npx tsc --noEmit -p @omniroute/opencode-plugin/tsconfig.json → clean, no output. (This
    package has its own tsconfig.json; it is not covered by typecheck:core or
    check:open-sse-typecheck.)
  • node scripts/check/check-file-size.mjs → only a pre-existing unrelated flag on
    open-sse/utils/stream.ts (base drift, not touched by this PR).
  • node scripts/check/check-complexity.mjs / check-cognitive-complexity.mjs → not
    applicable
    — both gates scan only src/, open-sse/, electron/, bin/
    (ESLINT_SCAN_DIRS in scripts/check/complexityEslintReport.mjs); @omniroute/* is out of
    scope.
  • node scripts/check/check-test-discovery.mjs → not applicable — the gate's own header
    comment documents @omniroute/* ficam fora do walk (têm CI próprio: opencode-*-ci.yml).
    Discovery for this package is instead the package's own test script, which this PR updates
    to include the new test file.
  • cd @omniroute/opencode-plugin && npm test (full 25-file suite, now 26 with this PR) →
    368/369 passing (370 with this PR's 2 new tests, 369 unaffected pre-existing). The one
    failure (scaffold.test.ts) is a pre-existing environment gap unrelated to this change: this
    worktree never ran npm run build, so dist/index.js doesn't exist yet — confirmed by ls dist failing before any of this PR's edits.

Existing tests aligned

None — no existing assertion encoded the buggy contract, so nothing needed realignment.

Not covered here

  • The plan-file's optional open question (whether /api/combos itself ever omits
    computed_context_length server-side for a combo with an explicit DB override, vs. the loss
    happening only in the plugin's own fetch) is left as documented follow-up, not blocking —
    this fix protects the client either way.
  • Per the plan-file's "consider, optional" item, no separate patch-version bump was made to
    @omniroute/opencode-plugin/package.json; checked recent precedent (b0557543, #12607,
    same class of fix) and this repo does not bump the package version per fix-PR.

diegosouzapw and others added 3 commits September 15, 2026 14:04
… start (#13000)

Root cause was two-fold in @omniroute/opencode-plugin: (1) the static
catalog builder (buildStaticProviderEntry, used by
createOmniRouteConfigHook) computed a combo's limit.context purely as
Math.min(member context_length) and never consulted the server-computed
combo.computed_context_length field at all, unlike the dynamic hook's
mapComboToModelV2; (2) even where computed_context_length IS consulted,
a background refresh whose live /api/combos response comes back without
the field (e.g. right after a restart, before the server finishes
recomputing it) had no fallback to the last-known-good disk snapshot,
so it silently overwrote a correct 245000 limit with the degraded
Math.min(member) value (163840 in the reported case).

Fix: buildStaticProviderEntry now prefers computed_context_length the
same way mapComboToModelV2 does, and doRefresh() backfills a combo's
missing/zero computed_context_length from warmSnapshot.rawCombos by id
before caching/publishing/persisting, scoped to that single field only.

Regression test:
@omniroute/opencode-plugin/tests/issue-13000-cold-start-combo-limit.test.ts
@diegosouzapw
diegosouzapw merged commit 8f6205e into release/v3.8.51 Sep 16, 2026
23 of 26 checks passed
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
… start (diegosouzapw#13000) (diegosouzapw#13759)

Merged in the 2026-09-16 sweep of the maintainer's own open PRs, at the owner's explicit instruction. No push was made to the PR branch: the merge took the head as the owning session left it (verified OPEN, non-draft and MERGEABLE against the release tip immediately before merging).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant