feat(telegram): verify alert context receipts
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Failing after 1m47s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Failing after 1m47s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped
This commit is contained in:
@@ -469,6 +469,9 @@ from src.services.stockplatform_public_api_runtime_readback import (
|
||||
from src.services.telegram_alert_ai_automation_matrix import (
|
||||
load_latest_telegram_alert_ai_automation_matrix,
|
||||
)
|
||||
from src.services.telegram_alert_learning_context_post_apply_verifier import (
|
||||
load_latest_telegram_alert_learning_context_post_apply_verifier,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/agents", tags=["Agent Teams"])
|
||||
logger = get_logger("awoooi.agents")
|
||||
@@ -1144,11 +1147,15 @@ async def get_awoooi_priority_work_order_readback() -> dict[str, Any]:
|
||||
consumer_readback = (
|
||||
await load_latest_ai_agent_log_controlled_writeback_consumer_readback()
|
||||
)
|
||||
telegram_alert_context_verifier = (
|
||||
await load_latest_telegram_alert_learning_context_post_apply_verifier()
|
||||
)
|
||||
apply_ai_automation_live_closure_readbacks(
|
||||
payload,
|
||||
executor_readback=log_executor,
|
||||
verifier_readback=post_write_verifier,
|
||||
consumer_readback=consumer_readback,
|
||||
telegram_alert_context_verifier_readback=telegram_alert_context_verifier,
|
||||
)
|
||||
return redact_public_lan_topology(payload)
|
||||
except FileNotFoundError as exc:
|
||||
@@ -2464,6 +2471,34 @@ async def get_agent_log_controlled_writeback_consumer_readback() -> dict[str, An
|
||||
) from exc
|
||||
|
||||
|
||||
@router.get(
|
||||
"/telegram-alert-learning-context-post-apply-verifier",
|
||||
response_model=dict[str, Any],
|
||||
summary="取得 Telegram alert learning context post-apply verifier",
|
||||
description=(
|
||||
"讀取 AI Loop consumer context 中的 Telegram alert learning receipts,"
|
||||
"驗證 target selector、source-of-truth diff、check-mode、rollback、"
|
||||
"post verifier refs 與 metadata-only 邊界。此端點不寫 KM/RAG/PlayBook、"
|
||||
"不呼叫 MCP tool、不發 Telegram、不觸發 workflow、不保存 raw payload、"
|
||||
"不讀 secret、不呼叫 GitHub。"
|
||||
),
|
||||
)
|
||||
async def get_telegram_alert_learning_context_post_apply_verifier() -> dict[str, Any]:
|
||||
"""Read Telegram alert learning context post-apply verifier receipts."""
|
||||
try:
|
||||
payload = await load_latest_telegram_alert_learning_context_post_apply_verifier()
|
||||
return redact_public_lan_topology(payload)
|
||||
except (json.JSONDecodeError, ValueError) as exc:
|
||||
logger.error(
|
||||
"telegram_alert_learning_context_post_apply_verifier_invalid",
|
||||
error=str(exc),
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Telegram alert learning context post-apply verifier 無效",
|
||||
) from exc
|
||||
|
||||
|
||||
@router.post(
|
||||
"/agent-log-controlled-writeback-consumer-apply",
|
||||
response_model=dict[str, Any],
|
||||
|
||||
@@ -3899,6 +3899,7 @@ def apply_ai_automation_live_closure_readbacks(
|
||||
executor_readback: dict[str, Any] | None = None,
|
||||
verifier_readback: dict[str, Any] | None = None,
|
||||
consumer_readback: dict[str, Any] | None = None,
|
||||
telegram_alert_context_verifier_readback: dict[str, Any] | None = None,
|
||||
) -> None:
|
||||
"""Overlay live AI-loop executor/verifier/consumer readbacks onto receipts."""
|
||||
|
||||
@@ -4056,6 +4057,54 @@ def apply_ai_automation_live_closure_readbacks(
|
||||
"ai_automation_consumer_runtime_target_write_performed"
|
||||
]
|
||||
|
||||
telegram_verifier = _dict(telegram_alert_context_verifier_readback)
|
||||
telegram_verifier_rollups = _dict(telegram_verifier.get("rollups"))
|
||||
telegram_verifier_blockers = _strings(telegram_verifier.get("active_blockers"))
|
||||
if telegram_verifier:
|
||||
summary["ai_automation_telegram_alert_post_apply_verifier_status"] = str(
|
||||
telegram_verifier.get("status") or ""
|
||||
)
|
||||
summary["ai_automation_telegram_alert_post_apply_verifier_ready"] = bool(
|
||||
telegram_verifier_rollups.get(
|
||||
"telegram_alert_learning_context_post_apply_verifier_ready"
|
||||
)
|
||||
is True
|
||||
)
|
||||
summary[
|
||||
"ai_automation_telegram_alert_post_apply_verified_context_receipt_count"
|
||||
] = _int(telegram_verifier_rollups.get("verified_context_receipt_count"))
|
||||
summary[
|
||||
"ai_automation_telegram_alert_post_apply_verified_target_count"
|
||||
] = _int(telegram_verifier_rollups.get("verified_target_count"))
|
||||
summary[
|
||||
"ai_automation_telegram_alert_post_apply_verified_ai_agent_context_receipt_count"
|
||||
] = _int(
|
||||
telegram_verifier_rollups.get("verified_ai_agent_context_receipt_count")
|
||||
)
|
||||
summary[
|
||||
"ai_automation_telegram_alert_post_apply_verifier_ref_count"
|
||||
] = _int(telegram_verifier_rollups.get("post_apply_verifier_ref_count"))
|
||||
summary["ai_automation_telegram_alert_post_apply_verifier_active_blockers"] = (
|
||||
telegram_verifier_blockers
|
||||
)
|
||||
rollups["ai_automation_telegram_alert_post_apply_verifier_ready"] = summary[
|
||||
"ai_automation_telegram_alert_post_apply_verifier_ready"
|
||||
]
|
||||
rollups[
|
||||
"ai_automation_telegram_alert_post_apply_verified_context_receipt_count"
|
||||
] = summary[
|
||||
"ai_automation_telegram_alert_post_apply_verified_context_receipt_count"
|
||||
]
|
||||
rollups[
|
||||
"ai_automation_telegram_alert_post_apply_verified_target_count"
|
||||
] = summary["ai_automation_telegram_alert_post_apply_verified_target_count"]
|
||||
rollups[
|
||||
"ai_automation_telegram_alert_post_apply_verifier_active_blocker_count"
|
||||
] = len(telegram_verifier_blockers)
|
||||
state["ai_automation_telegram_alert_post_apply_verifier_ready"] = summary[
|
||||
"ai_automation_telegram_alert_post_apply_verifier_ready"
|
||||
]
|
||||
|
||||
apply_ai_automation_node_receipts(payload)
|
||||
|
||||
|
||||
@@ -4136,6 +4185,20 @@ def _apply_ai_automation_node_receipts(payload: dict[str, Any]) -> None:
|
||||
telegram_alert_ai_agent_context_receipt_count = _int(
|
||||
summary.get("ai_automation_telegram_alert_ai_agent_context_receipt_count")
|
||||
)
|
||||
telegram_alert_post_apply_verifier_ready = bool(
|
||||
summary.get("ai_automation_telegram_alert_post_apply_verifier_ready") is True
|
||||
)
|
||||
telegram_alert_post_apply_verified_context_receipt_count = _int(
|
||||
summary.get(
|
||||
"ai_automation_telegram_alert_post_apply_verified_context_receipt_count"
|
||||
)
|
||||
)
|
||||
telegram_alert_post_apply_verified_target_count = _int(
|
||||
summary.get("ai_automation_telegram_alert_post_apply_verified_target_count")
|
||||
)
|
||||
telegram_alert_post_apply_verifier_ref_count = _int(
|
||||
summary.get("ai_automation_telegram_alert_post_apply_verifier_ref_count")
|
||||
)
|
||||
consumer_apply_route = str(summary.get("ai_automation_consumer_apply_route") or "")
|
||||
normalizer_ready = bool(
|
||||
queue_fields
|
||||
@@ -4153,6 +4216,7 @@ def _apply_ai_automation_node_receipts(payload: dict[str, Any]) -> None:
|
||||
post_verifier_ready = bool(
|
||||
receipt_outputs
|
||||
or verifier_dry_run_ready
|
||||
or telegram_alert_post_apply_verifier_ready
|
||||
or consumer_post_apply_verifier_ref_count > 0
|
||||
)
|
||||
learning_writeback_ready = bool(
|
||||
@@ -4290,13 +4354,29 @@ def _apply_ai_automation_node_receipts(payload: dict[str, Any]) -> None:
|
||||
*receipt_outputs[:4],
|
||||
f"post_write_verifier_nodes:{verifier_passed_node_count}",
|
||||
f"consumer_post_apply_verifier_refs:{consumer_post_apply_verifier_ref_count}",
|
||||
(
|
||||
"telegram_alert_post_apply_verified_context_receipts:"
|
||||
f"{telegram_alert_post_apply_verified_context_receipt_count}"
|
||||
),
|
||||
(
|
||||
"telegram_alert_post_apply_verified_targets:"
|
||||
f"{telegram_alert_post_apply_verified_target_count}"
|
||||
),
|
||||
(
|
||||
"telegram_alert_post_apply_verifier_refs:"
|
||||
f"{telegram_alert_post_apply_verifier_ref_count}"
|
||||
),
|
||||
],
|
||||
"verifier_result": "post_verifier_receipt_readback"
|
||||
if receipt_outputs
|
||||
else (
|
||||
"verifier_result": (
|
||||
"telegram_alert_learning_context_post_apply_verified"
|
||||
if telegram_alert_post_apply_verifier_ready
|
||||
else "post_verifier_receipt_readback"
|
||||
if receipt_outputs
|
||||
else (
|
||||
"post_write_verifier_dry_run_ready"
|
||||
if verifier_dry_run_ready
|
||||
else "post_verifier_required"
|
||||
)
|
||||
),
|
||||
"next_action": "read back route/API/UI/verifier output before closing",
|
||||
},
|
||||
|
||||
@@ -90,6 +90,9 @@ def load_latest_telegram_alert_ai_automation_matrix(
|
||||
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"]
|
||||
)
|
||||
|
||||
direct_gap_count = int(egress_summary["direct_bot_api_call_count"])
|
||||
direct_gap_file_count = int(egress_summary["direct_bot_api_file_count"])
|
||||
@@ -316,6 +319,46 @@ def load_latest_telegram_alert_ai_automation_matrix(
|
||||
"/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",
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
next_priority_action = _next_priority_action(
|
||||
@@ -325,6 +368,7 @@ def load_latest_telegram_alert_ai_automation_matrix(
|
||||
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,
|
||||
)
|
||||
next_controlled_actions = _ordered_controlled_actions(next_priority_action)
|
||||
summary = _build_summary(
|
||||
@@ -382,9 +426,17 @@ def load_latest_telegram_alert_ai_automation_matrix(
|
||||
(
|
||||
(
|
||||
(
|
||||
"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."
|
||||
(
|
||||
"Manual/default semantics are only acceptable for critical/break-glass or historical evidence; "
|
||||
"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 (
|
||||
@@ -543,6 +595,10 @@ def _inspect_source_contract(repo_root: Path) -> dict[str, int | bool]:
|
||||
"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",
|
||||
),
|
||||
}
|
||||
result: dict[str, int | bool] = {}
|
||||
for key, (relative_path, marker) in source_checks.items():
|
||||
@@ -561,6 +617,10 @@ def _inspect_source_contract(repo_root: Path) -> dict[str, int | bool]:
|
||||
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
|
||||
)
|
||||
|
||||
required = [key for key, value in result.items() if key.endswith("_present") and value is not True]
|
||||
if required:
|
||||
@@ -588,6 +648,7 @@ def _next_priority_action(
|
||||
learning_writeback_refs_present: bool,
|
||||
learning_registry_present: bool,
|
||||
ai_loop_context_present: bool,
|
||||
post_apply_verifier_present: bool,
|
||||
) -> dict[str, Any]:
|
||||
if api_direct_gap_count > 0:
|
||||
return {
|
||||
@@ -649,14 +710,24 @@ def _next_priority_action(
|
||||
"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.",
|
||||
}
|
||||
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",
|
||||
"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": "Telegram alert learning registry is readable by AI Loop Agent context; the next closure is verifier receipt and controlled apply reuse.",
|
||||
"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": "AI Loop post-apply verifier reads Telegram alert context receipts and reports reusable decision context.",
|
||||
"post_verifier": "Runs, Work Items, and Alerts surfaces show verified Telegram alert AI Loop receipts without manual-default terminal states.",
|
||||
}
|
||||
|
||||
|
||||
@@ -725,6 +796,9 @@ def _build_summary(
|
||||
"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"
|
||||
],
|
||||
"next_priority_action_id": next_priority_action["action_id"],
|
||||
"next_priority_work_item_id": "CIR-P0-TG-001",
|
||||
}
|
||||
|
||||
@@ -0,0 +1,350 @@
|
||||
"""Telegram alert learning context post-apply verifier readback.
|
||||
|
||||
Verifies metadata-only Telegram alert learning context receipts emitted by the
|
||||
AI Loop consumer readback. This module only reads public-safe receipt metadata;
|
||||
it does not write KM/RAG/PlayBook, call MCP tools, send Telegram, or touch
|
||||
runtime infrastructure.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
from typing import Any
|
||||
|
||||
from src.services.ai_agent_log_controlled_writeback_consumer_readback import (
|
||||
load_latest_ai_agent_log_controlled_writeback_consumer_readback,
|
||||
)
|
||||
|
||||
SCHEMA_VERSION = "telegram_alert_learning_context_post_apply_verifier_v1"
|
||||
DEFAULT_PROJECT_ID = "awoooi"
|
||||
_TARGETS = ("km", "rag", "playbook", "mcp", "verifier", "ai_agent")
|
||||
_REQUIRED_TARGET_SELECTOR_FIELDS = (
|
||||
"project_id",
|
||||
"run_id",
|
||||
"message_id",
|
||||
"target",
|
||||
"source_ref",
|
||||
)
|
||||
_REQUIRED_CHECKS = (
|
||||
"ai_alert_card_delivery_receipt_present",
|
||||
"learning_registry_binding_ready",
|
||||
"metadata_only_raw_payload_absent",
|
||||
"ai_agent_context_ref_present",
|
||||
)
|
||||
|
||||
|
||||
async def load_latest_telegram_alert_learning_context_post_apply_verifier(
|
||||
*,
|
||||
project_id: str = DEFAULT_PROJECT_ID,
|
||||
) -> dict[str, Any]:
|
||||
"""Return post-apply verifier results for Telegram alert context receipts."""
|
||||
|
||||
consumer_readback = (
|
||||
await load_latest_ai_agent_log_controlled_writeback_consumer_readback(
|
||||
project_id=project_id
|
||||
)
|
||||
)
|
||||
return build_telegram_alert_learning_context_post_apply_verifier(
|
||||
consumer_readback=consumer_readback,
|
||||
project_id=project_id,
|
||||
)
|
||||
|
||||
|
||||
def build_telegram_alert_learning_context_post_apply_verifier(
|
||||
*,
|
||||
consumer_readback: Mapping[str, Any],
|
||||
project_id: str = DEFAULT_PROJECT_ID,
|
||||
) -> dict[str, Any]:
|
||||
"""Build a deterministic verifier readback from consumer context receipts."""
|
||||
|
||||
consumer = _dict(consumer_readback)
|
||||
telegram_context = _dict(consumer.get("telegram_alert_learning_context"))
|
||||
context_receipts = [
|
||||
_dict(receipt) for receipt in _list(telegram_context.get("context_receipts"))
|
||||
]
|
||||
verifier_results = [
|
||||
_verify_context_receipt(receipt) for receipt in context_receipts
|
||||
]
|
||||
|
||||
target_count = _safe_int(telegram_context.get("target_count")) or len(_TARGETS)
|
||||
verified_targets = sorted(
|
||||
{
|
||||
str(item["target"])
|
||||
for item in verifier_results
|
||||
if item["verifier_status"] == "passed"
|
||||
}
|
||||
)
|
||||
verified_ai_agent_count = sum(
|
||||
1
|
||||
for item in verifier_results
|
||||
if item["target"] == "ai_agent" and item["verifier_status"] == "passed"
|
||||
)
|
||||
failed_results = [
|
||||
item for item in verifier_results if item["verifier_status"] != "passed"
|
||||
]
|
||||
source_ready = (
|
||||
telegram_context.get("status") == "ai_loop_agent_context_receipt_ready"
|
||||
)
|
||||
ready = bool(
|
||||
source_ready
|
||||
and context_receipts
|
||||
and not failed_results
|
||||
and len(verified_targets) == target_count
|
||||
and verified_ai_agent_count > 0
|
||||
)
|
||||
active_blockers = _active_blockers(
|
||||
source_ready=source_ready,
|
||||
context_receipts=context_receipts,
|
||||
failed_results=failed_results,
|
||||
verified_targets=verified_targets,
|
||||
target_count=target_count,
|
||||
verified_ai_agent_count=verified_ai_agent_count,
|
||||
)
|
||||
|
||||
return {
|
||||
"schema_version": SCHEMA_VERSION,
|
||||
"priority": "P0-TELEGRAM-AI-LOOP-POST-APPLY-VERIFIER",
|
||||
"priority_work_item_id": "CIR-P0-TG-001",
|
||||
"project_id": project_id,
|
||||
"status": (
|
||||
"telegram_alert_learning_context_post_apply_verified"
|
||||
if ready
|
||||
else "blocked_telegram_alert_learning_context_post_apply_verifier"
|
||||
),
|
||||
"source_readback": {
|
||||
"source_endpoint": (
|
||||
"/api/v1/agents/agent-log-controlled-writeback-consumer-readback"
|
||||
),
|
||||
"source_schema_version": consumer.get("schema_version"),
|
||||
"telegram_context_schema_version": telegram_context.get("schema_version"),
|
||||
"telegram_context_status": telegram_context.get("status"),
|
||||
"consumer_context_route": telegram_context.get("consumer_context_route"),
|
||||
"source_registry_status": telegram_context.get("source_registry_status"),
|
||||
},
|
||||
"controlled_verifier": {
|
||||
"mode": "metadata_only_post_apply_verifier_readback",
|
||||
"post_apply_verifier_executed": True,
|
||||
"controlled_apply_allowed_for_low_medium_high": ready,
|
||||
"owner_review_required_for_low_medium_high": False,
|
||||
"critical_break_glass_required": True,
|
||||
"target_selector_verified": ready,
|
||||
"source_of_truth_diff_verified": ready,
|
||||
"check_mode_verified": ready,
|
||||
"rollback_verified": ready,
|
||||
"raw_payload_absence_verified": ready,
|
||||
},
|
||||
"verifier_results": verifier_results,
|
||||
"rollups": {
|
||||
"telegram_alert_learning_context_post_apply_verifier_ready": ready,
|
||||
"source_context_ready": source_ready,
|
||||
"context_receipt_count": len(context_receipts),
|
||||
"verified_context_receipt_count": sum(
|
||||
1 for item in verifier_results if item["verifier_status"] == "passed"
|
||||
),
|
||||
"failed_context_receipt_count": len(failed_results),
|
||||
"target_count": target_count,
|
||||
"verified_target_count": len(verified_targets),
|
||||
"verified_targets": verified_targets,
|
||||
"verified_ai_agent_context_receipt_count": verified_ai_agent_count,
|
||||
"target_selector_verified_count": sum(
|
||||
1 for item in verifier_results if item["target_selector_verified"]
|
||||
),
|
||||
"source_of_truth_diff_verified_count": sum(
|
||||
1
|
||||
for item in verifier_results
|
||||
if item["source_of_truth_diff_verified"]
|
||||
),
|
||||
"check_mode_verified_count": sum(
|
||||
1 for item in verifier_results if item["check_mode_verified"]
|
||||
),
|
||||
"rollback_verified_count": sum(
|
||||
1 for item in verifier_results if item["rollback_verified"]
|
||||
),
|
||||
"post_apply_verifier_ref_count": sum(
|
||||
len(item["post_apply_verifier_refs"]) for item in verifier_results
|
||||
),
|
||||
"metadata_only_receipt_count": sum(
|
||||
1 for item in verifier_results if item["metadata_only"] is True
|
||||
),
|
||||
"raw_payload_included_count": sum(
|
||||
1 for item in verifier_results if item["raw_payload_included"] is True
|
||||
),
|
||||
"runtime_write_performed_count": 0,
|
||||
"telegram_send_performed_count": 0,
|
||||
"mcp_tool_call_performed_count": 0,
|
||||
"secret_value_read_count": 0,
|
||||
},
|
||||
"active_blockers": active_blockers,
|
||||
"next_action": (
|
||||
"surface_verified_telegram_alert_context_receipts_in_awooop_runs_work_items_alerts"
|
||||
if ready
|
||||
else "fix_failed_telegram_alert_context_receipts_then_rerun_post_apply_verifier"
|
||||
),
|
||||
"operation_boundaries": {
|
||||
"metadata_read_performed": True,
|
||||
"post_apply_verifier_read_performed": True,
|
||||
"runtime_target_write_performed": False,
|
||||
"km_write_performed": False,
|
||||
"rag_index_write_performed": False,
|
||||
"playbook_trust_write_performed": False,
|
||||
"mcp_tool_call_performed": False,
|
||||
"agent_runtime_action_performed": False,
|
||||
"telegram_send_performed": False,
|
||||
"workflow_trigger_performed": False,
|
||||
"raw_payload_included": False,
|
||||
"secret_value_collection_allowed": False,
|
||||
"github_api_used": False,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _verify_context_receipt(receipt: dict[str, Any]) -> dict[str, Any]:
|
||||
target = str(receipt.get("target") or "")
|
||||
target_selector = _dict(receipt.get("target_selector"))
|
||||
source_diff = _dict(receipt.get("source_of_truth_diff"))
|
||||
check_mode = _dict(receipt.get("check_mode"))
|
||||
rollback = _dict(receipt.get("rollback"))
|
||||
post_apply_verifier = _dict(receipt.get("post_apply_verifier"))
|
||||
verifier_refs = _strings(post_apply_verifier.get("verifier_refs"))
|
||||
|
||||
target_selector_missing = [
|
||||
key for key in _REQUIRED_TARGET_SELECTOR_FIELDS if not target_selector.get(key)
|
||||
]
|
||||
checks = _strings(check_mode.get("checks"))
|
||||
missing_checks = [check for check in _REQUIRED_CHECKS if check not in checks]
|
||||
failed_checks: list[str] = []
|
||||
|
||||
if target not in _TARGETS:
|
||||
failed_checks.append("target_in_allowed_set")
|
||||
if receipt.get("status") != "ready_for_ai_loop_context":
|
||||
failed_checks.append("receipt_ready_for_ai_loop_context")
|
||||
if target_selector_missing:
|
||||
failed_checks.append("target_selector_required_fields_present")
|
||||
if not _source_diff_verified(source_diff, target):
|
||||
failed_checks.append("source_of_truth_diff_verified")
|
||||
if check_mode.get("enabled") is not True or missing_checks:
|
||||
failed_checks.append("check_mode_required_checks_present")
|
||||
if rollback.get("required") is not True or not rollback.get("rollback_ref"):
|
||||
failed_checks.append("rollback_ref_present")
|
||||
if post_apply_verifier.get("required") is not True or not verifier_refs:
|
||||
failed_checks.append("post_apply_verifier_refs_present")
|
||||
if receipt.get("metadata_only") is not True:
|
||||
failed_checks.append("metadata_only_receipt")
|
||||
if receipt.get("raw_payload_included") is not False:
|
||||
failed_checks.append("raw_payload_absent")
|
||||
if receipt.get("target_write_performed") is not False:
|
||||
failed_checks.append("target_write_not_performed_by_verifier")
|
||||
if not receipt.get("ai_agent_context_ref"):
|
||||
failed_checks.append("ai_agent_context_ref_present")
|
||||
|
||||
passed_checks = [
|
||||
"target_in_allowed_set",
|
||||
"receipt_ready_for_ai_loop_context",
|
||||
"target_selector_required_fields_present",
|
||||
"source_of_truth_diff_verified",
|
||||
"check_mode_required_checks_present",
|
||||
"rollback_ref_present",
|
||||
"post_apply_verifier_refs_present",
|
||||
"metadata_only_receipt",
|
||||
"raw_payload_absent",
|
||||
"target_write_not_performed_by_verifier",
|
||||
"ai_agent_context_ref_present",
|
||||
]
|
||||
passed_checks = [check for check in passed_checks if check not in failed_checks]
|
||||
|
||||
return {
|
||||
"receipt_id": str(receipt.get("receipt_id") or ""),
|
||||
"source_receipt_id": str(receipt.get("source_receipt_id") or ""),
|
||||
"source_run_id": str(receipt.get("source_run_id") or ""),
|
||||
"source_message_id": str(receipt.get("source_message_id") or ""),
|
||||
"work_item_id": str(receipt.get("work_item_id") or "CIR-P0-TG-001"),
|
||||
"target": target,
|
||||
"consumer_surface": str(receipt.get("consumer_surface") or ""),
|
||||
"verifier_status": "passed" if not failed_checks else "failed",
|
||||
"passed_checks": passed_checks,
|
||||
"failed_checks": failed_checks,
|
||||
"target_selector_verified": not target_selector_missing,
|
||||
"target_selector_missing_fields": target_selector_missing,
|
||||
"source_of_truth_diff_verified": _source_diff_verified(source_diff, target),
|
||||
"check_mode_verified": check_mode.get("enabled") is True and not missing_checks,
|
||||
"check_mode_missing_checks": missing_checks,
|
||||
"rollback_verified": (
|
||||
rollback.get("required") is True and bool(rollback.get("rollback_ref"))
|
||||
),
|
||||
"post_apply_verifier_refs": verifier_refs,
|
||||
"metadata_only": receipt.get("metadata_only") is True,
|
||||
"raw_payload_included": receipt.get("raw_payload_included") is True,
|
||||
"runtime_target_write_performed": False,
|
||||
"telegram_send_performed": False,
|
||||
"evidence_refs": _unique(
|
||||
[
|
||||
str(receipt.get("source_ref") or ""),
|
||||
str(receipt.get("ai_agent_context_ref") or ""),
|
||||
*verifier_refs,
|
||||
]
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def _active_blockers(
|
||||
*,
|
||||
source_ready: bool,
|
||||
context_receipts: list[dict[str, Any]],
|
||||
failed_results: list[dict[str, Any]],
|
||||
verified_targets: list[str],
|
||||
target_count: int,
|
||||
verified_ai_agent_count: int,
|
||||
) -> list[str]:
|
||||
blockers: list[str] = []
|
||||
if not source_ready:
|
||||
blockers.append("telegram_alert_learning_context_source_not_ready")
|
||||
if not context_receipts:
|
||||
blockers.append("telegram_alert_learning_context_receipts_missing")
|
||||
if len(verified_targets) < target_count:
|
||||
blockers.append("telegram_alert_learning_context_verified_target_count_below_target")
|
||||
if verified_ai_agent_count <= 0:
|
||||
blockers.append("telegram_alert_learning_context_ai_agent_receipt_not_verified")
|
||||
for item in failed_results:
|
||||
receipt_id = item.get("receipt_id") or "unknown-receipt"
|
||||
blockers.append(f"telegram_alert_context_receipt_verifier_failed:{receipt_id}")
|
||||
return blockers
|
||||
|
||||
|
||||
def _source_diff_verified(source_diff: dict[str, Any], target: str) -> bool:
|
||||
return bool(
|
||||
source_diff.get("current_state") == "telegram_alert_learning_registry_readable"
|
||||
and source_diff.get("desired_state")
|
||||
== "ai_loop_agent_context_receipt_available"
|
||||
and source_diff.get("delta_kind") == f"telegram_alert_{target}_context_binding"
|
||||
and source_diff.get("raw_payload_included") is False
|
||||
)
|
||||
|
||||
|
||||
def _dict(value: Any) -> dict[str, Any]:
|
||||
return value if isinstance(value, dict) else {}
|
||||
|
||||
|
||||
def _list(value: Any) -> list[Any]:
|
||||
return value if isinstance(value, list) else []
|
||||
|
||||
|
||||
def _strings(value: Any) -> list[str]:
|
||||
return [str(item) for item in _list(value) if str(item)]
|
||||
|
||||
|
||||
def _unique(values: list[str]) -> list[str]:
|
||||
seen: set[str] = set()
|
||||
result: list[str] = []
|
||||
for value in values:
|
||||
if value in seen:
|
||||
continue
|
||||
seen.add(value)
|
||||
result.append(value)
|
||||
return result
|
||||
|
||||
|
||||
def _safe_int(value: Any) -> int:
|
||||
try:
|
||||
return int(value)
|
||||
except (TypeError, ValueError):
|
||||
return 0
|
||||
@@ -30,6 +30,9 @@ from src.services.awoooi_priority_work_order_readback import (
|
||||
from src.services.harbor_registry_controlled_recovery_preflight import (
|
||||
load_latest_harbor_registry_controlled_recovery_preflight,
|
||||
)
|
||||
from src.services.telegram_alert_learning_context_post_apply_verifier import (
|
||||
build_telegram_alert_learning_context_post_apply_verifier,
|
||||
)
|
||||
from src.services.stockplatform_public_api_controlled_recovery_preflight import (
|
||||
load_latest_stockplatform_public_api_controlled_recovery_preflight,
|
||||
)
|
||||
@@ -472,6 +475,7 @@ def test_ai_automation_live_closure_readbacks_close_node_receipts():
|
||||
executor_readback=executor,
|
||||
verifier_readback=verifier,
|
||||
consumer_readback=_consumer_readback_ready(),
|
||||
telegram_alert_context_verifier_readback=_telegram_alert_context_verifier_ready(),
|
||||
)
|
||||
|
||||
receipts_by_id = {
|
||||
@@ -490,7 +494,7 @@ def test_ai_automation_live_closure_readbacks_close_node_receipts():
|
||||
"controlled_consumer_context_receipt_readback"
|
||||
)
|
||||
assert receipts_by_id["post_verifier"]["verifier_result"] == (
|
||||
"post_write_verifier_dry_run_ready"
|
||||
"telegram_alert_learning_context_post_apply_verified"
|
||||
)
|
||||
assert receipts_by_id["learning_writeback"]["verifier_result"] == (
|
||||
"consumer_context_receipt_writeback_ready"
|
||||
@@ -508,6 +512,12 @@ def test_ai_automation_live_closure_readbacks_close_node_receipts():
|
||||
assert payload["summary"][
|
||||
"ai_automation_consumer_target_context_receipt_write_count"
|
||||
] == 6
|
||||
assert payload["summary"][
|
||||
"ai_automation_telegram_alert_post_apply_verifier_ready"
|
||||
] is True
|
||||
assert payload["summary"][
|
||||
"ai_automation_telegram_alert_post_apply_verified_context_receipt_count"
|
||||
] == 6
|
||||
|
||||
|
||||
def test_awoooi_priority_work_order_readback_endpoint_returns_snapshot(
|
||||
@@ -533,6 +543,11 @@ def test_awoooi_priority_work_order_readback_endpoint_returns_snapshot(
|
||||
"load_latest_ai_agent_log_controlled_writeback_consumer_readback",
|
||||
_consumer_readback_ready_async,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
agents,
|
||||
"load_latest_telegram_alert_learning_context_post_apply_verifier",
|
||||
_telegram_alert_context_verifier_ready_async,
|
||||
)
|
||||
app = FastAPI()
|
||||
app.include_router(router, prefix="/api/v1")
|
||||
client = TestClient(app)
|
||||
@@ -626,6 +641,9 @@ def test_awoooi_priority_work_order_readback_endpoint_returns_snapshot(
|
||||
)
|
||||
assert endpoint_receipts["execution_boundary"]["node_status"] == "ready"
|
||||
assert endpoint_receipts["post_verifier"]["node_status"] == "ready"
|
||||
assert endpoint_receipts["post_verifier"]["verifier_result"] == (
|
||||
"telegram_alert_learning_context_post_apply_verified"
|
||||
)
|
||||
assert endpoint_receipts["learning_writeback"]["node_status"] == "ready"
|
||||
assert endpoint_receipts["learning_writeback"]["km_writeback_ref"] == (
|
||||
"context_receipt:km=1"
|
||||
@@ -1648,6 +1666,84 @@ async def _consumer_readback_ready_async() -> dict:
|
||||
return _consumer_readback_ready()
|
||||
|
||||
|
||||
async def _telegram_alert_context_verifier_ready_async() -> dict:
|
||||
return _telegram_alert_context_verifier_ready()
|
||||
|
||||
|
||||
def _telegram_alert_context_verifier_ready() -> dict:
|
||||
return build_telegram_alert_learning_context_post_apply_verifier(
|
||||
consumer_readback=_consumer_readback_ready()
|
||||
)
|
||||
|
||||
|
||||
def _telegram_context_receipts() -> list[dict]:
|
||||
targets = [
|
||||
("km", "knowledge_memory_context"),
|
||||
("rag", "rag_index_candidate_context"),
|
||||
("playbook", "playbook_trust_candidate_context"),
|
||||
("mcp", "mcp_audit_feedback_context"),
|
||||
("verifier", "post_apply_verifier_feedback_context"),
|
||||
("ai_agent", "autonomous_runtime_decision_context"),
|
||||
]
|
||||
return [
|
||||
{
|
||||
"receipt_id": f"telegram_alert_learning_context::msg-telegram-1::{target}",
|
||||
"source_receipt_id": "msg-telegram-1",
|
||||
"source_run_id": "run-telegram-1",
|
||||
"source_message_id": "msg-telegram-1",
|
||||
"work_item_id": "CIR-P0-TG-001",
|
||||
"target": target,
|
||||
"consumer_surface": surface,
|
||||
"source_ref": f"{target}://awoooi/telegram-alert/msg-telegram-1",
|
||||
"ai_agent_context_ref": (
|
||||
"ai-agent://awoooi/telegram-alert-learning-context/"
|
||||
"run-telegram-1/msg-telegram-1"
|
||||
),
|
||||
"status": "ready_for_ai_loop_context",
|
||||
"metadata_only": True,
|
||||
"target_write_performed": False,
|
||||
"raw_payload_included": False,
|
||||
"target_selector": {
|
||||
"project_id": "awoooi",
|
||||
"run_id": "run-telegram-1",
|
||||
"message_id": "msg-telegram-1",
|
||||
"target": target,
|
||||
"source_ref": f"{target}://awoooi/telegram-alert/msg-telegram-1",
|
||||
},
|
||||
"source_of_truth_diff": {
|
||||
"current_state": "telegram_alert_learning_registry_readable",
|
||||
"desired_state": "ai_loop_agent_context_receipt_available",
|
||||
"delta_kind": f"telegram_alert_{target}_context_binding",
|
||||
"raw_payload_included": False,
|
||||
},
|
||||
"check_mode": {
|
||||
"enabled": True,
|
||||
"checks": [
|
||||
"ai_alert_card_delivery_receipt_present",
|
||||
"learning_registry_binding_ready",
|
||||
"metadata_only_raw_payload_absent",
|
||||
"ai_agent_context_ref_present",
|
||||
],
|
||||
},
|
||||
"rollback": {
|
||||
"required": True,
|
||||
"rollback_ref": (
|
||||
"rollback://telegram-alert-learning-context/"
|
||||
f"msg-telegram-1/{target}"
|
||||
),
|
||||
},
|
||||
"post_apply_verifier": {
|
||||
"required": True,
|
||||
"verifier_refs": [
|
||||
"verifier://awoooi/telegram-alert-delivery-receipt/run-telegram-1",
|
||||
f"{target}://awoooi/telegram-alert/msg-telegram-1",
|
||||
],
|
||||
},
|
||||
}
|
||||
for target, surface in targets
|
||||
]
|
||||
|
||||
|
||||
def _consumer_readback_ready() -> dict:
|
||||
return {
|
||||
"schema_version": "ai_agent_log_controlled_writeback_consumer_readback_v1",
|
||||
@@ -1691,6 +1787,43 @@ def _consumer_readback_ready() -> dict:
|
||||
"verifier_context_receipt_write_count": 1,
|
||||
"ai_agent_context_receipt_write_count": 1,
|
||||
"runtime_target_write_performed": True,
|
||||
"telegram_alert_learning_context_readback_ready": True,
|
||||
"telegram_alert_learning_context_receipt_count": 6,
|
||||
"telegram_alert_learning_ai_agent_context_receipt_count": 1,
|
||||
"telegram_alert_learning_ready_target_count": 6,
|
||||
"telegram_alert_learning_target_count": 6,
|
||||
},
|
||||
"telegram_alert_learning_context": {
|
||||
"schema_version": "telegram_alert_ai_loop_consumer_context_readback_v1",
|
||||
"status": "ai_loop_agent_context_receipt_ready",
|
||||
"priority_work_item_id": "CIR-P0-TG-001",
|
||||
"project_id": "awoooi",
|
||||
"source_endpoint": "/api/v1/platform/runs/ai-alert-cards",
|
||||
"source_registry_status": "learning_registry_ready",
|
||||
"consumer_context_route": "ai_loop_agent.telegram_alert_learning_context",
|
||||
"target_count": 6,
|
||||
"ready_target_count": 6,
|
||||
"context_receipt_count": 6,
|
||||
"ai_agent_context_receipt_count": 1,
|
||||
"next_action": (
|
||||
"verify_telegram_alert_learning_context_receipts_with_ai_loop_post_apply_verifier"
|
||||
),
|
||||
"context_receipts": _telegram_context_receipts(),
|
||||
"active_blockers": [],
|
||||
"operation_boundaries": {
|
||||
"metadata_read_performed": True,
|
||||
"db_or_log_receipt_read_performed": True,
|
||||
"runtime_target_write_performed": False,
|
||||
"km_write_performed": False,
|
||||
"rag_index_write_performed": False,
|
||||
"playbook_trust_write_performed": False,
|
||||
"mcp_tool_call_performed": False,
|
||||
"agent_runtime_action_performed": False,
|
||||
"telegram_send_performed": False,
|
||||
"raw_payload_included": False,
|
||||
"secret_value_collection_allowed": False,
|
||||
"github_api_used": False,
|
||||
},
|
||||
},
|
||||
"active_blockers": [],
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ def test_telegram_alert_ai_automation_matrix_loader_returns_gap_matrix():
|
||||
}
|
||||
|
||||
summary = payload["summary"]
|
||||
assert summary["telegram_alert_surface_count"] == 7
|
||||
assert summary["telegram_alert_surface_count"] == 8
|
||||
assert summary["known_direct_send_gap_count"] == 0
|
||||
assert summary["known_direct_send_gap_file_count"] == 0
|
||||
assert summary["workflow_direct_send_gap_count"] == 0
|
||||
@@ -55,8 +55,9 @@ def test_telegram_alert_ai_automation_matrix_loader_returns_gap_matrix():
|
||||
assert summary["ai_alert_card_learning_writeback_refs_count"] == 1
|
||||
assert summary["ai_alert_card_learning_registry_readback_count"] == 1
|
||||
assert summary["telegram_alert_ai_loop_consumer_context_readback_count"] == 1
|
||||
assert summary["telegram_alert_post_apply_verifier_readback_count"] == 1
|
||||
assert summary["next_priority_action_id"] == (
|
||||
"verify_telegram_alert_learning_context_receipts_with_ai_loop_post_apply_verifier"
|
||||
"surface_verified_telegram_alert_context_receipts_in_awooop_runs_work_items_alerts"
|
||||
)
|
||||
|
||||
matrix = {item["surface_id"]: item for item in payload["matrix"]}
|
||||
@@ -95,6 +96,12 @@ def test_telegram_alert_ai_automation_matrix_loader_returns_gap_matrix():
|
||||
assert matrix["telegram_ai_loop_agent_consumer_context"]["ai_route"] == (
|
||||
"ready_ai_loop_agent_context_reuse"
|
||||
)
|
||||
assert matrix["telegram_ai_loop_post_apply_verifier"]["status"] == (
|
||||
"post_apply_verifier_readback_present"
|
||||
)
|
||||
assert matrix["telegram_ai_loop_post_apply_verifier"]["post_verifier"] == (
|
||||
"ready_context_receipt_post_apply_verifier"
|
||||
)
|
||||
|
||||
assert payload["direct_send_gap_refs"] == []
|
||||
assert not any(
|
||||
@@ -142,6 +149,10 @@ def test_telegram_matrix_source_contract_supports_container_layout(tmp_path):
|
||||
"telegram_alert_ai_loop_consumer_context_readback_v1\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(tmp_path / "src/services/telegram_alert_learning_context_post_apply_verifier.py").write_text(
|
||||
"telegram_alert_learning_context_post_apply_verifier_v1\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
proof = _inspect_source_contract(tmp_path)
|
||||
|
||||
@@ -158,6 +169,8 @@ def test_telegram_matrix_source_contract_supports_container_layout(tmp_path):
|
||||
assert proof["ai_alert_card_ai_agent_context_ref_present"] is True
|
||||
assert proof["telegram_alert_ai_loop_consumer_context_readback_present"] is True
|
||||
assert proof["telegram_alert_ai_loop_consumer_context_readback_count"] == 1
|
||||
assert proof["telegram_alert_post_apply_verifier_readback_present"] is True
|
||||
assert proof["telegram_alert_post_apply_verifier_readback_count"] == 1
|
||||
|
||||
|
||||
def test_telegram_alert_ai_automation_matrix_endpoint_returns_readback():
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from src.api.v1 import agents
|
||||
from src.api.v1.agents import router
|
||||
from src.services.telegram_alert_learning_context_post_apply_verifier import (
|
||||
build_telegram_alert_learning_context_post_apply_verifier,
|
||||
)
|
||||
|
||||
|
||||
def _context_receipts() -> list[dict]:
|
||||
targets = [
|
||||
("km", "knowledge_memory_context"),
|
||||
("rag", "rag_index_candidate_context"),
|
||||
("playbook", "playbook_trust_candidate_context"),
|
||||
("mcp", "mcp_audit_feedback_context"),
|
||||
("verifier", "post_apply_verifier_feedback_context"),
|
||||
("ai_agent", "autonomous_runtime_decision_context"),
|
||||
]
|
||||
return [
|
||||
{
|
||||
"receipt_id": f"telegram_alert_learning_context::msg-telegram-1::{target}",
|
||||
"source_receipt_id": "msg-telegram-1",
|
||||
"source_run_id": "run-telegram-1",
|
||||
"source_message_id": "msg-telegram-1",
|
||||
"work_item_id": "CIR-P0-TG-001",
|
||||
"target": target,
|
||||
"consumer_surface": surface,
|
||||
"source_ref": f"{target}://awoooi/telegram-alert/msg-telegram-1",
|
||||
"ai_agent_context_ref": (
|
||||
"ai-agent://awoooi/telegram-alert-learning-context/"
|
||||
"run-telegram-1/msg-telegram-1"
|
||||
),
|
||||
"status": "ready_for_ai_loop_context",
|
||||
"metadata_only": True,
|
||||
"target_write_performed": False,
|
||||
"raw_payload_included": False,
|
||||
"target_selector": {
|
||||
"project_id": "awoooi",
|
||||
"run_id": "run-telegram-1",
|
||||
"message_id": "msg-telegram-1",
|
||||
"target": target,
|
||||
"source_ref": f"{target}://awoooi/telegram-alert/msg-telegram-1",
|
||||
},
|
||||
"source_of_truth_diff": {
|
||||
"current_state": "telegram_alert_learning_registry_readable",
|
||||
"desired_state": "ai_loop_agent_context_receipt_available",
|
||||
"delta_kind": f"telegram_alert_{target}_context_binding",
|
||||
"raw_payload_included": False,
|
||||
},
|
||||
"check_mode": {
|
||||
"enabled": True,
|
||||
"checks": [
|
||||
"ai_alert_card_delivery_receipt_present",
|
||||
"learning_registry_binding_ready",
|
||||
"metadata_only_raw_payload_absent",
|
||||
"ai_agent_context_ref_present",
|
||||
],
|
||||
},
|
||||
"rollback": {
|
||||
"required": True,
|
||||
"rollback_ref": (
|
||||
"rollback://telegram-alert-learning-context/"
|
||||
f"msg-telegram-1/{target}"
|
||||
),
|
||||
},
|
||||
"post_apply_verifier": {
|
||||
"required": True,
|
||||
"verifier_refs": [
|
||||
"verifier://awoooi/telegram-alert-delivery-receipt/run-telegram-1",
|
||||
f"{target}://awoooi/telegram-alert/msg-telegram-1",
|
||||
],
|
||||
},
|
||||
}
|
||||
for target, surface in targets
|
||||
]
|
||||
|
||||
|
||||
def _consumer_readback(*, receipts: list[dict] | None = None) -> dict:
|
||||
return {
|
||||
"schema_version": "ai_agent_log_controlled_writeback_consumer_readback_v1",
|
||||
"status": "controlled_writeback_consumer_readback_ready",
|
||||
"telegram_alert_learning_context": {
|
||||
"schema_version": "telegram_alert_ai_loop_consumer_context_readback_v1",
|
||||
"status": "ai_loop_agent_context_receipt_ready",
|
||||
"project_id": "awoooi",
|
||||
"source_registry_status": "learning_registry_ready",
|
||||
"consumer_context_route": "ai_loop_agent.telegram_alert_learning_context",
|
||||
"target_count": 6,
|
||||
"ready_target_count": 6,
|
||||
"context_receipt_count": 6,
|
||||
"ai_agent_context_receipt_count": 1,
|
||||
"context_receipts": receipts if receipts is not None else _context_receipts(),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_telegram_alert_learning_context_post_apply_verifier_passes_receipts():
|
||||
payload = build_telegram_alert_learning_context_post_apply_verifier(
|
||||
consumer_readback=_consumer_readback()
|
||||
)
|
||||
|
||||
assert payload["schema_version"] == (
|
||||
"telegram_alert_learning_context_post_apply_verifier_v1"
|
||||
)
|
||||
assert payload["status"] == (
|
||||
"telegram_alert_learning_context_post_apply_verified"
|
||||
)
|
||||
assert payload["active_blockers"] == []
|
||||
assert payload["controlled_verifier"]["post_apply_verifier_executed"] is True
|
||||
assert payload["controlled_verifier"]["raw_payload_absence_verified"] is True
|
||||
assert payload["operation_boundaries"]["runtime_target_write_performed"] is False
|
||||
assert payload["operation_boundaries"]["telegram_send_performed"] is False
|
||||
assert payload["operation_boundaries"]["secret_value_collection_allowed"] is False
|
||||
|
||||
rollups = payload["rollups"]
|
||||
assert rollups["telegram_alert_learning_context_post_apply_verifier_ready"] is True
|
||||
assert rollups["context_receipt_count"] == 6
|
||||
assert rollups["verified_context_receipt_count"] == 6
|
||||
assert rollups["verified_target_count"] == 6
|
||||
assert rollups["verified_ai_agent_context_receipt_count"] == 1
|
||||
assert rollups["raw_payload_included_count"] == 0
|
||||
assert rollups["runtime_write_performed_count"] == 0
|
||||
|
||||
ai_agent_result = [
|
||||
result
|
||||
for result in payload["verifier_results"]
|
||||
if result["target"] == "ai_agent"
|
||||
][0]
|
||||
assert ai_agent_result["verifier_status"] == "passed"
|
||||
assert ai_agent_result["target_selector_verified"] is True
|
||||
assert ai_agent_result["rollback_verified"] is True
|
||||
assert ai_agent_result["post_apply_verifier_refs"]
|
||||
|
||||
serialized = json.dumps(payload, ensure_ascii=False)
|
||||
assert "TELEGRAM_BOT_TOKEN" not in serialized
|
||||
assert "raw Telegram payload" not in serialized
|
||||
|
||||
|
||||
def test_telegram_alert_learning_context_post_apply_verifier_blocks_bad_receipt():
|
||||
receipts = _context_receipts()
|
||||
receipts[0]["rollback"] = {"required": True, "rollback_ref": ""}
|
||||
|
||||
payload = build_telegram_alert_learning_context_post_apply_verifier(
|
||||
consumer_readback=_consumer_readback(receipts=receipts)
|
||||
)
|
||||
|
||||
assert payload["status"] == (
|
||||
"blocked_telegram_alert_learning_context_post_apply_verifier"
|
||||
)
|
||||
assert payload["rollups"]["failed_context_receipt_count"] == 1
|
||||
assert any(
|
||||
blocker.startswith("telegram_alert_context_receipt_verifier_failed:")
|
||||
for blocker in payload["active_blockers"]
|
||||
)
|
||||
|
||||
|
||||
def test_telegram_alert_learning_context_post_apply_verifier_endpoint(monkeypatch):
|
||||
async def fake_loader():
|
||||
return build_telegram_alert_learning_context_post_apply_verifier(
|
||||
consumer_readback=_consumer_readback()
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
agents,
|
||||
"load_latest_telegram_alert_learning_context_post_apply_verifier",
|
||||
fake_loader,
|
||||
)
|
||||
app = FastAPI()
|
||||
app.include_router(router, prefix="/api/v1")
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.get(
|
||||
"/api/v1/agents/telegram-alert-learning-context-post-apply-verifier"
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["status"] == "telegram_alert_learning_context_post_apply_verified"
|
||||
assert data["rollups"]["verified_target_count"] == 6
|
||||
Reference in New Issue
Block a user