Skip to content

fix(#312): invalidate stale modelContextLimit on catalog miss (#313 + #314 combined) - #315

Merged
ranxianglei merged 2 commits into
masterfrom
fix/stale-limit-fallback
Aug 17, 2026
Merged

fix(#312): invalidate stale modelContextLimit on catalog miss (#313 + #314 combined)#315
ranxianglei merged 2 commits into
masterfrom
fix/stale-limit-fallback

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

What

Completes the #314 fix (merged) with #313's fail-safe as the fallback path — the "ideal combined fix" from the review of both PRs.

Background

Issue #312: after switching models (e.g. 200K → 1M), a 50% emergency-compression threshold fired at ~26% real usage, because experimental.chat.messages.transform fires before system.transform in one request, and only the system hook writes state.modelContextLimit — so the first request after a switch computes every percentage against the previous model's window.

This PR

Records the identity pair (modelProviderID / modelID) alongside the limit whenever the system hook writes it, persisted and restored together. On a catalog miss the messages hook now compares the request's model against that identity:

catalog miss + behavior
identity match keep the limit — no needless blindness when the catalog simply lacks an entry for the current model
identity mismatch invalidate (limit = undefined) — #313's fail-safe: never run percentage math against the wrong window
legacy state (no identity persisted) treated as stale — one blind turn per upgraded session, same trade-off #313 accepted

undefined is already the natural fresh-session state (before the first system.transform), so all consumers (nudges, GC, batch-cleanup, adaptive growth) tolerate it by construction. The same request's system.transform refreshes the pair right after, so the blind window is a single turn at most.

Supersedes

Changes

  • lib/state/types.tsSessionState.modelProviderID/modelID (optional, persisted)
  • lib/state/state.ts — init/reset/load keep the pair atomic with the limit
  • lib/state/persistence.ts — serialize/restore the pair
  • lib/hooks.ts — system hook records identity; messages hook: catalog hit → correct + record identity; miss + mismatch → invalidate
  • tests — legacy-state invalidation, identity-mismatch invalidation, same-identity keep (emergency still fires at 130% of the real window), system-hook identity recording, persistence round-trip

Verification

  • tsc --noEmit clean
  • 991/991 tests pass (was 988; net +3)
  • prettier-clean on all touched hunks (pre-existing format dirt elsewhere left untouched)

Completes the #314 fix with #313's fail-safe as the fallback path.

#314 (merged) reconciles state.modelContextLimit from the model-limit
catalog when the request's user message names a known model. When the
catalog MISSES (fresh instance + failed hydration + never-used model),
the stale limit survived and every percentage threshold still ran against
the previous model's window — the exact #312 false positive, narrowed to
a rare corner but not eliminated.

This PR records the identity pair (modelProviderID/modelID) alongside
the limit whenever the system hook writes it, and on a catalog miss the
messages hook compares the request's model against that identity:
- match   → keep the limit (no needless blindness when the catalog
            simply lacks an entry for the CURRENT model)
- mismatch→ invalidate (limit = undefined); consumers already tolerate
            undefined (fresh sessions run with it until the first
            system.transform), and this same request's system.transform
            refreshes the pair anyway
- legacy persisted states carry no identity → treated as stale (one
  blind turn per upgraded session, same as #313)

The identity pair is persisted/restored together with the limit.

Tests: legacy-state invalidation, identity-mismatch invalidation,
same-identity keep (emergency still fires at 130%), system-hook identity
recording, persistence round-trip. 991/991 pass, tsc clean.
@github-actions

github-actions Bot commented Aug 16, 2026

Copy link
Copy Markdown

📦 Built Plugin Artifact

Branch: fix/stale-limit-fallback (e6b7b90)

Option A — Install from npm PR tag (recommended)

opencode plugin opencode-acp@pr-315 --global

Each push to this PR publishes a new version under the pr-315 npm tag.

Option B — Install from GitHub

opencode plugin "github:ranxianglei/opencode-acp#fix/stale-limit-fallback" --global

Option C — Download artifact

  1. Download the artifact from the Actions run
  2. Extract the tarball and install:
tar xzf opencode-acp-pr315.tgz
cp -r package/dist ~/.cache/opencode/packages/opencode-acp@latest/node_modules/opencode-acp/dist
  1. Restart opencode to pick up changes.

This comment is automatically updated on each push.

@ranxianglei
ranxianglei merged commit 0a63a10 into master Aug 17, 2026
3 of 4 checks passed
@ranxianglei ranxianglei mentioned this pull request Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant