fix(awooop): honor approval repair metadata
This commit is contained in:
@@ -146,6 +146,19 @@ def _approval_has_no_action(approvals: list[dict[str, Any]]) -> bool:
|
||||
return any(_looks_like_no_action(row.get("action")) for row in approvals)
|
||||
|
||||
|
||||
def _approval_suppresses_repair_execution(approvals: list[dict[str, Any]]) -> bool:
|
||||
for row in approvals:
|
||||
metadata = row.get("extra_metadata")
|
||||
if not isinstance(metadata, dict):
|
||||
continue
|
||||
execution_kind = str(metadata.get("execution_kind") or "").lower()
|
||||
if metadata.get("repair_executed") is False:
|
||||
return True
|
||||
if execution_kind in {"no_action", "diagnostic", "parse_failed", "unsupported_action"}:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _is_no_action_operation(row: dict[str, Any]) -> bool:
|
||||
"""Return true for durable audit rows that represent observation, not repair."""
|
||||
if str(row.get("operation_type") or "") != "playbook_executed":
|
||||
@@ -209,7 +222,8 @@ def build_incident_reconciliation(
|
||||
attempted = sum(int(row.get("sensors_attempted") or 0) for row in evidence_rows)
|
||||
succeeded = sum(int(row.get("sensors_succeeded") or 0) for row in evidence_rows)
|
||||
repair_rows = auto_repair_executions or []
|
||||
effective_ops = _effective_execution_ops(automation_ops)
|
||||
approval_suppressed = _approval_suppresses_repair_execution(approvals)
|
||||
effective_ops = [] if approval_suppressed else _effective_execution_ops(automation_ops)
|
||||
executed_ops = [
|
||||
row
|
||||
for row in effective_ops
|
||||
@@ -363,7 +377,8 @@ def _truth_status(
|
||||
if incident is not None:
|
||||
incident_status = str(incident.get("status") or "unknown")
|
||||
repair_rows = auto_repair_executions or []
|
||||
effective_ops = _effective_execution_ops(automation_ops)
|
||||
approval_suppressed = _approval_suppresses_repair_execution(approvals)
|
||||
effective_ops = [] if approval_suppressed else _effective_execution_ops(automation_ops)
|
||||
has_execution_records = bool(effective_ops or repair_rows)
|
||||
stage = "received"
|
||||
stage_status = incident_status.lower()
|
||||
@@ -488,16 +503,21 @@ def build_automation_quality(
|
||||
evidence_succeeded = sum(int(row.get("sensors_succeeded") or 0) for row in evidence_rows)
|
||||
gateway_total = int(gateway_mcp_summary.get("total") or 0)
|
||||
legacy_total = int(legacy_mcp_summary.get("total") or 0)
|
||||
effective_ops = _effective_execution_ops(automation_ops)
|
||||
approval_statuses = {str(row.get("status") or "").upper() for row in approvals}
|
||||
approval_actions = " ".join(str(row.get("action") or "") for row in approvals).upper()
|
||||
approval_no_action = _approval_has_no_action(approvals)
|
||||
approval_suppressed = _approval_suppresses_repair_execution(approvals)
|
||||
effective_ops = (
|
||||
[]
|
||||
if approval_suppressed
|
||||
else _effective_execution_ops(automation_ops)
|
||||
)
|
||||
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}
|
||||
has_execution = bool(effective_ops or auto_repair_executions)
|
||||
verification_result = _latest_verification_result(incident, evidence_rows)
|
||||
approval_statuses = {str(row.get("status") or "").upper() for row in approvals}
|
||||
approval_actions = " ".join(str(row.get("action") or "") for row in approvals).upper()
|
||||
approval_no_action = _approval_has_no_action(approvals)
|
||||
|
||||
gate("source_persisted", "passed", str(incident.get("incident_id")))
|
||||
gate("outbound_recorded", "passed" if outbound_rows else "missing", str(len(outbound_rows)))
|
||||
@@ -519,6 +539,8 @@ def build_automation_quality(
|
||||
|
||||
if any(status in {"PENDING", "WAITING_APPROVAL"} for status in approval_statuses):
|
||||
gate("approval_state", "warning", "waiting_approval")
|
||||
elif approval_statuses and approval_suppressed and not has_execution:
|
||||
gate("approval_state", "warning", "approved_diagnostic_or_observe_only")
|
||||
elif approval_statuses and (approval_no_action or "NO_ACTION" in approval_actions) and not has_execution:
|
||||
gate("approval_state", "failed", "approved_no_action_without_execution")
|
||||
elif approvals:
|
||||
@@ -559,6 +581,8 @@ def build_automation_quality(
|
||||
verdict = "auto_repaired_verification_degraded"
|
||||
elif has_execution:
|
||||
verdict = "execution_unverified"
|
||||
elif approval_suppressed:
|
||||
verdict = "manual_required_diagnostic_only"
|
||||
elif approval_statuses and (approval_no_action or "NO_ACTION" in approval_actions):
|
||||
verdict = "manual_required_no_action"
|
||||
elif any(status in {"PENDING", "WAITING_APPROVAL"} for status in approval_statuses):
|
||||
@@ -608,6 +632,7 @@ def build_automation_quality(
|
||||
"effective_execution_records": len(effective_ops),
|
||||
"noop_operation_records": len(noop_ops),
|
||||
"audit_only_operation_records": len(audit_only_ops),
|
||||
"approval_repair_suppressed": approval_suppressed,
|
||||
"auto_repair_execution_records": len(auto_repair_executions),
|
||||
"verification_result": verification_result,
|
||||
"knowledge_entries": len(km_entries),
|
||||
|
||||
Reference in New Issue
Block a user