from __future__ import annotations from datetime import datetime, timezone from typing import Any from uuid import UUID import pytest from fastapi import FastAPI from fastapi.testclient import TestClient from src.api.v1.ai_slo import router from src.models.approval import ApprovalRequest, ApprovalStatus, DataImpact, RiskLevel from src.models.incident import Incident, IncidentStatus, Severity, Signal from src.models.playbook import ( ActionType, Playbook, RepairStep, RiskLevel as PlaybookRiskLevel, ) from src.services.adr100_remediation_service import ( Adr100RemediationService, RemediationNotFoundError, ) from src.services.auto_repair_service import AutoRepairService class _FakeSloService: def __init__(self, items: list[dict[str, Any]]) -> None: self.items = items async def fetch_report(self) -> dict[str, Any]: return { "verification_coverage": { "remediation_queue": { "items": self.items, }, }, } class _FakeIncidentRepository: def __init__(self, incident: Incident | None) -> None: self.incident = incident async def get_by_id(self, incident_id: str) -> Incident | None: if self.incident and self.incident.incident_id == incident_id: return self.incident return None class _FakeVerifier: def __init__(self, state: dict[str, Any]) -> None: self.state = state self.calls = 0 async def _collect_post_state(self, incident: Incident) -> dict[str, Any]: self.calls += 1 return self.state class _FakeAlertOperationLogRepository: def __init__(self) -> None: self.calls: list[dict[str, Any]] = [] self.records: list[Any] = [] async def append(self, event_type: str, **kwargs: Any): self.calls.append({"event_type": event_type, **kwargs}) record = type( "AlertOperationRecord", (), { "id": f"aol-{len(self.records) + 1}", "incident_id": kwargs.get("incident_id"), "auto_repair_id": kwargs.get("auto_repair_id"), "event_type": event_type, "actor": kwargs.get("actor"), "success": kwargs.get("success"), "context": kwargs.get("context") or {}, "created_at": datetime(2026, 5, 14, 14, 45, len(self.records), tzinfo=timezone.utc), }, )() self.records.append(record) return record async def list_recent( self, limit: int = 50, offset: int = 0, event_type: str | None = None, incident_id: str | None = None, ): rows = [ record for record in self.records if (event_type is None or record.event_type == event_type) and (incident_id is None or record.incident_id == incident_id) ] rows = sorted(rows, key=lambda record: record.created_at, reverse=True) return rows[offset:offset + limit], len(rows) class _FakeTimelineService: def __init__(self) -> None: self.calls: list[dict[str, Any]] = [] async def add_event(self, **kwargs: Any) -> dict[str, Any]: self.calls.append(kwargs) return {"id": "timeline-1"} class _FakeApprovalService: def __init__(self) -> None: self.requests: list[Any] = [] self.fingerprints: list[str] = [] self.existing: ApprovalRequest | None = None async def create_approval(self, request: Any) -> ApprovalRequest: return await self.create_approval_with_fingerprint(request, "") async def create_approval_with_fingerprint( self, request: Any, fingerprint: str, ) -> ApprovalRequest: self.requests.append(request) self.fingerprints.append(fingerprint) return ApprovalRequest( id=UUID("00000000-0000-0000-0000-00000000a100"), action=request.action, description=request.description, status=ApprovalStatus.PENDING, risk_level=request.risk_level, blast_radius=request.blast_radius, dry_run_checks=request.dry_run_checks, required_signatures=1, signatures=[], requested_by=request.requested_by, expires_at=request.expires_at, metadata=request.metadata, incident_id=request.incident_id, matched_playbook_id=request.matched_playbook_id, ) async def find_by_fingerprint(self, fingerprint: str) -> ApprovalRequest | None: self.fingerprints.append(f"lookup:{fingerprint}") return self.existing class _FakeAwoooPApprovalProjector: def __init__(self) -> None: self.calls: list[dict[str, Any]] = [] async def project_runtime_replay_approval( self, *, item: dict[str, Any], incident: Incident, request: Any, payload: dict[str, Any], ) -> dict[str, Any]: self.calls.append({ "item": item, "incident": incident, "request": request, "payload": payload, }) return { "schema_version": "adr100_runtime_replay_awooop_projection_v1", "projected": True, "inserted": True, "deduplicated": False, "projection_mode": "approval_projection_only", "run_id": "11111111-1111-5111-8111-111111111111", "project_id": "awoooi", "state": "waiting_approval", "trigger_type": "adr100_runtime_replay_gate5", "trigger_ref": "adr100_gate5:INC-20260514-TEST01:00000000-0000-0000-0000-00000000a100", "decision_endpoint_enabled": False, "execution_authorized": False, "repair_attempted": False, "repair_executed": False, "step_journal": { "step_seq": 1, "result_status": "pending", "was_blocked": True, "block_reason": "approval_projection_only", }, } class _NoopPlaybookService: async def get_recommendations(self, *_args, **_kwargs): # noqa: ANN002, ANN003 return [] async def get_by_id(self, _playbook_id: str) -> Playbook | None: return None async def record_execution(self, _playbook_id: str, _success: bool) -> bool: return True class _FakePlaybookService(_NoopPlaybookService): def __init__(self, playbook: Playbook | None) -> None: self.playbook = playbook async def get_by_id(self, playbook_id: str) -> Playbook | None: if self.playbook and self.playbook.playbook_id == playbook_id: return self.playbook return None async def _no_cooldown(*_args, **_kwargs) -> tuple[bool, str]: # noqa: ANN002, ANN003 return True, "test" def _incident() -> Incident: now = datetime.now(timezone.utc) return Incident( incident_id="INC-20260514-TEST01", status=IncidentStatus.INVESTIGATING, severity=Severity.P2, affected_services=["momo-scheduler"], alert_category="infrastructure", signals=[ Signal( alert_name="DockerContainerMemoryLimitPressure", severity=Severity.P2, source="prometheus", fired_at=now, labels={ "alertname": "DockerContainerMemoryLimitPressure", "host": "110", "container_name": "momo-scheduler", }, ), ], ) def _queue_item(**overrides: Any) -> dict[str, Any]: item = { "work_item_id": "verification:INC-20260514-TEST01:are-1", "incident_id": "INC-20260514-TEST01", "auto_repair_id": "are-1", "alertname": "DockerContainerMemoryLimitPressure", "playbook_id": "PB-1", "verification_result": "degraded", "remediation_status": "ready_for_replay", "remediation_action": "replay_with_supported_executor", "remediation_owner": "auto_repair_executor", } item.update(overrides) return item def _service( *, item: dict[str, Any], incident: Incident | None = None, state: dict[str, Any] | None = None, playbook_service: Any | None = None, approval_service: Any | None = None, awooop_approval_projector: Any | None = None, timeline_service: Any | None = None, alert_operation_log_repository: Any | None = None, record_history: bool = False, ) -> Adr100RemediationService: return Adr100RemediationService( slo_service=_FakeSloService([item]), incident_repository=_FakeIncidentRepository(incident or _incident()), auto_repair_service=AutoRepairService( playbook_service=_NoopPlaybookService(), cooldown_checker=_no_cooldown, ), playbook_service=playbook_service, verifier=_FakeVerifier(state or {"k8s_get_pod_status": {"phase": "Running"}}), approval_service=approval_service, awooop_approval_projector=awooop_approval_projector, timeline_service=timeline_service, alert_operation_log_repository=alert_operation_log_repository, record_history=record_history, ) def _runtime_replay_playbook() -> Playbook: return Playbook( playbook_id="PB-1", name="Docker container restart", description="Replay Docker restart through governed MCP write route.", repair_steps=[ RepairStep( step_number=1, action_type=ActionType.SSH_COMMAND, command="ssh {host} 'docker restart {container}'", expected_result="container restarted", requires_approval=False, risk_level=PlaybookRiskLevel.MEDIUM, ) ], ) @pytest.mark.asyncio async def test_preview_marks_replay_work_item_read_only(): svc = _service(item=_queue_item()) result = await svc.preview("verification:INC-20260514-TEST01:are-1") assert result["allowed"] is True assert result["mode"] == "replay" assert result["safety_level"] == "read_only" assert result["writes_incident_state"] is False assert result["plan"]["agent_id"] == "auto_repair_executor" assert result["plan"]["writes"] == [] @pytest.mark.asyncio async def test_preview_marks_observe_only_work_item_as_ticket_proposal(): item = _queue_item( remediation_status="needs_playbook_ticket", remediation_action="promote_diagnostic_to_repair_playbook", remediation_owner="solver_or_operator", failure_class="observe_only_playbook", ) svc = _service(item=item) result = await svc.preview("verification:INC-20260514-TEST01:are-1") assert result["allowed"] is True assert result["mode"] == "ticket" assert result["writes_incident_state"] is False assert result["writes_auto_repair_result"] is False assert result["plan"]["agent_id"] == "openclaw_playbook_planner" assert result["plan"]["required_scope"] == "record_only" assert result["plan"]["target_action"] == "promote_diagnostic_to_repair_playbook" @pytest.mark.asyncio async def test_dry_run_ticket_proposal_records_internal_history_only(): alert_repo = _FakeAlertOperationLogRepository() timeline = _FakeTimelineService() item = _queue_item( remediation_status="needs_playbook_ticket", remediation_action="promote_diagnostic_to_repair_playbook", remediation_owner="solver_or_operator", failure_class="observe_only_playbook", ) svc = _service( item=item, timeline_service=timeline, alert_operation_log_repository=alert_repo, record_history=True, ) result = await svc.dry_run("verification:INC-20260514-TEST01:are-1") assert result["allowed"] is True assert result["executed"] is True assert result["mode"] == "ticket" assert result["verification_result_preview"] == "ticket_proposal" assert result["writes_ticket"] is False assert result["creates_external_ticket"] is False assert result["ticket_preview"]["would_create"] is True assert result["ticket_preview"]["external_ticket_created"] is False assert result["ticket_preview"]["playbook_id"] == "PB-1" assert "momo-scheduler" in result["ticket_preview"]["target"] assert result["history"]["recorded"] is True assert alert_repo.calls[0]["event_type"] == "PRE_FLIGHT_PASSED" assert alert_repo.calls[0]["context"]["ticket_preview"]["next_step"] == ( "author_mutating_repair_step" ) assert alert_repo.calls[0]["context"]["creates_external_ticket"] is False assert timeline.calls[0]["actor_role"] == "ticket" @pytest.mark.asyncio async def test_create_approval_request_is_record_only_and_does_not_authorize_repair(): alert_repo = _FakeAlertOperationLogRepository() timeline = _FakeTimelineService() approval_service = _FakeApprovalService() item = _queue_item( remediation_status="needs_playbook_ticket", remediation_action="promote_diagnostic_to_repair_playbook", remediation_owner="solver_or_operator", failure_class="observe_only_playbook", ) svc = _service( item=item, approval_service=approval_service, timeline_service=timeline, alert_operation_log_repository=alert_repo, record_history=True, ) result = await svc.create_approval_request("verification:INC-20260514-TEST01:are-1") assert result["schema_version"] == "adr100_remediation_approval_v1" assert result["allowed"] is True assert result["mode"] == "approval" assert result["writes_approval_record"] is True assert result["deduplicated"] is False assert len(result["fingerprint"]) == 64 assert result["writes_incident_state"] is False assert result["writes_auto_repair_result"] is False assert result["approval_id"] == "00000000-0000-0000-0000-00000000a100" assert result["approval"]["status"] == "pending" assert result["approval"]["risk_level"] == "medium" assert result["plan"]["required_scope"] == "record_only" assert result["history"]["recorded"] is True assert approval_service.requests[0].risk_level == RiskLevel.MEDIUM assert approval_service.requests[0].metadata["approval_kind"] == "adr100_playbook_authoring" assert approval_service.requests[0].metadata["execution_authorized"] is False assert approval_service.requests[0].metadata["repair_executed"] is False assert approval_service.fingerprints[0].startswith("lookup:") assert len(approval_service.fingerprints[0].removeprefix("lookup:")) == 64 assert len(approval_service.fingerprints[1]) == 64 assert alert_repo.calls[0]["event_type"] == "APPROVAL_ESCALATED" assert alert_repo.calls[0]["approval_id"] == "00000000-0000-0000-0000-00000000a100" assert alert_repo.calls[0]["context"]["writes_approval_record"] is True assert timeline.calls[0]["actor_role"] == "approval" @pytest.mark.asyncio async def test_create_approval_request_deduplicates_existing_pending_approval(): approval_service = _FakeApprovalService() approval_service.existing = ApprovalRequest( id=UUID("00000000-0000-0000-0000-00000000a101"), action="PLAYBOOK_AUTHORING_RECORD_ONLY: existing", description="existing", status=ApprovalStatus.PENDING, risk_level=RiskLevel.MEDIUM, required_signatures=1, requested_by="adr100_remediation_service", metadata={"approval_kind": "adr100_playbook_authoring"}, incident_id="INC-20260514-TEST01", matched_playbook_id="PB-1", ) item = _queue_item( remediation_status="needs_playbook_ticket", remediation_action="promote_diagnostic_to_repair_playbook", failure_class="observe_only_playbook", ) svc = _service(item=item, approval_service=approval_service) result = await svc.create_approval_request("verification:INC-20260514-TEST01:are-1") assert result["approval_id"] == "00000000-0000-0000-0000-00000000a101" assert result["writes_approval_record"] is False assert result["deduplicated"] is True assert approval_service.requests == [] @pytest.mark.asyncio async def test_create_approval_request_for_runtime_replay_creates_gate5_record_only(): alert_repo = _FakeAlertOperationLogRepository() timeline = _FakeTimelineService() approval_service = _FakeApprovalService() awooop_projector = _FakeAwoooPApprovalProjector() svc = _service( item=_queue_item(), playbook_service=_FakePlaybookService(_runtime_replay_playbook()), approval_service=approval_service, awooop_approval_projector=awooop_projector, timeline_service=timeline, alert_operation_log_repository=alert_repo, record_history=True, ) result = await svc.create_approval_request("verification:INC-20260514-TEST01:are-1") assert result["schema_version"] == "adr100_remediation_approval_v1" assert result["allowed"] is True assert result["mode"] == "approval" assert result["approval_kind"] == "adr100_runtime_replay_gate5" assert result["verification_result_preview"] == "runtime_replay_approval_requested" assert result["writes_approval_record"] is True assert result["writes_incident_state"] is False assert result["writes_auto_repair_result"] is False assert result["replay_gate"]["status"] == "runtime_replay_ready" assert result["replay_gate"]["repair_executed"] is False assert result["awooop_projection"]["projected"] is True assert result["awooop_projection"]["projection_mode"] == "approval_projection_only" assert result["awooop_projection"]["state"] == "waiting_approval" assert result["awooop_projection"]["decision_endpoint_enabled"] is False assert result["awooop_projection"]["execution_authorized"] is False assert result["awooop_projection"]["repair_executed"] is False assert result["approval"]["status"] == "pending" assert result["plan"]["step"] == "request_runtime_replay_gate5_approval" assert awooop_projector.calls[0]["payload"]["approval_kind"] == ( "adr100_runtime_replay_gate5" ) request = approval_service.requests[0] assert request.action.startswith("RUNTIME_REPLAY_GATE5:") assert request.blast_radius.data_impact == DataImpact.WRITE assert request.metadata["approval_kind"] == "adr100_runtime_replay_gate5" assert request.metadata["execution_authorized"] is False assert request.metadata["repair_attempted"] is False assert request.metadata["repair_executed"] is False assert request.metadata["required_scope"] == "write_after_approval" assert request.metadata["mcp_gate"] == "gate5_required" assert request.metadata["write_routes"][0]["tool_name"] == "ssh_docker_restart" assert request.metadata["write_routes"][0]["required_scope"] == "write" assert request.metadata["replay_gate"]["status"] == "runtime_replay_ready" assert alert_repo.calls[0]["event_type"] == "APPROVAL_ESCALATED" assert alert_repo.calls[0]["action_detail"] == ( "adr100_runtime_replay_gate5_approval_requested" ) assert alert_repo.calls[0]["context"]["approval_kind"] == "adr100_runtime_replay_gate5" assert alert_repo.calls[0]["context"]["replay_gate"]["status"] == "runtime_replay_ready" assert alert_repo.calls[0]["context"]["awooop_projection"]["state"] == "waiting_approval" assert timeline.calls[0]["title"] == "ADR-100 runtime replay Gate 5 approval requested" @pytest.mark.asyncio async def test_create_approval_request_blocks_runtime_replay_when_gate_not_ready(): approval_service = _FakeApprovalService() alert_repo = _FakeAlertOperationLogRepository() awooop_projector = _FakeAwoooPApprovalProjector() svc = _service( item=_queue_item(), playbook_service=_FakePlaybookService(None), approval_service=approval_service, awooop_approval_projector=awooop_projector, alert_operation_log_repository=alert_repo, record_history=True, ) result = await svc.create_approval_request("verification:INC-20260514-TEST01:are-1") assert result["allowed"] is False assert result["writes_approval_record"] is False assert result["approval_id"] is None assert result["verification_result_preview"] == "runtime_replay_gate_blocked" assert result["replay_gate"]["status"] == "blocked_playbook_not_found" assert approval_service.requests == [] assert awooop_projector.calls == [] assert alert_repo.calls[0]["event_type"] == "PRE_FLIGHT_FAILED" assert alert_repo.calls[0]["context"]["replay_gate"]["status"] == ( "blocked_playbook_not_found" ) @pytest.mark.asyncio async def test_dry_run_reverify_collects_state_without_writes(): item = _queue_item( remediation_status="ready_for_reverify", remediation_action="reverify_with_promql_template", remediation_owner="post_execution_verifier", ) svc = _service(item=item, state={"k8s_get_pod_status": {"phase": "Running"}}) result = await svc.dry_run("verification:INC-20260514-TEST01:are-1") assert result["allowed"] is True assert result["executed"] is True assert result["mode"] == "reverify" assert result["verification_result_preview"] == "success" assert result["writes_auto_repair_result"] is False assert result["post_state_summary"]["tool_count"] == 1 assert result["mcp_route"]["agent_id"] == "post_execution_verifier" assert result["mcp_route"]["required_scope"] == "read" assert result["history"]["recorded"] is False @pytest.mark.asyncio async def test_dry_run_replay_validates_supported_executor_route(): svc = _service(item=_queue_item()) result = await svc.dry_run("verification:INC-20260514-TEST01:are-1") assert result["allowed"] is True assert result["mode"] == "replay" assert result["mcp_route"]["agent_id"] == "auto_repair_executor" assert result["mcp_route"]["tool_name"] == "ssh_diagnose" assert result["mcp_route"]["required_scope"] == "read" assert result["mcp_route"]["params"]["host"] == "192.168.0.110" assert result["mcp_route"]["params"]["container_name"] == "momo-scheduler" assert result["diagnostic_command_preview"].startswith("ssh 110") assert result["replay_gate"]["status"] == "blocked_playbook_not_found" assert result["replay_gate"]["can_runtime_replay"] is False @pytest.mark.asyncio async def test_dry_run_replay_surfaces_runtime_write_gate_without_executing(): alert_repo = _FakeAlertOperationLogRepository() svc = _service( item=_queue_item(), playbook_service=_FakePlaybookService(_runtime_replay_playbook()), alert_operation_log_repository=alert_repo, record_history=True, ) result = await svc.dry_run("verification:INC-20260514-TEST01:are-1") assert result["allowed"] is True assert result["mode"] == "replay" assert result["writes_incident_state"] is False assert result["writes_auto_repair_result"] is False gate = result["replay_gate"] assert gate["schema_version"] == "adr100_replay_gate_v1" assert gate["status"] == "runtime_replay_ready" assert gate["can_runtime_replay"] is True assert gate["execution_authorized"] is False assert gate["repair_executed"] is False assert gate["mutating_step_count"] == 1 assert gate["supported_write_route_count"] == 1 assert gate["unsupported_step_count"] == 0 assert gate["next_step"] == "queue_runtime_replay_with_gate5_projection" assert gate["steps"][0]["write_route"]["tool_name"] == "ssh_docker_restart" assert gate["steps"][0]["write_route"]["required_scope"] == "write" assert gate["steps"][0]["write_route"]["params"]["host"] == "192.168.0.110" assert gate["steps"][0]["write_route"]["params"]["container_name"] == "momo-scheduler" assert alert_repo.calls[0]["context"]["replay_gate"]["status"] == "runtime_replay_ready" @pytest.mark.asyncio async def test_dry_run_blocks_when_incident_missing(): svc = _service(item=_queue_item(), incident=None) svc._incident_repository = _FakeIncidentRepository(None) result = await svc.dry_run("verification:INC-20260514-TEST01:are-1") assert result["allowed"] is False assert result["executed"] is False assert result["verification_result_preview"] == "blocked" assert any(check["name"] == "incident_loaded" and not check["passed"] for check in result["checks"]) @pytest.mark.asyncio async def test_dry_run_records_alert_operation_and_timeline_history(): alert_repo = _FakeAlertOperationLogRepository() timeline = _FakeTimelineService() svc = _service( item=_queue_item(), timeline_service=timeline, alert_operation_log_repository=alert_repo, record_history=True, ) result = await svc.dry_run("verification:INC-20260514-TEST01:are-1") assert result["history"] == { "recorded": True, "alert_operation_id": "aol-1", "timeline_event_id": "timeline-1", } assert alert_repo.calls[0]["event_type"] == "PRE_FLIGHT_PASSED" assert alert_repo.calls[0]["incident_id"] == "INC-20260514-TEST01" assert alert_repo.calls[0]["success"] is True assert alert_repo.calls[0]["context"]["schema_version"] == ( "adr100_remediation_dry_run_history_v1" ) assert alert_repo.calls[0]["context"]["writes_incident_state"] is False assert timeline.calls[0]["event_type"] == "verifier" assert timeline.calls[0]["status"] == "success" assert timeline.calls[0]["actor_role"] == "replay" @pytest.mark.asyncio async def test_history_lists_dry_run_records_grouped_by_work_item(): alert_repo = _FakeAlertOperationLogRepository() svc = _service( item=_queue_item(), alert_operation_log_repository=alert_repo, record_history=True, ) await svc.dry_run("verification:INC-20260514-TEST01:are-1") history = await svc.history(limit=10) assert history["schema_version"] == "adr100_remediation_history_v1" assert history["total"] == 1 assert history["items"][0]["work_item_id"] == "verification:INC-20260514-TEST01:are-1" assert history["items"][0]["agent_id"] == "auto_repair_executor" assert history["items"][0]["tool_name"] == "ssh_diagnose" assert history["items"][0]["required_scope"] == "read" assert history["items"][0]["writes_incident_state"] is False assert history["by_work_item"][0]["count"] == 1 assert history["by_work_item"][0]["latest_tool_name"] == "ssh_diagnose" @pytest.mark.asyncio async def test_missing_work_item_raises_not_found(): svc = _service(item=_queue_item()) with pytest.raises(RemediationNotFoundError): await svc.preview("verification:missing") def test_ai_slo_remediation_endpoints(monkeypatch): app = FastAPI() app.include_router(router, prefix="/api/v1") class _FakeService: async def preview(self, work_item_id: str, mode: str = "auto") -> dict[str, Any]: return {"work_item_id": work_item_id, "mode": mode, "allowed": True} async def dry_run(self, work_item_id: str, mode: str = "auto") -> dict[str, Any]: return {"work_item_id": work_item_id, "mode": mode, "executed": True} async def create_approval_request( self, work_item_id: str, mode: str = "approval", ) -> dict[str, Any]: return { "schema_version": "adr100_remediation_approval_v1", "work_item_id": work_item_id, "mode": mode, "approval_id": "approval-1", } async def history( self, *, limit: int = 50, incident_id: str | None = None, work_item_id: str | None = None, ) -> dict[str, Any]: return { "schema_version": "adr100_remediation_history_v1", "limit": limit, "filters": { "incident_id": incident_id, "work_item_id": work_item_id, }, "items": [], "by_work_item": [], } monkeypatch.setattr( "src.api.v1.ai_slo.get_adr100_remediation_service", lambda: _FakeService(), ) client = TestClient(app) preview = client.get( "/api/v1/ai/slo/remediation/preview", params={"work_item_id": "verification:INC:are-1", "mode": "reverify"}, ) dry_run = client.post( "/api/v1/ai/slo/remediation/dry-run", json={"work_item_id": "verification:INC:are-1", "mode": "replay"}, ) history = client.get( "/api/v1/ai/slo/remediation/history", params={"limit": 10, "work_item_id": "verification:INC:are-1"}, ) approval = client.post( "/api/v1/ai/slo/remediation/approval-request", json={"work_item_id": "verification:INC:are-1", "mode": "approval"}, ) assert preview.status_code == 200 assert preview.json()["mode"] == "reverify" assert dry_run.status_code == 200 assert dry_run.json()["executed"] is True assert approval.status_code == 200 assert approval.json()["approval_id"] == "approval-1" assert history.status_code == 200 assert history.json()["schema_version"] == "adr100_remediation_history_v1" assert history.json()["filters"]["work_item_id"] == "verification:INC:are-1"