feat(awooop): apply source correlation links
All checks were successful
Code Review / ai-code-review (push) Successful in 12s
CD Pipeline / tests (push) Successful in 4m1s
CD Pipeline / build-and-deploy (push) Successful in 4m8s
CD Pipeline / post-deploy-checks (push) Successful in 2m2s

This commit is contained in:
Your Name
2026-05-21 10:23:29 +08:00
parent d25237a31f
commit fe3bf5dc18
8 changed files with 1011 additions and 7 deletions

View File

@@ -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_apply,
build_source_correlation_review_decision,
fetch_channel_event_dossier,
fetch_channel_event_dossier_coverage,
@@ -509,6 +510,178 @@ def test_build_dossier_recurrence_closes_source_review_after_decision() -> None:
assert item["work_item"]["next_step"] == "verify_source_match_in_status_chain"
def test_source_correlation_apply_requires_accepted_review_and_plans_source_link() -> None:
accepted_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"],
"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,
source_review_decisions_by_work_item={
"source-evidence:sentry:received:issue-1": accepted_decision,
},
)
apply_payload = build_source_correlation_apply(
recurrence,
work_item_id="source-evidence:sentry:received:issue-1",
)
assert apply_payload["schema_version"] == "awooop_source_correlation_apply_v1"
assert apply_payload["allowed"] is True
assert apply_payload["apply_status"] == "ready_to_apply"
assert apply_payload["target_incident_id"] == "INC-20260520-ABC123"
assert apply_payload["writes_source_event"] is True
assert apply_payload["writes_incident_state"] is False
assert apply_payload["writes_auto_repair_result"] is False
assert apply_payload["writes_ticket"] is False
assert apply_payload["source_event_stage"] == "source_correlation_linked"
assert apply_payload["source_event_provider_event_id"] == (
"sentry:source_correlation_linked:issue-1"
)
assert apply_payload["plan"]["writes"] == [
"awooop_conversation_event",
"timeline_events",
"alert_operation_log",
]
assert apply_payload["next_step"] == "verify_source_link_in_status_chain"
def test_source_correlation_apply_blocks_without_accepted_review() -> 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"]},
},
"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,
)
apply_payload = build_source_correlation_apply(
recurrence,
work_item_id="source-evidence:sentry:received:issue-1",
)
assert apply_payload["allowed"] is False
assert apply_payload["executed"] is False
assert apply_payload["writes_source_event"] is False
assert apply_payload["apply_status"] == "blocked"
assert apply_payload["plan"]["writes"] == []
assert apply_payload["next_step"] == "fix_preflight_checks"
def test_build_dossier_recurrence_surfaces_source_apply_history() -> None:
apply_record = {
"schema_version": "awooop_source_correlation_apply_v1",
"apply_id": "apply-1",
"work_item_id": "source-evidence:sentry:received:issue-1",
"apply_status": "applied",
"target_incident_id": "INC-20260520-ABC123",
"review_id": "review-1",
"source_event_id": "source-event-1",
"source_event_provider_event_id": (
"sentry:source_correlation_linked:issue-1"
),
"recorded_at": "2026-05-20T13:12: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_applies_by_work_item={
"source-evidence:sentry:received:issue-1": apply_record,
},
)
item = recurrence["items"][0]
assert recurrence["summary"]["source_correlation_applied_group_total"] == 1
assert item["source_correlation_apply"] == apply_record
assert item["work_item"]["matched_incident_id"] == "INC-20260520-ABC123"
assert item["work_item"]["next_step"] == "verify_source_link_in_status_chain"
def test_build_dossier_recurrence_opens_work_item_for_completed_run_without_repair() -> None:
recurrence = build_dossier_recurrence(
[
@@ -760,6 +933,101 @@ async def test_source_correlation_dry_run_history_records_without_incident(
)
@pytest.mark.asyncio
async def test_source_correlation_apply_history_appends_source_event_and_audit(
monkeypatch,
) -> None:
source_calls: list[dict[str, object]] = []
timeline_calls: list[dict[str, object]] = []
alert_calls: list[dict[str, object]] = []
async def fake_record_external_alert_event(**kwargs): # noqa: ANN003
source_calls.append(kwargs)
return UUID("99999999-9999-4999-8999-999999999999")
class FakeTimeline:
async def add_event(self, **kwargs): # noqa: ANN001
timeline_calls.append(kwargs)
return {"id": "timeline-1"}
class FakeRecord:
id = "alert-op-1"
class FakeRepo:
async def append(self, event_type: str, **kwargs): # noqa: ANN001
alert_calls.append({"event_type": event_type, **kwargs})
return FakeRecord()
from src.repositories import alert_operation_log_repository
from src.services import approval_db, channel_hub
monkeypatch.setattr(
channel_hub,
"record_external_alert_event",
fake_record_external_alert_event,
)
monkeypatch.setattr(approval_db, "get_timeline_service", lambda: FakeTimeline())
monkeypatch.setattr(
alert_operation_log_repository,
"get_alert_operation_log_repository",
lambda: FakeRepo(),
)
history = await channel_event_dossier_service._record_source_correlation_apply_history(
{
"schema_version": "awooop_source_correlation_apply_v1",
"source": "channel_event_dossier.recurrence",
"project_id": "awoooi",
"work_item_id": "source-evidence:sentry:received:issue-1",
"review_id": "review-1",
"target_incident_id": "INC-20260520-ABC123",
"reviewer_id": "operator_console",
"operator_note": "matches incident",
"allowed": True,
"apply_status": "ready_to_apply",
"safety_level": "source_review_append_only_apply",
"writes_incident_state": False,
"writes_source_event": True,
"writes_auto_repair_result": False,
"writes_ticket": False,
"creates_external_ticket": False,
"latest_provider_event_id": "sentry:received:issue-1",
"source_event_provider_event_id": (
"sentry:source_correlation_linked:issue-1"
),
"source_event_stage": "source_correlation_linked",
"raw_event_id": "issue-1",
"provider": "sentry",
"alertname": "Sentry Issue",
"severity": "error",
"namespace": "awoooi-prod",
"target_resource": "web",
"fingerprint": "fp-sentry-issue-1",
"checks": [],
"current_state_summary": {},
"plan": {"writes": ["awooop_conversation_event"]},
"read_model_route": {},
"next_step": "verify_source_link_in_status_chain",
}
)
assert history == {
"recorded": True,
"source_event_id": "99999999-9999-4999-8999-999999999999",
"alert_operation_id": "alert-op-1",
"timeline_event_id": "timeline-1",
}
assert source_calls[0]["stage"] == "source_correlation_linked"
assert source_calls[0]["incident_id"] == "INC-20260520-ABC123"
assert source_calls[0]["event_id"] == "issue-1"
assert timeline_calls[0]["incident_id"] == "INC-20260520-ABC123"
assert alert_calls[0]["actor"] == "awooop_source_correlation_apply_service"
assert alert_calls[0]["context"]["schema_version"] == (
"awooop_source_correlation_apply_v1"
)
assert alert_calls[0]["context"]["apply_status"] == "applied"
def test_build_recurrence_work_item_handoff_records_ticket_proposal_contract() -> None:
recurrence = build_dossier_recurrence(
[