Repository navigation
fix(auth): never auto is_active=0 on unpaid/ban flaps; recover after renew - #15293
Closed
RaviTharuma wants to merge 3 commits into
Closed
RaviTharuma wants to merge 3 commits into
RaviTharuma wants to merge 3 commits into
Conversation
…renew writeTerminalStatus no longer defaults isActive=false on terminal testStatus (incl. credits_exhausted); callers pass isActive explicitly. chatCore FORBIDDEN/ACCOUNT_DEACTIVATED record testStatus for selection skip + alerts and only deactivate via the gated maybeAutoDisableBannedAccount (autoDisableBannedAccounts + scope). Unrecoverable OAuth refresh sets testStatus=expired only, keeping is_active=1. credits_exhausted / expired accounts recover after billing renew / re-auth without a dashboard re-enable. Regression: tests/unit/terminal-status-no-auto-deactivate-14853.test.ts (RED before fix, GREEN after). Fixes #14853
2 of 3 tasks
…atCore ban blocks The #14853 fix made chatCore FORBIDDEN/ACCOUNT_DEACTIVATED record testStatus only, gating is_active=0 behind autoDisableBannedAccounts (+ scope). Two unit tests still asserted the old ungated is_active=0: - anthropic-request-not-allowed-cooldown-escalation: "any other claude 403 still bans" now enables autoDisableBannedAccounts before the 403; the explicit-isActive 3rd-refusal escalation path is unchanged. Adds a flag-OFF regression proving a real ban keeps is_active=1 (recover after flap clears). - probe-testall-isolation RESTORE: probeCanDisable alone no longer deactivates; real-traffic path also needs autoDisableBannedAccounts — enables both, resets in finally. Default isolation tests unchanged. Extracts the duplicated FORBIDDEN/ACCOUNT_DEACTIVATED writeTerminalStatus + maybeAutoDisableBannedAccount blocks into chatCore/gatedTerminalBan.ts (recordGatedBanTerminalStatus). open-sse/handlers/chatCore.ts 6465 -> 6425, back under the frozen 6441 ceiling. Refs #14853
Contributor
Author
|
CI follow-ups on fork head:
Fast Quality Gates remaining (baseline / unrelated): mutation-test-coverage (25 unrelated stryker tap.testFiles) and vuln-ratchet (41>27, no lockfile change). Happy to sync in a separate hygiene PR; this PR stays credentials-only. |
The #14853 DRY extract moved the two FORBIDDEN / ACCOUNT_DEACTIVATED lastError: persistentMessage writes out of chatCore's classifier block into chatCore/gatedTerminalBan.ts, so the classifier now holds 7 (was >=9). Follow the #12864 pattern already used for requestRejectedFailure.ts: lower the classifier count to >=7 (what stayed) and hold the extracted module to the same invariant — lastError must use the projected persistentMessage, never a raw upstream message. Refs #14853
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Reopens only the credentials-flap behavior fix from #14854 (closed), without the
AGENTS.mdedits and with a failing-then-passing regression test per Hard Rules #8 / #18.Stops OmniRoute from permanently sidelining accounts on temporary unpaid / ban-looking flaps so operators can pick them back up after billing renew / re-auth without a dashboard re-enable.
writeTerminalStatus: no longer defaultsisActive=falseon terminaltestStatus(includingcredits_exhausted). Callers must passisActiveexplicitly.chatCore:FORBIDDEN/ACCOUNT_DEACTIVATEDrecord terminaltestStatusfor selection skip + alerts, and only deactivate viamaybeAutoDisableBannedAccount(autoDisableBannedAccounts+ scope) — the same gateauth.tsalready uses.testStatus=expiredonly (keepsis_active=1);updateProviderCredentialsalready skipsisActivewhen omitted.BAN_DETECTION.mdupdated for unpaid recovery + gatedisActive. NoAGENTS.mdchanges.Behavior after this PR
testStatusis_activecredits_exhausted1; recovery re-probe can clear after renewFORBIDDEN/ deactivated0only ifautoDisableBannedAccountsallowsexpired1Related Issues
AGENTS.mdedits, adds regression test)Validation
node --import tsx/esm --test tests/unit/terminal-status-no-auto-deactivate-14853.test.ts— RED against pre-fixterminalStatus.ts(2 fail), GREEN after fix (3 pass)terminal-status-origin,auth-terminal-status,probe-gate-autodisable(21 pass)npm run typecheck:corecleannpm run lint(eslint on changed files) clean; prettier cleanrelease/v3.8.51base tipTests Added Or Updated
tests/unit/terminal-status-no-auto-deactivate-14853.test.ts(new regression):credits_exhaustedwithout explicitisActivekeepsis_active=1bannedwithout explicitisActiverecordstestStatusbut keepsis_active=1isActive=falsestill deactivates (gated auto-disable path honored)Coverage Notes
open-sse/handlers/chatCore.tsandsrc/shared/utils/terminalStatus.ts. The new regression test directly covers thewriteTerminalStatusdefault change; the chatCore paths now route permanent deactivation through the already-testedmaybeAutoDisableBannedAccountgate.Reviewer Notes
FORBIDDEN/ACCOUNT_DEACTIVATEDbranches now callmaybeAutoDisableBannedAccount({ permanent: true })instead of inlineisActive: false, matchingauth.ts. WithautoDisableBannedAccountson (+ scope), true bans still deactivate; otherwise the connection stays active with a terminaltestStatusfor selection skip + alerts.