fix(auth): scope model suspension reasons to prevent stale sibling resume - #188
Open
warelik wants to merge 2 commits into
Open
fix(auth): scope model suspension reasons to prevent stale sibling resume#188warelik wants to merge 2 commits into
warelik wants to merge 2 commits into
Conversation
added 2 commits
August 20, 2026 11:54
Add model_not_supported to resumableCooldownReasons so a model suspended with model_not_supported resumes when that same model succeeds. The failure sets a 12-hour temporary suspension whose registry counterpart would otherwise never clear even after the cooldown expires and the model serves requests successfully.
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.
Problem
When multiple models share a single credential, model failure and recovery handling in
MarkResultsuffered from two severe defects:MarkResultcheckedGetClientModelSuspensionReasonand compared it to"invalid_api_key"before callingResumeClientModel. Under concurrent requests, the suspension reason could change between check and resume. Furthermore, unrelated sibling model successes could erroneously clear model-specific suspensions (e.g.not_found,quota,payment_required), putting dead endpoints back into active rotation and preventing proper failover.model_not_supported:MarkResultsuspends unsupported models with reasonmodel_not_supportedand a 12-hour retry window. When reason-scoping was introduced,model_not_supportedwas omitted from the resumable per-model set, causing models to remain permanently suspended even after subsequent successful requests on the same model.Fix
internal/registry/model_registry.go:749: AddedSuspendClientModelReplacingReasonsto allow model-specific reasons to atomically overwrite credential-wide ones.internal/registry/model_registry.go:828: AddedResumeClientModelIfReasonto atomically inspect the recorded suspension reason and remove the suspension under a single lock only if the reason matches the permitted set.sdk/cliproxy/auth/conductor_cooldown.go:29: DefinedresumableCooldownReasons(includingmodel_not_supported,not_found,quota,invalid_api_key,invalid_grant,unauthorized,payment_required) andcredentialWideCooldownReasons(invalid_api_key).sdk/cliproxy/auth/conductor_cooldown.go:990: UpdatedMarkResultto atomically resume sibling models only for credential-wide reasons (ResumeClientModelIfReason), resume own model for all valid per-model reasons, and overwrite credential-wide suspensions when a specific failure occurs (SuspendClientModelReplacingReasons).Tests
TestResumeClientModelIfReason_RacePreservesNewerSuspension: Pins atomic reason checking in registry, verifying that a newer suspension reason is preserved and not accidentally cleared.TestSuspendClientModelReplacingReasons: Pins reason replacement rules when suspending clients.TestManager_ModelNotSupportedSuspensionResumesOnOwnSuccess: Pins thatmodel_not_supportedsuspensions are cleared upon own-model success.TestManager_ModelSpecificResumableSiblingSuspensionSurvivesSiblingSuccess: Pins that model-specific suspensions (not_found,quota) survive sibling model success.TestManager_CredentialWideSiblingSuspensionResumesOnSiblingSuccess: Pins that credential-wide suspensions (invalid_api_key) resume when a sibling succeeds.TestManager_ModelSpecificFailureOverwritesCredentialWideSuspension: Pins that a model-specific failure replaces a stale credential-wide suspension.Reverse bite-check
Reverting
model_not_supportedfromresumableCooldownReasonsinsdk/cliproxy/auth/conductor_cooldown.gocausesTestManager_ModelNotSupportedSuspensionResumesOnOwnSuccessto fail immediately:Reverting reason verification in
ResumeClientModelIfReason(internal/registry/model_registry.go) so it unconditionally clears suspensions causesTestResumeClientModelIfReason_RacePreservesNewerSuspensionto fail:Verification
TMPDIR=/Users/warelik/.cache/gotmp GOCACHE=/Users/warelik/.cache/gocache go build ./... TMPDIR=/Users/warelik/.cache/gotmp GOCACHE=/Users/warelik/.cache/gocache go vet ./internal/registry/... ./sdk/cliproxy/auth/... gofmt -l internal/registry/model_registry.go internal/registry/model_registry_resume_reason_test.go sdk/cliproxy/auth/conductor_availability_test.go sdk/cliproxy/auth/conductor_cooldown.go TMPDIR=/Users/warelik/.cache/gotmp GOCACHE=/Users/warelik/.cache/gocache go test -v ./internal/registry/... ./sdk/cliproxy/auth/...Output:
Tooling note
The
jbcontextsemantic-search CLI is installed but non-functional in this environment(
jbcontext searchfails withthe OS keychain is not accessible). The equivalentreview passes were performed with the repository's own tooling and manual inspection
instead; this is disclosed for transparency about how the change was reviewed.