"""Incident readback must not regress durable closure to stale cache state.""" from datetime import UTC, datetime from unittest.mock import AsyncMock import pytest from src.api.v1 import incidents as incidents_api from src.models.incident import Incident, IncidentStatus, Severity from src.repositories import incident_repository as incident_repository_module from src.services.incident_service import IncidentService def _incident(status: IncidentStatus, *, minute: int) -> Incident: timestamp = datetime(2026, 7, 11, 11, minute, tzinfo=UTC) return Incident( incident_id="INC-20260711-SOURCE-TRUTH", status=status, severity=Severity.P2, affected_services=["awoooi-api"], created_at=datetime(2026, 7, 11, 10, 0, tzinfo=UTC), updated_at=timestamp, resolved_at=timestamp if status is IncidentStatus.RESOLVED else None, ) @pytest.mark.asyncio async def test_readback_prefers_durable_resolved_incident_over_stale_cache(monkeypatch): service = IncidentService() durable = _incident(IncidentStatus.RESOLVED, minute=38) cached = _incident(IncidentStatus.INVESTIGATING, minute=11) monkeypatch.setattr( service, "get_from_episodic_memory", AsyncMock(return_value=durable), ) working_read = AsyncMock(return_value=cached) monkeypatch.setattr(service, "get_from_working_memory", working_read) result = await service.get_for_readback( durable.incident_id, project_id="awoooi", ) assert result is durable assert result.status is IncidentStatus.RESOLVED working_read.assert_not_awaited() service.get_from_episodic_memory.assert_awaited_once_with( durable.incident_id, project_id="awoooi", ) @pytest.mark.asyncio async def test_readback_falls_back_to_working_memory_when_durable_record_unavailable( monkeypatch, ): service = IncidentService() cached = _incident(IncidentStatus.INVESTIGATING, minute=11) monkeypatch.setattr( service, "get_from_episodic_memory", AsyncMock(return_value=None), ) monkeypatch.setattr( service, "get_from_working_memory", AsyncMock(return_value=cached), ) result = await service.get_for_readback( cached.incident_id, project_id="awoooi", ) assert result is cached @pytest.mark.asyncio async def test_incident_detail_endpoint_uses_durable_readback(monkeypatch): durable = _incident(IncidentStatus.RESOLVED, minute=38) class _Service: get_for_readback = AsyncMock(return_value=durable) service = _Service() monkeypatch.setattr(incidents_api, "get_incident_service", lambda: service) result = await incidents_api.get_incident( durable.incident_id, project_id="awoooi", ) assert result.incident_id == durable.incident_id assert result.status == IncidentStatus.RESOLVED.value service.get_for_readback.assert_awaited_once_with( durable.incident_id, project_id="awoooi", ) @pytest.mark.asyncio async def test_active_incidents_come_from_durable_repository(monkeypatch): service = IncidentService() durable_active = _incident(IncidentStatus.INVESTIGATING, minute=38) class _Repository: get_active = AsyncMock(return_value=[durable_active]) repository = _Repository() monkeypatch.setattr( incident_repository_module, "get_incident_repository", lambda: repository, ) incidents = await service.get_active_incidents(project_id="awoooi") assert incidents == [durable_active] repository.get_active.assert_awaited_once_with(project_id="awoooi")