From 8db5733d1ca7349f2e73637a0ee01c3ab108c94a Mon Sep 17 00:00:00 2001 From: moe-berri Date: Wed, 30 Sep 2026 11:23:05 -0700 Subject: [PATCH] refactor(roi): isolate outage validation and verify uncached retry --- litellm/proxy/roi_calculator/sync.py | 16 +++++++++------- tests/unit/proxy/roi_calculator/test_sync.py | 10 ++++++++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/litellm/proxy/roi_calculator/sync.py b/litellm/proxy/roi_calculator/sync.py index bd909c9a036..da78a7b3dc2 100644 --- a/litellm/proxy/roi_calculator/sync.py +++ b/litellm/proxy/roi_calculator/sync.py @@ -245,6 +245,14 @@ class _ProcessedPull(NamedTuple): metadata_unavailable: bool = False +def _processed_records(processed: tuple[_ProcessedPull, ...]) -> Mapping[int, ROIPullRecord]: + if processed and all(item.metadata_unavailable for item in processed): + raise SourceError( + "GitHub could not provide PR metadata. No new report was published; try analysis again later." + ) + return MappingProxyType({item.position: item.record for item in processed}) + + class SyncManager: def __init__( self, @@ -479,13 +487,7 @@ class SyncManager: if not worker_task.done(): worker_task.cancel() await asyncio.gather(*workers, return_exceptions=True) - if processed and all(item.metadata_unavailable for item in processed): - raise SourceError( - "GitHub could not provide PR metadata. No new report was published; try analysis again later." - ) - processed_by_index: Final[Mapping[int, ROIPullRecord]] = MappingProxyType( - {item.position: item.record for item in processed} - ) + processed_by_index: Final = _processed_records(processed) report: Final = ROIReport( mode="live", start=start.isoformat(), diff --git a/tests/unit/proxy/roi_calculator/test_sync.py b/tests/unit/proxy/roi_calculator/test_sync.py index 4e827a7d1da..548712ec65c 100644 --- a/tests/unit/proxy/roi_calculator/test_sync.py +++ b/tests/unit/proxy/roi_calculator/test_sync.py @@ -295,12 +295,18 @@ async def test_metadata_outage_keeps_previous_report_and_retries_on_next_run() - assert manager.status.needs_attention == 1 assert manager.status.error is not None and "No new report was published" in manager.status.error assert repository.values["roi_calculator_report"] == previous - assert await manager.start(_settings(), repository, _spend_reader(), _completion(), _transport()) + assert await manager.start( + _settings(estimator_prompt="New prompt invalidates saved estimates"), + repository, + _spend_reader(), + _completion(), + _transport(), + ) await _wait_until_finished(manager) recovered: Final = TypeAdapter(ROIReport).validate_python(repository.values["roi_calculator_report"]) assert recovered["pulls"][0]["estimate"]["status"] == "estimated" assert recovered["pulls"][0]["estimate"]["hours"] == 4 - assert manager.status.reused == 1 + assert manager.status.reused == 0 @pytest.mark.asyncio