feat(agents): classify runtime apply repair readback

This commit is contained in:
Your Name
2026-06-28 19:30:27 +08:00
parent d5c9d467c1
commit 688bfd7740
2 changed files with 299 additions and 0 deletions

View File

@@ -219,3 +219,128 @@ def test_runtime_receipt_readback_summarizes_live_executor_closure_rows():
"closed": True,
"missing": [],
}
assert readback["latest_failure_classification"]["classification"] == (
"latest_controlled_apply_closed_success"
)
assert readback["controlled_retry_package"]["status"] == "not_required_for_latest_apply"
def test_runtime_receipt_readback_classifies_closed_failed_apply_as_ai_repair():
apply_op_id = "94925d5e-6fdc-49c3-90e8-f0a0d57a6a58"
incident_id = "INC-20260628-A40A9A"
readback = build_runtime_receipt_readback_from_rows(
project_id="awoooi",
db_read_status="ok",
operation_count_rows=[
{
"operation_type": "ansible_apply_executed",
"status": "failed",
"total": 1,
"recent": 1,
},
],
operation_latest_rows=[
{
"op_id": apply_op_id,
"parent_op_id": "8b555f41-e81f-4d8e-956b-fb20d358db63",
"operation_type": "ansible_apply_executed",
"status": "failed",
"actor": "ansible_controlled_apply_worker",
"incident_id": incident_id,
"catalog_id": "ansible:188-ai-web",
"playbook_path": "infra/ansible/playbooks/188-ai-web.yml",
"execution_mode": "controlled_apply",
"returncode": "2",
"duration_ms": 4797,
},
],
verifier_count_rows=[
{"verification_result": "failed", "total": 1, "recent": 1},
],
verifier_latest_rows=[
{
"id": "evidence-1",
"incident_id": incident_id,
"verification_result": "failed",
"apply_op_id": apply_op_id,
"catalog_id": "ansible:188-ai-web",
"playbook_path": "infra/ansible/playbooks/188-ai-web.yml",
"returncode": "2",
},
],
km_count_rows=[
{"status": "REVIEW", "total": 1, "recent": 1},
],
km_latest_rows=[
{
"id": "km-1",
"title": "AI 自動修復沉澱INC-20260628-A40A9A",
"related_incident_id": incident_id,
"related_playbook_id": "ansible:188-ai-web",
"path_type": "ansible_apply_receipt:94925d5e",
"status": "REVIEW",
"created_by": "ai_agent_ansible_worker",
},
],
telegram_count_rows=[
{"send_status": "sent", "total": 1, "recent": 1},
],
telegram_latest_rows=[
{
"message_id": "telegram-row-1",
"run_id": "telegram-run-1",
"message_type": "final",
"send_status": "sent",
"provider_message_id": "32016",
"incident_id": incident_id,
"action": "controlled_apply_result",
},
],
)
classification = readback["latest_failure_classification"]
assert classification["classification"] == "closed_failed_apply_requires_ai_repair"
assert classification["action"] == "queue_check_mode_replay_and_playbook_repair_candidate"
assert classification["target_selector"] == {
"incident_id": incident_id,
"apply_op_id": apply_op_id,
"parent_op_id": "8b555f41-e81f-4d8e-956b-fb20d358db63",
"catalog_id": "ansible:188-ai-web",
"playbook_path": "infra/ansible/playbooks/188-ai-web.yml",
"execution_mode": "controlled_apply",
}
assert classification["evidence"]["returncode"] == "2"
assert classification["evidence"]["verification_result"] == "failed"
assert classification["evidence"]["latest_flow_closed"] is True
assert classification["evidence"]["output_tail_in_readback"] is False
assert classification["evidence"]["unredacted_output_required"] is False
assert classification["safe_next_steps"] == [
"run_no_write_check_mode_replay",
"extract_sanitized_failed_task_summary",
"write_km_playbook_repair_candidate",
"retry_controlled_apply_only_after_check_mode_passes",
]
retry = readback["controlled_retry_package"]
assert retry["package_id"] == "ansible_retry:94925d5e"
assert retry["status"] == "ready_for_no_write_check_mode_replay"
assert retry["source_of_truth"] == {
"catalog_id": "ansible:188-ai-web",
"playbook_path": "infra/ansible/playbooks/188-ai-web.yml",
"source_diff_required_before_retry": True,
"failed_task_summary_required": True,
}
assert retry["preflight"]["no_write_check_mode_replay_required"] is True
assert retry["preflight"]["reuse_parent_check_mode_op_id"] == (
"8b555f41-e81f-4d8e-956b-fb20d358db63"
)
assert retry["apply_gate"]["controlled_apply_retry_allowed_now"] is False
assert retry["apply_gate"]["requires_check_mode_success_before_apply"] is True
assert retry["rollback"]["destructive_rollback_allowed"] is False
assert retry["post_apply"] == {
"post_apply_verifier_required": True,
"km_playbook_trust_writeback_required": True,
"telegram_receipt_required": True,
}
assert retry["next_ai_action"] == "run_no_write_check_mode_replay"