fix(api): distinguish ansible dry run from repair
Some checks failed
Code Review / ai-code-review (push) Successful in 14s
CD Pipeline / tests (push) Successful in 1m35s
CD Pipeline / build-and-deploy (push) Successful in 5m0s
CD Pipeline / post-deploy-checks (push) Successful in 1m33s
Ansible / Reboot Recovery Contract / validate (push) Has been cancelled

This commit is contained in:
Your Name
2026-06-25 20:52:22 +08:00
parent 8080606112
commit d7b3997b4a
9 changed files with 362 additions and 23 deletions

View File

@@ -3963,6 +3963,22 @@ def _has_nonrepair_operation_evidence(facts: dict[str, Any]) -> bool:
)
def _status_chain_ansible_dry_run_only(
execution_section: dict[str, Any],
facts: dict[str, Any],
) -> bool:
ansible = execution_section.get("ansible")
if not isinstance(ansible, dict):
return False
return (
_safe_int(ansible.get("check_mode_total")) > 0
and _safe_int(ansible.get("apply_total")) == 0
and not bool(ansible.get("applied"))
and not bool(ansible.get("controlled_apply"))
and _safe_int(facts.get("auto_repair_execution_records")) == 0
)
def _latest_remediation_history_item(
history: dict[str, Any] | None,
) -> dict[str, Any]:
@@ -4795,6 +4811,12 @@ def _build_awooop_status_chain(
mcp_section = _status_chain_mcp_section(truth_chain)
execution_section = _status_chain_execution_section(truth_chain)
ansible_dry_run_only = _status_chain_ansible_dry_run_only(execution_section, facts)
if ansible_dry_run_only:
verdict = "ansible_check_mode_only"
repair_state = "ansible_check_mode_only"
next_step = "owner_review_apply_gate_or_create_verifier_plan"
needs_human = True
source_section = _status_chain_source_section(truth_chain)
if source_correlation is not None:
source_section["correlation"] = source_correlation
@@ -4809,7 +4831,23 @@ def _build_awooop_status_chain(
if fetch_error:
blockers.append("truth_chain_fetch_failed")
outcome = {}
if isinstance(quality.get("operator_outcome"), dict):
if ansible_dry_run_only:
outcome_quality = dict(quality)
outcome_facts = dict(facts)
ansible = execution_section.get("ansible") if isinstance(execution_section.get("ansible"), dict) else {}
outcome_facts["ansible_check_mode_total"] = _safe_int(ansible.get("check_mode_total"))
outcome_facts["ansible_apply_total"] = _safe_int(ansible.get("apply_total"))
outcome_quality["facts"] = outcome_facts
outcome_quality["verdict"] = "ansible_check_mode_only"
outcome_quality.pop("operator_outcome", None)
outcome = build_operator_outcome(
truth_status=truth_status,
automation_quality=outcome_quality,
remediation_state=remediation_state,
fetch_error=fetch_error,
source_id=source_id,
)
elif isinstance(quality.get("operator_outcome"), dict):
outcome = dict(quality["operator_outcome"])
else:
outcome = build_operator_outcome(
@@ -4849,6 +4887,7 @@ def _build_awooop_status_chain(
"latest_mode": latest.get("mode"),
"latest_at": latest.get("created_at"),
"latest_preview": latest.get("verification_result_preview"),
"ansible_dry_run_only": ansible_dry_run_only,
},
"writes": {
"incident": latest.get("writes_incident_state"),