The badges flagged UI that shipped a while ago, so they no longer tell
anyone anything. Dropped all four render sites: the Settings and Admin
Settings items in the left nav, the UI Settings tab in the admin panel,
and the Submitted MCPs tab.
The NewBadge component stays so the next genuinely new surface can use
it again. BetaBadge and the "hide new badges" account toggle are
untouched, since that toggle still gates BetaBadge.
test_google_login_only_threads_user_code_when_enabled cleared the whole
process environment for the duration of the call. mutmut's trampoline reads
os.environ['MUTANT_UNDER_TEST'] with a bare subscript, so the first
trampolined callee inside the block, _get_cli_sso_flow_or_raise, raised
KeyError. The bare `except Exception: pass` swallowed it and the assertion
then read call_args on a mock that was never called, which is where
"'NoneType' object has no attribute 'kwargs'" came from.
The test only needs the SSO provider variables unset, so it now preserves the
rest of the environment instead of clearing everything. google_login does not
raise here, so the try/except is gone and any future exception propagates; the
added assert turns a silent early return into a readable failure instead of an
AttributeError.
Root cause measured in a trampolined copy of the mutated folder with
MUTANT_UNDER_TEST=stats: the old test fails there with
KeyError: 'MUTANT_UNDER_TEST' inside _mutmut_trampoline, the new one passes.
That was the only test the mutation run could not execute, so the --deselect
comes back out and it counts toward the score again.
When a router-facing model_name alias contains a '/' whose leading segment
is not a registered provider (e.g. 'vertex/claude-opus-5' for deployment
'vertex_ai/claude-opus-5'), _select_model_name_for_cost_calc re-prefixed
it into a non-existent key ('vertex_ai/vertex/claude-opus-5'), so cost
lookup silently priced every streamed request at $0 - token counts were
recorded, no error raised, budgets never tripped.
After prefixing, walk the alias tail and return the first assembly that
exists in litellm.model_cost ('vertex_ai/claude-opus-5'). Provider/region
segments in the head are preserved, and an alias that resolves to no
known key keeps the previous behavior (no crash, legacy double-prefix).
Fixes#38069
With the coverage fix in place the run generates mutants, then dies before
testing any of them: "1 failed ... failed to collect stats. runner returned 1".
The offender is one test. google_login is called inside a bare
`except Exception: pass` and the assertion then reads the mock's call_args, so
an early raise inside mutmut's mutants/ sandbox surfaces as
"'NoneType' object has no attribute 'kwargs'" rather than as the real error.
Deselected rather than ignored, so the other 248 tests in test_ui_sso.py still
contribute to the score.
This is measured rather than guessed. mutmut's stats phase hardcodes -x, so a
failing run only ever names its first offender, which is why deselecting looked
like whack-a-mole before. pytest_add_cli_args is appended after -x, and a later
--maxfail wins, so overriding it once let the whole folder run inside the
sandbox: 1 failed, 2901 passed. That one test is the only one that cannot run
there.
What is still not known is why it raises early in the sandbox. It is not the
suite and not the copied tree: the same folder passes outside mutants/ on the
runner image (2930), passes on a copied tree put first on PYTHONPATH (2902),
and passes with and without the test_saml_sso.py ignore. What is left is
mutmut's trampolines.
The streamed-id regression test built a bare BaseLiteLLMOpenAIResponseObject with a
top-level id, hitting the wrong _encrypt_response_id branch. A real streamed create
emits ResponseCompletedEvent, whose client-visible id lives on event.response.id, so
the test now drives that production event shape and reads collected[0].response.id.
Mutating the alias route gate or disabling the .response.id encryption branch both
fail the test.