feat(telegram): expose alert learning writeback refs
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 56s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
AI 技術雷達監控 / ai-technology-watch (push) Successful in 45s

This commit is contained in:
Your Name
2026-07-02 19:57:38 +08:00
parent 9fb0478752
commit 502a4a1ca6
10 changed files with 299 additions and 18 deletions

View File

@@ -1378,6 +1378,23 @@ async def list_ai_alert_card_delivery_readback(
'0'
) <> '0'
) AS runtime_write_gate_open_count,
COUNT(*) FILTER (
WHERE COALESCE(
m.source_envelope #>>
'{{ai_automation_alert_card,delivery_receipt_readback_required}}',
''
) = 'true'
AND COALESCE(
m.source_envelope #>>
'{{ai_automation_alert_card,event_type}}',
''
) <> ''
AND COALESCE(
m.source_envelope #>>
'{{ai_automation_alert_card,lane}}',
''
) <> ''
) AS learning_writeback_ready_total,
MAX(m.sent_at) AS latest_sent_at,
MAX(m.queued_at) AS latest_queued_at
FROM awooop_outbound_message m
@@ -1464,6 +1481,10 @@ def _ai_alert_card_delivery_summary_from_row(
runtime_write_gate_open_count = _safe_int(
row.get("runtime_write_gate_open_count")
)
learning_writeback_ready_total = _safe_int(
row.get("learning_writeback_ready_total")
)
learning_writeback_missing_total = max(total - learning_writeback_ready_total, 0)
status_value = "no_delivery_receipt" if total == 0 else "observed"
if failed_total > 0:
status_value = "delivery_failure_observed"
@@ -1486,6 +1507,18 @@ def _ai_alert_card_delivery_summary_from_row(
),
"runtime_write_gate_open_count": runtime_write_gate_open_count,
"runtime_write_allowed": runtime_write_gate_open_count > 0,
"learning_writeback_ready_total": learning_writeback_ready_total,
"learning_writeback_missing_total": learning_writeback_missing_total,
"km_writeback_ref_ready_total": learning_writeback_ready_total,
"playbook_writeback_ref_ready_total": learning_writeback_ready_total,
"rag_chunk_ref_ready_total": learning_writeback_ready_total,
"mcp_evidence_ref_ready_total": learning_writeback_ready_total,
"post_verifier_ref_ready_total": learning_writeback_ready_total,
"learning_writeback_next_action": (
"none"
if total > 0 and learning_writeback_missing_total == 0
else "ensure_ai_alert_cards_include_event_type_lane_and_delivery_receipt"
),
"latest_sent_at": row.get("latest_sent_at"),
"latest_queued_at": row.get("latest_queued_at"),
"production_write_count": 0,
@@ -1502,6 +1535,13 @@ def _ai_alert_card_delivery_item(row: Mapping[str, Any]) -> dict[str, Any]:
alert_card.get("runtime_write_gate_count")
)
event_at = row.get("sent_at") or row.get("queued_at")
learning_writeback_refs = _ai_alert_card_learning_writeback_refs(
alert_card=alert_card,
source_refs=source_refs,
message_id=row.get("message_id"),
run_id=run_id,
project_id=project_id,
)
return {
"message_id": row.get("message_id"),
"run_id": run_id,
@@ -1527,6 +1567,11 @@ def _ai_alert_card_delivery_item(row: Mapping[str, Any]) -> dict[str, Any]:
"delivery_receipt_readback_required": bool(
alert_card.get("delivery_receipt_readback_required")
),
"learning_writeback_ready": (
learning_writeback_refs["status"] == "ready"
),
"learning_writeback_status": learning_writeback_refs["status"],
"learning_writeback_refs": learning_writeback_refs,
"source_refs": source_refs,
"run_state": row.get("run_state"),
"agent_id": row.get("agent_id"),
@@ -1539,6 +1584,77 @@ def _ai_alert_card_delivery_item(row: Mapping[str, Any]) -> dict[str, Any]:
}
def _slug_ref(value: Any, fallback: str) -> str:
slug = re.sub(r"[^a-z0-9_.:-]+", "-", str(value or "").strip().lower())
slug = slug.strip("-")
return slug or fallback
def _ai_alert_card_learning_writeback_refs(
*,
alert_card: Mapping[str, Any],
source_refs: Mapping[str, Any],
message_id: Any,
run_id: Any,
project_id: str,
) -> dict[str, Any]:
"""Build deterministic KM / PlayBook / RAG / MCP refs for one alert receipt."""
event_type = str(alert_card.get("event_type") or "")
lane = str(alert_card.get("lane") or "")
target = str(alert_card.get("target") or "")
delivery_required = bool(alert_card.get("delivery_receipt_readback_required"))
event_slug = _slug_ref(event_type, "unknown-event")
lane_slug = _slug_ref(lane, "unknown-lane")
target_slug = _slug_ref(target, "unknown-target")
message_ref = _slug_ref(message_id, "unknown-message")
run_ref = _slug_ref(run_id, "unknown-run")
missing = [
key
for key, value in (
("event_type", event_type),
("lane", lane),
("delivery_receipt_readback_required", delivery_required),
)
if value in ("", False, None)
]
status = "ready" if not missing else "missing_required_alert_card_metadata"
fingerprints = source_refs.get("fingerprints") if isinstance(source_refs, Mapping) else []
alert_ids = source_refs.get("alert_ids") if isinstance(source_refs, Mapping) else []
return {
"schema_version": "ai_alert_card_learning_writeback_refs_v1",
"status": status,
"work_item_id": "CIR-P0-TG-001",
"receipt_source": "awooop_outbound_message",
"receipt_id": str(message_id or ""),
"run_id": str(run_id or ""),
"project_id": project_id,
"km_entry_ref": f"km://{project_id}/telegram-ai-alert-card/{event_slug}",
"playbook_candidate_ref": (
f"playbook://{project_id}/telegram-ai-alert-card/{lane_slug}/{target_slug}"
),
"rag_chunk_ref": (
f"rag://{project_id}/telegram-ai-alert-card/{event_slug}/{message_ref}"
),
"mcp_evidence_ref": (
f"mcp://{project_id}/awooop_outbound_message/{message_ref}"
),
"post_verifier_ref": (
f"verifier://{project_id}/telegram-alert-delivery-receipt/{run_ref}"
),
"source_fingerprints": fingerprints if isinstance(fingerprints, list) else [],
"alert_ids": alert_ids if isinstance(alert_ids, list) else [],
"missing_required_fields": missing,
"production_write_performed": False,
"runtime_send_performed": False,
"next_action": (
"none"
if status == "ready"
else "ensure_ai_alert_cards_include_event_type_lane_and_delivery_receipt"
),
}
async def _fetch_callback_reply_audit_summary(
db: Any,
*,