feat(awooop): surface status chain in operator console
All checks were successful
Code Review / ai-code-review (push) Successful in 9s
CD Pipeline / tests (push) Successful in 1m16s
CD Pipeline / build-and-deploy (push) Successful in 3m31s
CD Pipeline / post-deploy-checks (push) Successful in 1m18s

This commit is contained in:
Your Name
2026-05-19 10:13:33 +08:00
parent 30b2f5bd6e
commit 784ebf49ef
8 changed files with 615 additions and 4 deletions

View File

@@ -11,15 +11,16 @@ from src.api.v1.platform.operator_runs import (
ListRunsResponse,
)
from src.services.platform_operator_service import (
_build_awooop_status_chain,
_callback_reply_event_item,
_callback_reply_summary_matches_status,
_collect_run_incident_ids,
_callback_reply_event_item,
_legacy_mcp_timeline_status,
_legacy_mcp_timeline_summary,
_list_filter_context_limit,
_outbound_timeline_title,
_outbound_timeline_status,
_outbound_timeline_summary,
_outbound_timeline_title,
_remediation_summary_matches_incident_id,
_remediation_summary_matches_status,
_remediation_timeline_summary,
@@ -348,6 +349,11 @@ def test_list_callback_replies_response_preserves_callback_evidence() -> None:
"action": "detail",
"incident_id": "INC-20260513-79ED5E",
},
"awooop_status_chain": {
"schema_version": "awooop_status_chain_v1",
"repair_state": "read_only_dry_run",
"needs_human": True,
},
"run_detail_href": (
"/awooop/runs/5c0306e0-591a-5445-9a33-80f499426b38"
"?project_id=awoooi"
@@ -362,6 +368,9 @@ def test_list_callback_replies_response_preserves_callback_evidence() -> None:
dumped = response.model_dump(mode="json")
assert dumped["items"][0]["status"] == "fallback_sent"
assert dumped["items"][0]["callback_reply"]["action"] == "detail"
assert dumped["items"][0]["awooop_status_chain"]["repair_state"] == (
"read_only_dry_run"
)
assert dumped["items"][0]["run_detail_href"].endswith("project_id=awoooi")
@@ -396,6 +405,97 @@ def test_remediation_timeline_summary_surfaces_route_and_write_flags() -> None:
assert "writes_auto_repair=False" in summary
def test_awooop_status_chain_marks_verified_repair() -> None:
chain = _build_awooop_status_chain(
incident_ids=["INC-20260513-79ED5E"],
source_id="INC-20260513-79ED5E",
truth_chain={
"truth_status": {
"current_stage": "execution_succeeded",
"stage_status": "success",
"needs_human": False,
"blockers": [],
},
"automation_quality": {
"verdict": "auto_repaired_verified",
"facts": {
"auto_repair_execution_records": 1,
"automation_operation_records": 1,
"verification_result": "healthy",
"mcp_gateway_total": 2,
"knowledge_entries": 1,
},
"blockers": [],
},
},
remediation_history={
"total": 1,
"items": [
{
"incident_id": "INC-20260513-79ED5E",
"agent_id": "auto_repair_executor",
"tool_name": "rollout_restart",
"required_scope": "write",
"verification_result_preview": "healthy",
"writes_incident_state": True,
"writes_auto_repair_result": True,
}
],
},
)
assert chain["repair_state"] == "auto_repaired_verified"
assert chain["verification"] == "healthy"
assert chain["needs_human"] is False
assert chain["next_step"] == "monitor_for_regression"
assert chain["evidence"]["latest_route"] == "auto_repair_executor/rollout_restart/write"
def test_awooop_status_chain_marks_read_only_manual_gate() -> None:
chain = _build_awooop_status_chain(
incident_ids=["INC-20260513-79ED5E"],
source_id="INC-20260513-79ED5E",
truth_chain={
"truth_status": {
"current_stage": "approval_required",
"stage_status": "waiting",
"needs_human": True,
"blockers": ["pending_human_approval"],
},
"automation_quality": {
"verdict": "approval_required",
"facts": {
"auto_repair_execution_records": 0,
"automation_operation_records": 0,
"verification_result": "missing",
"mcp_gateway_total": 1,
"knowledge_entries": 0,
},
"blockers": [],
},
},
remediation_history={
"total": 2,
"items": [
{
"incident_id": "INC-20260513-79ED5E",
"agent_id": "investigator",
"tool_name": "ssh_diagnose",
"required_scope": "read",
"verification_result_preview": "degraded",
"writes_incident_state": False,
"writes_auto_repair_result": False,
}
],
},
)
assert chain["repair_state"] == "read_only_dry_run"
assert chain["needs_human"] is True
assert chain["next_step"] == "approve_or_escalate_from_awooop"
assert chain["blockers"] == ["pending_human_approval"]
def test_legacy_mcp_timeline_summary_surfaces_tool_context() -> None:
record = {
"incident_id": "INC-20260514-F85F21",