feat(awooop): record source correlation review decisions
This commit is contained in:
@@ -15,6 +15,7 @@ from src.services.channel_event_dossier_service import (
|
||||
build_recurrence_work_item_dry_run,
|
||||
build_recurrence_work_item_handoff,
|
||||
build_recurrence_work_item_preview,
|
||||
build_source_correlation_review_decision,
|
||||
fetch_channel_event_dossier,
|
||||
fetch_channel_event_dossier_coverage,
|
||||
fetch_channel_event_dossier_recurrence,
|
||||
@@ -268,6 +269,7 @@ def test_build_dossier_recurrence_groups_events_and_run_state() -> None:
|
||||
assert recurrence["summary"]["automation_gap_group_total"] == 0
|
||||
assert recurrence["summary"]["failed_repair_group_total"] == 1
|
||||
assert recurrence["summary"]["source_correlation_review_group_total"] == 1
|
||||
assert recurrence["summary"]["source_correlation_decision_recorded_group_total"] == 0
|
||||
|
||||
host_group = recurrence["items"][0]
|
||||
assert host_group["recurrence_key"] == "fingerprint:fp-host-disk"
|
||||
@@ -287,6 +289,7 @@ def test_build_dossier_recurrence_groups_events_and_run_state() -> None:
|
||||
"schema_version": "awooop_recurrence_work_item_link_v1",
|
||||
"work_item_id": "verification:INC-20260513-ABCD:repair-1",
|
||||
"incident_id": "INC-20260513-ABCD",
|
||||
"matched_incident_id": None,
|
||||
"auto_repair_id": "repair-1",
|
||||
"status": "open",
|
||||
"kind": "verification",
|
||||
@@ -304,6 +307,7 @@ def test_build_dossier_recurrence_groups_events_and_run_state() -> None:
|
||||
"schema_version": "awooop_recurrence_work_item_link_v1",
|
||||
"work_item_id": "source-evidence:sentry:received:issue-1",
|
||||
"incident_id": None,
|
||||
"matched_incident_id": None,
|
||||
"auto_repair_id": None,
|
||||
"status": "open",
|
||||
"kind": "source_correlation_review",
|
||||
@@ -355,6 +359,7 @@ def test_build_recurrence_work_item_preview_allows_source_correlation_review() -
|
||||
item = recurrence["items"][0]
|
||||
work_item_id = "source-evidence:signoz:upstream_canary:canary-1"
|
||||
assert recurrence["summary"]["source_correlation_review_group_total"] == 1
|
||||
assert recurrence["summary"]["source_correlation_decision_recorded_group_total"] == 0
|
||||
assert recurrence["summary"]["open_work_item_group_total"] == 1
|
||||
assert item["latest_stage"] == "upstream_canary"
|
||||
assert item["repair_summary"]["status"] == "source_correlation_review"
|
||||
@@ -386,6 +391,124 @@ def test_build_recurrence_work_item_preview_allows_source_correlation_review() -
|
||||
)
|
||||
|
||||
|
||||
def test_source_correlation_review_decision_records_accepted_audit_contract() -> None:
|
||||
recurrence = build_dossier_recurrence(
|
||||
[
|
||||
{
|
||||
"event_id": "event-1",
|
||||
"project_id": "awoooi",
|
||||
"channel_type": "internal",
|
||||
"provider_event_id": "sentry:received:issue-1",
|
||||
"content_hash": "a" * 64,
|
||||
"content_preview": "Sentry issue",
|
||||
"content_redacted": "Sentry issue",
|
||||
"redaction_version": "audit_sink_v1",
|
||||
"source_envelope": {
|
||||
"provider": "sentry",
|
||||
"stage": "received",
|
||||
"source_refs": {
|
||||
"sentry_issue_ids": ["issue-1"],
|
||||
"alert_ids": ["sentry:received:issue-1"],
|
||||
},
|
||||
"log_correlation": {
|
||||
"alertname": "Sentry Issue",
|
||||
"severity": "error",
|
||||
"namespace": "awoooi-prod",
|
||||
"target_resource": "web",
|
||||
"fingerprint": "fp-sentry-issue-1",
|
||||
},
|
||||
},
|
||||
"is_duplicate": False,
|
||||
"provider_ts": None,
|
||||
"received_at": "2026-05-20T13:10:00",
|
||||
"run_id": None,
|
||||
"run_state": None,
|
||||
"run_agent_id": None,
|
||||
}
|
||||
],
|
||||
project_id="awoooi",
|
||||
limit=20,
|
||||
)
|
||||
|
||||
decision = build_source_correlation_review_decision(
|
||||
recurrence,
|
||||
work_item_id="source-evidence:sentry:received:issue-1",
|
||||
decision="accepted",
|
||||
target_incident_id="INC-20260520-ABC123",
|
||||
reviewer_id="operator_console",
|
||||
operator_note="matches current frontend incident",
|
||||
)
|
||||
|
||||
assert decision["schema_version"] == "awooop_source_correlation_review_decision_v1"
|
||||
assert decision["allowed"] is True
|
||||
assert decision["executed"] is True
|
||||
assert decision["decision"] == "accepted"
|
||||
assert decision["review_status"] == "accepted"
|
||||
assert decision["target_incident_id"] == "INC-20260520-ABC123"
|
||||
assert decision["writes_incident_state"] is False
|
||||
assert decision["writes_source_event"] is False
|
||||
assert decision["writes_auto_repair_result"] is False
|
||||
assert decision["writes_ticket"] is False
|
||||
assert decision["creates_external_ticket"] is False
|
||||
assert decision["plan"]["step"] == "record_source_correlation_review_decision"
|
||||
assert decision["plan"]["writes"] == ["alert_operation_log", "timeline_events"]
|
||||
assert decision["next_step"] == "verify_source_match_in_status_chain"
|
||||
|
||||
|
||||
def test_build_dossier_recurrence_closes_source_review_after_decision() -> None:
|
||||
decision = {
|
||||
"schema_version": "awooop_source_correlation_review_decision_v1",
|
||||
"review_id": "review-1",
|
||||
"work_item_id": "source-evidence:sentry:received:issue-1",
|
||||
"decision": "accepted",
|
||||
"review_status": "accepted",
|
||||
"target_incident_id": "INC-20260520-ABC123",
|
||||
"reviewer_id": "operator_console",
|
||||
"latest_provider_event_id": "sentry:received:issue-1",
|
||||
"recorded_at": "2026-05-20T13:11:00",
|
||||
}
|
||||
recurrence = build_dossier_recurrence(
|
||||
[
|
||||
{
|
||||
"event_id": "event-1",
|
||||
"project_id": "awoooi",
|
||||
"channel_type": "internal",
|
||||
"provider_event_id": "sentry:received:issue-1",
|
||||
"content_hash": "a" * 64,
|
||||
"content_preview": "Sentry issue",
|
||||
"content_redacted": "Sentry issue",
|
||||
"redaction_version": "audit_sink_v1",
|
||||
"source_envelope": {
|
||||
"provider": "sentry",
|
||||
"stage": "received",
|
||||
"source_refs": {"sentry_issue_ids": ["issue-1"]},
|
||||
},
|
||||
"is_duplicate": False,
|
||||
"provider_ts": None,
|
||||
"received_at": "2026-05-20T13:10:00",
|
||||
"run_id": None,
|
||||
"run_state": None,
|
||||
"run_agent_id": None,
|
||||
}
|
||||
],
|
||||
project_id="awoooi",
|
||||
limit=20,
|
||||
source_review_decisions_by_work_item={
|
||||
"source-evidence:sentry:received:issue-1": decision,
|
||||
},
|
||||
)
|
||||
|
||||
item = recurrence["items"][0]
|
||||
assert recurrence["summary"]["open_work_item_group_total"] == 0
|
||||
assert recurrence["summary"]["source_correlation_review_group_total"] == 0
|
||||
assert recurrence["summary"]["source_correlation_decision_recorded_group_total"] == 1
|
||||
assert item["source_correlation_review"] == decision
|
||||
assert item["repair_summary"]["status"] == "source_correlation_accepted"
|
||||
assert item["work_item"]["status"] == "closed"
|
||||
assert item["work_item"]["matched_incident_id"] == "INC-20260520-ABC123"
|
||||
assert item["work_item"]["next_step"] == "verify_source_match_in_status_chain"
|
||||
|
||||
|
||||
def test_build_dossier_recurrence_opens_work_item_for_completed_run_without_repair() -> None:
|
||||
recurrence = build_dossier_recurrence(
|
||||
[
|
||||
@@ -433,6 +556,7 @@ def test_build_dossier_recurrence_opens_work_item_for_completed_run_without_repa
|
||||
"schema_version": "awooop_recurrence_work_item_link_v1",
|
||||
"work_item_id": "incident:INC-20260517-F25B4A",
|
||||
"incident_id": "INC-20260517-F25B4A",
|
||||
"matched_incident_id": None,
|
||||
"auto_repair_id": None,
|
||||
"status": "open",
|
||||
"kind": "automation_gap",
|
||||
@@ -852,7 +976,7 @@ async def test_fetch_channel_event_dossier_uses_typed_run_filter(monkeypatch) ->
|
||||
async def test_fetch_channel_event_dossier_coverage_uses_typed_provider_filter(
|
||||
monkeypatch,
|
||||
) -> None:
|
||||
captured: dict[str, object] = {}
|
||||
captured: list[dict[str, object]] = []
|
||||
|
||||
class FakeMappings:
|
||||
def all(self) -> list[dict[str, object]]:
|
||||
@@ -864,8 +988,7 @@ async def test_fetch_channel_event_dossier_coverage_uses_typed_provider_filter(
|
||||
|
||||
class FakeDb:
|
||||
async def execute(self, statement, params): # noqa: ANN001
|
||||
captured["sql"] = str(statement)
|
||||
captured["params"] = params
|
||||
captured.append({"sql": str(statement), "params": params})
|
||||
return FakeResult()
|
||||
|
||||
class FakeContext:
|
||||
@@ -889,8 +1012,9 @@ async def test_fetch_channel_event_dossier_coverage_uses_typed_provider_filter(
|
||||
|
||||
assert result["project_id"] == "awoooi"
|
||||
assert result["limit"] == 200
|
||||
assert "source_envelope->>'provider'" in str(captured["sql"])
|
||||
assert captured["params"] == {
|
||||
coverage_query = captured[0]
|
||||
assert "source_envelope->>'provider'" in str(coverage_query["sql"])
|
||||
assert coverage_query["params"] == {
|
||||
"project_id": "awoooi",
|
||||
"provider": "sentry",
|
||||
"limit": 200,
|
||||
@@ -901,7 +1025,7 @@ async def test_fetch_channel_event_dossier_coverage_uses_typed_provider_filter(
|
||||
async def test_fetch_channel_event_dossier_recurrence_uses_joined_typed_filter(
|
||||
monkeypatch,
|
||||
) -> None:
|
||||
captured: dict[str, object] = {}
|
||||
captured: list[dict[str, object]] = []
|
||||
|
||||
class FakeMappings:
|
||||
def all(self) -> list[dict[str, object]]:
|
||||
@@ -913,8 +1037,7 @@ async def test_fetch_channel_event_dossier_recurrence_uses_joined_typed_filter(
|
||||
|
||||
class FakeDb:
|
||||
async def execute(self, statement, params): # noqa: ANN001
|
||||
captured["sql"] = str(statement)
|
||||
captured["params"] = params
|
||||
captured.append({"sql": str(statement), "params": params})
|
||||
return FakeResult()
|
||||
|
||||
class FakeContext:
|
||||
@@ -938,10 +1061,11 @@ async def test_fetch_channel_event_dossier_recurrence_uses_joined_typed_filter(
|
||||
|
||||
assert result["project_id"] == "awoooi"
|
||||
assert result["limit"] == 300
|
||||
assert "LEFT JOIN awooop_run_state r" in str(captured["sql"])
|
||||
assert "e.source_envelope->>'provider'" in str(captured["sql"])
|
||||
assert ":provider IS NULL" not in str(captured["sql"])
|
||||
assert captured["params"] == {
|
||||
recurrence_query = captured[0]
|
||||
assert "LEFT JOIN awooop_run_state r" in str(recurrence_query["sql"])
|
||||
assert "e.source_envelope->>'provider'" in str(recurrence_query["sql"])
|
||||
assert ":provider IS NULL" not in str(recurrence_query["sql"])
|
||||
assert recurrence_query["params"] == {
|
||||
"project_id": "awoooi",
|
||||
"provider": "alertmanager",
|
||||
"limit": 300,
|
||||
|
||||
Reference in New Issue
Block a user