Files
OmniRoute/changelog.d
Rick7C2 614ff4b60a fix(sse): thread errorText into shouldMarkAccountExhaustedFrom429 (#13008)
* fix(sse): thread errorText into shouldMarkAccountExhaustedFrom429

shouldPreserveQuotaSignals() (open-sse/services/quotaResetParsing.ts) gained
an errorText parameter so an explicit quota-exhausted body could override the
apikey-category default, but only one of its two call sites was updated.
checkFallbackError() passes the upstream body; shouldMarkAccountExhaustedFrom429()
still called it with the provider alone.

With errorText undefined the helper's
`Boolean(errorText) && looksLikeQuotaExhausted(errorText)` branch can never be
true, so for every apikey-category provider without per-model quotas the
connection was never marked quota-exhausted -- even when the upstream body
explicitly said a long-window cap was hit.

Thread errorText through the helper and pass it at the src/sse/handlers/chat.ts
call site. The parameter is optional and additive: OAuth-category providers and
callers that pass no body keep their existing behavior, and plain rate limits
("Rate limit exceeded, retry in 20s", "Too Many Requests") still fall through to
the short generic cooldown.

Regression guard: tests/unit/quota-signal-errortext-threading.test.ts

* test(sse): pin the chat.ts call site that forwards errorText

The errorText parameter added in the previous commit is optional, so dropping
it at the only production call site (src/sse/handlers/chat.ts) is neither a
type error nor a test failure -- the four existing cases call the helper
directly and none of them assert the wiring. The half of the patch that makes
it do anything in production could be reverted, or lost in a refactor, with
the whole suite green. That is the same failure mode this branch fixes (a
two-argument helper with a call site silently passing one), one level up.

handleSingleModelChat is not exported, so the call cannot be driven or spied
without widening the production surface. Assert at the source level instead,
following tests/unit/api-key-provider-quota-bypass-scope.test.ts, and parse
the argument list rather than regex-matching formatted text so a Prettier
reflow cannot cause a false failure or a false pass. Also pins that there is
exactly one call site, and what errorStr holds.

Verified by mutation: dropping errorStr at chat.ts now fails 1 of 5.

* chore: number quota signal changelog fragment

Co-Authored-By: Paperclip <noreply@paperclip.ing>

---------

Co-authored-by: TogetherWeOwn <eng@togetherweown.com>
Co-authored-by: togetherweown[bot] <togetherweown[bot]@users.noreply.github.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-19 00:03:18 -03:00
..
2026-07-13 09:12:40 -03:00

changelog.d/ — changelog fragments

A PR never edits CHANGELOG.md directly during the cycle. Instead it adds ONE new file here — its changelog entry as a fragment. Two PRs never touch the same file, so changelog merge conflicts (the "CHANGELOG-eat" cascade that forced a re-sync push + full CI re-run after every sibling merge) are structurally impossible.

Convention

Directory Aggregates under
features/ ### ✨ New Features
fixes/ ### 🐛 Bug Fixes
maintenance/ ### 📝 Maintenance
  • Filename: <PR-number>-<short-slug>.md (e.g. fixes/6700-dockerfile-better-sqlite3.md). The PR number prefix keeps aggregation order deterministic.
  • Content: the exact bullet line(s) that should land in CHANGELOG.md, starting with - . Multi-line (continuation) bullets are fine. Keep the repo's credit format: (#PR — thanks @user).
  • One fragment per PR (rarely more, e.g. a PR that both fixes and adds).

Example

changelog.d/fixes/6496-cloudflare-relay-worker-syntax.md:

- **fix(providers):** Cloudflare relay Worker deploys use Service Worker syntax with `body_part` metadata ([#6496](https://github.com/diegosouzapw/OmniRoute/pull/6496)) — thanks @SeaXen

Aggregation

The release captain (or /generate-release) folds all fragments into CHANGELOG.md and deletes them:

node scripts/release/aggregate-changelog.mjs            # write + delete fragments
node scripts/release/aggregate-changelog.mjs --dry-run  # preview only

Fragment well-formedness is enforced by npm run check:changelog-integrity (the same gate that guards against CHANGELOG-eat for legacy direct edits).