litellm/MUTATIONS.md
shrey kharbanda bf60fa3960 test(e2e): cover sail completion_window pricing and service_tier rewrite
Live proxy suites for the sail provider added in #42840: chat with
service_tier flex, balanced and absent bills each window's cost-map
rates read at run time and echoes no service_tier; /v1/responses with
extra_body.metadata.completion_window balanced bills the _balanced
keys; a flex-only sail model refuses the asap and balanced windows
with sail's own 400 and leaves only a zero-spend failure row; openai
keeps its own service_tier and bills the tier it reports back.

MUTATIONS.md records the five production mutations, each killed, and
the final green run. It is review evidence and not meant to merge.
2026-09-24 16:34:59 +00:00

13 KiB

Mutation evidence for the tests/e2e Sail service_tier suites (PR #42840)

Review evidence for branch litellm_sail_tests_e2e, created from tip d7bc17fa47 (merge base 0c1c3e18d5). This file is not meant to merge

Tests on the branch

Test File
TestSailServiceTier::test_chat_prices_each_service_tier_as_its_window_and_echoes_none tests/e2e/llm_translation/test_sail_service_tier_e2e.py
TestSailServiceTier::test_responses_extra_body_completion_window_prices_that_window tests/e2e/llm_translation/test_sail_service_tier_e2e.py
TestSailServiceTier::test_flex_only_model_serves_flex_and_refuses_the_windows_other_tiers_become tests/e2e/llm_translation/test_sail_service_tier_e2e.py
TestSailCompletionWindowPricing::test_each_service_tier_bills_its_windows_cost_map_rates tests/e2e/quota_management/spend_tracking/test_sail_completion_window_pricing_e2e.py
TestSailCompletionWindowPricing::test_responses_completion_window_in_extra_body_bills_balanced_rates tests/e2e/quota_management/spend_tracking/test_sail_completion_window_pricing_e2e.py
TestSailCompletionWindowPricing::test_flex_only_model_refuses_default_tier_and_bills_nothing tests/e2e/quota_management/spend_tracking/test_sail_completion_window_pricing_e2e.py
TestOpenAIKeepsItsOwnServiceTier::test_openai_bills_the_tier_it_reports_and_refuses_balanced_unbilled tests/e2e/quota_management/spend_tracking/test_sail_completion_window_pricing_e2e.py

Shared helpers live in tests/e2e/completion_window_pricing.py (runtime cost-map lookup of the cheapest Sail model that carries base, _balanced and _flex rates, and of the cheapest flex-only Sail model, plus the 1e-9 relative tolerance helper). tests/e2e/models.py gained the six *_balanced and *_flex cost-map fields on CostMapEntry

Harness

Proxy booted per tests/e2e/CONTRIBUTING.md from the repo checkout with LITELLM_LOCAL_MODEL_COST_MAP=True, real Postgres (DATABASE_URL), real Redis, proxy_batch_write_at: 5, and SAIL_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY from the 1Password Shared vault in the proxy environment. Every mutation run was: edit one production file, restart the proxy, run the tests named below with --reruns 0, restore the file, confirm git status is clean under litellm/. No test file was changed between the red and the green run of a mutation. The mutation runs happened before the final refactor that swapped pytest.approx for the typed within_rel / all_within_rel helpers; the assertion messages are identical, only the trailing assert explanation pytest prints differs. The final green run below is on the exact branch contents

At the merge base 0c1c3e18d5 there is no sail provider, so every Sail test fails at /model/new before making a request. The mutations below are the meaningful bar: each one leaves the provider registered and breaks one behaviour the PR introduces

Kill table: 5 killed / 5 applied

Id File Mutation Tests that went red
M1 litellm/llms/openai_like/dynamic_config.py ServiceTier.BALANCED.value: "balanced" -> ServiceTier.BALANCED.value: "flex" test_flex_only_model_serves_flex_and_refuses_the_windows_other_tiers_become
M2 litellm/cost_calculator.py _provider_bills_by_completion_window body -> return False test_responses_extra_body_completion_window_prices_that_window, test_responses_completion_window_in_extra_body_bills_balanced_rates
M3 litellm/litellm_core_utils/llm_cost_calc/utils.py removed ServiceTier.BALANCED.value: ServiceTier.BALANCED.value, from _SERVICE_TIER_TO_COST_KEY_SUFFIX test_chat_prices_each_service_tier_as_its_window_and_echoes_none, test_each_service_tier_bills_its_windows_cost_map_rates
M4 litellm/llms/openai_like/dynamic_config.py "default": "asap" -> "default": "flex" test_flex_only_model_serves_flex_and_refuses_the_windows_other_tiers_become, test_flex_only_model_refuses_default_tier_and_bills_nothing
M5 litellm/cost_calculator.py non-window-provider branch of _service_tier_billed_by_completion_window: return service_tier -> return ServiceTier.FLEX.value test_openai_bills_the_tier_it_reports_and_refuses_balanced_unbilled

Every test on the branch is red under at least one of M1 to M5

M1 balanced window sent as flex

@@ -21,7 +21,7 @@ from .json_loader import SimpleProviderConfig
-        ServiceTier.BALANCED.value: "balanced",
+        ServiceTier.BALANCED.value: "flex",

Run: pytest tests/e2e/llm_translation/test_sail_service_tier_e2e.py tests/e2e/quota_management/spend_tracking/test_sail_completion_window_pricing_e2e.py -k "flex_only or each_service_tier_bills"

Result: 1 failed, 2 passed, 2 deselected in 171.37s

Failing assertion (test_sail_service_tier_e2e.py:217):

AssertionError: expected sail's 400 for service_tier='balanced', got 200: {"id":"resp_01a0d42b-225c-7fb0-8265-71b0f6285c28",...,"model":"sail-flex-6bb4ace67ce7","object":"chat.completion",...,"usage":{"completion_tokens":64,"prompt_tokens":28,"total_tokens":92,...}}
assert 200 == 400

The flex-only Sail model accepts completion_window=flex and refuses balanced; with balanced rewritten to flex the provider served the call instead of refusing it. The two billing tests kept passing under this mutation because balanced and flex both still price through the cost-map suffix path, which is why the flex-only refusal test exists

Restore: git status --short -- litellm/llms/openai_like/dynamic_config.py empty

M2 completion_window billing gate off

@@ -982,7 +982,7 @@ def _provider_bills_by_completion_window(custom_llm_provider: str | None) -> boo
-    return provider is not None and provider.special_handling.get("service_tier_as_completion_window") is True
+    return False

Run: pytest ... -k responses

Result: 2 failed, 5 deselected in 107.53s

Failing assertions:

test_sail_service_tier_e2e.py:177: AssertionError: resp_QeexFiEG... priced 3.96e-06, expected 3.08e-06 from input_tokens=16 output_tokens=14 input_tokens_details=_ResponsesInputDetails(cached_tokens=0) output_tokens_details=_ResponsesOutputDetails(reasoning_tokens=12) at the balanced rates TierRates(input=7e-08, output=1.4e-07, cache_read=2e-08)
test_sail_completion_window_pricing_e2e.py:157: AssertionError: balanced row resp_vHYEtxB9... billed (input, output, cache_read, reasoning, total) (1.8e-06, 8.1e-06, 0.0, 7.74e-06, 9.9e-06), expected (1.4000000000000001e-06, 6.300000000000001e-06, 0.0, 6.020000000000001e-06, 7.7e-06) from prompt_tokens=20 cached_tokens=0 completion_tokens=45 reasoning_tokens=43 at the balanced rates TierRates(input=7e-08, output=1.4e-07, cache_read=2e-08)

Both /v1/responses calls were billed at the base (asap) rates once the gate stopped recognising Sail's completion_window

Restore: the mutate script's own restore step tripped on its text-match guard, so the line was restored by hand and git status --short -- litellm/cost_calculator.py confirmed empty before the next run

M3 balanced cost suffix dropped

@@ -69,7 +69,6 @@ _SERVICE_TIER_SUFFIXES: Final[tuple[str, ...]] = tuple(
-        ServiceTier.BALANCED.value: ServiceTier.BALANCED.value,

Run: pytest ... -k "each_service_tier or chat_prices_each"

Result: 2 failed in 130.02s

Failing assertions:

test_sail_service_tier_e2e.py:146: AssertionError: x-litellm-response-cost per tier {'flex': 4.78e-06, 'balanced': 7.92e-06, None: 8.64e-06} != each window's rates times its usage {'flex': 4.78e-06, 'balanced': 6.16e-06, None: 8.64e-06} (rates WindowPricedModel(model='sail/deepseek-ai/DeepSeek-V4-Flash-0731', asap=TierRates(input=9e-08, output=1.8e-07, cache_read=2e-08), balanced=TierRates(input=7e-08, output=1.4e-07, cache_read=2e-08), flex=TierRates(input=5e-08, output=9e-08, cache_read=1e-08)))
test_sail_completion_window_pricing_e2e.py:157: AssertionError: balanced row resp_01a0d432-5695-7a4b-93d6-1aaf5f91188f billed (input, output, cache_read, reasoning, total) (1.62e-06, 9.36e-06, 0.0, 9e-06, 1.098e-05), expected (1.26e-06, 7.280000000000001e-06, 0.0, 7.000000000000001e-06, 8.540000000000001e-06) from prompt_tokens=18 cached_tokens=0 completion_tokens=52 reasoning_tokens=50 at the balanced rates TierRates(input=7e-08, output=1.4e-07, cache_read=2e-08)

Balanced chat calls fell back to base rates; flex and absent stayed correct, so exactly the balanced cell moved

Restore: restored by hand after the script's guard tripped, git status clean under litellm/

M4 default tier sent as flex

@@ -23,7 +23,7 @@ _SERVICE_TIER_TO_COMPLETION_WINDOW: Final[Mapping[str, str]] = MappingProxyType(
-        "default": "asap",
+        "default": "flex",

Run: pytest ... -k flex_only

Result: 2 failed in 160.92s

Failing assertions:

test_sail_service_tier_e2e.py:217: AssertionError: expected sail's 400 for service_tier='default', got 200: {"id":"resp_01a0d435-10b7-75b2-9bdf-7512013c8494",...,"model":"sail-flex-e9a7dbaa3bc9",...}
assert 200 == 400
test_sail_completion_window_pricing_e2e.py:292: AssertionError: expected the provider's 400, got 200: {"id":"resp_01a0d436-865b-774b-a4fe-b08fe6e2e592",...,"model":"sail-flexonly-656400d84243",...}
assert 200 == 400

Restore: git status --short -- litellm/llms/openai_like/dynamic_config.py empty

M5 window billing hook leaks flex onto other providers

@@ -999,7 +999,7 @@ def _service_tier_billed_by_completion_window(
-        return service_tier
+        return ServiceTier.FLEX.value

Run: pytest tests/e2e/quota_management/spend_tracking/test_sail_completion_window_pricing_e2e.py -k openai

Result: 1 failed in 88.49s

Failing assertion:

test_sail_completion_window_pricing_e2e.py:157: AssertionError: openai default row chatcmpl-ERgTzeELuKMNg9PbdAIuPhXmJDUBO billed (input, output, cache_read, reasoning, total) (4.75e-05, 0.000255, 0.0, 0.000105, 0.00030250000000000003), expected (9.5e-05, 0.00051, 0.0, 0.00021, 0.0006050000000000001) from prompt_tokens=19 cached_tokens=0 completion_tokens=17 reasoning_tokens=7 at the openai default rates TierRates(input=5e-06, output=3e-05, cache_read=5e-07)

The untiered OpenAI row was priced at OpenAI's _flex cost-map rates and its cost_breakdown.service_tier read flex, so the Sail-only hook had leaked into every provider's billing. The Sail tests all stay green under M5, which is the point of keeping the OpenAI test

Restore: git status --short -- litellm/cost_calculator.py empty

Final green run at the tip, production code unmutated

git status --short -- litellm/ empty, proxy restarted, then

LITELLM_PROXY_URL=http://localhost:4000 LITELLM_MASTER_KEY=sk-1234 .venv/bin/python -m pytest tests/e2e/llm_translation/test_sail_service_tier_e2e.py tests/e2e/quota_management/spend_tracking/test_sail_completion_window_pricing_e2e.py --reruns 0 -p no:cacheprovider -v -rA --tb=short
PASSED tests/e2e/llm_translation/test_sail_service_tier_e2e.py::TestSailServiceTier::test_chat_prices_each_service_tier_as_its_window_and_echoes_none
PASSED tests/e2e/llm_translation/test_sail_service_tier_e2e.py::TestSailServiceTier::test_responses_extra_body_completion_window_prices_that_window
PASSED tests/e2e/llm_translation/test_sail_service_tier_e2e.py::TestSailServiceTier::test_flex_only_model_serves_flex_and_refuses_the_windows_other_tiers_become
PASSED tests/e2e/quota_management/spend_tracking/test_sail_completion_window_pricing_e2e.py::TestSailCompletionWindowPricing::test_each_service_tier_bills_its_windows_cost_map_rates
PASSED tests/e2e/quota_management/spend_tracking/test_sail_completion_window_pricing_e2e.py::TestSailCompletionWindowPricing::test_responses_completion_window_in_extra_body_bills_balanced_rates
PASSED tests/e2e/quota_management/spend_tracking/test_sail_completion_window_pricing_e2e.py::TestSailCompletionWindowPricing::test_flex_only_model_refuses_default_tier_and_bills_nothing
PASSED tests/e2e/quota_management/spend_tracking/test_sail_completion_window_pricing_e2e.py::TestOpenAIKeepsItsOwnServiceTier::test_openai_bills_the_tier_it_reports_and_refuses_balanced_unbilled
======================== 7 passed in 264.95s (0:04:24) =========================

Cells the live providers would not let the tests prove

OpenAI service_tier: balanced with the latest openai/gpt-5.5 row on the account behind the vault key is refused by OpenAI itself: Invalid value: 'balanced'. Supported values are: 'auto', 'default', 'fast', 'flex', and 'priority'. The test therefore proves the tier is forwarded untouched (OpenAI's own 400 comes back, with a zero-spend failure row and no cost_breakdown) and that the untiered call is billed at the tier OpenAI reports back. The requested cell "openai balanced bills the same as no tier" is UNVERIFIED: no OpenAI model on this account accepts balanced

Anthropic service_tier: balanced versus no tier is UNVERIFIED: every request through the vault's Anthropic key fails with Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits., so no Anthropic test is on the branch rather than a test that skips or passes vacuously

Sail /v1/responses returns metadata.completion_window: "standard" alongside supercache_* fields even when the request carried balanced, so the tests do not pin Sail's echoed metadata (a vendor fact) and assert the balanced billing instead, which M2 shows is driven by the requested window