Files
awoooi/apps/api/src/services/telegram_alert_ai_automation_matrix.py
ogt 847a6ed0d5
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 2m33s
CD Pipeline / build-and-deploy (push) Successful in 6m43s
CD Pipeline / post-deploy-checks (push) Successful in 1m48s
AWOOOI Harbor 110 Local Repair / workflow-shape (push) Successful in 1s
AWOOOI Harbor 110 Local Repair / harbor-110-local-repair (push) Successful in 50s
fix(alerts): close controlled canary lifecycle
2026-07-11 12:56:25 +08:00

909 lines
41 KiB
Python

"""Telegram alert AI automation matrix readback.
Builds a repo-committed, metadata-only matrix that shows whether Telegram alert
surfaces are wired into AI automation receipts instead of ending as manual
messages. This module never sends Telegram, calls Bot API, reads secrets, or
writes runtime queues.
"""
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
from src.services.snapshot_paths import (
default_evaluations_dir,
default_security_dir,
resolve_repo_root,
)
_SCHEMA_VERSION = "telegram_alert_ai_automation_matrix_v1"
_EGRESS_INVENTORY = "telegram-notification-egress-inventory.snapshot.json"
_OWNER_ACCEPTANCE = "telegram-notification-egress-owner-response-acceptance.snapshot.json"
_MIGRATION_PLAN = "telegram-notification-egress-migration-plan-draft.snapshot.json"
_READABILITY_GUARD = "telegram-alert-readability-guard.snapshot.json"
_DIGEST_POLICY_PATTERN = "ai_agent_telegram_action_required_digest_policy_*.json"
_AWOOOP_VERIFIED_CONTEXT_SURFACE_SOURCE = (
"apps/web/src/components/awooop/autonomous-runtime-receipt-panel.tsx"
)
_AWOOOP_VERIFIED_CONTEXT_SURFACE_MARKER = (
"telegram-alert-post-apply-verifier-readback"
)
def load_latest_telegram_alert_ai_automation_matrix(
security_dir: Path | None = None,
evaluations_dir: Path | None = None,
) -> dict[str, Any]:
"""Return the latest Telegram alert AI automation matrix."""
anchor = Path(__file__)
security = security_dir or default_security_dir(anchor)
evaluations = evaluations_dir or default_evaluations_dir(anchor)
repo_root = resolve_repo_root(anchor)
egress_inventory = _load_required_json(security / _EGRESS_INVENTORY)
owner_acceptance = _load_required_json(security / _OWNER_ACCEPTANCE)
migration_plan = _load_required_json(security / _MIGRATION_PLAN)
readability_guard = _load_required_json(security / _READABILITY_GUARD)
digest_policy = _load_latest_json(evaluations, _DIGEST_POLICY_PATTERN)
_require_schema(
egress_inventory,
"telegram_notification_egress_inventory_v1",
_EGRESS_INVENTORY,
)
_require_schema(
owner_acceptance,
"telegram_notification_egress_owner_response_acceptance_v1",
_OWNER_ACCEPTANCE,
)
_require_schema(
migration_plan,
"telegram_notification_egress_migration_plan_draft_v1",
_MIGRATION_PLAN,
)
_require_schema(
readability_guard,
"telegram_alert_readability_guard_v1",
_READABILITY_GUARD,
)
_require_schema(
digest_policy,
"ai_agent_telegram_action_required_digest_policy_v1",
_DIGEST_POLICY_PATTERN,
)
_require_safe_boundaries(
egress_inventory,
owner_acceptance,
migration_plan,
readability_guard,
digest_policy,
)
egress_summary = egress_inventory["summary"]
owner_summary = owner_acceptance["summary"]
migration_summary = migration_plan["summary"]
readability_summary = readability_guard["summary"]
digest_rollups = digest_policy["rollups"]
source_proof = _inspect_source_contract(repo_root)
source_contract_missing_markers = list(
source_proof.get("source_contract_missing_markers") or []
)
learning_writeback_refs_present = bool(
source_proof["ai_alert_card_learning_writeback_refs_present"]
)
learning_registry_present = bool(
source_proof["ai_alert_card_learning_registry_readback_present"]
)
ai_loop_context_present = bool(
source_proof["telegram_alert_ai_loop_consumer_context_readback_present"]
)
post_apply_verifier_present = bool(
source_proof["telegram_alert_post_apply_verifier_readback_present"]
)
post_apply_verifier_surface_present = bool(
source_proof["telegram_alert_post_apply_verifier_awooop_surface_present"]
)
direct_gap_count = int(egress_summary["direct_bot_api_call_count"])
direct_gap_file_count = int(egress_summary["direct_bot_api_file_count"])
api_direct_gap_count = int(egress_summary["api_direct_bot_api_call_count"])
ops_script_gap_count = int(egress_summary["ops_script_direct_bot_api_call_count"])
migration_candidate_count = int(migration_summary["migration_candidate_count"])
direct_gap_closed = direct_gap_count == 0
direct_gap_refs = [
{
"surface_id": item["egress_surface_id"],
"surface_kind": item["surface_kind"],
"path": item["path"],
"line": item["line"],
"line_hash": item["line_hash"],
}
for item in egress_inventory.get("direct_bot_api_calls", [])
]
matrix = [
{
"surface_id": "telegram_gateway_ai_alert_cards",
"priority_work_item_id": "CIR-P0-TG-001",
"surface_kind": "gateway_final_exit",
"status": "ai_controlled_receipt_path_ready",
"known_item_count": int(readability_summary["final_exit_contract_count"]),
"db_or_log_receipt": "ready_via_awooop_outbound_message_mirror",
"ai_route": "ready_ai_automation_alert_card_v1",
"controlled_queue": "ready_controlled_playbook_queue",
"post_verifier": "ready_telegram_alert_readability_guard",
"learning_writeback": "ready_learning_writeback_refs",
"manual_default_gap_count": 0,
"direct_send_gap_count": 0,
"evidence_refs": [
"docs/security/telegram-alert-readability-guard.snapshot.json",
"apps/api/src/services/telegram_gateway.py",
"/api/v1/platform/runs/ai-alert-cards",
],
},
{
"surface_id": "telegram_direct_bot_api_egress_gap",
"priority_work_item_id": "CIR-P0-TG-001",
"surface_kind": "direct_bot_api_gap",
"status": (
"gap_closed_no_direct_bot_api_routes_detected"
if direct_gap_closed
else "gap_open_requires_controlled_migration"
),
"known_item_count": direct_gap_count,
"db_or_log_receipt": (
"ready_no_direct_routes_remaining"
if direct_gap_closed
else "missing_or_not_proven_for_direct_path"
),
"ai_route": (
"ready_no_direct_routes_remaining"
if direct_gap_closed
else "missing_or_not_proven_for_direct_path"
),
"controlled_queue": (
"ready_not_applicable_no_direct_migration_queue_needed"
if direct_gap_closed
else "missing_or_not_proven_for_direct_path"
),
"post_verifier": (
"ready_metadata_inventory_clear"
if direct_gap_closed
else "metadata_inventory_ready"
),
"learning_writeback": (
"ready_bind_gateway_receipts_to_learning_writeback"
if direct_gap_closed
else "migration_candidate_ready_not_applied"
),
"manual_default_gap_count": direct_gap_count,
"direct_send_gap_count": direct_gap_count,
"evidence_refs": [
"docs/security/telegram-notification-egress-inventory.snapshot.json",
"docs/security/telegram-notification-egress-migration-plan-draft.snapshot.json",
],
},
{
"surface_id": "telegram_action_required_digest_policy",
"priority_work_item_id": "CIR-P0-TG-001",
"surface_kind": "ai_digest_policy",
"status": "no_send_policy_ready",
"known_item_count": int(digest_rollups["rule_count"]),
"db_or_log_receipt": "ready_source_policy_receipt_no_runtime_write",
"ai_route": "ready_action_required_and_failure_only_rules",
"controlled_queue": "ready_policy_gate_no_direct_send",
"post_verifier": "ready_policy_loader_validation",
"learning_writeback": "ready_next_task_ids",
"manual_default_gap_count": 0,
"direct_send_gap_count": 0,
"evidence_refs": [
"docs/evaluations/ai_agent_telegram_action_required_digest_policy_2026-06-11.json",
"/api/v1/agents/agent-telegram-action-required-digest-policy",
],
},
{
"surface_id": "telegram_egress_controlled_migration_candidates",
"priority_work_item_id": "CIR-P0-TG-001",
"surface_kind": "migration_candidate",
"status": (
"controlled_migration_complete_no_candidates"
if migration_candidate_count == 0
else "controlled_apply_candidates_ready"
),
"known_item_count": migration_candidate_count,
"db_or_log_receipt": (
"ready_no_direct_migration_candidates"
if migration_candidate_count == 0
else "required_before_candidate_close"
),
"ai_route": (
"ready_no_direct_migration_candidates"
if migration_candidate_count == 0
else "migration_plan_ready"
),
"controlled_queue": (
"ready_not_applicable_no_direct_migration_queue_needed"
if migration_candidate_count == 0
else "ready_for_controlled_apply_review"
),
"post_verifier": (
"ready_owner_acceptance_ledger_clear"
if migration_candidate_count == 0
else "owner_acceptance_ledger_ready"
),
"learning_writeback": (
"ready_bind_gateway_receipts_to_learning_writeback"
if migration_candidate_count == 0
else "candidate_acceptance_metadata_ready"
),
"manual_default_gap_count": 0,
"direct_send_gap_count": direct_gap_count,
"evidence_refs": [
"docs/security/telegram-notification-egress-owner-response-acceptance.snapshot.json",
"docs/security/telegram-notification-egress-migration-plan-draft.snapshot.json",
],
},
{
"surface_id": "telegram_ai_alert_card_delivery_readback_endpoint",
"priority_work_item_id": "CIR-P0-TG-001",
"surface_kind": "production_readback_endpoint",
"status": "readback_endpoint_present",
"known_item_count": source_proof["ai_alert_card_delivery_readback_endpoint_count"],
"db_or_log_receipt": "ready_awooop_outbound_message_query",
"ai_route": "ready_event_type_lane_target_filters",
"controlled_queue": "ready_not_applicable_read_only_query_no_send",
"post_verifier": "ready_source_contract_present",
"learning_writeback": "ready_delivery_receipt_summary_and_learning_writeback_refs",
"manual_default_gap_count": 0,
"direct_send_gap_count": 0,
"evidence_refs": [
"apps/api/src/api/v1/platform/operator_runs.py",
"apps/api/src/db/awooop_models.py",
],
},
{
"surface_id": "telegram_alert_learning_registry_readback",
"priority_work_item_id": "CIR-P0-TG-001",
"surface_kind": "learning_registry_readback",
"status": (
"registry_readback_present"
if learning_registry_present
else "registry_readback_missing"
),
"known_item_count": source_proof[
"ai_alert_card_learning_registry_readback_count"
],
"db_or_log_receipt": "ready_awooop_outbound_message_learning_refs",
"ai_route": "ready_ai_loop_agent_consumer_context",
"controlled_queue": "ready_metadata_only_consumer_binding",
"post_verifier": "ready_registry_source_contract_present",
"learning_writeback": (
"ready_km_rag_playbook_mcp_verifier_ai_agent_registry"
if learning_registry_present
else "missing_registry_readback"
),
"manual_default_gap_count": 0,
"direct_send_gap_count": 0,
"evidence_refs": [
"apps/api/src/services/platform_operator_service.py",
"/api/v1/platform/runs/ai-alert-cards",
],
},
{
"surface_id": "telegram_ai_loop_agent_consumer_context",
"priority_work_item_id": "CIR-P0-TG-001",
"surface_kind": "ai_loop_agent_consumer_context",
"status": (
"ai_loop_context_readback_present"
if ai_loop_context_present
else "ai_loop_context_readback_missing"
),
"known_item_count": source_proof[
"telegram_alert_ai_loop_consumer_context_readback_count"
],
"db_or_log_receipt": "ready_ai_alert_card_registry_receipts",
"ai_route": (
"ready_ai_loop_agent_context_reuse"
if ai_loop_context_present
else "missing_ai_loop_agent_context_reuse"
),
"controlled_queue": (
"ready_metadata_only_context_receipt"
if ai_loop_context_present
else "missing_context_receipt"
),
"post_verifier": (
"ready_ai_loop_context_source_contract_present"
if ai_loop_context_present
else "missing_ai_loop_context_source_contract"
),
"learning_writeback": (
"ready_agent_context_receipt_readback"
if ai_loop_context_present
else "missing_agent_context_receipt_readback"
),
"manual_default_gap_count": 0,
"direct_send_gap_count": 0,
"evidence_refs": [
"apps/api/src/services/ai_agent_log_controlled_writeback_consumer_readback.py",
"/api/v1/agents/agent-log-controlled-writeback-consumer-readback",
],
},
{
"surface_id": "telegram_ai_loop_post_apply_verifier",
"priority_work_item_id": "CIR-P0-TG-001",
"surface_kind": "ai_loop_post_apply_verifier",
"status": (
"post_apply_verifier_readback_present"
if post_apply_verifier_present
else "post_apply_verifier_readback_missing"
),
"known_item_count": source_proof[
"telegram_alert_post_apply_verifier_readback_count"
],
"db_or_log_receipt": "ready_ai_loop_context_receipt_source",
"ai_route": (
"ready_verified_context_reuse"
if post_apply_verifier_present
else "missing_verified_context_reuse"
),
"controlled_queue": (
"ready_metadata_only_verifier"
if post_apply_verifier_present
else "missing_metadata_only_verifier"
),
"post_verifier": (
"ready_context_receipt_post_apply_verifier"
if post_apply_verifier_present
else "missing_context_receipt_post_apply_verifier"
),
"learning_writeback": (
"ready_verified_context_receipt_for_km_playbook_trust"
if post_apply_verifier_present
else "missing_verified_context_receipt"
),
"manual_default_gap_count": 0,
"direct_send_gap_count": 0,
"evidence_refs": [
"apps/api/src/services/telegram_alert_learning_context_post_apply_verifier.py",
"/api/v1/agents/telegram-alert-learning-context-post-apply-verifier",
],
},
{
"surface_id": "telegram_verified_context_awooop_operator_surface",
"priority_work_item_id": "CIR-P0-TG-001",
"surface_kind": "awooop_operator_surface",
"status": (
"verified_context_receipt_surface_present"
if post_apply_verifier_surface_present
else "verified_context_receipt_surface_missing"
),
"known_item_count": source_proof[
"telegram_alert_post_apply_verifier_awooop_surface_count"
],
"db_or_log_receipt": "ready_consumes_post_apply_verifier_readback",
"ai_route": (
"ready_operator_visible_ai_loop_receipts"
if post_apply_verifier_surface_present
else "missing_operator_visible_ai_loop_receipts"
),
"controlled_queue": "ready_read_only_ui_surface_no_send_no_apply",
"post_verifier": (
"ready_awooop_surface_source_contract_present"
if post_apply_verifier_surface_present
else "missing_awooop_surface_source_contract"
),
"learning_writeback": (
"ready_human_observable_ai_agent_learning_receipts"
if post_apply_verifier_surface_present
else "missing_human_observable_ai_agent_learning_receipts"
),
"manual_default_gap_count": 0,
"direct_send_gap_count": 0,
"evidence_refs": [
"apps/web/src/components/awooop/autonomous-runtime-receipt-panel.tsx",
"/zh-TW/awooop/runs",
"/zh-TW/awooop/work-items",
"/zh-TW/awooop/alerts",
],
},
]
next_priority_action = _next_priority_action(
api_direct_gap_count=api_direct_gap_count,
ops_script_gap_count=ops_script_gap_count,
direct_gap_count=direct_gap_count,
learning_writeback_refs_present=learning_writeback_refs_present,
learning_registry_present=learning_registry_present,
ai_loop_context_present=ai_loop_context_present,
post_apply_verifier_present=post_apply_verifier_present,
post_apply_verifier_surface_present=post_apply_verifier_surface_present,
)
next_controlled_actions = _ordered_controlled_actions(next_priority_action)
summary = _build_summary(
matrix=matrix,
direct_gap_count=direct_gap_count,
direct_gap_file_count=direct_gap_file_count,
egress_summary=egress_summary,
owner_summary=owner_summary,
migration_summary=migration_summary,
readability_summary=readability_summary,
digest_rollups=digest_rollups,
source_proof=source_proof,
next_priority_action=next_priority_action,
)
return {
"schema_version": _SCHEMA_VERSION,
"status": (
"telegram_alert_ai_automation_matrix_ready_with_direct_send_gaps"
if direct_gap_count
else "blocked_telegram_alert_ai_automation_matrix_source_contract_gaps"
if source_contract_missing_markers
else "telegram_alert_ai_automation_matrix_ready"
),
"mode": "metadata_only_no_secret_no_telegram_send_no_runtime_write",
"priority_work_item_id": "CIR-P0-TG-001",
"source_refs": {
"egress_inventory": f"docs/security/{_EGRESS_INVENTORY}",
"owner_acceptance": f"docs/security/{_OWNER_ACCEPTANCE}",
"migration_plan": f"docs/security/{_MIGRATION_PLAN}",
"readability_guard": f"docs/security/{_READABILITY_GUARD}",
"digest_policy": "docs/evaluations/ai_agent_telegram_action_required_digest_policy_2026-06-11.json",
},
"operation_boundaries": {
"telegram_send_performed": False,
"bot_api_call_performed": False,
"gateway_queue_write_performed": False,
"runtime_write_performed": False,
"secret_value_read": False,
"raw_payload_stored": False,
"receiver_route_changed": False,
"workflow_dispatch_performed": False,
"production_write_performed": False,
"metadata_only": True,
},
"summary": summary,
"matrix": matrix,
"direct_send_gap_refs": direct_gap_refs,
"next_controlled_actions": next_controlled_actions,
"operator_interpretation": [
"TelegramGateway AI alert cards already expose AI route, controlled queue, final-exit formatter, outbound mirror metadata, and readback endpoint support.",
(
"Known direct Bot API surfaces are clear; keep future Telegram sends on the gateway receipt path."
if direct_gap_closed
else "Known direct Bot API surfaces remain the concrete AI automation gap; API direct senders are clear when api_direct_send_gap_count is 0."
),
(
(
(
(
"Manual/default semantics are only acceptable for critical/break-glass or historical evidence; "
+ (
(
"Telegram alert AI Loop context receipts are visible in AwoooP operator surfaces; "
"the next P0 step is full monitoring alert DB/log coverage audit."
)
if post_apply_verifier_surface_present
else (
"Telegram alert AI Loop context has a post-apply verifier readback, "
"so the next P0 step is surfacing verified receipts in Runs / Work Items / Alerts."
)
)
)
if post_apply_verifier_present
else (
"Manual/default semantics are only acceptable for critical/break-glass or historical evidence; "
"Telegram alert registry is now consumable by AI Loop Agent context, "
"so the next P0 step is post-apply verifier receipt."
)
)
if ai_loop_context_present
else (
"Manual/default semantics are only acceptable for critical/break-glass or historical evidence; "
"KM / PlayBook / RAG / MCP / verifier / AI Agent registry readback is present, "
"so the next P0 step is AI Loop Agent consumer context."
)
if learning_registry_present
else (
"Manual/default semantics are only acceptable for critical/break-glass or historical evidence; "
"learning refs are present, so the next P0 step is KM / PlayBook / RAG / MCP registry readback."
)
if learning_writeback_refs_present
else "Manual/default semantics are only acceptable for critical/break-glass or historical evidence; the next P0 step is learning/writeback readback."
)
if direct_gap_closed
else "Manual/default semantics are only acceptable for critical/break-glass or historical evidence; direct send gaps remain controlled migration candidates."
),
],
}
def _ordered_controlled_actions(next_priority_action: dict[str, Any]) -> list[dict[str, Any]]:
actions = [
next_priority_action,
{
"action_id": "migrate_api_direct_sender_to_gateway",
"scope": "apps/api/src/services/channel_hub.py",
"priority": "P0",
"why": "API direct Bot API path is the remaining high-blast-radius bypass.",
"requires_secret": False,
"requires_runtime_send": False,
"post_verifier": "telegram-notification-egress-inventory direct gap count decreases and TelegramGateway mirror tests pass.",
},
{
"action_id": "migrate_ops_script_direct_senders_to_receipt_path",
"scope": "scripts/ops direct Bot API sendMessage surfaces",
"priority": "P0",
"why": "Ops script direct sends can bypass DB/log receipt and AI automation card metadata.",
"requires_secret": False,
"requires_runtime_send": False,
"post_verifier": "egress inventory and owner acceptance matrix show no unreviewed direct sends.",
},
_legacy_bind_ai_alert_cards_action(),
]
ordered: list[dict[str, Any]] = []
seen: set[str] = set()
for action in actions:
action_id = str(action["action_id"])
if action_id in seen:
continue
seen.add(action_id)
ordered.append(action)
return ordered
def _load_required_json(path: Path) -> dict[str, Any]:
if not path.exists():
raise FileNotFoundError(f"required Telegram matrix source missing: {path}")
with path.open(encoding="utf-8") as handle:
payload = json.load(handle)
if not isinstance(payload, dict):
raise ValueError(f"{path}: expected JSON object")
return payload
def _load_latest_json(directory: Path, pattern: str) -> dict[str, Any]:
candidates = sorted(directory.glob(pattern))
if not candidates:
raise FileNotFoundError(f"no matching snapshots found in {directory}: {pattern}")
return _load_required_json(candidates[-1])
def _require_schema(payload: dict[str, Any], expected: str, label: str) -> None:
actual = payload.get("schema_version")
if actual != expected:
raise ValueError(f"{label}: expected schema_version={expected}, got {actual!r}")
def _require_safe_boundaries(*payloads: dict[str, Any]) -> None:
forbidden_true_keys = {
"telegram_send_authorized",
"bot_api_call_authorized",
"telegram_direct_send_allowed",
"telegram_gateway_queue_write_allowed",
"runtime_execution_authorized",
"runtime_execution_allowed",
"runtime_gate_open",
"workflow_dispatch_authorized",
"production_deploy_authorized",
"production_write_authorized",
"secret_value_collection_allowed",
"secret_plaintext_allowed",
"raw_payload_storage_allowed",
"conversation_transcript_allowed",
}
for payload in payloads:
for section_key in (
"operation_boundaries",
"execution_boundaries",
"approval_boundaries",
):
section = payload.get(section_key) or {}
if not isinstance(section, dict):
continue
unsafe = sorted(
key
for key in forbidden_true_keys
if section.get(key) not in (None, False)
)
if unsafe:
raise ValueError(
f"{payload.get('schema_version')}.{section_key}: unsafe true flags {unsafe}"
)
def _inspect_source_contract(repo_root: Path) -> dict[str, Any]:
source_checks = {
"telegram_gateway_mirror_present": (
"apps/api/src/services/telegram_gateway.py",
"_mirror_outbound_message",
),
"telegram_gateway_record_outbound_present": (
"apps/api/src/services/telegram_gateway.py",
"record_outbound_message",
),
"ai_alert_card_metadata_present": (
"apps/api/src/services/telegram_gateway.py",
"ai_automation_alert_card_mirror_v1",
),
"outbound_message_model_present": (
"apps/api/src/db/awooop_models.py",
"__tablename__ = \"awooop_outbound_message\"",
),
"ai_alert_card_delivery_readback_endpoint_present": (
"apps/api/src/api/v1/platform/operator_runs.py",
"/runs/ai-alert-cards",
),
"ai_alert_card_learning_writeback_refs_present": (
"apps/api/src/api/v1/platform/operator_runs.py",
"learning_writeback_refs",
),
"ai_alert_card_learning_writeback_summary_present": (
"apps/api/src/api/v1/platform/operator_runs.py",
"learning_writeback_ready_total",
),
"ai_alert_card_learning_registry_readback_present": (
"apps/api/src/services/platform_operator_service.py",
"ai_alert_card_learning_registry_readback_v1",
),
"ai_alert_card_ai_agent_context_ref_present": (
"apps/api/src/services/platform_operator_service.py",
"ai_agent_context_ref",
),
"telegram_alert_ai_loop_consumer_context_readback_present": (
"apps/api/src/services/ai_agent_log_controlled_writeback_consumer_readback.py",
"telegram_alert_ai_loop_consumer_context_readback_v1",
),
"telegram_alert_post_apply_verifier_readback_present": (
"apps/api/src/services/telegram_alert_learning_context_post_apply_verifier.py",
"telegram_alert_learning_context_post_apply_verifier_v1",
),
"telegram_alert_post_apply_verifier_awooop_surface_present": (
_AWOOOP_VERIFIED_CONTEXT_SURFACE_SOURCE,
_AWOOOP_VERIFIED_CONTEXT_SURFACE_MARKER,
),
}
result: dict[str, int | bool] = {}
for key, (relative_path, marker) in source_checks.items():
text = _read_source_contract_text(repo_root, relative_path)
present = marker in text
result[key] = present
if key == "ai_alert_card_delivery_readback_endpoint_present":
result["ai_alert_card_delivery_readback_endpoint_count"] = 1 if present else 0
if key == "ai_alert_card_learning_writeback_refs_present":
result["ai_alert_card_learning_writeback_refs_count"] = 1 if present else 0
if key == "ai_alert_card_learning_registry_readback_present":
result["ai_alert_card_learning_registry_readback_count"] = (
1 if present else 0
)
if key == "telegram_alert_ai_loop_consumer_context_readback_present":
result["telegram_alert_ai_loop_consumer_context_readback_count"] = (
1 if present else 0
)
if key == "telegram_alert_post_apply_verifier_readback_present":
result["telegram_alert_post_apply_verifier_readback_count"] = (
1 if present else 0
)
if key == "telegram_alert_post_apply_verifier_awooop_surface_present":
result["telegram_alert_post_apply_verifier_awooop_surface_count"] = (
1 if present else 0
)
required = [
key
for key, value in result.items()
if key.endswith("_present") and value is not True
]
result["source_contract_ready"] = not required
result["source_contract_missing_markers"] = required
return result
def _read_source_contract_text(repo_root: Path, relative_path: str) -> str:
candidates = [repo_root / relative_path]
api_prefix = "apps/api/"
if relative_path.startswith(api_prefix):
candidates.append(repo_root / relative_path.removeprefix(api_prefix))
if (
relative_path == _AWOOOP_VERIFIED_CONTEXT_SURFACE_SOURCE
and not (repo_root / "apps").exists()
):
candidates.append(repo_root / "src/services/telegram_alert_ai_automation_matrix.py")
for path in candidates:
if path.exists():
return path.read_text(encoding="utf-8", errors="replace")
return ""
def _next_priority_action(
*,
api_direct_gap_count: int,
ops_script_gap_count: int,
direct_gap_count: int,
learning_writeback_refs_present: bool,
learning_registry_present: bool,
ai_loop_context_present: bool,
post_apply_verifier_present: bool,
post_apply_verifier_surface_present: bool,
) -> dict[str, Any]:
if api_direct_gap_count > 0:
return {
"action_id": "migrate_api_direct_sender_to_gateway",
"scope": "apps/api/src/services/channel_hub.py",
"priority": "P0",
"why": "API direct Bot API path is the remaining high-blast-radius bypass.",
"requires_secret": False,
"requires_runtime_send": False,
"post_verifier": "telegram-notification-egress-inventory direct gap count decreases and TelegramGateway mirror tests pass.",
}
if ops_script_gap_count > 0:
return {
"action_id": "migrate_ops_script_direct_senders_to_receipt_path",
"scope": "scripts/ops direct Bot API sendMessage surfaces",
"priority": "P0",
"why": "Only ops script direct Bot API paths remain after API sender convergence.",
"requires_secret": False,
"requires_runtime_send": False,
"post_verifier": "telegram-notification-egress-inventory reports ops=0 and owner acceptance candidates=0 for direct Bot API surfaces.",
}
if direct_gap_count > 0:
return {
"action_id": "migrate_remaining_direct_senders_to_receipt_path",
"scope": "remaining direct Bot API sendMessage surfaces",
"priority": "P0",
"why": "Direct Bot API paths still bypass the controlled receipt path.",
"requires_secret": False,
"requires_runtime_send": False,
"post_verifier": "telegram-notification-egress-inventory direct gap count reaches 0.",
}
if not learning_writeback_refs_present:
return {
"action_id": "bind_ai_alert_cards_to_learning_writeback",
"scope": "ai_automation_alert_card_v1 outbound mirror metadata",
"priority": "P0",
"why": "All direct Bot API gaps are clear; close the learning/writeback loop.",
"requires_secret": False,
"requires_runtime_send": False,
"post_verifier": "/api/v1/platform/runs/ai-alert-cards readback shows delivery_receipt_readback_required and learning writeback refs.",
}
if not learning_registry_present:
return {
"action_id": "promote_telegram_alert_learning_refs_to_km_rag_mcp_registry",
"scope": "AI alert card receipt refs -> KM / PlayBook / RAG / MCP registry readback",
"priority": "P0",
"why": "Alert cards now expose learning refs; the next closure is registry/readback integration for AI Loop Agent reuse.",
"requires_secret": False,
"requires_runtime_send": False,
"post_verifier": "KM / PlayBook / RAG / MCP registry readback includes CIR-P0-TG-001 alert-card receipt refs.",
}
if not ai_loop_context_present:
return {
"action_id": "consume_telegram_alert_learning_registry_in_ai_loop_agent_context",
"scope": "KM / PlayBook / RAG / MCP / verifier registry -> AI Loop Agent consumer context",
"priority": "P0",
"why": "Telegram alert learning registry is readable; the next closure is AI Loop Agent consumer context reuse and apply receipt.",
"requires_secret": False,
"requires_runtime_send": False,
"post_verifier": "AI Loop Agent context readback references the CIR-P0-TG-001 Telegram alert learning registry.",
}
if not post_apply_verifier_present:
return {
"action_id": "verify_telegram_alert_learning_context_receipts_with_ai_loop_post_apply_verifier",
"scope": "AI Loop Agent Telegram alert consumer context -> post-apply verifier receipt",
"priority": "P0",
"why": "Telegram alert learning registry is readable by AI Loop Agent context; the next closure is verifier receipt and controlled apply reuse.",
"requires_secret": False,
"requires_runtime_send": False,
"post_verifier": "AI Loop post-apply verifier reads Telegram alert context receipts and reports reusable decision context.",
}
if not post_apply_verifier_surface_present:
return {
"action_id": "surface_verified_telegram_alert_context_receipts_in_awooop_runs_work_items_alerts",
"scope": "Verified Telegram alert context receipts -> AwoooP Runs / Work Items / Alerts",
"priority": "P0",
"why": "Post-apply verifier is source-controlled; the next closure is visible AI automation proof across operator surfaces.",
"requires_secret": False,
"requires_runtime_send": False,
"post_verifier": "Runs, Work Items, and Alerts surfaces show verified Telegram alert AI Loop receipts without manual-default terminal states.",
}
return {
"action_id": "audit_all_telegram_monitoring_alerts_db_log_ai_automation_coverage",
"scope": "Telegram monitoring alerts -> DB/log ledger, KM/RAG/MCP/PlayBook, and AI Agent context coverage",
"priority": "P0",
"why": "Verified Telegram alert AI Loop receipts are now visible in AwoooP; the next closure is proving every monitoring alert path is persisted and reusable by AI Agent automation.",
"requires_secret": False,
"requires_runtime_send": False,
"post_verifier": "Telegram alert matrix shows every monitoring alert surface has DB/log receipt, AI route, controlled queue, and no manual-default terminal state.",
}
def _legacy_bind_ai_alert_cards_action() -> dict[str, Any]:
return {
"action_id": "bind_ai_alert_cards_to_learning_writeback",
"scope": "ai_automation_alert_card_v1 outbound mirror metadata",
"priority": "P0",
"why": "All direct Bot API gaps are clear; close the learning/writeback loop.",
"requires_secret": False,
"requires_runtime_send": False,
"post_verifier": "/api/v1/platform/runs/ai-alert-cards readback shows delivery_receipt_readback_required and learning writeback refs.",
}
def _build_summary(
*,
matrix: list[dict[str, Any]],
direct_gap_count: int,
direct_gap_file_count: int,
egress_summary: dict[str, Any],
owner_summary: dict[str, Any],
migration_summary: dict[str, Any],
readability_summary: dict[str, Any],
digest_rollups: dict[str, Any],
source_proof: dict[str, Any],
next_priority_action: dict[str, Any],
) -> dict[str, Any]:
def ready(key: str, prefix: str) -> int:
return sum(
1 for item in matrix if str(item[key]).startswith(prefix)
)
return {
"telegram_alert_surface_count": len(matrix),
"known_direct_send_gap_count": direct_gap_count,
"known_direct_send_gap_file_count": direct_gap_file_count,
"workflow_direct_send_gap_count": int(egress_summary["workflow_direct_bot_api_call_count"]),
"ops_script_direct_send_gap_count": int(egress_summary["ops_script_direct_bot_api_call_count"]),
"ci_script_direct_send_gap_count": int(egress_summary["ci_script_direct_bot_api_call_count"]),
"api_direct_send_gap_count": int(egress_summary["api_direct_bot_api_call_count"]),
"gateway_normalized_callsite_count": int(egress_summary["gateway_normalized_callsite_count"]),
"db_or_log_receipt_ready_surface_count": ready("db_or_log_receipt", "ready"),
"ai_route_ready_surface_count": ready("ai_route", "ready"),
"controlled_queue_ready_surface_count": ready("controlled_queue", "ready"),
"post_verifier_ready_surface_count": ready("post_verifier", "ready"),
"learning_writeback_ready_surface_count": ready("learning_writeback", "ready"),
"manual_default_gap_count": sum(int(item["manual_default_gap_count"]) for item in matrix),
"direct_gap_migration_candidate_count": int(migration_summary["migration_candidate_count"]),
"owner_acceptance_candidate_count": int(owner_summary["acceptance_candidate_count"]),
"owner_response_required_as_evidence_count": int(migration_summary["owner_response_required_count"]),
"readability_final_exit_contract_count": int(readability_summary["final_exit_contract_count"]),
"digest_rule_count": int(digest_rollups["rule_count"]),
"digest_action_required_rule_count": len(digest_rollups["action_required_rule_ids"]),
"digest_failure_escalation_rule_count": len(digest_rollups["failure_escalation_rule_ids"]),
"digest_suppressed_success_rule_count": len(digest_rollups["suppressed_success_rule_ids"]),
"telegram_send_performed_count": 0,
"bot_api_call_performed_count": 0,
"secret_value_read_count": 0,
"runtime_write_performed_count": 0,
"ai_alert_card_delivery_readback_endpoint_count": source_proof[
"ai_alert_card_delivery_readback_endpoint_count"
],
"ai_alert_card_learning_writeback_refs_count": source_proof[
"ai_alert_card_learning_writeback_refs_count"
],
"ai_alert_card_learning_registry_readback_count": source_proof[
"ai_alert_card_learning_registry_readback_count"
],
"telegram_alert_ai_loop_consumer_context_readback_count": source_proof[
"telegram_alert_ai_loop_consumer_context_readback_count"
],
"telegram_alert_post_apply_verifier_readback_count": source_proof[
"telegram_alert_post_apply_verifier_readback_count"
],
"telegram_alert_post_apply_verifier_awooop_surface_count": source_proof[
"telegram_alert_post_apply_verifier_awooop_surface_count"
],
"source_contract_ready": bool(source_proof.get("source_contract_ready")),
"source_contract_missing_marker_count": len(
source_proof.get("source_contract_missing_markers") or []
),
"source_contract_missing_markers": list(
source_proof.get("source_contract_missing_markers") or []
),
"next_priority_action_id": next_priority_action["action_id"],
"next_priority_work_item_id": "CIR-P0-TG-001",
}