feat(awooop): surface ai automation node receipts
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / tests (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 / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / tests (push) Has been cancelled
This commit is contained in:
@@ -47,6 +47,20 @@ _METRIC_LINE_RE = re.compile(
|
||||
_COMMANDER_INSERTED_REQUIREMENT_SOURCE = (
|
||||
"docs/workplans/2026-07-02-commander-inserted-requirements-priority-ledger.md"
|
||||
)
|
||||
_AI_AUTOMATION_NODE_RECEIPT_SCHEMA_VERSION = "ai_automation_node_receipt_v1"
|
||||
_AI_AUTOMATION_NODE_RECEIPT_REQUIRED_FIELDS = [
|
||||
"trace_id",
|
||||
"run_id",
|
||||
"work_item_id",
|
||||
"node_id",
|
||||
"node_status",
|
||||
"timestamp",
|
||||
"evidence_refs",
|
||||
"verifier_result",
|
||||
"rollback_result",
|
||||
"km_writeback_ref",
|
||||
"playbook_trust_writeback_ref",
|
||||
]
|
||||
_COMMANDER_INSERTED_REQUIREMENT_WORK_ITEMS: list[dict[str, Any]] = [
|
||||
{
|
||||
"id": "CIR-P0-001",
|
||||
@@ -816,6 +830,7 @@ def load_latest_awoooi_priority_work_order_readback(
|
||||
_require_mainline_consistency(payload, str(path))
|
||||
_apply_commander_inserted_requirement_work_items(payload)
|
||||
_mark_runtime_generated_at(payload)
|
||||
apply_ai_automation_node_receipts(payload)
|
||||
return payload
|
||||
|
||||
|
||||
@@ -965,6 +980,7 @@ def apply_controlled_cd_lane_live_metric_readback(
|
||||
)
|
||||
|
||||
_mark_runtime_generated_at(payload)
|
||||
apply_ai_automation_node_receipts(payload)
|
||||
|
||||
|
||||
def apply_stockplatform_public_api_runtime_readback(
|
||||
@@ -1516,6 +1532,7 @@ def apply_ai_loop_current_blocker_execution_queue(
|
||||
pressure_blocker=pressure_blocker,
|
||||
node_load_classifier=node_load_classifier,
|
||||
)
|
||||
apply_ai_automation_node_receipts(payload)
|
||||
return
|
||||
|
||||
if not _ai_loop_current_blocker_can_override(
|
||||
@@ -2101,6 +2118,7 @@ def apply_ai_loop_current_blocker_execution_queue(
|
||||
summary["ai_loop_current_blocker_forbidden_runtime_action_count"] = len(
|
||||
forbidden_runtime_actions
|
||||
)
|
||||
apply_ai_automation_node_receipts(payload)
|
||||
|
||||
|
||||
def _record_ai_loop_current_blocker_production_resolution(
|
||||
@@ -2226,6 +2244,7 @@ def _record_ai_loop_current_blocker_production_resolution(
|
||||
if blocker and blocker not in resolved_blockers
|
||||
]
|
||||
break
|
||||
apply_ai_automation_node_receipts(payload)
|
||||
|
||||
|
||||
def _ai_loop_current_blocker_can_override(
|
||||
@@ -3371,6 +3390,213 @@ def _apply_commander_inserted_requirement_work_items(
|
||||
)
|
||||
|
||||
|
||||
def apply_ai_automation_node_receipts(payload: dict[str, Any]) -> None:
|
||||
"""Refresh metadata-only AI automation node receipts after live overlays."""
|
||||
_apply_ai_automation_node_receipts(payload)
|
||||
|
||||
|
||||
def _apply_ai_automation_node_receipts(payload: dict[str, Any]) -> None:
|
||||
summary = _dict(payload.setdefault("summary", {}))
|
||||
rollups = _dict(payload.setdefault("rollups", {}))
|
||||
runtime_timestamp = str(
|
||||
payload.get("runtime_readback_generated_at")
|
||||
or summary.get("runtime_readback_generated_at")
|
||||
or payload.get("generated_at")
|
||||
or ""
|
||||
)
|
||||
source_sha = str(summary.get("latest_successful_deployed_source_short_sha") or "")
|
||||
cd_run_id = str(summary.get("ai_loop_current_blocker_current_cd_run_id") or "")
|
||||
cd_run_status = str(
|
||||
summary.get("ai_loop_current_blocker_current_cd_run_status") or ""
|
||||
)
|
||||
blocker_id = str(summary.get("ai_loop_current_blocker_id") or "")
|
||||
safe_next_action_id = str(
|
||||
summary.get("ai_loop_current_blocker_safe_next_action_id") or ""
|
||||
)
|
||||
safe_next_action_stage = str(
|
||||
summary.get("ai_loop_current_blocker_safe_next_action_stage") or ""
|
||||
)
|
||||
receipt_inputs = _strings(
|
||||
summary.get("ai_loop_current_blocker_harbor_recovery_receipt_input_ids")
|
||||
)
|
||||
receipt_outputs = _strings(
|
||||
summary.get("ai_loop_current_blocker_harbor_recovery_receipt_output_ids")
|
||||
)
|
||||
queue_fields = _strings(
|
||||
summary.get("ai_loop_current_blocker_queue_readback_normalizer_field_ids")
|
||||
)
|
||||
log_grouping_keys = _strings(summary.get("ai_loop_log_source_grouping_keys"))
|
||||
|
||||
base_refs = [
|
||||
"awoooi-priority-work-order-readback",
|
||||
_COMMANDER_INSERTED_REQUIREMENT_SOURCE,
|
||||
]
|
||||
if source_sha:
|
||||
base_refs.append(f"production_source:{source_sha}")
|
||||
if cd_run_id:
|
||||
base_refs.append(f"gitea_cd_run:{cd_run_id}:{cd_run_status or 'unknown'}")
|
||||
|
||||
node_specs = [
|
||||
{
|
||||
"node_id": "sensor_evidence",
|
||||
"node_label": "Sensor / Evidence",
|
||||
"node_status": "ready",
|
||||
"work_item_id": "CIR-P0-AILOOP-001",
|
||||
"lane_id": "p0_runtime_lane",
|
||||
"evidence_refs": [*base_refs, *receipt_inputs[:3]],
|
||||
"verifier_result": "production_readback_present",
|
||||
"next_action": "keep source/CD/runtime readback attached to this trace",
|
||||
},
|
||||
{
|
||||
"node_id": "normalizer_log_tags",
|
||||
"node_label": "Normalizer / LOG tags",
|
||||
"node_status": "ready" if queue_fields or log_grouping_keys else "queued",
|
||||
"work_item_id": "CIR-P0-LOG-002",
|
||||
"lane_id": "log_tagging_classification_clustering",
|
||||
"evidence_refs": [*queue_fields[:4], *log_grouping_keys[:4]],
|
||||
"verifier_result": "queue_normalizer_fields_readback"
|
||||
if queue_fields
|
||||
else "normalizer_contract_required",
|
||||
"next_action": "extend tag taxonomy to Telegram, CPU, backup, freshness",
|
||||
},
|
||||
{
|
||||
"node_id": "ai_lane_route",
|
||||
"node_label": "AI Lane",
|
||||
"node_status": "ready",
|
||||
"work_item_id": "CIR-P0-AILOOP-001",
|
||||
"lane_id": "ai_loop_agent_mainline",
|
||||
"evidence_refs": [blocker_id, safe_next_action_stage],
|
||||
"verifier_result": "ai_loop_current_blocker_routed",
|
||||
"next_action": "keep every alert/work item attached to an AI lane",
|
||||
},
|
||||
{
|
||||
"node_id": "candidate_action",
|
||||
"node_label": "Candidate",
|
||||
"node_status": "ready" if safe_next_action_id else "queued",
|
||||
"work_item_id": "CIR-P0-AILOOP-002",
|
||||
"lane_id": "p0_runtime_lane",
|
||||
"evidence_refs": [safe_next_action_id, safe_next_action_stage],
|
||||
"verifier_result": "safe_next_action_readback"
|
||||
if safe_next_action_id
|
||||
else "candidate_action_required",
|
||||
"next_action": "emit candidate action with target selector and dry-run",
|
||||
},
|
||||
{
|
||||
"node_id": "gate_policy",
|
||||
"node_label": "Gate",
|
||||
"node_status": "ready",
|
||||
"work_item_id": "CIR-P0-013",
|
||||
"lane_id": "controlled_apply_gate_taxonomy",
|
||||
"evidence_refs": ["non_accident_gate_as_evidence", "break_glass_reserved"],
|
||||
"verifier_result": "controlled_apply_policy_readback",
|
||||
"next_action": "keep low/medium/high in controlled apply unless hard blocker",
|
||||
},
|
||||
{
|
||||
"node_id": "execution_boundary",
|
||||
"node_label": "Execution Boundary",
|
||||
"node_status": "queued",
|
||||
"work_item_id": "CIR-P0-AILOOP-002",
|
||||
"lane_id": "telegram_alert_ai_automation",
|
||||
"evidence_refs": ["metadata_only", "no_secret_no_runtime_write"],
|
||||
"verifier_result": "execution_receipt_required",
|
||||
"next_action": "attach Telegram alert receipt and controlled executor result",
|
||||
},
|
||||
{
|
||||
"node_id": "post_verifier",
|
||||
"node_label": "Verifier",
|
||||
"node_status": "ready" if receipt_outputs else "queued",
|
||||
"work_item_id": "CIR-P0-AILOOP-002",
|
||||
"lane_id": "p0_runtime_lane",
|
||||
"evidence_refs": receipt_outputs[:4],
|
||||
"verifier_result": "post_verifier_receipt_readback"
|
||||
if receipt_outputs
|
||||
else "post_verifier_required",
|
||||
"next_action": "read back route/API/UI/verifier output before closing",
|
||||
},
|
||||
{
|
||||
"node_id": "learning_writeback",
|
||||
"node_label": "Learning / Writeback",
|
||||
"node_status": "queued",
|
||||
"work_item_id": "CIR-P1-KM-002",
|
||||
"lane_id": "km_rag_mcp_playbook_integration",
|
||||
"evidence_refs": ["KM", "RAG", "MCP", "PlayBook trust"],
|
||||
"verifier_result": "writeback_receipt_required",
|
||||
"next_action": "write KM/RAG/MCP/PlayBook trust refs after verifier",
|
||||
},
|
||||
]
|
||||
|
||||
receipts = []
|
||||
for index, node in enumerate(node_specs, start=1):
|
||||
receipts.append(
|
||||
{
|
||||
"schema_version": _AI_AUTOMATION_NODE_RECEIPT_SCHEMA_VERSION,
|
||||
"trace_id": "trace:awoooi-ai-loop-current-p0",
|
||||
"run_id": cd_run_id or f"priority-readback:{source_sha or 'runtime'}",
|
||||
"node_order": index,
|
||||
"timestamp": runtime_timestamp,
|
||||
"metadata_only": True,
|
||||
"rollback_result": "not_started_no_runtime_write",
|
||||
"km_writeback_ref": ""
|
||||
if node["node_status"] != "queued"
|
||||
else "queued",
|
||||
"playbook_trust_writeback_ref": ""
|
||||
if node["node_status"] != "queued"
|
||||
else "queued",
|
||||
"mcp_evidence_ref": "metadata_registry",
|
||||
"telegram_receipt_ref": "metadata_only"
|
||||
if node["lane_id"] == "telegram_alert_ai_automation"
|
||||
else "",
|
||||
**node,
|
||||
}
|
||||
)
|
||||
|
||||
status_counts = {
|
||||
status: sum(1 for item in receipts if item["node_status"] == status)
|
||||
for status in ("ready", "queued", "blocked")
|
||||
}
|
||||
lanes = sorted({str(item["lane_id"]) for item in receipts})
|
||||
work_items = sorted({str(item["work_item_id"]) for item in receipts})
|
||||
|
||||
payload["ai_automation_node_receipt_schema"] = {
|
||||
"schema_version": _AI_AUTOMATION_NODE_RECEIPT_SCHEMA_VERSION,
|
||||
"required_fields": _AI_AUTOMATION_NODE_RECEIPT_REQUIRED_FIELDS,
|
||||
"metadata_only": True,
|
||||
"hard_blockers_preserved": [
|
||||
"secret_plaintext",
|
||||
"destructive_data_change",
|
||||
"reboot_or_node_drain",
|
||||
"force_push_or_repo_ref_delete",
|
||||
"paid_provider_route_change",
|
||||
],
|
||||
}
|
||||
payload["ai_automation_node_receipts"] = receipts
|
||||
|
||||
rollups["ai_automation_node_receipt_count"] = len(receipts)
|
||||
rollups["ai_automation_node_receipt_ready_count"] = status_counts["ready"]
|
||||
rollups["ai_automation_node_receipt_queued_count"] = status_counts["queued"]
|
||||
rollups["ai_automation_node_receipt_blocked_count"] = status_counts["blocked"]
|
||||
rollups["ai_automation_node_receipt_required_field_count"] = len(
|
||||
_AI_AUTOMATION_NODE_RECEIPT_REQUIRED_FIELDS
|
||||
)
|
||||
rollups["ai_automation_node_receipt_metadata_only"] = True
|
||||
rollups["ai_automation_node_receipt_lanes"] = lanes
|
||||
rollups["ai_automation_node_receipt_work_items"] = work_items
|
||||
|
||||
summary["ai_automation_node_receipt_schema_version"] = (
|
||||
_AI_AUTOMATION_NODE_RECEIPT_SCHEMA_VERSION
|
||||
)
|
||||
summary["ai_automation_node_receipt_count"] = len(receipts)
|
||||
summary["ai_automation_node_receipt_ready_count"] = status_counts["ready"]
|
||||
summary["ai_automation_node_receipt_queued_count"] = status_counts["queued"]
|
||||
summary["ai_automation_node_receipt_blocked_count"] = status_counts["blocked"]
|
||||
summary["ai_automation_node_receipt_required_field_count"] = len(
|
||||
_AI_AUTOMATION_NODE_RECEIPT_REQUIRED_FIELDS
|
||||
)
|
||||
summary["ai_automation_node_receipt_metadata_only"] = True
|
||||
summary["ai_automation_node_receipt_lanes"] = lanes
|
||||
summary["ai_automation_node_receipt_work_items"] = work_items
|
||||
|
||||
|
||||
def _mark_runtime_generated_at(payload: dict[str, Any]) -> None:
|
||||
snapshot_generated_at = str(
|
||||
payload.get("snapshot_generated_at") or payload.get("generated_at") or ""
|
||||
|
||||
Reference in New Issue
Block a user