fix(api): prefer latest repair terminal truth
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m45s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m45s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
This commit is contained in:
@@ -697,7 +697,11 @@ def build_automation_quality(
|
||||
noop_ops = [row for row in automation_ops if _is_no_action_operation(row)]
|
||||
audit_only_ops = [row for row in automation_ops if _is_audit_only_operation(row)]
|
||||
automation_statuses = {str(row.get("status") or "").lower() for row in effective_ops}
|
||||
auto_repair_successes = {row.get("success") for row in auto_repair_executions}
|
||||
latest_auto_repair_success = (
|
||||
auto_repair_executions[0].get("success")
|
||||
if auto_repair_executions
|
||||
else None
|
||||
)
|
||||
has_execution = bool(effective_ops or auto_repair_executions)
|
||||
verification_result = _latest_verification_result(incident, evidence_rows)
|
||||
|
||||
@@ -758,7 +762,11 @@ def build_automation_quality(
|
||||
gate("timeline_recorded", "passed" if timeline_events else "missing", str(len(timeline_events)))
|
||||
|
||||
if has_execution and (
|
||||
False in auto_repair_successes or automation_statuses & {"failed", "error"}
|
||||
latest_auto_repair_success is False
|
||||
or (
|
||||
latest_auto_repair_success is None
|
||||
and automation_statuses & {"failed", "error"}
|
||||
)
|
||||
):
|
||||
verdict = "execution_failed"
|
||||
elif has_execution and verification_status == "success":
|
||||
@@ -824,6 +832,7 @@ def build_automation_quality(
|
||||
"audit_only_operation_records": len(audit_only_ops),
|
||||
"approval_repair_suppressed": approval_suppressed,
|
||||
"auto_repair_execution_records": len(auto_repair_executions),
|
||||
"latest_auto_repair_success": latest_auto_repair_success,
|
||||
"verification_result": verification_result,
|
||||
"knowledge_entries": len(km_entries),
|
||||
"timeline_events": len(timeline_events),
|
||||
|
||||
@@ -889,6 +889,35 @@ def test_automation_quality_marks_verified_auto_repair() -> None:
|
||||
assert quality["blockers"] == []
|
||||
|
||||
|
||||
def test_latest_verified_repair_supersedes_historical_failed_apply() -> None:
|
||||
quality = build_automation_quality(
|
||||
incident={
|
||||
"incident_id": "INC-REPAIRED-AFTER-FAILURE",
|
||||
"status": "RESOLVED",
|
||||
"verification_result": "success",
|
||||
},
|
||||
approvals=[],
|
||||
evidence_rows=[{"sensors_attempted": 3, "sensors_succeeded": 3}],
|
||||
automation_ops=[
|
||||
{"operation_type": "ansible_apply_executed", "status": "success"},
|
||||
{"operation_type": "ansible_apply_executed", "status": "failed"},
|
||||
],
|
||||
auto_repair_executions=[
|
||||
{"id": "repair-new", "success": True, "playbook_id": "pb-v5"},
|
||||
{"id": "repair-old", "success": False, "playbook_id": "pb-v4"},
|
||||
],
|
||||
gateway_mcp_summary={"total": 3},
|
||||
legacy_mcp_summary={"total": 0},
|
||||
outbound_rows=[{"message_id": "m-success"}],
|
||||
km_entries=[{"id": "km-success"}],
|
||||
timeline_events=[{"id": "tl-success"}],
|
||||
)
|
||||
|
||||
assert quality["verdict"] == "auto_repaired_verified"
|
||||
assert quality["facts"]["latest_auto_repair_success"] is True
|
||||
assert quality["blockers"] == []
|
||||
|
||||
|
||||
def test_automation_quality_marks_degraded_auto_repair_verification() -> None:
|
||||
quality = build_automation_quality(
|
||||
incident={
|
||||
|
||||
Reference in New Issue
Block a user