fix(agent): expose runtime receipt recovery action
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 39s
CD Pipeline / build-and-deploy (push) Successful in 8m10s
CD Pipeline / post-deploy-checks (push) Successful in 1m39s

This commit is contained in:
Your Name
2026-07-01 18:32:18 +08:00
parent 7aa9cb66ec
commit ffaced9b1b
2 changed files with 181 additions and 1 deletions

View File

@@ -844,6 +844,95 @@ def _build_log_integration_taxonomy(
}
def _build_runtime_receipt_readback_recovery(
*,
db_read_status: str,
log_integration_taxonomy: Mapping[str, Any],
error_type: str | None,
) -> dict[str, Any]:
"""Expose the next controlled action when live receipt/log evidence is absent."""
taxonomy_rollups = log_integration_taxonomy.get("rollups")
if not isinstance(taxonomy_rollups, Mapping):
taxonomy_rollups = {}
source_families = log_integration_taxonomy.get("source_families")
if not isinstance(source_families, list):
source_families = []
inactive_source_family_ids = [
str(source.get("source_family_id"))
for source in source_families
if isinstance(source, Mapping) and _int_value(source.get("total")) <= 0
]
classified_event_total = _int_value(taxonomy_rollups.get("classified_event_total"))
recent_classified_event_total = _int_value(
taxonomy_rollups.get("recent_classified_event_total")
)
db_unavailable = db_read_status != "ok"
no_live_log_events = classified_event_total <= 0
if db_unavailable:
status = "blocked_runtime_receipt_db_readback_unavailable"
safe_next_action_id = (
"repair_runtime_receipt_db_readback_then_rerun_log_integration_taxonomy"
)
safe_next_action_stage = "runtime_receipt_db_context_or_schema_recovery"
safe_next_action = (
"Restore the API readback path for automation_operation_log, KM, MCP, "
"timeline, PlayBook, and alert evidence counters, then rerun the "
"runtime-control endpoint readback."
)
blocker_fields = ["db_read_status"]
elif no_live_log_events:
status = "blocked_live_log_source_family_events_missing"
safe_next_action_id = (
"connect_service_tool_package_logs_to_trace_ledger_then_rerun_taxonomy"
)
safe_next_action_stage = "log_source_ingestion_and_labeling_required"
safe_next_action = (
"Route sanitized service, package, tool, MCP, executor, verifier, KM, "
"PlayBook, and notification receipts into the trace ledger with labels."
)
blocker_fields = ["classified_event_total", "active_source_family_count"]
else:
status = "completed_live_runtime_receipts_observed"
safe_next_action_id = "keep_log_learning_loop_monitored"
safe_next_action_stage = "monitoring"
safe_next_action = "Keep the LOG -> KM/RAG/MCP/PlayBook learning loop monitored."
blocker_fields = []
return {
"schema_version": "ai_agent_runtime_receipt_readback_recovery_v1",
"status": status,
"db_read_status": db_read_status,
"error_type": error_type,
"safe_next_action_id": safe_next_action_id,
"safe_next_action_stage": safe_next_action_stage,
"safe_next_action": safe_next_action,
"post_recovery_verifier": (
"GET /api/v1/agents/agent-autonomous-runtime-control and require "
"runtime_receipt_readback.db_read_status=ok plus active_source_family_count>0"
),
"classified_event_total": classified_event_total,
"recent_classified_event_total": recent_classified_event_total,
"source_family_count": _int_value(taxonomy_rollups.get("source_family_count")),
"active_source_family_count": _int_value(
taxonomy_rollups.get("active_source_family_count")
),
"inactive_source_family_ids": inactive_source_family_ids,
"blocker_fields": blocker_fields,
"operation_boundaries": {
"readback_only": True,
"km_write_performed": False,
"rag_index_write_performed": False,
"playbook_trust_write_performed": False,
"mcp_tool_call_performed": False,
"runtime_repair_performed": False,
"raw_log_payload_persisted": False,
"secret_value_collection_allowed": False,
"github_api_used": False,
},
}
def _decision_wiring_stage(
*,
stage_id: str,
@@ -1938,6 +2027,8 @@ def _build_work_item_progress(
if not isinstance(source_families, list):
source_families = []
inactive_source_count = _int_value(taxonomy_rollups.get("inactive_source_family_count"))
active_source_count = _int_value(taxonomy_rollups.get("active_source_family_count"))
classified_event_total = _int_value(taxonomy_rollups.get("classified_event_total"))
missing_required = trace_ledger.get("missing_required_stage_ids")
if not isinstance(missing_required, list):
missing_required = []
@@ -2033,10 +2124,12 @@ def _build_work_item_progress(
and multi_product_taxonomy.get("status") == "completed"
and multi_product_missing == 0
)
runtime_truth_complete = db_read_status == "ok" and classified_event_total > 0
deployed_readback_complete = (
db_read_status == "ok"
and trace_ledger.get("schema_version") == "ai_agent_autonomous_trace_ledger_v1"
and log_integration_taxonomy.get("schema_version") == "ai_agent_log_integration_taxonomy_v1"
and classified_event_total > 0
)
ordered_items = [
@@ -2044,8 +2137,23 @@ def _build_work_item_progress(
"work_item_id": "P0-A-runtime-truth",
"priority": "P0-A",
"title": "Controlled apply runtime truth readback",
"status": "completed",
"status": (
"completed"
if runtime_truth_complete
else "blocked"
if db_read_status != "ok"
else "in_progress"
),
"exit_criteria": "production API reports db_read_status=ok and live executor receipts",
"blocker": None
if runtime_truth_complete
else (
"runtime_receipt_db_readback_unavailable"
if db_read_status != "ok"
else "live_log_classified_event_total_zero"
),
"db_read_status": db_read_status,
"classified_event_total": classified_event_total,
},
{
"work_item_id": "P0-B-trace-ledger",
@@ -2060,6 +2168,8 @@ def _build_work_item_progress(
"title": "Project/product/site/service/package/tool log taxonomy",
"status": "completed",
"exit_criteria": "log_integration_taxonomy lists source families, labels, and public-safety policy",
"active_source_family_count": active_source_count,
"classified_event_total": classified_event_total,
},
{
"work_item_id": "P0-D-ui-visibility",
@@ -3021,6 +3131,11 @@ def build_runtime_receipt_readback_from_rows(
timeline_summary=timeline_summary,
playbook_trust_summary=playbook_trust_summary,
)
runtime_receipt_readback_recovery = _build_runtime_receipt_readback_recovery(
db_read_status=db_read_status,
log_integration_taxonomy=log_integration_taxonomy,
error_type=error_type,
)
agent_decision_wiring = _build_agent_decision_wiring(
operation_summary=operation_summary,
verifier_summary=verifier_summary,
@@ -3196,6 +3311,7 @@ def build_runtime_receipt_readback_from_rows(
"autonomous_execution_loop_ledger": loop_ledger,
"trace_ledger": trace_ledger,
"log_integration_taxonomy": log_integration_taxonomy,
"runtime_receipt_readback_recovery": runtime_receipt_readback_recovery,
"log_controlled_writeback_executor": log_controlled_writeback_executor,
"log_controlled_writeback_consumer": dict(log_controlled_writeback_consumer),
"agent_decision_wiring": agent_decision_wiring,
@@ -3258,6 +3374,9 @@ def _attach_runtime_receipt_readback(
log_dispatch_summary = (
operation_counts.get(LOG_CONTROLLED_WRITEBACK_DISPATCH_OPERATION_TYPE) or {}
)
runtime_recovery = readback.get("runtime_receipt_readback_recovery")
if not isinstance(runtime_recovery, Mapping):
runtime_recovery = {}
rollups.update({
"live_ansible_apply_executed_count": _int_value(
readback.get("ansible_apply_executed", {}).get("total")
@@ -3345,6 +3464,15 @@ def _attach_runtime_receipt_readback(
"recent_classified_event_total"
)
),
"live_runtime_receipt_recovery_status": runtime_recovery.get("status") or "",
"live_runtime_receipt_safe_next_action_id": runtime_recovery.get(
"safe_next_action_id"
)
or "",
"live_runtime_receipt_safe_next_action_stage": runtime_recovery.get(
"safe_next_action_stage"
)
or "",
"live_log_controlled_writeback_executor_batch_count": _int_value(
log_executor_rollups.get("execution_batch_count")
),