feat(governance): 新增 Agent Telegram digest policy
All checks were successful
CD Pipeline / tests (push) Successful in 1m28s
Code Review / ai-code-review (push) Successful in 14s
CD Pipeline / build-and-deploy (push) Successful in 4m8s
CD Pipeline / post-deploy-checks (push) Successful in 1m55s

This commit is contained in:
Your Name
2026-06-11 14:34:49 +08:00
parent 0d536f1406
commit 785494cb77
15 changed files with 1683 additions and 31 deletions

View File

@@ -58,6 +58,9 @@ from src.services.ai_agent_deployment_layout import (
from src.services.ai_agent_proactive_operations_contract import (
load_latest_ai_agent_proactive_operations_contract,
)
from src.services.ai_agent_telegram_action_required_digest_policy import (
load_latest_ai_agent_telegram_action_required_digest_policy,
)
from src.services.ai_agent_tool_adoption_approval_package import (
load_latest_ai_agent_tool_adoption_approval_package,
)
@@ -645,6 +648,35 @@ async def get_agent_tool_adoption_approval_package() -> dict[str, Any]:
) from exc
@router.get(
"/agent-telegram-action-required-digest-policy",
response_model=dict[str, Any],
summary="取得 AI Agent Telegram action-required digest policy",
description=(
"讀取最新已提交的 AI Agent Telegram action-required digest policy"
"此端點只回傳 critical / action-required / failure-only digest 規則與 redaction 邊界,"
"不送 Telegram、不寫 Telegram Gateway queue、不改 Alertmanager route / receiver、"
"不寫 AwoooP event、不觸發 workflow、不查外部掃描、不執行 runtime、不讀取 secret、"
"不回傳工作視窗對話內容。"
),
)
async def get_agent_telegram_action_required_digest_policy() -> dict[str, Any]:
"""Return the latest read-only AI Agent Telegram action-required digest policy."""
try:
return await asyncio.to_thread(load_latest_ai_agent_telegram_action_required_digest_policy)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("ai_agent_telegram_action_required_digest_policy_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent Telegram action-required digest policy 無效",
) from exc
@router.get(
"/runtime-surface-inventory",
response_model=dict[str, Any],

View File

@@ -0,0 +1,289 @@
"""
AI Agent Telegram action-required digest policy snapshot.
Loads the latest committed, read-only policy for deciding which AI Agent,
version, tool-adoption, scanner, and upgrade signals may become
action-required Telegram digest candidates. This module never sends Telegram
messages, writes Telegram Gateway queues, changes Alertmanager receivers,
triggers workflows, reads secrets, or exposes work-window transcripts.
"""
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
from src.services.snapshot_paths import default_evaluations_dir
_DEFAULT_EVALUATIONS_DIR = default_evaluations_dir(Path(__file__))
_SNAPSHOT_PATTERN = "ai_agent_telegram_action_required_digest_policy_*.json"
_SCHEMA_VERSION = "ai_agent_telegram_action_required_digest_policy_v1"
_RUNTIME_AUTHORITY = "policy_only_no_telegram_send_or_route_change"
_TRANSCRIPT_MARKERS = {
"# In app browser",
"My request for Codex",
"Current URL:",
"AGENTS.md instructions",
"<environment_context>",
"批准!繼續",
}
def load_latest_ai_agent_telegram_action_required_digest_policy(
evaluations_dir: Path | None = None,
) -> dict[str, Any]:
"""Load the newest committed AI Agent Telegram digest policy."""
directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR
candidates = sorted(directory.glob(_SNAPSHOT_PATTERN))
if not candidates:
raise FileNotFoundError(
f"no AI Agent Telegram action-required digest policy snapshots found in {directory}"
)
latest = candidates[-1]
with latest.open(encoding="utf-8") as handle:
payload = json.load(handle)
if not isinstance(payload, dict):
raise ValueError(f"{latest}: expected JSON object")
_require_schema(payload, _SCHEMA_VERSION, str(latest))
_require_read_only_boundaries(payload, str(latest))
_require_rollup_consistency(payload, str(latest))
_require_success_noise_suppression(payload, str(latest))
_require_digest_gate_safety(payload, str(latest))
_require_message_redaction(payload, str(latest))
_require_no_plaintext_secret_payload_keys(payload, str(latest))
_require_no_conversation_transcript_content(payload, str(latest))
return payload
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_read_only_boundaries(payload: dict[str, Any], label: str) -> None:
program_status = payload.get("program_status") or {}
if program_status.get("read_only_mode") is not True:
raise ValueError(f"{label}: program_status.read_only_mode must be true")
if program_status.get("runtime_authority") != _RUNTIME_AUTHORITY:
raise ValueError(f"{label}: runtime_authority must stay {_RUNTIME_AUTHORITY}")
operation_boundaries = payload.get("operation_boundaries") or {}
if operation_boundaries.get("read_only_policy_allowed") is not True:
raise ValueError(f"{label}: read_only_policy_allowed must be true")
blocked_operation_flags = {
"telegram_direct_send_allowed",
"telegram_test_message_allowed",
"telegram_gateway_queue_write_allowed",
"alertmanager_route_change_allowed",
"telegram_receiver_change_allowed",
"awooop_event_write_allowed",
"workflow_trigger_allowed",
"external_scan_allowed",
"runtime_execution_allowed",
"secret_plaintext_allowed",
"conversation_transcript_allowed",
}
allowed_operation_flags = sorted(
flag
for flag in blocked_operation_flags
if operation_boundaries.get(flag) is not False
)
if allowed_operation_flags:
raise ValueError(
f"{label}: operation boundaries must remain false: {allowed_operation_flags}"
)
approval_boundaries = payload.get("approval_boundaries") or {}
allowed_approval_flags = sorted(
flag for flag, value in approval_boundaries.items() if value is not False
)
if allowed_approval_flags:
raise ValueError(
f"{label}: approval boundaries must remain false: {allowed_approval_flags}"
)
def _require_rollup_consistency(payload: dict[str, Any], label: str) -> None:
rules = payload.get("digest_rules") or []
channels = payload.get("digest_channels") or []
categories = payload.get("trigger_categories") or []
rollups = payload.get("rollups") or {}
expected_counts = {
"rule_count": len(rules),
"channel_count": len(channels),
"trigger_category_count": len(categories),
}
mismatched = {
key: {"expected": expected, "actual": rollups.get(key)}
for key, expected in expected_counts.items()
if rollups.get(key) != expected
}
if mismatched:
raise ValueError(f"{label}: rollup counts must match payload sections: {mismatched}")
by_decision: dict[str, int] = {}
for rule in rules:
decision = str(rule.get("decision"))
by_decision[decision] = by_decision.get(decision, 0) + 1
if rollups.get("by_decision") != by_decision:
raise ValueError(f"{label}: rollups.by_decision must match digest rule decisions")
expected_lists = {
"action_required_rule_ids": {
rule.get("rule_id")
for rule in rules
if rule.get("decision") == "draft_action_required_digest"
},
"failure_escalation_rule_ids": {
rule.get("rule_id")
for rule in rules
if rule.get("decision") == "draft_failure_escalation_digest"
},
"suppressed_success_rule_ids": {
rule.get("rule_id")
for rule in rules
if rule.get("decision") == "suppress_success_noise"
},
}
for key, expected in expected_lists.items():
if set(rollups.get(key) or []) != expected:
raise ValueError(f"{label}: rollups.{key} mismatch")
zero_rollups = {
"telegram_direct_send_allowed_count",
"telegram_gateway_queue_write_allowed_count",
"route_change_allowed_count",
"conversation_transcript_allowed_count",
}
nonzero = sorted(key for key in zero_rollups if rollups.get(key) != 0)
if nonzero:
raise ValueError(f"{label}: digest safety counters must remain 0: {nonzero}")
def _require_success_noise_suppression(payload: dict[str, Any], label: str) -> None:
noisy_channels = [
channel.get("channel_id")
for channel in payload.get("digest_channels") or []
if channel.get("success_immediate_allowed") is not False
or channel.get("direct_send_allowed") is not False
]
if noisy_channels:
raise ValueError(f"{label}: digest channels must suppress success/direct send: {noisy_channels}")
noisy_rules = [
rule.get("rule_id")
for rule in payload.get("digest_rules") or []
if rule.get("signal_state") in {"success", "verified"}
and rule.get("decision") != "suppress_success_noise"
]
if noisy_rules:
raise ValueError(f"{label}: success/verified signals must suppress digest noise: {noisy_rules}")
summary_policy = str(payload.get("rate_limit_policy", {}).get("success_policy") or "")
if "成功" not in summary_policy or "不得" not in summary_policy or "Telegram" not in summary_policy:
raise ValueError(f"{label}: rate_limit_policy.success_policy must block success spam")
def _require_digest_gate_safety(payload: dict[str, Any], label: str) -> None:
unsafe_rules = [
rule.get("rule_id")
for rule in payload.get("digest_rules") or []
if rule.get("decision") in {
"draft_action_required_digest",
"draft_failure_escalation_digest",
}
and (
not rule.get("required_evidence")
or rule.get("telegram_direct_send_allowed") is not False
or rule.get("requires_openclaw_review") is not True
)
]
if unsafe_rules:
raise ValueError(f"{label}: digest candidate rules need evidence and OpenClaw gate: {unsafe_rules}")
immediate_non_failure = [
rule.get("rule_id")
for rule in payload.get("digest_rules") or []
if rule.get("decision") == "draft_failure_escalation_digest"
and rule.get("signal_state") not in {"failed", "blocked", "critical"}
]
if immediate_non_failure:
raise ValueError(f"{label}: failure escalation digest must stay failure-only: {immediate_non_failure}")
def _require_message_redaction(payload: dict[str, Any], label: str) -> None:
template = payload.get("message_template_contract") or {}
required_fields = set(template.get("required_fields") or [])
required = {
"stage",
"severity",
"target_id",
"evidence_ref",
"blocked_reason",
"next_action",
"owner_agent",
"approval_gate",
}
if not required.issubset(required_fields):
raise ValueError(f"{label}: message_template_contract.required_fields missing digest context")
forbidden_fields = set(template.get("forbidden_fields") or [])
required_forbidden = {
"secret_value",
"token",
"authorization_header",
"work_window_transcript",
"codex_user_message",
"prompt_text",
"chain_of_thought",
"session_id",
"browser_context",
}
if not required_forbidden.issubset(forbidden_fields):
raise ValueError(f"{label}: message_template_contract.forbidden_fields missing redaction boundary")
display = payload.get("display_redaction_contract") or {}
if display.get("conversation_transcript_display_allowed") is not False:
raise ValueError(f"{label}: conversation transcript display must remain false")
if display.get("redaction_required") is not True:
raise ValueError(f"{label}: display redaction must be required")
def _require_no_plaintext_secret_payload_keys(value: Any, label: str, path: str = "$") -> None:
if isinstance(value, dict):
forbidden_key_fragments = {
"secret_value",
"token_plaintext",
"authorization_header",
"private_key",
"credential_value",
}
for key, nested in value.items():
normalized_key = str(key).lower()
if any(fragment in normalized_key for fragment in forbidden_key_fragments):
raise ValueError(f"{label}: forbidden plaintext secret key at {path}.{key}")
_require_no_plaintext_secret_payload_keys(nested, label, f"{path}.{key}")
elif isinstance(value, list):
for index, nested in enumerate(value):
_require_no_plaintext_secret_payload_keys(nested, label, f"{path}[{index}]")
def _require_no_conversation_transcript_content(value: Any, label: str, path: str = "$") -> None:
if isinstance(value, str):
for marker in _TRANSCRIPT_MARKERS:
if marker in value:
raise ValueError(
f"{label}: forbidden work-window conversation content at {path}: {marker}"
)
elif isinstance(value, dict):
for key, nested in value.items():
_require_no_conversation_transcript_content(nested, label, f"{path}.{key}")
elif isinstance(value, list):
for index, nested in enumerate(value):
_require_no_conversation_transcript_content(nested, label, f"{path}[{index}]")

View File

@@ -13,9 +13,9 @@ def test_load_latest_ai_agent_proactive_operations_contract_reads_committed_snap
data = load_latest_ai_agent_proactive_operations_contract()
assert data["schema_version"] == "ai_agent_proactive_operations_contract_v1"
assert data["program_status"]["overall_completion_percent"] == 55
assert data["program_status"]["current_task_id"] == "P2-402C"
assert data["program_status"]["next_task_id"] == "P2-402D"
assert data["program_status"]["overall_completion_percent"] == 68
assert data["program_status"]["current_task_id"] == "P2-402D"
assert data["program_status"]["next_task_id"] == "P2-402E"
assert data["program_status"]["read_only_mode"] is True
assert data["program_status"]["runtime_authority"] == "contract_only_no_version_or_runtime_update"
assert data["approval_boundaries"]["runtime_version_update_allowed"] is False

View File

@@ -16,9 +16,9 @@ def test_ai_agent_proactive_operations_contract_endpoint_returns_committed_snaps
assert response.status_code == 200
data = response.json()
assert data["schema_version"] == "ai_agent_proactive_operations_contract_v1"
assert data["program_status"]["overall_completion_percent"] == 55
assert data["program_status"]["current_task_id"] == "P2-402C"
assert data["program_status"]["next_task_id"] == "P2-402D"
assert data["program_status"]["overall_completion_percent"] == 68
assert data["program_status"]["current_task_id"] == "P2-402D"
assert data["program_status"]["next_task_id"] == "P2-402E"
assert data["program_status"]["read_only_mode"] is True
assert data["approval_boundaries"]["runtime_version_update_allowed"] is False
assert data["approval_boundaries"]["package_upgrade_allowed"] is False

View File

@@ -0,0 +1,270 @@
from __future__ import annotations
import json
import pytest
from src.services.ai_agent_telegram_action_required_digest_policy import (
load_latest_ai_agent_telegram_action_required_digest_policy,
)
def test_load_latest_ai_agent_telegram_action_required_digest_policy_reads_committed_snapshot():
data = load_latest_ai_agent_telegram_action_required_digest_policy()
assert data["schema_version"] == "ai_agent_telegram_action_required_digest_policy_v1"
assert data["program_status"]["overall_completion_percent"] == 68
assert data["program_status"]["current_task_id"] == "P2-402D"
assert data["program_status"]["next_task_id"] == "P2-402E"
assert data["program_status"]["read_only_mode"] is True
assert data["program_status"]["runtime_authority"] == "policy_only_no_telegram_send_or_route_change"
assert data["operation_boundaries"]["read_only_policy_allowed"] is True
assert data["operation_boundaries"]["telegram_direct_send_allowed"] is False
assert data["operation_boundaries"]["telegram_gateway_queue_write_allowed"] is False
assert data["operation_boundaries"]["alertmanager_route_change_allowed"] is False
assert data["operation_boundaries"]["conversation_transcript_allowed"] is False
assert data["approval_boundaries"]["telegram_digest_send_approved"] is False
assert data["rollups"]["rule_count"] == len(data["digest_rules"]) == 8
assert data["rollups"]["channel_count"] == len(data["digest_channels"]) == 3
assert data["rollups"]["trigger_category_count"] == len(data["trigger_categories"]) == 5
assert data["rollups"]["by_decision"]["suppress_success_noise"] == 2
assert data["rollups"]["by_decision"]["draft_failure_escalation_digest"] == 3
assert data["rollups"]["by_decision"]["draft_action_required_digest"] == 3
assert data["rollups"]["telegram_direct_send_allowed_count"] == 0
assert data["rollups"]["telegram_gateway_queue_write_allowed_count"] == 0
assert data["rollups"]["route_change_allowed_count"] == 0
assert data["rollups"]["conversation_transcript_allowed_count"] == 0
assert "work_window_transcript" in data["message_template_contract"]["forbidden_fields"]
assert all(
rule["decision"] == "suppress_success_noise"
for rule in data["digest_rules"]
if rule["signal_state"] in {"success", "verified"}
)
def test_ai_agent_telegram_action_required_digest_policy_blocks_direct_send(tmp_path):
snapshot = _snapshot()
snapshot["operation_boundaries"]["telegram_direct_send_allowed"] = True
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="operation boundaries"):
load_latest_ai_agent_telegram_action_required_digest_policy(tmp_path)
def test_ai_agent_telegram_action_required_digest_policy_rejects_rollup_mismatch(tmp_path):
snapshot = _snapshot()
snapshot["rollups"]["rule_count"] = 99
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="rollup counts"):
load_latest_ai_agent_telegram_action_required_digest_policy(tmp_path)
def test_ai_agent_telegram_action_required_digest_policy_rejects_success_noise(tmp_path):
snapshot = _snapshot()
snapshot["digest_rules"][0]["decision"] = "draft_action_required_digest"
snapshot["digest_rules"][0]["requires_openclaw_review"] = True
snapshot["rollups"]["by_decision"] = {
"draft_action_required_digest": 2,
"draft_failure_escalation_digest": 1,
}
snapshot["rollups"]["action_required_rule_ids"] = [
"repo_only_freshness_snapshot_success",
"tool_install_or_ci_change_needs_approval",
]
snapshot["rollups"]["suppressed_success_rule_ids"] = []
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="success/verified signals"):
load_latest_ai_agent_telegram_action_required_digest_policy(tmp_path)
def test_ai_agent_telegram_action_required_digest_policy_rejects_transcript_markers(tmp_path):
snapshot = _snapshot()
snapshot["message_template_contract"]["action_required_message_policy"] = (
"禁止放入:" + "My request for Codex"
)
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="forbidden work-window conversation content"):
load_latest_ai_agent_telegram_action_required_digest_policy(tmp_path)
def test_ai_agent_telegram_action_required_digest_policy_requires_redaction_fields(tmp_path):
snapshot = _snapshot()
snapshot["message_template_contract"]["forbidden_fields"].remove("work_window_transcript")
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="forbidden_fields"):
load_latest_ai_agent_telegram_action_required_digest_policy(tmp_path)
def _write_snapshot(tmp_path, snapshot: dict) -> None:
(tmp_path / "ai_agent_telegram_action_required_digest_policy_2026-06-11.json").write_text(
json.dumps(snapshot),
encoding="utf-8",
)
def _snapshot() -> dict:
return {
"schema_version": "ai_agent_telegram_action_required_digest_policy_v1",
"generated_at": "2026-06-11T23:58:00+08:00",
"program_status": {
"overall_completion_percent": 68,
"current_priority": "P2",
"current_task_id": "P2-402D",
"next_task_id": "P2-402E",
"read_only_mode": True,
"runtime_authority": "policy_only_no_telegram_send_or_route_change",
"status_note": "測試。",
},
"source_refs": ["docs/evaluations/example.json"],
"trigger_categories": [
{
"category_id": "success_noise",
"owner_agent": "Hermes",
"policy_intent": "測試。",
"blocked_now": ["send"],
},
{
"category_id": "tool_adoption_approval_required",
"owner_agent": "OpenClaw",
"policy_intent": "測試。",
"blocked_now": ["send"],
},
],
"digest_channels": [
{
"channel_id": "telegram_ops_digest_draft",
"purpose": "測試。",
"success_immediate_allowed": False,
"direct_send_allowed": False,
"queue_write_allowed": False,
"requires_telegram_gateway_e2e": True,
}
],
"digest_rules": [
{
"rule_id": "repo_only_freshness_snapshot_success",
"category_id": "success_noise",
"signal_state": "success",
"severity": "info",
"decision": "suppress_success_noise",
"owner_agent": "Hermes",
"required_evidence": ["snapshot"],
"channels": ["telegram_ops_digest_draft"],
"requires_openclaw_review": False,
"telegram_direct_send_allowed": False,
"next_action": "測試。",
},
{
"rule_id": "version_watch_source_failed",
"category_id": "tool_adoption_approval_required",
"signal_state": "failed",
"severity": "warning",
"decision": "draft_failure_escalation_digest",
"owner_agent": "Hermes",
"required_evidence": ["source_id"],
"channels": ["telegram_ops_digest_draft"],
"requires_openclaw_review": True,
"telegram_direct_send_allowed": False,
"next_action": "測試。",
},
{
"rule_id": "tool_install_or_ci_change_needs_approval",
"category_id": "tool_adoption_approval_required",
"signal_state": "action_required",
"severity": "warning",
"decision": "draft_action_required_digest",
"owner_agent": "OpenClaw",
"required_evidence": ["tool_id"],
"channels": ["telegram_ops_digest_draft"],
"requires_openclaw_review": True,
"telegram_direct_send_allowed": False,
"next_action": "測試。",
},
],
"message_template_contract": {
"required_fields": [
"stage",
"severity",
"target_id",
"evidence_ref",
"blocked_reason",
"next_action",
"owner_agent",
"approval_gate",
],
"forbidden_fields": [
"secret_value",
"token",
"authorization_header",
"work_window_transcript",
"codex_user_message",
"prompt_text",
"chain_of_thought",
"session_id",
"browser_context",
],
"success_message_policy": "成功不得送 Telegram。",
"action_required_message_policy": "測試。",
"failure_message_policy": "測試。",
},
"rate_limit_policy": {
"success_policy": "成功不得 Telegram 洗版。",
"digest_window_minutes": 30,
"dedupe_key_fields": ["category_id"],
"max_digest_items": 10,
"fallback_policy": "測試。",
},
"display_redaction_contract": {
"conversation_transcript_display_allowed": False,
"redaction_required": True,
"allowed_frontend_fields": ["政策規則摘要"],
"forbidden_frontend_content": ["內部對話內容"],
},
"agent_roles": [],
"operation_boundaries": {
"read_only_policy_allowed": True,
"telegram_direct_send_allowed": False,
"telegram_test_message_allowed": False,
"telegram_gateway_queue_write_allowed": False,
"alertmanager_route_change_allowed": False,
"telegram_receiver_change_allowed": False,
"awooop_event_write_allowed": False,
"workflow_trigger_allowed": False,
"external_scan_allowed": False,
"runtime_execution_allowed": False,
"secret_plaintext_allowed": False,
"conversation_transcript_allowed": False,
},
"approval_boundaries": {
"telegram_digest_send_approved": False,
"telegram_gateway_queue_write_approved": False,
"telegram_route_change_approved": False,
"alertmanager_receiver_change_approved": False,
"awooop_event_write_approved": False,
"workflow_trigger_approved": False,
"runtime_execution_approved": False,
"secret_plaintext_approved": False,
},
"rollups": {
"rule_count": 3,
"channel_count": 1,
"trigger_category_count": 2,
"by_decision": {
"suppress_success_noise": 1,
"draft_failure_escalation_digest": 1,
"draft_action_required_digest": 1,
},
"action_required_rule_ids": ["tool_install_or_ci_change_needs_approval"],
"failure_escalation_rule_ids": ["version_watch_source_failed"],
"suppressed_success_rule_ids": ["repo_only_freshness_snapshot_success"],
"telegram_direct_send_allowed_count": 0,
"telegram_gateway_queue_write_allowed_count": 0,
"route_change_allowed_count": 0,
"conversation_transcript_allowed_count": 0,
"next_approval_task_ids": ["P2-402E"],
},
}

View File

@@ -0,0 +1,52 @@
from __future__ import annotations
import json
from fastapi import FastAPI
from fastapi.testclient import TestClient
from src.api.v1.agents import router
def test_agent_telegram_action_required_digest_policy_endpoint_returns_committed_snapshot():
app = FastAPI()
app.include_router(router, prefix="/api/v1")
client = TestClient(app)
response = client.get("/api/v1/agents/agent-telegram-action-required-digest-policy")
assert response.status_code == 200
data = response.json()
assert data["schema_version"] == "ai_agent_telegram_action_required_digest_policy_v1"
assert data["program_status"]["overall_completion_percent"] == 68
assert data["program_status"]["current_task_id"] == "P2-402D"
assert data["program_status"]["next_task_id"] == "P2-402E"
assert data["program_status"]["read_only_mode"] is True
assert data["operation_boundaries"]["telegram_direct_send_allowed"] is False
assert data["operation_boundaries"]["telegram_test_message_allowed"] is False
assert data["operation_boundaries"]["telegram_gateway_queue_write_allowed"] is False
assert data["operation_boundaries"]["alertmanager_route_change_allowed"] is False
assert data["operation_boundaries"]["telegram_receiver_change_allowed"] is False
assert data["operation_boundaries"]["conversation_transcript_allowed"] is False
assert data["approval_boundaries"]["telegram_digest_send_approved"] is False
assert data["rollups"]["rule_count"] == 8
assert data["rollups"]["channel_count"] == 3
assert data["rollups"]["trigger_category_count"] == 5
assert data["rollups"]["telegram_direct_send_allowed_count"] == 0
assert data["rollups"]["telegram_gateway_queue_write_allowed_count"] == 0
assert data["rollups"]["route_change_allowed_count"] == 0
assert data["rollups"]["conversation_transcript_allowed_count"] == 0
assert any(
rule["rule_id"] == "telegram_delivery_silence_detected"
for rule in data["digest_rules"]
)
serialized = json.dumps(data, ensure_ascii=False)
for marker in [
"批准!繼續",
"My request for Codex",
"Current URL:",
"# In app browser",
"AGENTS.md instructions",
]:
assert marker not in serialized

View File

@@ -1,3 +1,26 @@
## 2026-06-11P2-402D AI Agent Telegram action-required digest policy
**背景**P2-402C 已把 Renovate / OSV-Scanner / Trivy / Syft / Grype 的採用批准包建立完成但所有工具安裝、CI 變更、外部查詢與 Telegram 實發都仍未開 gate。本階段接續建立 Telegram action-required digest policy先定義哪些 AI Agent / 版本 / 工具 / 掃描 / 升級訊號可成為 critical / action-required / failure-only digest 草案,並明確壓制成功洗版。
**完成內容:**
- 新增 `ai_agent_telegram_action_required_digest_policy_v1` schema。
- 新增 committed snapshot`docs/evaluations/ai_agent_telegram_action_required_digest_policy_2026-06-11.json`
- 新增只讀 loader`apps/api/src/services/ai_agent_telegram_action_required_digest_policy.py`
- 新增治理 API`GET /api/v1/agents/agent-telegram-action-required-digest-policy`
- 新增 loader / API / direct-send boundary / success-noise suppression / rollup mismatch / transcript redaction 測試。
- 新增分析報告:`docs/ai/AI_AGENT_TELEGRAM_ACTION_REQUIRED_DIGEST_POLICY_2026-06-11.md`
- 同步 `AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md``AI_AGENT_PROACTIVE_OPERATIONS_2026-06-11.md` 與 MASTER §3.2.1c。
**完成度與下一步:**
- P2-402D`100%`
- AI Agent 主動營運與版本生命週期整體:`68%`
- Current task`P2-402D`
- Next task`P2-402E` Gitea PR 草案 lane。
**安全邊界:**
- 本波只做 digest policy 與只讀 API。
- 未送 Telegram、未寫 Telegram Gateway queue、未改 Alertmanager route / receiver、未寫 AwoooP event、未觸發 workflow、未查外部掃描、未執行 runtime、未讀取或輸出 secret、未顯示工作視窗對話內容。
## 2026-06-11P0 Telegram 批准後執行真相鏈止血
**背景**:使用者指出每個 Telegram 告警批准後都只得到「已記錄觀察,未執行修復」,代表前一輪只補到告警送達與 recurrence 可見,尚未把 approval -> execution -> verifier -> KM / PlayBook 的執行真相鏈閉合。Production status-chain 抽查 `INC-20260611-BB1D9D` 確認舊流程為 `latest_action=OBSERVE``completion_status=completed_no_repair``repair_status=not_executed`;另一個具備 `kubectl rollout restart` 的事件雖有 execution record但缺少 `auto_repair_executions` 與 verifier / KM 收斂證據。

View File

@@ -13,7 +13,7 @@
| 工具 / 服務 / 套件 AI 自動化 | 92% | P0 已完成P1 服務 / runtime / 監控 / provider / service health / 備份 / DR / 套件與供應鏈只讀基線已完成P1-007 失敗限定通知合約與前端 redaction 合約已完成;下一主線是 P2-004 依賴 / 供應鏈漂移監控 | 狀態分類、盤點 schema、權限矩陣、靜態盤點種子、只讀 API、UI 骨架、驗證、自動化待辦 schema / 快照 / API / 分組 UI、Backup / DR 目標盤點、準備度矩陣、備份通知政策、Backup / DR 證據 UI、復原演練批准包模板、異地 / escrow 準備度狀態、任務批准邊界、確定性進度彙總、Python 套件 / 供應鏈只讀基線、JS pnpm/npm 只讀基線、Docker build surface 只讀基線、CVE / license / drift 嚴重度政策、定期依賴漂移與外部資料來源檢查設計、依賴升級批准包模板、runtime_surface_inventory_v1 schema / snapshot / API / UI、gitea_workflow_runner_health_v1 schema / snapshot / API / UI、observability_contract_matrix_v1 schema / snapshot / API / UI、ai_provider_route_matrix_v1 schema / snapshot / API / UI、service_health_gap_matrix_v1 schema / snapshot / API / UI、service health evidence cards UI、service_health_failure_notification_policy_v1 schema / snapshot / API / UI 已完成 |
| OpenClaw / Hermes / NemoTron 佈建布局 | 45% | P1-401 / P1-402 已完成;仍是只讀 layout 與治理頁顯示,不是 runtime deploy | `ai_agent_deployment_layout_v1` schema、`ai_agent_deployment_layout_2026-06-11.json``GET /api/v1/agents/agent-deployment-layout`、治理頁自動化盤點 UI、`AI_AGENT_DEPLOYMENT_LAYOUT_2026-06-11.md` |
| OpenClaw / Hermes / NemoTron 主動溝通與學習契約 | 35% | P2-401A 已完成只讀 contractruntime worker、DB migration、Telegram 實發、SDK / 付費服務仍未開 gate | `ai_agent_communication_learning_contract_v1` schema、`ai_agent_communication_learning_contract_2026-06-11.json``GET /api/v1/agents/agent-communication-learning-contract`、MASTER §3.2.1b / §3.4.3 |
| AI Agent 主動營運委派與版本生命週期 | 55% | P2-402A / P2-402B / P2-402C 已完成;已建立 repo-only 版本新鮮度快照、工具採用批准包與 API。定期排程、外部版本查詢、工具安裝、CI 變更、套件升級、主機更新、container pull、auto merge、Telegram 實發仍未開 gate | `ai_agent_proactive_operations_contract_v1``ai_agent_version_freshness_snapshot_v1``ai_agent_tool_adoption_approval_package_v1``GET /api/v1/agents/agent-proactive-operations-contract``GET /api/v1/agents/agent-version-freshness-snapshot``GET /api/v1/agents/agent-tool-adoption-approval-package`、MASTER §3.2.1c |
| AI Agent 主動營運委派與版本生命週期 | 68% | P2-402A / P2-402B / P2-402C / P2-402D 已完成;已建立 repo-only 版本新鮮度快照、工具採用批准包、Telegram action-required digest policy 與 API。定期排程、外部版本查詢、工具安裝、CI 變更、套件升級、主機更新、container pull、auto merge、Telegram 實發仍未開 gate | `ai_agent_proactive_operations_contract_v1``ai_agent_version_freshness_snapshot_v1``ai_agent_tool_adoption_approval_package_v1``ai_agent_telegram_action_required_digest_policy_v1``GET /api/v1/agents/agent-proactive-operations-contract``GET /api/v1/agents/agent-version-freshness-snapshot``GET /api/v1/agents/agent-tool-adoption-approval-package``GET /api/v1/agents/agent-telegram-action-required-digest-policy`MASTER §3.2.1c |
| 本工作清單與分析報告 | 100% | 已完成 | 本 MD 文件 |
AI Agent 自動化工作包目前完成度:**92%**。本工作清單文件本身完成度:**100%**。
@@ -22,7 +22,7 @@ AI Agent 自動化工作包目前完成度:**92%**。本工作清單文件本
三 Agent 主動溝通與學習契約目前完成度:**35%**。已完成只讀 schema / snapshot / API / 測試與 MASTER 同步;下一步依優先順序推 `P2-401B` AgentSession / Redis Streams migration 與 worker gate但在批准前仍不得啟動 runtime loop。
AI Agent 主動營運委派與版本生命週期目前完成度:**55%**。已完成 12 類版本 domain、24 類可委派能力、5 種 cadence、8 類 MCP、4 類 RAG memory、只讀 API、`P2-402B` repo-only daily version freshness snapshot,以及 `P2-402C` Renovate / OSV-Scanner / Trivy / Syft / Grype 工具採用批准包;下一步是 `P2-402D` Telegram action-required digest policy外部 registry / package source / host probe / 工具安裝 / CI 變更 / Telegram 實發仍需 gate。
AI Agent 主動營運委派與版本生命週期目前完成度:**68%**。已完成 12 類版本 domain、24 類可委派能力、5 種 cadence、8 類 MCP、4 類 RAG memory、只讀 API、`P2-402B` repo-only daily version freshness snapshot`P2-402C` Renovate / OSV-Scanner / Trivy / Syft / Grype 工具採用批准包,以及 `P2-402D` Telegram action-required digest policy;下一步是 `P2-402E` Gitea PR 草案 lane,外部 registry / package source / host probe / 工具安裝 / CI 變更 / Telegram 實發仍需 gate。
完成度計算模型:
@@ -954,7 +954,7 @@ UI
| P2-402A | 完成 | 100 | Hermes + OpenClaw + Nemotron | 定義 AI Agent 主動營運委派與版本生命週期12 類版本 domain、24 類可委派能力、MCP/RAG/Telegram policy | `ai_agent_proactive_operations_contract_v1` / snapshot / 只讀 API / MASTER 同步 | 只讀;不啟用排程、不升級、不 host update、不 pull image、不 auto merge、不發 Telegram |
| P2-402B | 完成 | 100 | Hermes | 建立 repo-only daily version freshness snapshot | `ai_agent_version_freshness_snapshot_v1` / snapshot / 只讀 API / 測試12 類 repo-only source、5 個 daily step、3 Agent role | 只讀workflow schedule 未啟用、外部 lookup 未開、不得升級或發 Telegram |
| P2-402C | 完成 | 100 | OpenClaw | 建立 Renovate / OSV-Scanner / Trivy / Syft / Grype 工具採用批准包 | `ai_agent_tool_adoption_approval_package_v1` / snapshot / 只讀 API / 測試5 工具、5 官方來源、4 採用 lane、6 批准欄位 | 只讀tool install、CI change、external lookup、vulnerability DB、PR、Telegram 全部未啟用 |
| P2-402D | 待辦 | 0 | OpenClaw | 建立 Telegram action-required digest policy | critical / action-required / failure-only digest | Telegram Gateway E2E |
| P2-402D | 完成 | 100 | OpenClaw | 建立 Telegram action-required digest policy | `ai_agent_telegram_action_required_digest_policy_v1` / snapshot / 只讀 API / 測試8 條 digest rule、3 個 channel 草案、5 類 trigger category、成功降噪與 redaction policy | 只讀;Telegram send、Gateway queue write、route / receiver change、workflow、runtime 全部未啟用 |
| P2-402E | 待辦 | 0 | Hermes | 設計 Gitea PR 草案 lane | grouping、automerge=false、tests、rollback、owner response | bot / branch policy approval |
| P2-402F | 待辦 | 0 | OpenClaw | 建立 host OS / K3s / stateful services 版本只讀盤點 | host / K3s / DB / Redis / MinIO / Gitea 版本矩陣 | host readonly probe + maintenance window approval |
| P2-402G | 待辦 | 0 | Hermes | 接入 governance UI 顯示可委派能力 | 自主等級、gate、owner、Telegram policy | frontend UI change approval |

View File

@@ -1,7 +1,7 @@
# AI Agent 主動營運委派與版本生命週期分析報告
> 日期2026-06-11台北時間
> 文件定位P2-402A / P2-402B / P2-402C 只讀契約摘要。權威細節以 MASTER §3.2.1c、`ai_agent_proactive_operations_contract_v1`、`ai_agent_version_freshness_snapshot_v1``ai_agent_tool_adoption_approval_package_v1` 為準。
> 文件定位P2-402A / P2-402B / P2-402C / P2-402D 只讀契約摘要。權威細節以 MASTER §3.2.1c、`ai_agent_proactive_operations_contract_v1`、`ai_agent_version_freshness_snapshot_v1``ai_agent_tool_adoption_approval_package_v1` 與 `ai_agent_telegram_action_required_digest_policy_v1` 為準。
## 1. 本波完成度
@@ -10,7 +10,8 @@
| 主動營運委派契約 | 100% | 已完成 schema / snapshot / API / 測試 |
| Repo-only 版本新鮮度快照 | 100% | P2-402B 已完成 schema / committed snapshot / API / 測試 |
| 工具採用批准包 | 100% | P2-402C 已完成 Renovate / OSV-Scanner / Trivy / Syft / Grype schema / committed snapshot / API / 測試 |
| 整體主動營運與版本生命週期 | 55% | 已完成架構、repo-only freshness 與工具採用批准包runtime 排程、工具安裝、CI 變更與更新仍未開 gate |
| Telegram action-required digest policy | 100% | P2-402D 已完成 critical / action-required / failure-only digest schema / committed snapshot / API / 測試 |
| 整體主動營運與版本生命週期 | 68% | 已完成架構、repo-only freshness、工具採用批准包與 Telegram digest policyruntime 排程、工具安裝、CI 變更與更新仍未開 gate |
## 2. 可交給 AI Agent 的工作分類
@@ -38,6 +39,9 @@
| `docs/schemas/ai_agent_tool_adoption_approval_package_v1.schema.json` | 工具採用批准包 schema工具安裝、CI 變更、外部查詢、漏洞 DB、PR、Telegram 全部預設 false |
| `docs/evaluations/ai_agent_tool_adoption_approval_package_2026-06-11.json` | Renovate / OSV-Scanner / Trivy / Syft / Grype 官方來源、採用 lane、批准欄位、rollback plan |
| `GET /api/v1/agents/agent-tool-adoption-approval-package` | 只讀 API不安裝工具、不改 CI、不查外部、不建 PR、不發 Telegram |
| `docs/schemas/ai_agent_telegram_action_required_digest_policy_v1.schema.json` | Telegram action-required digest policy schemadirect send、queue write、route / receiver change、workflow、transcript 全部預設 false |
| `docs/evaluations/ai_agent_telegram_action_required_digest_policy_2026-06-11.json` | 8 條 digest rule、3 個 channel 草案、5 類 trigger category、成功降噪、redaction、fallback policy |
| `GET /api/v1/agents/agent-telegram-action-required-digest-policy` | 只讀 API不送 Telegram、不寫 queue、不改 route / receiver、不觸發 workflow |
## 4. P2-402B Repo-only 版本新鮮度快照
@@ -64,17 +68,26 @@
P2-402C 的重點是把「哪些工具可被採用、採用前要填哪些批准欄位、風險與 rollback 如何定義」固定成資料契約。它不是工具導入本身工具安裝、CI workflow、外部 registry / vulnerability DB、Gitea PR、Telegram 實發都維持 blocked。
## 6. 下一步優先順序
## 6. P2-402D Telegram Action-Required Digest Policy
| 類別 | 決策 | Telegram 邊界 |
|---|---|---|
| 成功 / 已驗證 / 快照完成 | `suppress_success_noise` | 不即時送 Telegram只進每日 KM / LOGBOOK 摘要草案 |
| 版本來源失敗 / Telegram silence / critical CVE 或 EOL | `draft_failure_escalation_digest` | 只產 failure escalation digest 草案;需 OpenClaw review不能直發 |
| 工具安裝 / CI 變更 / scanner disagreement / no executable repair candidate | `draft_action_required_digest` | 只產 action-required digest 草案;未批准不得寫 Gateway queue |
本波把「哪些事情值得通知」和「哪些成功訊息必須壓掉」固定成資料契約。Telegram Gateway queue write、direct send、route / receiver change、AwoooP event write、workflow trigger、runtime execution 仍全部為 false。
## 7. 下一步優先順序
| ID | 優先 | 任務 | 關卡 |
|---|---|---|---|
| P2-402C | 0 | Renovate / OSV-Scanner / Trivy / Syft / Grype 採用批准包 | 已完成只讀tool install / CI change 未啟用 |
| P2-402D | 1 | Telegram action-required digest policy | Telegram Gateway E2E |
| P2-402E | 2 | Gitea PR 草案 lane | bot / branch policy approval |
| P2-402F | 3 | host OS / K3s / stateful services 版本只讀盤點 | host probe / maintenance approval |
| P2-402G | 4 | governance UI 顯示可委派能力 | frontend UI approval |
| P2-402D | 0 | Telegram action-required digest policy | 已完成只讀Telegram send / queue write 未啟用 |
| P2-402E | 1 | Gitea PR 草案 lane | bot / branch policy approval |
| P2-402F | 2 | host OS / K3s / stateful services 版本只讀盤點 | host probe / maintenance approval |
| P2-402G | 3 | governance UI 顯示可委派能力 | frontend UI approval |
## 7. 仍維持 false 的安全邊界
## 8. 仍維持 false 的安全邊界
- `runtime_version_update_allowed=false`
- `package_upgrade_allowed=false`

View File

@@ -0,0 +1,55 @@
# AI Agent Telegram Action-Required Digest Policy 工作報告
> 日期2026-06-11台北時間
> 狀態P2-402D 已完成;整體 AI Agent 主動營運與版本生命週期完成度 68%。
> 邊界:本文件與對應 API 只提供 Telegram digest policy不送 Telegram、不寫 Telegram Gateway queue、不改 Alertmanager route / receiver、不寫 AwoooP event、不觸發 workflow、不執行 runtime、不讀取 secret、不顯示工作視窗對話內容。
## 1. 本波完成項目
| 項目 | 狀態 | 產出 |
|---|---|---|
| Telegram digest policy schema | 完成 | `docs/schemas/ai_agent_telegram_action_required_digest_policy_v1.schema.json` |
| Telegram digest policy snapshot | 完成 | `docs/evaluations/ai_agent_telegram_action_required_digest_policy_2026-06-11.json` |
| API loader | 完成 | `apps/api/src/services/ai_agent_telegram_action_required_digest_policy.py` |
| 只讀 API | 完成 | `GET /api/v1/agents/agent-telegram-action-required-digest-policy` |
| 測試 | 完成 | loader / API / direct-send boundary / success-noise suppression / rollup mismatch / transcript redaction |
| 主契約同步 | 完成 | `ai_agent_proactive_operations_contract_v1` 完成度 68%current `P2-402D`next `P2-402E` |
## 2. Digest 規則摘要
| 決策 | 規則數 | 用途 | 邊界 |
|---|---:|---|---|
| `suppress_success_noise` | 2 | repo-only freshness 成功、工具批准包完成等成功訊號只進每日摘要 | 不即時 Telegram、不寫 queue |
| `draft_failure_escalation_digest` | 3 | version watch source failed、critical CVE / EOL、Telegram delivery silence | 需 OpenClaw review只產草案 |
| `draft_action_required_digest` | 3 | 工具安裝 / CI 變更需批准、scanner disagreement、approval 後沒有可執行修復候選 | 需 evidence ref、owner、approval gate |
## 3. Agent 分工
| Agent | 本波可做 | 本波不可做 |
|---|---|---|
| Hermes | 彙整 repo-only freshness、source failure、工具採用 evidence refs 與每日摘要草案 | 直接發 Telegram、寫 Gateway queue、觸發 workflow |
| OpenClaw | 仲裁 critical / action-required / failure-only digest 草案,確認 blast radius、rollback 與 approval gate | 自行批准發送、改 route / receiver、把成功訊息升級為告警 |
| NemoTron | 針對 scanner disagreement、AI Agent / model / prompt / tool-call risk 產生離線 replay note | 呼叫付費模型、新增 SDK、開 shadow / canary |
## 4. 仍維持 false 的邊界
- `telegram_direct_send_allowed=false`
- `telegram_test_message_allowed=false`
- `telegram_gateway_queue_write_allowed=false`
- `alertmanager_route_change_allowed=false`
- `telegram_receiver_change_allowed=false`
- `awooop_event_write_allowed=false`
- `workflow_trigger_allowed=false`
- `external_scan_allowed=false`
- `runtime_execution_allowed=false`
- `secret_plaintext_allowed=false`
- `conversation_transcript_allowed=false`
## 5. 下一步代辦
| 優先 | ID | 工作 | 完成標準 |
|---:|---|---|---|
| 1 | P2-402E | Gitea PR 草案 lane | Renovate grouping、automerge=false、測試要求、rollback、owner response、bot / branch policy approval |
| 2 | P2-402F | host OS / K3s / stateful services 版本只讀盤點 | 主機、K3s、PostgreSQL、Redis、MinIO、Harbor、Gitea 只讀版本矩陣 |
| 3 | P2-402G | Governance UI 顯示可委派能力 | 前端顯示 autonomy level、gate、owner、Telegram policy無執行按鈕 |
| 4 | 候選池 | Telegram Gateway E2E 批准包 | queue write / send / callback / fallback path 的測試與 rollout gate |

View File

@@ -37,7 +37,7 @@
| 優先 | ID | 工作 | 完成標準 | 目前狀態 |
|---:|---|---|---|---|
| 1 | P2-402D | Telegram action-required digest policy | 定義 critical / action-required / failure-only禁止成功洗版接 Telegram Gateway E2E gate | 待辦 |
| 1 | P2-402D | Telegram action-required digest policy | 定義 critical / action-required / failure-only禁止成功洗版接 Telegram Gateway E2E gate | 完成 |
| 2 | P2-402E | Gitea PR 草案 lane | Renovate grouping、automerge=false、測試要求、rollback、owner response | 待辦 |
| 3 | P2-402F | host OS / K3s / stateful services 版本只讀盤點 | 主機、K3s、PostgreSQL、Redis、MinIO、Harbor、Gitea 只讀版本矩陣 | 待辦 |
| 4 | P2-402G | Governance UI 顯示可委派能力 | 前端顯示 autonomy level、gate、owner、Telegram policy無執行按鈕 | 待辦 |

View File

@@ -2,13 +2,13 @@
"schema_version": "ai_agent_proactive_operations_contract_v1",
"generated_at": "2026-06-11T21:30:00+08:00",
"program_status": {
"overall_completion_percent": 55,
"overall_completion_percent": 68,
"current_priority": "P2",
"current_task_id": "P2-402C",
"next_task_id": "P2-402D",
"current_task_id": "P2-402D",
"next_task_id": "P2-402E",
"read_only_mode": true,
"runtime_authority": "contract_only_no_version_or_runtime_update",
"status_note": "P2-402C 已建立 Renovate / OSV-Scanner / Trivy / Syft / Grype 工具採用批准包、schema、snapshot、只讀 API 與測試;本波仍不安裝工具、不改 CI、不查外部 registry、不下載漏洞 DB、不建立 PR、不發 Telegram。"
"status_note": "P2-402D 已建立 Telegram action-required digest policy、schema、snapshot、只讀 API 與測試;本波仍不送 Telegram、不寫 Gateway queue、不改 Alertmanager route / receiver、不觸發 workflow、不執行 runtime。"
},
"external_source_evidence": [
{
@@ -628,16 +628,16 @@
"completion_percent": 100,
"owner_agent": "OpenClaw",
"summary": "建立 Renovate / OSV-Scanner / Trivy / Syft / Grype 工具採用批准包、官方來源 evidence、採用 lane、批准欄位、schema、snapshot、只讀 API 與測試。",
"next_gate": "P2-402D_telegram_action_required_digest_policy"
"next_gate": "P2-402D_completed"
},
{
"task_id": "P2-402D",
"priority": "P2",
"status": "planned",
"completion_percent": 0,
"status": "done",
"completion_percent": 100,
"owner_agent": "OpenClaw",
"summary": "建立 Telegram action-required digest policy,只通知 critical / action-required不發成功洗版。",
"next_gate": "telegram_gateway_e2e_required"
"summary": "建立 Telegram action-required digest policy、schema、snapshot、只讀 API 與測試;定義 critical / action-required / failure-only digest 草案、成功降噪、redaction 與 fallback gap 邊界。",
"next_gate": "P2-402E_gitea_pr_draft_lane"
},
{
"task_id": "P2-402E",

View File

@@ -0,0 +1,405 @@
{
"schema_version": "ai_agent_telegram_action_required_digest_policy_v1",
"generated_at": "2026-06-11T23:58:00+08:00",
"program_status": {
"overall_completion_percent": 68,
"current_priority": "P2",
"current_task_id": "P2-402D",
"next_task_id": "P2-402E",
"read_only_mode": true,
"runtime_authority": "policy_only_no_telegram_send_or_route_change",
"status_note": "P2-402D 建立 Telegram action-required digest policy本波只定義 critical / action-required / failure-only digest 規則,不送 Telegram、不寫 Gateway queue、不改 Alertmanager route、不改 receiver、不觸發 workflow。"
},
"source_refs": [
"docs/evaluations/ai_agent_proactive_operations_contract_2026-06-11.json",
"docs/evaluations/ai_agent_version_freshness_snapshot_2026-06-11.json",
"docs/evaluations/ai_agent_tool_adoption_approval_package_2026-06-11.json",
"docs/evaluations/service_health_failure_notification_policy_2026-06-05.json",
"docs/evaluations/backup_notification_policy_2026-06-04.json",
"docs/LOGBOOK.md"
],
"trigger_categories": [
{
"category_id": "success_noise",
"owner_agent": "Hermes",
"policy_intent": "成功、完成、已驗證、只讀快照更新不得即時送 Telegram只能留在 committed evidence 或日摘要。",
"blocked_now": [
"成功巡檢即時 Telegram",
"成功掃描即時 Telegram",
"只讀 snapshot 完成即時 Telegram"
]
},
{
"category_id": "version_watch_failure",
"owner_agent": "Hermes",
"policy_intent": "版本來源連續失敗、資料過期、watch source 失聯時產生 action-required digest 草案。",
"blocked_now": [
"直接寫 Telegram Gateway queue",
"直接送 Bot",
"觸發外部 registry lookup"
]
},
{
"category_id": "critical_security_or_eol",
"owner_agent": "OpenClaw",
"policy_intent": "critical CVE、EOL approaching、production incompatibility risk 才可進 failure escalation digest 草案。",
"blocked_now": [
"下載 vulnerability DB",
"掃描 live image",
"升級套件或 image"
]
},
{
"category_id": "tool_adoption_approval_required",
"owner_agent": "OpenClaw",
"policy_intent": "Renovate / OSV-Scanner / Trivy / Syft / Grype 採用需要人類批准時,僅產 action-required digest 草案。",
"blocked_now": [
"安裝工具",
"改 CI workflow",
"建立 Gitea PR"
]
},
{
"category_id": "telegram_delivery_silence",
"owner_agent": "OpenClaw",
"policy_intent": "Telegram delivery silence、fallback gap、callback failure 屬於告警必到風險,進 failure escalation digest 草案。",
"blocked_now": [
"直接發測試訊息",
"改 receiver",
"改 Alertmanager route"
]
}
],
"digest_channels": [
{
"channel_id": "telegram_ops_digest_draft",
"purpose": "Telegram action-required / failure-only digest 草案P2-402D 只定義政策,不送出。",
"success_immediate_allowed": false,
"direct_send_allowed": false,
"queue_write_allowed": false,
"requires_telegram_gateway_e2e": true
},
{
"channel_id": "awooop_action_queue_draft",
"purpose": "AwoooP action-required queue 草案;本波不寫 event、不建立 operator task。",
"success_immediate_allowed": false,
"direct_send_allowed": false,
"queue_write_allowed": false,
"requires_telegram_gateway_e2e": false
},
{
"channel_id": "daily_km_digest_only",
"purpose": "成功與資訊性訊號只能進每日 KM / LOGBOOK 摘要草案。",
"success_immediate_allowed": false,
"direct_send_allowed": false,
"queue_write_allowed": false,
"requires_telegram_gateway_e2e": false
}
],
"digest_rules": [
{
"rule_id": "repo_only_freshness_snapshot_success",
"category_id": "success_noise",
"signal_state": "success",
"severity": "info",
"decision": "suppress_success_noise",
"owner_agent": "Hermes",
"required_evidence": [
"committed snapshot ref",
"rollup counters"
],
"channels": [
"daily_km_digest_only"
],
"requires_openclaw_review": false,
"telegram_direct_send_allowed": false,
"next_action": "只寫 LOGBOOK / KM 摘要草案,不送 Telegram。"
},
{
"rule_id": "tool_adoption_package_completed_success",
"category_id": "success_noise",
"signal_state": "verified",
"severity": "info",
"decision": "suppress_success_noise",
"owner_agent": "Hermes",
"required_evidence": [
"schema ref",
"API verification ref"
],
"channels": [
"daily_km_digest_only"
],
"requires_openclaw_review": false,
"telegram_direct_send_allowed": false,
"next_action": "保留 committed evidence不發成功洗版。"
},
{
"rule_id": "version_watch_source_failed",
"category_id": "version_watch_failure",
"signal_state": "failed",
"severity": "warning",
"decision": "draft_failure_escalation_digest",
"owner_agent": "Hermes",
"required_evidence": [
"source_id",
"last_success_at",
"failure_count",
"fallback_source"
],
"channels": [
"telegram_ops_digest_draft",
"awooop_action_queue_draft"
],
"requires_openclaw_review": true,
"telegram_direct_send_allowed": false,
"next_action": "OpenClaw 確認是否升級為 action-required Telegram digest。"
},
{
"rule_id": "critical_cve_or_eol_requires_owner",
"category_id": "critical_security_or_eol",
"signal_state": "critical",
"severity": "critical",
"decision": "draft_failure_escalation_digest",
"owner_agent": "OpenClaw",
"required_evidence": [
"official advisory ref",
"affected component",
"blast radius",
"rollback plan"
],
"channels": [
"telegram_ops_digest_draft",
"awooop_action_queue_draft"
],
"requires_openclaw_review": true,
"telegram_direct_send_allowed": false,
"next_action": "產生 owner packet 與批准包;未批准不得升級。"
},
{
"rule_id": "telegram_delivery_silence_detected",
"category_id": "telegram_delivery_silence",
"signal_state": "failed",
"severity": "critical",
"decision": "draft_failure_escalation_digest",
"owner_agent": "OpenClaw",
"required_evidence": [
"delivery route",
"last_successful_send",
"fallback path",
"failed callback evidence"
],
"channels": [
"telegram_ops_digest_draft",
"awooop_action_queue_draft"
],
"requires_openclaw_review": true,
"telegram_direct_send_allowed": false,
"next_action": "保留告警必到 fallback 檢查;本波不直接送測試訊息。"
},
{
"rule_id": "tool_install_or_ci_change_needs_approval",
"category_id": "tool_adoption_approval_required",
"signal_state": "action_required",
"severity": "warning",
"decision": "draft_action_required_digest",
"owner_agent": "OpenClaw",
"required_evidence": [
"tool_id",
"approval_requirements",
"secret_storage_plan",
"rollback_plan"
],
"channels": [
"telegram_ops_digest_draft",
"awooop_action_queue_draft"
],
"requires_openclaw_review": true,
"telegram_direct_send_allowed": false,
"next_action": "要求 operator approval id未批准不得安裝工具或改 CI。"
},
{
"rule_id": "scanner_disagreement_needs_review",
"category_id": "tool_adoption_approval_required",
"signal_state": "action_required",
"severity": "warning",
"decision": "draft_action_required_digest",
"owner_agent": "NemoTron",
"required_evidence": [
"scanner_a_ref",
"scanner_b_ref",
"disagreement_summary",
"affected package or image"
],
"channels": [
"telegram_ops_digest_draft"
],
"requires_openclaw_review": true,
"telegram_direct_send_allowed": false,
"next_action": "NemoTron 產生離線 replay / assumption noteOpenClaw 仲裁是否 action-required。"
},
{
"rule_id": "no_executable_repair_candidate_after_approval",
"category_id": "telegram_delivery_silence",
"signal_state": "blocked",
"severity": "warning",
"decision": "draft_action_required_digest",
"owner_agent": "OpenClaw",
"required_evidence": [
"incident_id",
"approval_id",
"latest_action",
"repair_candidate_gap"
],
"channels": [
"telegram_ops_digest_draft",
"awooop_action_queue_draft"
],
"requires_openclaw_review": true,
"telegram_direct_send_allowed": false,
"next_action": "標記 no-action / non-executable避免誤導 operator 以為已執行修復。"
}
],
"message_template_contract": {
"required_fields": [
"stage",
"severity",
"target_id",
"evidence_ref",
"blocked_reason",
"next_action",
"owner_agent",
"approval_gate"
],
"forbidden_fields": [
"secret_value",
"token",
"authorization_header",
"work_window_transcript",
"codex_user_message",
"prompt_text",
"chain_of_thought",
"session_id",
"browser_context"
],
"success_message_policy": "成功、完成、已驗證、只讀快照更新不得即時送 Telegram / AwoooP只能進每日摘要或 LOGBOOK。",
"action_required_message_policy": "只允許輸出 evidence ref、blocked reason、next action、owner agent、approval gate本波不送出。",
"failure_message_policy": "只有 failed / blocked / critical 且具備 evidence ref 與 OpenClaw review gate 時,才可成為 failure escalation digest 草案。"
},
"rate_limit_policy": {
"success_policy": "成功巡檢、成功掃描、成功快照不得即時 Telegram 洗版。",
"digest_window_minutes": 30,
"dedupe_key_fields": [
"category_id",
"target_id",
"evidence_ref",
"owner_agent"
],
"max_digest_items": 10,
"fallback_policy": "若 Telegram Gateway 或 callback 失敗,保留 AwoooP / LOGBOOK evidence refs 與 fallback gap不直接重送 Bot。"
},
"display_redaction_contract": {
"conversation_transcript_display_allowed": false,
"redaction_required": true,
"allowed_frontend_fields": [
"政策規則摘要",
"已提交證據參照",
"blocked reason",
"next action",
"owner agent",
"approval gate"
],
"forbidden_frontend_content": [
"內部對話內容",
"Codex / 使用者訊息逐字稿",
"提示詞 / 思考鏈",
"工作階段識別碼 / 瀏覽器脈絡",
"機密 / 權杖 / 授權標頭"
]
},
"agent_roles": [
{
"agent_id": "hermes",
"digest_responsibility": "彙整 repo-only freshness、source failure、工具採用 evidence refs 與每日摘要草案。",
"blocked_now": [
"直接發 Telegram",
"寫 Telegram Gateway queue",
"觸發 workflow"
]
},
{
"agent_id": "openclaw",
"digest_responsibility": "仲裁 critical / action-required / failure-only digest 草案,確認 blast radius、rollback 與 approval gate。",
"blocked_now": [
"自行批准 Telegram 發送",
"改 route / receiver",
"把成功訊息升級為告警"
]
},
{
"agent_id": "nemotron",
"digest_responsibility": "針對 scanner disagreement、AI Agent / model / prompt / tool-call risk 產生離線 replay note。",
"blocked_now": [
"呼叫付費模型",
"新增 SDK",
"開 shadow / canary"
]
}
],
"operation_boundaries": {
"read_only_policy_allowed": true,
"telegram_direct_send_allowed": false,
"telegram_test_message_allowed": false,
"telegram_gateway_queue_write_allowed": false,
"alertmanager_route_change_allowed": false,
"telegram_receiver_change_allowed": false,
"awooop_event_write_allowed": false,
"workflow_trigger_allowed": false,
"external_scan_allowed": false,
"runtime_execution_allowed": false,
"secret_plaintext_allowed": false,
"conversation_transcript_allowed": false
},
"approval_boundaries": {
"telegram_digest_send_approved": false,
"telegram_gateway_queue_write_approved": false,
"telegram_route_change_approved": false,
"alertmanager_receiver_change_approved": false,
"awooop_event_write_approved": false,
"workflow_trigger_approved": false,
"runtime_execution_approved": false,
"secret_plaintext_approved": false
},
"rollups": {
"rule_count": 8,
"channel_count": 3,
"trigger_category_count": 5,
"by_decision": {
"suppress_success_noise": 2,
"draft_failure_escalation_digest": 3,
"draft_action_required_digest": 3
},
"action_required_rule_ids": [
"tool_install_or_ci_change_needs_approval",
"scanner_disagreement_needs_review",
"no_executable_repair_candidate_after_approval"
],
"failure_escalation_rule_ids": [
"version_watch_source_failed",
"critical_cve_or_eol_requires_owner",
"telegram_delivery_silence_detected"
],
"suppressed_success_rule_ids": [
"repo_only_freshness_snapshot_success",
"tool_adoption_package_completed_success"
],
"telegram_direct_send_allowed_count": 0,
"telegram_gateway_queue_write_allowed_count": 0,
"route_change_allowed_count": 0,
"conversation_transcript_allowed_count": 0,
"next_approval_task_ids": [
"P2-402E",
"P2-402F",
"P2-402G"
]
}
}

View File

@@ -0,0 +1,503 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://awoooi.wooo.work/schemas/ai_agent_telegram_action_required_digest_policy_v1.schema.json",
"title": "AI Agent Telegram Action Required Digest Policy v1",
"type": "object",
"additionalProperties": false,
"required": [
"schema_version",
"generated_at",
"program_status",
"source_refs",
"trigger_categories",
"digest_channels",
"digest_rules",
"message_template_contract",
"rate_limit_policy",
"display_redaction_contract",
"agent_roles",
"operation_boundaries",
"approval_boundaries",
"rollups"
],
"properties": {
"schema_version": {
"const": "ai_agent_telegram_action_required_digest_policy_v1"
},
"generated_at": {
"type": "string"
},
"program_status": {
"type": "object",
"additionalProperties": false,
"required": [
"overall_completion_percent",
"current_priority",
"current_task_id",
"next_task_id",
"read_only_mode",
"runtime_authority",
"status_note"
],
"properties": {
"overall_completion_percent": {
"type": "integer",
"minimum": 0,
"maximum": 100
},
"current_priority": {
"type": "string"
},
"current_task_id": {
"type": "string"
},
"next_task_id": {
"type": "string"
},
"read_only_mode": {
"const": true
},
"runtime_authority": {
"const": "policy_only_no_telegram_send_or_route_change"
},
"status_note": {
"type": "string"
}
}
},
"source_refs": {
"type": "array",
"items": {
"type": "string"
}
},
"trigger_categories": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"category_id",
"owner_agent",
"policy_intent",
"blocked_now"
],
"properties": {
"category_id": {
"type": "string"
},
"owner_agent": {
"type": "string"
},
"policy_intent": {
"type": "string"
},
"blocked_now": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
},
"digest_channels": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"channel_id",
"purpose",
"success_immediate_allowed",
"direct_send_allowed",
"queue_write_allowed",
"requires_telegram_gateway_e2e"
],
"properties": {
"channel_id": {
"type": "string"
},
"purpose": {
"type": "string"
},
"success_immediate_allowed": {
"const": false
},
"direct_send_allowed": {
"const": false
},
"queue_write_allowed": {
"const": false
},
"requires_telegram_gateway_e2e": {
"type": "boolean"
}
}
}
},
"digest_rules": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"rule_id",
"category_id",
"signal_state",
"severity",
"decision",
"owner_agent",
"required_evidence",
"channels",
"requires_openclaw_review",
"telegram_direct_send_allowed",
"next_action"
],
"properties": {
"rule_id": {
"type": "string"
},
"category_id": {
"type": "string"
},
"signal_state": {
"type": "string"
},
"severity": {
"type": "string"
},
"decision": {
"enum": [
"suppress_success_noise",
"draft_action_required_digest",
"draft_failure_escalation_digest",
"hold_for_owner_packet"
]
},
"owner_agent": {
"type": "string"
},
"required_evidence": {
"type": "array",
"items": {
"type": "string"
}
},
"channels": {
"type": "array",
"items": {
"type": "string"
}
},
"requires_openclaw_review": {
"type": "boolean"
},
"telegram_direct_send_allowed": {
"const": false
},
"next_action": {
"type": "string"
}
}
}
},
"message_template_contract": {
"type": "object",
"additionalProperties": false,
"required": [
"required_fields",
"forbidden_fields",
"success_message_policy",
"action_required_message_policy",
"failure_message_policy"
],
"properties": {
"required_fields": {
"type": "array",
"items": {
"type": "string"
}
},
"forbidden_fields": {
"type": "array",
"items": {
"type": "string"
}
},
"success_message_policy": {
"type": "string"
},
"action_required_message_policy": {
"type": "string"
},
"failure_message_policy": {
"type": "string"
}
}
},
"rate_limit_policy": {
"type": "object",
"additionalProperties": false,
"required": [
"success_policy",
"digest_window_minutes",
"dedupe_key_fields",
"max_digest_items",
"fallback_policy"
],
"properties": {
"success_policy": {
"type": "string"
},
"digest_window_minutes": {
"type": "integer",
"minimum": 1
},
"dedupe_key_fields": {
"type": "array",
"items": {
"type": "string"
}
},
"max_digest_items": {
"type": "integer",
"minimum": 1
},
"fallback_policy": {
"type": "string"
}
}
},
"display_redaction_contract": {
"type": "object",
"additionalProperties": false,
"required": [
"conversation_transcript_display_allowed",
"redaction_required",
"allowed_frontend_fields",
"forbidden_frontend_content"
],
"properties": {
"conversation_transcript_display_allowed": {
"const": false
},
"redaction_required": {
"const": true
},
"allowed_frontend_fields": {
"type": "array",
"items": {
"type": "string"
}
},
"forbidden_frontend_content": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"agent_roles": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"agent_id",
"digest_responsibility",
"blocked_now"
],
"properties": {
"agent_id": {
"type": "string"
},
"digest_responsibility": {
"type": "string"
},
"blocked_now": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
},
"operation_boundaries": {
"type": "object",
"additionalProperties": false,
"required": [
"read_only_policy_allowed",
"telegram_direct_send_allowed",
"telegram_test_message_allowed",
"telegram_gateway_queue_write_allowed",
"alertmanager_route_change_allowed",
"telegram_receiver_change_allowed",
"awooop_event_write_allowed",
"workflow_trigger_allowed",
"external_scan_allowed",
"runtime_execution_allowed",
"secret_plaintext_allowed",
"conversation_transcript_allowed"
],
"properties": {
"read_only_policy_allowed": {
"const": true
},
"telegram_direct_send_allowed": {
"const": false
},
"telegram_test_message_allowed": {
"const": false
},
"telegram_gateway_queue_write_allowed": {
"const": false
},
"alertmanager_route_change_allowed": {
"const": false
},
"telegram_receiver_change_allowed": {
"const": false
},
"awooop_event_write_allowed": {
"const": false
},
"workflow_trigger_allowed": {
"const": false
},
"external_scan_allowed": {
"const": false
},
"runtime_execution_allowed": {
"const": false
},
"secret_plaintext_allowed": {
"const": false
},
"conversation_transcript_allowed": {
"const": false
}
}
},
"approval_boundaries": {
"type": "object",
"additionalProperties": false,
"required": [
"telegram_digest_send_approved",
"telegram_gateway_queue_write_approved",
"telegram_route_change_approved",
"alertmanager_receiver_change_approved",
"awooop_event_write_approved",
"workflow_trigger_approved",
"runtime_execution_approved",
"secret_plaintext_approved"
],
"properties": {
"telegram_digest_send_approved": {
"const": false
},
"telegram_gateway_queue_write_approved": {
"const": false
},
"telegram_route_change_approved": {
"const": false
},
"alertmanager_receiver_change_approved": {
"const": false
},
"awooop_event_write_approved": {
"const": false
},
"workflow_trigger_approved": {
"const": false
},
"runtime_execution_approved": {
"const": false
},
"secret_plaintext_approved": {
"const": false
}
}
},
"rollups": {
"type": "object",
"additionalProperties": false,
"required": [
"rule_count",
"channel_count",
"trigger_category_count",
"by_decision",
"action_required_rule_ids",
"failure_escalation_rule_ids",
"suppressed_success_rule_ids",
"telegram_direct_send_allowed_count",
"telegram_gateway_queue_write_allowed_count",
"route_change_allowed_count",
"conversation_transcript_allowed_count",
"next_approval_task_ids"
],
"properties": {
"rule_count": {
"type": "integer",
"minimum": 0
},
"channel_count": {
"type": "integer",
"minimum": 0
},
"trigger_category_count": {
"type": "integer",
"minimum": 0
},
"by_decision": {
"type": "object",
"additionalProperties": {
"type": "integer",
"minimum": 0
}
},
"action_required_rule_ids": {
"type": "array",
"items": {
"type": "string"
}
},
"failure_escalation_rule_ids": {
"type": "array",
"items": {
"type": "string"
}
},
"suppressed_success_rule_ids": {
"type": "array",
"items": {
"type": "string"
}
},
"telegram_direct_send_allowed_count": {
"const": 0
},
"telegram_gateway_queue_write_allowed_count": {
"const": 0
},
"route_change_allowed_count": {
"const": 0
},
"conversation_transcript_allowed_count": {
"const": 0
},
"next_approval_task_ids": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
}

View File

@@ -670,7 +670,7 @@ Repo / registry / release notes / K8s / host / observability / backup evidence
| 檔案 / API | 用途 |
|---|---|
| `docs/schemas/ai_agent_proactive_operations_contract_v1.schema.json` | 主動營運委派、版本生命週期、MCP、RAG、Telegram policy、approval boundary 契約 |
| `docs/evaluations/ai_agent_proactive_operations_contract_2026-06-11.json` | 12 類版本 domain、24 類可委派能力、5 種 cadence、8 類 MCP、4 類 RAG memory完成度 `55%` |
| `docs/evaluations/ai_agent_proactive_operations_contract_2026-06-11.json` | 12 類版本 domain、24 類可委派能力、5 種 cadence、8 類 MCP、4 類 RAG memory完成度 `68%` |
| `apps/api/src/services/ai_agent_proactive_operations_contract.py` | 只讀 loader強制 runtime update / package upgrade / host upgrade / workflow schedule / auto merge / Telegram direct send 全部 false |
| `GET /api/v1/agents/agent-proactive-operations-contract` | 治理 API只回傳 committed snapshot不啟用排程、不升級、不呼叫付費服務 |
| `docs/schemas/ai_agent_version_freshness_snapshot_v1.schema.json` | P2-402B repo-only 版本新鮮度 schema鎖定 schedule / external lookup / upgrade / Telegram / PR / host probe 全部 false |
@@ -679,13 +679,16 @@ Repo / registry / release notes / K8s / host / observability / backup evidence
| `docs/schemas/ai_agent_tool_adoption_approval_package_v1.schema.json` | P2-402C 工具採用批准包 schema鎖定 tool install / CI change / external lookup / vulnerability DB / PR / Telegram 全部 false |
| `docs/evaluations/ai_agent_tool_adoption_approval_package_2026-06-11.json` | P2-402C committed snapshotRenovate / OSV-Scanner / Trivy / Syft / Grype 官方來源、採用 lane、批准欄位與 rollback gate |
| `GET /api/v1/agents/agent-tool-adoption-approval-package` | 只讀 API只回傳工具採用批准包不安裝工具、不改 CI、不查外部、不建 PR、不發 Telegram |
| `docs/schemas/ai_agent_telegram_action_required_digest_policy_v1.schema.json` | P2-402D Telegram action-required digest policy schema鎖定 direct send / Gateway queue write / route change / receiver change / workflow / transcript 全部 false |
| `docs/evaluations/ai_agent_telegram_action_required_digest_policy_2026-06-11.json` | P2-402D committed snapshot8 條 digest rule、3 個 channel 草案、5 類 trigger category、成功降噪、failure-only 與 redaction policy |
| `GET /api/v1/agents/agent-telegram-action-required-digest-policy` | 只讀 API只回傳 digest policy不送 Telegram、不寫 queue、不改 route / receiver、不觸發 workflow |
**採用順序:**
1. 先做 repo-only daily freshnessmanifest / lockfile / Dockerfile / K8s YAML / runbook / snapshot。✅ P2-402B 已建立 committed snapshot/API每日排程仍未授權。
2. 再評估 external primary source weekly watchRenovate、OSV-Scanner、Trivy、Syft、Grype、Kubernetes skew policy、Docker Scout。✅ P2-402C 已建立工具採用批准包工具安裝、CI 變更、外部查詢仍未授權。
3. 建立 Telegram action-required digest policy先定義 critical / action-required / failure-only 通知門檻,禁止成功洗版。下一步 P2-402D。
4. 再進 Gitea PR 草案 lanegrouping、automerge=false、tests、rollback、owner response。
3. 建立 Telegram action-required digest policy先定義 critical / action-required / failure-only 通知門檻,禁止成功洗版。 P2-402D 已建立 policy snapshot/APITelegram 實發與 queue write 仍未授權
4. 再進 Gitea PR 草案 lanegrouping、automerge=false、tests、rollback、owner response。下一步 P2-402E。
5. 最後才進人工批准後的 dry-run / smoke / canary / production rollout。
#### 3.2.2 核心缺口與災難場景
@@ -1323,6 +1326,7 @@ Repo / registry / release notes / K8s / host / observability / backup evidence
| 主動營運委派與版本生命週期契約 | `docs/evaluations/ai_agent_proactive_operations_contract_2026-06-11.json` + `GET /api/v1/agents/agent-proactive-operations-contract` | 先固定 12 類版本 domain、24 類可委派能力、MCP/RAG/Telegram 邊界;不啟用排程、不自動升版 | L4×D2 / L7×D4 / L6×D6 |
| Repo-only 版本新鮮度快照 | `docs/evaluations/ai_agent_version_freshness_snapshot_2026-06-11.json` + `GET /api/v1/agents/agent-version-freshness-snapshot` | P2-402B讓 Hermes 可每日產生 repo-only freshness evidence packet目前只讀 API不啟用 schedule、不查外部、不升級 | L4×D2 / L7×D4 / L6×D6 |
| 工具採用批准包 | `docs/evaluations/ai_agent_tool_adoption_approval_package_2026-06-11.json` + `GET /api/v1/agents/agent-tool-adoption-approval-package` | P2-402C讓 OpenClaw / Hermes / NemoTron 用官方來源評估 Renovate / OSV-Scanner / Trivy / Syft / Grype目前只讀 API不安裝工具、不改 CI、不查外部、不建 PR、不發 Telegram | L4×D2 / L7×D4 / L6×D6 |
| Telegram action-required digest policy | `docs/evaluations/ai_agent_telegram_action_required_digest_policy_2026-06-11.json` + `GET /api/v1/agents/agent-telegram-action-required-digest-policy` | P2-402D讓 OpenClaw / Hermes / NemoTron 先定義 critical / action-required / failure-only digest 與成功降噪;目前只讀 API不送 Telegram、不寫 queue、不改 route / receiver | L4×D2 / L7×D4 / L6×D6 |
**退出條件(量化)**
@@ -1706,6 +1710,12 @@ Phase 6 完成後
- 更新 `ai_agent_proactive_operations_contract_2026-06-11.json`:整體完成度 `55%`current task `P2-402C`next task `P2-402D`
- 本波仍不安裝工具、不改 CI、不查外部 registry、不下載 vulnerability DB、不升級套件、不寫 lockfile、不 build/pull image、不建立 Gitea PR、不 auto merge、不發 TelegramP2-402D 才建立 Telegram action-required digest policy。
### 2026-06-11 23:58 (台北) — §3.2 / §5 — 完成 P2-402D Telegram action-required digest policy — 回應統帥要求告警搭配 Telegram Bot 但先禁止直發與成功洗版
- 新增 `ai_agent_telegram_action_required_digest_policy_v1` schema / committed snapshot / loader / API / 測試,定義 8 條 digest rule、3 個 channel 草案、5 類 trigger category、message redaction、dedupe / rate-limit 與 fallback policy。
- 更新 `ai_agent_proactive_operations_contract_2026-06-11.json`:整體完成度 `68%`current task `P2-402D`next task `P2-402E`
- 本波仍不送 Telegram、不寫 Telegram Gateway queue、不改 Alertmanager route / receiver、不寫 AwoooP event、不觸發 workflow、不查外部掃描、不執行 runtime、不讀取或輸出 secret、不回傳工作視窗對話內容P2-402E 才設計 Gitea PR 草案 lane。
### 2026-04-15 (台北) — 全檔 — 建立 v2 骨架§0/§1 完成 — 統帥批准「單 MASTER + 4 道閘門」結構
- 從 v1plans/2026-04-15-MASTER-ai-autonomous-flywheel.md繼承核心發現