feat(governance): 新增 TG canary delivery rehearsal
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
"""
|
||||
AI Agent professional task expansion and Telegram runtime bridge snapshot.
|
||||
|
||||
Loads the latest committed P2-405D read-only contract. The contract expands
|
||||
professional AI Agent work and defines Telegram no-send previews, but it does
|
||||
not write Telegram Gateway queues, send Telegram messages, call the Bot API,
|
||||
read secrets, or execute production changes.
|
||||
Loads the latest committed P2-405E read-only contract. The contract expands
|
||||
professional AI Agent work and defines Telegram no-send previews plus canary
|
||||
delivery rehearsal evidence, but it does not write Telegram Gateway queues,
|
||||
send Telegram messages, call the Bot API, read secrets, or execute production
|
||||
changes.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -30,6 +31,7 @@ _EXPECTED_RECEIPT_EXPECTATION_COUNT = 6
|
||||
_EXPECTED_CANARY_PACKAGE_COUNT = 1
|
||||
_EXPECTED_CANARY_APPROVAL_PACKET_COUNT = 1
|
||||
_EXPECTED_CANARY_DELIVERY_GATE_COUNT = 1
|
||||
_EXPECTED_CANARY_DELIVERY_REHEARSAL_COUNT = 1
|
||||
_ZERO_ROLLUP_FIELDS = {
|
||||
"current_live_count",
|
||||
"gateway_queue_write_count",
|
||||
@@ -62,6 +64,10 @@ _ZERO_ROLLUP_FIELDS = {
|
||||
"canary_delivery_receipt_write_enabled_count",
|
||||
"canary_delivery_secret_read_enabled_count",
|
||||
"canary_delivery_paid_api_enabled_count",
|
||||
"canary_delivery_rehearsal_live_send_enabled_count",
|
||||
"canary_delivery_rehearsal_gateway_queue_write_enabled_count",
|
||||
"canary_delivery_rehearsal_bot_api_call_enabled_count",
|
||||
"canary_delivery_rehearsal_receipt_write_enabled_count",
|
||||
}
|
||||
_FORBIDDEN_PUBLIC_TERMS = {
|
||||
"work_window_transcript",
|
||||
@@ -109,11 +115,11 @@ def _require_schema(payload: dict[str, Any], label: str) -> None:
|
||||
status = payload.get("program_status") or {}
|
||||
expected = {
|
||||
"current_priority": "P2",
|
||||
"current_task_id": "P2-405D",
|
||||
"next_task_id": "P2-405E",
|
||||
"current_task_id": "P2-405E",
|
||||
"next_task_id": "P2-405F",
|
||||
"read_only_mode": True,
|
||||
"runtime_authority": _RUNTIME_AUTHORITY,
|
||||
"overall_completion_percent": 96,
|
||||
"overall_completion_percent": 98,
|
||||
}
|
||||
mismatches = _mismatches(status, expected)
|
||||
if mismatches:
|
||||
@@ -155,6 +161,7 @@ def _require_telegram_bridge(payload: dict[str, Any], label: str) -> None:
|
||||
_require_receipt_and_canary_package(bridge, label)
|
||||
_require_canary_send_approval_packet(bridge, label)
|
||||
_require_canary_delivery_gate(bridge, label)
|
||||
_require_canary_delivery_rehearsal(bridge, label)
|
||||
|
||||
|
||||
def _require_no_send_previews(bridge: dict[str, Any], label: str) -> None:
|
||||
@@ -427,6 +434,81 @@ def _require_canary_delivery_gate(bridge: dict[str, Any], label: str) -> None:
|
||||
raise ValueError(f"{label}: canary delivery decision log must remain empty")
|
||||
|
||||
|
||||
def _require_canary_delivery_rehearsal(bridge: dict[str, Any], label: str) -> None:
|
||||
rehearsal = bridge.get("canary_delivery_rehearsal") or {}
|
||||
expected = {
|
||||
"status": "ready_no_send_rehearsal",
|
||||
"rehearsal_ready": True,
|
||||
"selected_message_type": "daily_agent_workload_digest",
|
||||
"selected_preview_id": "p2_405b_preview_daily_agent_workload_digest_v1",
|
||||
"selected_receipt_expectation_id": "p2_405b_receipt_daily_agent_workload_digest_v1",
|
||||
"target_room_env": "SRE_GROUP_CHAT_ID",
|
||||
"target_room_value_visible": False,
|
||||
"preview_hash_algorithm": "sha256_preview_only",
|
||||
}
|
||||
mismatches = _mismatches(rehearsal, expected)
|
||||
if mismatches:
|
||||
raise ValueError(f"{label}: canary_delivery_rehearsal mismatch: {mismatches}")
|
||||
if not rehearsal:
|
||||
raise ValueError(
|
||||
f"{label}: expected {_EXPECTED_CANARY_DELIVERY_REHEARSAL_COUNT} "
|
||||
"canary delivery rehearsal"
|
||||
)
|
||||
|
||||
envelope = rehearsal.get("gateway_envelope_preview") or {}
|
||||
expected_envelope = {
|
||||
"message_type": "daily_agent_workload_digest",
|
||||
"target_room_env_ref": "SRE_GROUP_CHAT_ID",
|
||||
"dedup_key": rehearsal.get("dedup_key"),
|
||||
"preview_hash": rehearsal.get("sanitized_preview_hash"),
|
||||
"risk_tier": "low",
|
||||
"queue_write_enabled": False,
|
||||
"bot_api_call_enabled": False,
|
||||
"telegram_send_enabled": False,
|
||||
"delivery_receipt_write_enabled": False,
|
||||
}
|
||||
mismatches = _mismatches(envelope, expected_envelope)
|
||||
if mismatches:
|
||||
raise ValueError(f"{label}: canary rehearsal envelope mismatch: {mismatches}")
|
||||
|
||||
readback = rehearsal.get("readback_drill") or {}
|
||||
if readback.get("owner_agent") != "hermes":
|
||||
raise ValueError(f"{label}: canary rehearsal readback owner must be hermes")
|
||||
checks = readback.get("required_checks") or []
|
||||
if len(checks) != 8:
|
||||
raise ValueError(f"{label}: canary rehearsal must define 8 readback checks")
|
||||
if readback.get("completed_check_count") != len(checks):
|
||||
raise ValueError(f"{label}: canary rehearsal completed checks must match checks")
|
||||
if readback.get("failed_check_count") != 0:
|
||||
raise ValueError(f"{label}: canary rehearsal failed checks must remain zero")
|
||||
if readback.get("production_receipt_write_enabled") is not False:
|
||||
raise ValueError(f"{label}: canary rehearsal production receipt write must remain false")
|
||||
if readback.get("live_receipt_readback_enabled") is not False:
|
||||
raise ValueError(f"{label}: canary rehearsal live receipt readback must remain false")
|
||||
|
||||
if len(rehearsal.get("dry_run_steps") or []) != 6:
|
||||
raise ValueError(f"{label}: canary rehearsal must define 6 dry-run steps")
|
||||
if len(rehearsal.get("stop_conditions") or []) != 7:
|
||||
raise ValueError(f"{label}: canary rehearsal must define 7 stop conditions")
|
||||
if len(rehearsal.get("rollback_mute_controls") or []) != 5:
|
||||
raise ValueError(f"{label}: canary rehearsal must define 5 rollback/mute controls")
|
||||
|
||||
execution_flags = rehearsal.get("execution_flags") or {}
|
||||
expected_execution = {
|
||||
"live_delivery_enabled": False,
|
||||
"gateway_queue_write_enabled": False,
|
||||
"bot_api_call_enabled": False,
|
||||
"telegram_send_enabled": False,
|
||||
"delivery_receipt_write_enabled": False,
|
||||
"production_write_enabled": False,
|
||||
"secret_read_enabled": False,
|
||||
"paid_api_enabled": False,
|
||||
}
|
||||
mismatches = _mismatches(execution_flags, expected_execution)
|
||||
if mismatches:
|
||||
raise ValueError(f"{label}: canary rehearsal execution flags mismatch: {mismatches}")
|
||||
|
||||
|
||||
def _require_professional_tasks(payload: dict[str, Any], label: str) -> None:
|
||||
domains = payload.get("professional_task_domains") or []
|
||||
if len(domains) != _EXPECTED_DOMAIN_COUNT:
|
||||
@@ -562,6 +644,38 @@ def _require_rollups(payload: dict[str, Any], label: str) -> None:
|
||||
"canary_delivery_rollback_mute_control_count": len(
|
||||
(bridge.get("canary_delivery_gate") or {}).get("rollback_mute_controls") or []
|
||||
),
|
||||
"canary_delivery_rehearsal_count": 1
|
||||
if bridge.get("canary_delivery_rehearsal")
|
||||
else 0,
|
||||
"canary_delivery_rehearsal_step_count": len(
|
||||
(bridge.get("canary_delivery_rehearsal") or {}).get("dry_run_steps") or []
|
||||
),
|
||||
"canary_delivery_rehearsal_readback_check_count": len(
|
||||
(
|
||||
(bridge.get("canary_delivery_rehearsal") or {}).get("readback_drill")
|
||||
or {}
|
||||
).get("required_checks")
|
||||
or []
|
||||
),
|
||||
"canary_delivery_rehearsal_stop_condition_count": len(
|
||||
(bridge.get("canary_delivery_rehearsal") or {}).get("stop_conditions") or []
|
||||
),
|
||||
"canary_delivery_rehearsal_rollback_mute_control_count": len(
|
||||
(bridge.get("canary_delivery_rehearsal") or {}).get("rollback_mute_controls")
|
||||
or []
|
||||
),
|
||||
"canary_delivery_rehearsal_completed_check_count": (
|
||||
(
|
||||
(bridge.get("canary_delivery_rehearsal") or {}).get("readback_drill")
|
||||
or {}
|
||||
).get("completed_check_count")
|
||||
),
|
||||
"canary_delivery_rehearsal_failed_check_count": (
|
||||
(
|
||||
(bridge.get("canary_delivery_rehearsal") or {}).get("readback_drill")
|
||||
or {}
|
||||
).get("failed_check_count")
|
||||
),
|
||||
}
|
||||
mismatches = _mismatches(rollups, expected)
|
||||
if mismatches:
|
||||
|
||||
@@ -18,9 +18,9 @@ def test_load_latest_ai_agent_professional_task_expansion_snapshot() -> None:
|
||||
snapshot = load_latest_ai_agent_professional_task_expansion()
|
||||
|
||||
assert snapshot["schema_version"] == "ai_agent_professional_task_expansion_v1"
|
||||
assert snapshot["program_status"]["current_task_id"] == "P2-405D"
|
||||
assert snapshot["program_status"]["next_task_id"] == "P2-405E"
|
||||
assert snapshot["program_status"]["overall_completion_percent"] == 96
|
||||
assert snapshot["program_status"]["current_task_id"] == "P2-405E"
|
||||
assert snapshot["program_status"]["next_task_id"] == "P2-405F"
|
||||
assert snapshot["program_status"]["overall_completion_percent"] == 98
|
||||
assert snapshot["program_status"]["runtime_authority"] == (
|
||||
"professional_task_expansion_and_telegram_bridge_read_only_no_send"
|
||||
)
|
||||
@@ -106,6 +106,17 @@ def test_load_latest_ai_agent_professional_task_expansion_snapshot() -> None:
|
||||
assert rollups["canary_delivery_receipt_write_enabled_count"] == 0
|
||||
assert rollups["canary_delivery_secret_read_enabled_count"] == 0
|
||||
assert rollups["canary_delivery_paid_api_enabled_count"] == 0
|
||||
assert rollups["canary_delivery_rehearsal_count"] == 1
|
||||
assert rollups["canary_delivery_rehearsal_step_count"] == 6
|
||||
assert rollups["canary_delivery_rehearsal_readback_check_count"] == 8
|
||||
assert rollups["canary_delivery_rehearsal_stop_condition_count"] == 7
|
||||
assert rollups["canary_delivery_rehearsal_rollback_mute_control_count"] == 5
|
||||
assert rollups["canary_delivery_rehearsal_completed_check_count"] == 8
|
||||
assert rollups["canary_delivery_rehearsal_failed_check_count"] == 0
|
||||
assert rollups["canary_delivery_rehearsal_live_send_enabled_count"] == 0
|
||||
assert rollups["canary_delivery_rehearsal_gateway_queue_write_enabled_count"] == 0
|
||||
assert rollups["canary_delivery_rehearsal_bot_api_call_enabled_count"] == 0
|
||||
assert rollups["canary_delivery_rehearsal_receipt_write_enabled_count"] == 0
|
||||
|
||||
|
||||
def test_professional_tasks_cover_required_agents_and_reporting() -> None:
|
||||
@@ -245,6 +256,38 @@ def test_canary_delivery_gate_waits_for_explicit_delivery_fields() -> None:
|
||||
assert all(value is False for value in gate["execution_flags"].values())
|
||||
|
||||
|
||||
def test_canary_delivery_rehearsal_is_ready_without_live_send() -> None:
|
||||
snapshot = load_latest_ai_agent_professional_task_expansion()
|
||||
rehearsal = snapshot["telegram_runtime_bridge"]["canary_delivery_rehearsal"]
|
||||
|
||||
assert rehearsal["status"] == "ready_no_send_rehearsal"
|
||||
assert rehearsal["rehearsal_ready"] is True
|
||||
assert rehearsal["selected_message_type"] == "daily_agent_workload_digest"
|
||||
assert rehearsal["selected_preview_id"] == "p2_405b_preview_daily_agent_workload_digest_v1"
|
||||
assert rehearsal["target_room_env"] == "SRE_GROUP_CHAT_ID"
|
||||
assert rehearsal["target_room_value_visible"] is False
|
||||
assert rehearsal["sanitized_preview_hash"].startswith("sha256:")
|
||||
assert rehearsal["dedup_key"] == "awoooi:agent-report:daily:2026-06-18:v1"
|
||||
assert len(rehearsal["dry_run_steps"]) == 6
|
||||
assert len(rehearsal["stop_conditions"]) == 7
|
||||
assert len(rehearsal["rollback_mute_controls"]) == 5
|
||||
|
||||
envelope = rehearsal["gateway_envelope_preview"]
|
||||
assert envelope["queue_write_enabled"] is False
|
||||
assert envelope["bot_api_call_enabled"] is False
|
||||
assert envelope["telegram_send_enabled"] is False
|
||||
assert envelope["delivery_receipt_write_enabled"] is False
|
||||
|
||||
readback = rehearsal["readback_drill"]
|
||||
assert readback["owner_agent"] == "hermes"
|
||||
assert len(readback["required_checks"]) == 8
|
||||
assert readback["completed_check_count"] == 8
|
||||
assert readback["failed_check_count"] == 0
|
||||
assert readback["production_receipt_write_enabled"] is False
|
||||
assert readback["live_receipt_readback_enabled"] is False
|
||||
assert all(value is False for value in rehearsal["execution_flags"].values())
|
||||
|
||||
|
||||
def test_rejects_telegram_send_enabled(tmp_path: Path) -> None:
|
||||
snapshot = copy.deepcopy(load_latest_ai_agent_professional_task_expansion())
|
||||
snapshot["telegram_runtime_bridge"]["telegram_send_enabled"] = True
|
||||
@@ -359,6 +402,28 @@ def test_rejects_canary_delivery_gateway_queue_write_enabled(tmp_path: Path) ->
|
||||
load_latest_ai_agent_professional_task_expansion(tmp_path)
|
||||
|
||||
|
||||
def test_rejects_canary_delivery_rehearsal_send_enabled(tmp_path: Path) -> None:
|
||||
snapshot = copy.deepcopy(load_latest_ai_agent_professional_task_expansion())
|
||||
rehearsal = snapshot["telegram_runtime_bridge"]["canary_delivery_rehearsal"]
|
||||
rehearsal["execution_flags"]["telegram_send_enabled"] = True
|
||||
snapshot["rollups"]["canary_delivery_rehearsal_live_send_enabled_count"] = 1
|
||||
_write_snapshot(tmp_path, snapshot)
|
||||
|
||||
with pytest.raises(ValueError, match="canary rehearsal execution flags mismatch"):
|
||||
load_latest_ai_agent_professional_task_expansion(tmp_path)
|
||||
|
||||
|
||||
def test_rejects_canary_delivery_rehearsal_receipt_write_enabled(tmp_path: Path) -> None:
|
||||
snapshot = copy.deepcopy(load_latest_ai_agent_professional_task_expansion())
|
||||
rehearsal = snapshot["telegram_runtime_bridge"]["canary_delivery_rehearsal"]
|
||||
rehearsal["readback_drill"]["production_receipt_write_enabled"] = True
|
||||
snapshot["rollups"]["canary_delivery_rehearsal_receipt_write_enabled_count"] = 1
|
||||
_write_snapshot(tmp_path, snapshot)
|
||||
|
||||
with pytest.raises(ValueError, match="production receipt write must remain false"):
|
||||
load_latest_ai_agent_professional_task_expansion(tmp_path)
|
||||
|
||||
|
||||
def test_rejects_high_risk_without_approval(tmp_path: Path) -> None:
|
||||
snapshot = copy.deepcopy(load_latest_ai_agent_professional_task_expansion())
|
||||
high_task = next(task for task in snapshot["professional_tasks"] if task["risk_tier"] == "high")
|
||||
|
||||
@@ -17,9 +17,9 @@ def test_ai_agent_professional_task_expansion_endpoint() -> None:
|
||||
assert response.status_code == 200
|
||||
payload = response.json()
|
||||
assert payload["schema_version"] == "ai_agent_professional_task_expansion_v1"
|
||||
assert payload["program_status"]["current_task_id"] == "P2-405D"
|
||||
assert payload["program_status"]["next_task_id"] == "P2-405E"
|
||||
assert payload["program_status"]["overall_completion_percent"] == 96
|
||||
assert payload["program_status"]["current_task_id"] == "P2-405E"
|
||||
assert payload["program_status"]["next_task_id"] == "P2-405F"
|
||||
assert payload["program_status"]["overall_completion_percent"] == 98
|
||||
assert payload["program_status"]["runtime_authority"] == (
|
||||
"professional_task_expansion_and_telegram_bridge_read_only_no_send"
|
||||
)
|
||||
@@ -54,6 +54,13 @@ def test_ai_agent_professional_task_expansion_endpoint() -> None:
|
||||
assert payload["rollups"]["canary_delivery_attempt_allowed_count"] == 0
|
||||
assert payload["rollups"]["canary_delivery_gateway_queue_write_enabled_count"] == 0
|
||||
assert payload["rollups"]["canary_delivery_bot_api_call_enabled_count"] == 0
|
||||
assert payload["rollups"]["canary_delivery_rehearsal_count"] == 1
|
||||
assert payload["rollups"]["canary_delivery_rehearsal_step_count"] == 6
|
||||
assert payload["rollups"]["canary_delivery_rehearsal_readback_check_count"] == 8
|
||||
assert payload["rollups"]["canary_delivery_rehearsal_failed_check_count"] == 0
|
||||
assert payload["rollups"]["canary_delivery_rehearsal_gateway_queue_write_enabled_count"] == 0
|
||||
assert payload["rollups"]["canary_delivery_rehearsal_bot_api_call_enabled_count"] == 0
|
||||
assert payload["rollups"]["canary_delivery_rehearsal_receipt_write_enabled_count"] == 0
|
||||
assert payload["telegram_runtime_bridge"]["canary_approval_package"]["live_send_enabled"] is False
|
||||
assert payload["telegram_runtime_bridge"]["canary_send_approval_packet"]["approval_granted"] is False
|
||||
assert (
|
||||
@@ -63,5 +70,16 @@ def test_ai_agent_professional_task_expansion_endpoint() -> None:
|
||||
assert payload["telegram_runtime_bridge"]["canary_delivery_gate"]["delivery_approved"] is False
|
||||
assert payload["telegram_runtime_bridge"]["canary_delivery_gate"]["delivery_attempt_allowed"] is False
|
||||
assert payload["telegram_runtime_bridge"]["canary_delivery_gate"]["target_room_value_visible"] is False
|
||||
assert payload["telegram_runtime_bridge"]["canary_delivery_rehearsal"]["rehearsal_ready"] is True
|
||||
assert (
|
||||
payload["telegram_runtime_bridge"]["canary_delivery_rehearsal"]["selected_message_type"]
|
||||
== "daily_agent_workload_digest"
|
||||
)
|
||||
assert (
|
||||
payload["telegram_runtime_bridge"]["canary_delivery_rehearsal"]["gateway_envelope_preview"][
|
||||
"telegram_send_enabled"
|
||||
]
|
||||
is False
|
||||
)
|
||||
assert len(payload["telegram_runtime_bridge"]["no_send_message_previews"]) == 6
|
||||
assert len(payload["telegram_runtime_bridge"]["receipt_expectations"]) == 6
|
||||
|
||||
@@ -4351,6 +4351,41 @@
|
||||
"next_gate": "下一關"
|
||||
}
|
||||
},
|
||||
"reportDeliveryHero": {
|
||||
"title": "Telegram / TG Bot 日週月報派送演練",
|
||||
"subtitle": "{current} 已整理日報、週報、月報實發批准包;下一關 {next} 才能進入 fixture readback,不直接實發。",
|
||||
"source": "{generated} · {current}",
|
||||
"route": "正式目標:{room}",
|
||||
"statusLine": "這裡顯示 AI Agent 報告要如何送到 Telegram:先走 AwoooI SRE 戰情室、先做 no-send 演練、先確認 dedup / redaction / 回執欄位;目前 scheduler、Gateway queue、Bot API、Telegram 實發、讀報回執與 AI 分析全部仍為 0。",
|
||||
"routeGateTitle": "Telegram 路由與 TG Bot 閘門",
|
||||
"receiptTitle": "讀報回執與 AI 分析演練",
|
||||
"metrics": {
|
||||
"packets": "批准包",
|
||||
"routeGates": "路由閘門",
|
||||
"receipts": "回執演練",
|
||||
"approvalRequired": "需審核",
|
||||
"telegramSends": "Telegram 實發",
|
||||
"liveWrites": "live 寫入"
|
||||
},
|
||||
"flags": {
|
||||
"scheduler": "scheduler: {value}",
|
||||
"gateway": "Gateway queue: {value}",
|
||||
"telegram": "Telegram send: {value}",
|
||||
"botApi": "Bot API: {value}",
|
||||
"receipt": "receipt write: {value}",
|
||||
"analysis": "AI analysis: {value}",
|
||||
"ownerReview": "人工審核: {value}"
|
||||
},
|
||||
"labels": {
|
||||
"noSendMode": "no-send: {value}",
|
||||
"requiredEvidence": "證據 {count}",
|
||||
"gateway": "queue write: {value}",
|
||||
"telegram": "send: {value}",
|
||||
"requiredFields": "欄位 {count}",
|
||||
"liveSendCount": "live send {count}",
|
||||
"receiptWrite": "receipt write: {value}"
|
||||
}
|
||||
},
|
||||
"reportRuntimeReadiness": {
|
||||
"title": "P2-403L 報表派送與自動處理啟動閘門",
|
||||
"source": "{generated} · {current} → {next}",
|
||||
@@ -6468,7 +6503,7 @@
|
||||
}
|
||||
},
|
||||
"professionalTaskExpansion": {
|
||||
"title": "P2-405D AI Agent TG Canary Delivery Gate",
|
||||
"title": "P2-405E AI Agent TG Canary 乾跑派送演練",
|
||||
"source": "產生 {generated};目前 {current};下一步 {next}",
|
||||
"runtime": "runtime={value}",
|
||||
"telegramTitle": "Telegram Runtime Bridge",
|
||||
@@ -6494,7 +6529,10 @@
|
||||
"deliveryGate": "delivery gate",
|
||||
"deliveryFields": "交付欄位",
|
||||
"deliveryPreflight": "交付 preflight",
|
||||
"deliveryHoldReasons": "hold reason"
|
||||
"deliveryHoldReasons": "hold reason",
|
||||
"deliveryRehearsal": "派送演練",
|
||||
"rehearsalChecks": "演練檢查",
|
||||
"rehearsalStops": "停止條件"
|
||||
},
|
||||
"previewTitle": "Telegram no-send 訊息預覽",
|
||||
"canaryTitle": "Canary 批准包",
|
||||
@@ -6532,7 +6570,18 @@
|
||||
"deliveryApproved": "delivery approved={value}",
|
||||
"attemptAllowed": "attempt allowed={value}",
|
||||
"targetVerified": "target verified={value}",
|
||||
"holdReason": "hold={value}"
|
||||
"holdReason": "hold={value}",
|
||||
"rehearsalReady": "演練就緒={value}",
|
||||
"targetRoom": "目標聊天室 env={value}",
|
||||
"targetEnv": "目標 env={value}",
|
||||
"previewHash": "preview hash={value}",
|
||||
"readbackOwner": "readback owner={value}",
|
||||
"completedChecks": "檢查 {done}/{total}",
|
||||
"failedChecks": "失敗檢查={count}",
|
||||
"receiptWrite": "receipt write={value}",
|
||||
"liveReadback": "live readback={value}",
|
||||
"stopCondition": "停止={value}",
|
||||
"nextGate": "下一關={value}"
|
||||
},
|
||||
"riskTiers": {
|
||||
"low": "低風險",
|
||||
@@ -6540,7 +6589,10 @@
|
||||
"high": "高風險",
|
||||
"critical": "Critical"
|
||||
},
|
||||
"canaryDeliveryGateTitle": "P2-405D Canary Delivery Gate"
|
||||
"canaryDeliveryGateTitle": "P2-405D Canary 派送閘門",
|
||||
"canaryDeliveryRehearsalTitle": "P2-405E Canary 乾跑派送演練",
|
||||
"rehearsalEnvelopeTitle": "Gateway envelope 演練",
|
||||
"rehearsalReadbackTitle": "回執讀回演練"
|
||||
},
|
||||
"resultCaptureReleaseVerifierOwnerReviewPacket": {
|
||||
"title": "P2-137 釋出驗證器負責人審查包",
|
||||
|
||||
@@ -4351,6 +4351,41 @@
|
||||
"next_gate": "下一關"
|
||||
}
|
||||
},
|
||||
"reportDeliveryHero": {
|
||||
"title": "Telegram / TG Bot 日週月報派送演練",
|
||||
"subtitle": "{current} 已整理日報、週報、月報實發批准包;下一關 {next} 才能進入 fixture readback,不直接實發。",
|
||||
"source": "{generated} · {current}",
|
||||
"route": "正式目標:{room}",
|
||||
"statusLine": "這裡顯示 AI Agent 報告要如何送到 Telegram:先走 AwoooI SRE 戰情室、先做 no-send 演練、先確認 dedup / redaction / 回執欄位;目前 scheduler、Gateway queue、Bot API、Telegram 實發、讀報回執與 AI 分析全部仍為 0。",
|
||||
"routeGateTitle": "Telegram 路由與 TG Bot 閘門",
|
||||
"receiptTitle": "讀報回執與 AI 分析演練",
|
||||
"metrics": {
|
||||
"packets": "批准包",
|
||||
"routeGates": "路由閘門",
|
||||
"receipts": "回執演練",
|
||||
"approvalRequired": "需審核",
|
||||
"telegramSends": "Telegram 實發",
|
||||
"liveWrites": "live 寫入"
|
||||
},
|
||||
"flags": {
|
||||
"scheduler": "scheduler: {value}",
|
||||
"gateway": "Gateway queue: {value}",
|
||||
"telegram": "Telegram send: {value}",
|
||||
"botApi": "Bot API: {value}",
|
||||
"receipt": "receipt write: {value}",
|
||||
"analysis": "AI analysis: {value}",
|
||||
"ownerReview": "人工審核: {value}"
|
||||
},
|
||||
"labels": {
|
||||
"noSendMode": "no-send: {value}",
|
||||
"requiredEvidence": "證據 {count}",
|
||||
"gateway": "queue write: {value}",
|
||||
"telegram": "send: {value}",
|
||||
"requiredFields": "欄位 {count}",
|
||||
"liveSendCount": "live send {count}",
|
||||
"receiptWrite": "receipt write: {value}"
|
||||
}
|
||||
},
|
||||
"reportRuntimeReadiness": {
|
||||
"title": "P2-403L 報表派送與自動處理啟動閘門",
|
||||
"source": "{generated} · {current} → {next}",
|
||||
@@ -6468,7 +6503,7 @@
|
||||
}
|
||||
},
|
||||
"professionalTaskExpansion": {
|
||||
"title": "P2-405D AI Agent TG Canary Delivery Gate",
|
||||
"title": "P2-405E AI Agent TG Canary 乾跑派送演練",
|
||||
"source": "產生 {generated};目前 {current};下一步 {next}",
|
||||
"runtime": "runtime={value}",
|
||||
"telegramTitle": "Telegram Runtime Bridge",
|
||||
@@ -6494,7 +6529,10 @@
|
||||
"deliveryGate": "delivery gate",
|
||||
"deliveryFields": "交付欄位",
|
||||
"deliveryPreflight": "交付 preflight",
|
||||
"deliveryHoldReasons": "hold reason"
|
||||
"deliveryHoldReasons": "hold reason",
|
||||
"deliveryRehearsal": "派送演練",
|
||||
"rehearsalChecks": "演練檢查",
|
||||
"rehearsalStops": "停止條件"
|
||||
},
|
||||
"previewTitle": "Telegram no-send 訊息預覽",
|
||||
"canaryTitle": "Canary 批准包",
|
||||
@@ -6532,7 +6570,18 @@
|
||||
"deliveryApproved": "delivery approved={value}",
|
||||
"attemptAllowed": "attempt allowed={value}",
|
||||
"targetVerified": "target verified={value}",
|
||||
"holdReason": "hold={value}"
|
||||
"holdReason": "hold={value}",
|
||||
"rehearsalReady": "演練就緒={value}",
|
||||
"targetRoom": "目標聊天室 env={value}",
|
||||
"targetEnv": "目標 env={value}",
|
||||
"previewHash": "preview hash={value}",
|
||||
"readbackOwner": "readback owner={value}",
|
||||
"completedChecks": "檢查 {done}/{total}",
|
||||
"failedChecks": "失敗檢查={count}",
|
||||
"receiptWrite": "receipt write={value}",
|
||||
"liveReadback": "live readback={value}",
|
||||
"stopCondition": "停止={value}",
|
||||
"nextGate": "下一關={value}"
|
||||
},
|
||||
"riskTiers": {
|
||||
"low": "低風險",
|
||||
@@ -6540,7 +6589,10 @@
|
||||
"high": "高風險",
|
||||
"critical": "Critical"
|
||||
},
|
||||
"canaryDeliveryGateTitle": "P2-405D Canary Delivery Gate"
|
||||
"canaryDeliveryGateTitle": "P2-405D Canary 派送閘門",
|
||||
"canaryDeliveryRehearsalTitle": "P2-405E Canary 乾跑派送演練",
|
||||
"rehearsalEnvelopeTitle": "Gateway envelope 演練",
|
||||
"rehearsalReadbackTitle": "回執讀回演練"
|
||||
},
|
||||
"resultCaptureReleaseVerifierOwnerReviewPacket": {
|
||||
"title": "P2-137 釋出驗證器負責人審查包",
|
||||
|
||||
@@ -3721,9 +3721,14 @@ export function AutomationInventoryTab() {
|
||||
+ professionalTaskExpansion.rollups.canary_delivery_bot_api_call_enabled_count
|
||||
+ professionalTaskExpansion.rollups.canary_delivery_secret_read_enabled_count
|
||||
+ professionalTaskExpansion.rollups.canary_delivery_paid_api_enabled_count
|
||||
+ professionalTaskExpansion.rollups.canary_delivery_rehearsal_live_send_enabled_count
|
||||
+ professionalTaskExpansion.rollups.canary_delivery_rehearsal_gateway_queue_write_enabled_count
|
||||
+ professionalTaskExpansion.rollups.canary_delivery_rehearsal_bot_api_call_enabled_count
|
||||
+ professionalTaskExpansion.rollups.canary_delivery_rehearsal_receipt_write_enabled_count
|
||||
)
|
||||
const professionalTaskCanarySendPacket = professionalTaskExpansion.telegram_runtime_bridge.canary_send_approval_packet
|
||||
const professionalTaskCanaryDeliveryGate = professionalTaskExpansion.telegram_runtime_bridge.canary_delivery_gate
|
||||
const professionalTaskCanaryDeliveryRehearsal = professionalTaskExpansion.telegram_runtime_bridge.canary_delivery_rehearsal
|
||||
const professionalTaskCanaryApprovalGaps = (
|
||||
professionalTaskExpansion.rollups.canary_approval_granted_count
|
||||
+ professionalTaskExpansion.rollups.canary_selected_message_type_count
|
||||
@@ -4178,6 +4183,129 @@ export function AutomationInventoryTab() {
|
||||
</div>
|
||||
</GlassCard>
|
||||
|
||||
<GlassCard variant="subtle" padding="md">
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 14, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'flex-start', gap: 10, minWidth: 0 }}>
|
||||
<div style={{
|
||||
width: 38,
|
||||
height: 38,
|
||||
borderRadius: 8,
|
||||
border: '0.5px solid #19875440',
|
||||
background: 'rgba(25,135,84,0.08)',
|
||||
color: '#198754',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexShrink: 0,
|
||||
}}>
|
||||
<BellRing size={18} />
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 5, minWidth: 0 }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 18, fontWeight: 700, color: '#141413', lineHeight: 1.15, overflowWrap: 'anywhere' }}>
|
||||
{t('reportDeliveryHero.title')}
|
||||
</span>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 11, color: '#5c5a55', lineHeight: 1.55, overflowWrap: 'anywhere' }}>
|
||||
{t('reportDeliveryHero.subtitle', {
|
||||
current: reportLiveDeliveryApprovalPackage.program_status.current_task_id,
|
||||
next: reportLiveDeliveryApprovalPackage.program_status.next_task_id,
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'flex-end', gap: 6, minWidth: 0 }}>
|
||||
<Chip value={t('reportDeliveryHero.route', { room: 'AwoooI SRE 戰情室' })} />
|
||||
<Chip value={t('reportDeliveryHero.source', {
|
||||
generated: formatDateTime(reportLiveDeliveryApprovalPackage.generated_at),
|
||||
current: reportLiveDeliveryApprovalPackage.program_status.current_task_id,
|
||||
})} muted />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 11, border: '0.5px solid #b7d6c4', borderRadius: 7, background: '#f8fffb', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 11, color: '#375446', lineHeight: 1.55, overflowWrap: 'anywhere' }}>
|
||||
{t('reportDeliveryHero.statusLine')}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={t('reportDeliveryHero.flags.scheduler', { value: String(reportLiveDeliveryApprovalPackage.delivery_approval_truth.scheduler_enabled) })} muted />
|
||||
<Chip value={t('reportDeliveryHero.flags.gateway', { value: String(reportLiveDeliveryApprovalPackage.delivery_approval_truth.gateway_queue_write_enabled) })} muted />
|
||||
<Chip value={t('reportDeliveryHero.flags.telegram', { value: String(reportLiveDeliveryApprovalPackage.delivery_approval_truth.telegram_send_enabled) })} muted />
|
||||
<Chip value={t('reportDeliveryHero.flags.botApi', { value: String(reportLiveDeliveryApprovalPackage.delivery_approval_truth.bot_api_call_enabled) })} muted />
|
||||
<Chip value={t('reportDeliveryHero.flags.receipt', { value: String(reportLiveDeliveryApprovalPackage.delivery_approval_truth.report_receipt_write_enabled) })} muted />
|
||||
<Chip value={t('reportDeliveryHero.flags.analysis', { value: String(reportLiveDeliveryApprovalPackage.delivery_approval_truth.ai_analysis_run_enabled) })} muted />
|
||||
<Chip value={t('reportDeliveryHero.flags.ownerReview', { value: String(reportLiveDeliveryApprovalPackage.delivery_approval_truth.owner_review_required_before_delivery) })} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(148px, 1fr))', gap: 10 }} className="automation-inventory-live-read-kpi-grid">
|
||||
<MetricCard label={t('reportDeliveryHero.metrics.packets')} value={reportDeliveryPackets} tone="warn" icon={<FileText size={16} />} />
|
||||
<MetricCard label={t('reportDeliveryHero.metrics.routeGates')} value={reportDeliveryRouteGates} tone="warn" icon={<Route size={16} />} />
|
||||
<MetricCard label={t('reportDeliveryHero.metrics.receipts')} value={reportDeliveryReceipts} tone="warn" icon={<Archive size={16} />} />
|
||||
<MetricCard label={t('reportDeliveryHero.metrics.approvalRequired')} value={reportDeliveryApprovalRequired} tone="warn" icon={<Lock size={16} />} />
|
||||
<MetricCard label={t('reportDeliveryHero.metrics.telegramSends')} value={reportDeliveryTelegramSends} tone={reportDeliveryTelegramSends === 0 ? 'ok' : 'danger'} icon={<BellRing size={16} />} />
|
||||
<MetricCard label={t('reportDeliveryHero.metrics.liveWrites')} value={reportDeliveryLiveWrites} tone={reportDeliveryLiveWrites === 0 ? 'ok' : 'danger'} icon={<Database size={16} />} />
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(230px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{visibleReportDeliveryPackets.map(packet => (
|
||||
<div key={`delivery-hero-${packet.packet_id}`} style={{ padding: 12, border: '0.5px solid #b7d6c4', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 9, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, minWidth: 0 }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 14, fontWeight: 700, color: '#141413', overflowWrap: 'anywhere' }}>
|
||||
{packet.display_name}
|
||||
</span>
|
||||
<Chip value={t(`reportLiveDeliveryApprovalPackage.cadences.${packet.cadence}` as never)} muted />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#5c5a55', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{packet.operator_guidance}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={redisDryRunValueLabel('agents', packet.owner_agent)} muted />
|
||||
<Chip value={t(`reportLiveDeliveryApprovalPackage.packetStatuses.${packet.status}` as never)} muted={packet.status === 'ready_for_owner_review'} />
|
||||
<Chip value={t(`reportLiveDeliveryApprovalPackage.riskTiers.${packet.risk_tier}` as never)} muted={packet.risk_tier !== 'critical'} />
|
||||
<Chip value={t('reportDeliveryHero.labels.noSendMode', { value: String(packet.no_send_mode) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)', gap: 10 }} className="automation-inventory-live-read-grid">
|
||||
<div style={{ padding: 12, border: '0.5px solid #b7d6c4', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 9, minWidth: 0 }}>
|
||||
<SmallLabel>{t('reportDeliveryHero.routeGateTitle')}</SmallLabel>
|
||||
{visibleReportRouteGates.slice(0, 3).map(gate => (
|
||||
<div key={`delivery-hero-gate-${gate.gate_id}`} style={{ display: 'flex', flexDirection: 'column', gap: 5, minWidth: 0 }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 12, fontWeight: 700, color: '#141413', overflowWrap: 'anywhere' }}>
|
||||
{gate.display_name}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={t(`reportLiveDeliveryApprovalPackage.gateStatuses.${gate.status}` as never)} muted={gate.status === 'ready_for_owner_review'} />
|
||||
<Chip value={t('reportDeliveryHero.labels.requiredEvidence', { count: gate.required_evidence.length })} muted />
|
||||
<Chip value={t('reportDeliveryHero.labels.gateway', { value: String(gate.gateway_queue_write_enabled) })} muted />
|
||||
<Chip value={t('reportDeliveryHero.labels.telegram', { value: String(gate.telegram_send_enabled) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 12, border: '0.5px solid #b7d6c4', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 9, minWidth: 0 }}>
|
||||
<SmallLabel>{t('reportDeliveryHero.receiptTitle')}</SmallLabel>
|
||||
{visibleReportDeliveryReceipts.map(receipt => (
|
||||
<div key={`delivery-hero-receipt-${receipt.receipt_id}`} style={{ display: 'flex', flexDirection: 'column', gap: 5, minWidth: 0 }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 12, fontWeight: 700, color: '#141413', overflowWrap: 'anywhere' }}>
|
||||
{receipt.display_name}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={t(`reportLiveDeliveryApprovalPackage.receiptStatuses.${receipt.status}` as never)} muted={receipt.status === 'ready_for_owner_review'} />
|
||||
<Chip value={t('reportDeliveryHero.labels.requiredFields', { count: receipt.required_fields.length })} muted />
|
||||
<Chip value={t('reportDeliveryHero.labels.liveSendCount', { count: receipt.live_send_count })} muted />
|
||||
<Chip value={t('reportDeliveryHero.labels.receiptWrite', { value: String(receipt.receipt_write_allowed) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</GlassCard>
|
||||
|
||||
<GlassCard variant="subtle" padding="md">
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 13, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
|
||||
@@ -4342,6 +4470,9 @@ export function AutomationInventoryTab() {
|
||||
<MetricCard label={t('professionalTaskExpansion.metrics.deliveryFields')} value={professionalTaskExpansion.rollups.canary_delivery_required_field_count} tone="warn" icon={<ClipboardCheck size={16} />} />
|
||||
<MetricCard label={t('professionalTaskExpansion.metrics.deliveryPreflight')} value={professionalTaskExpansion.rollups.canary_delivery_preflight_check_count} tone="warn" icon={<ShieldCheck size={16} />} />
|
||||
<MetricCard label={t('professionalTaskExpansion.metrics.deliveryHoldReasons')} value={professionalTaskExpansion.rollups.canary_delivery_hold_reason_count} tone="danger" icon={<Lock size={16} />} />
|
||||
<MetricCard label={t('professionalTaskExpansion.metrics.deliveryRehearsal')} value={professionalTaskExpansion.rollups.canary_delivery_rehearsal_count} tone="ok" icon={<Route size={16} />} />
|
||||
<MetricCard label={t('professionalTaskExpansion.metrics.rehearsalChecks')} value={`${professionalTaskExpansion.rollups.canary_delivery_rehearsal_completed_check_count}/${professionalTaskExpansion.rollups.canary_delivery_rehearsal_readback_check_count}`} tone="ok" icon={<ClipboardCheck size={16} />} />
|
||||
<MetricCard label={t('professionalTaskExpansion.metrics.rehearsalStops')} value={professionalTaskExpansion.rollups.canary_delivery_rehearsal_stop_condition_count} tone="danger" icon={<ShieldAlert size={16} />} />
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))', gap: 10 }}>
|
||||
@@ -4512,6 +4643,56 @@ export function AutomationInventoryTab() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 10, border: '0.5px solid #a7d4bd', borderRadius: 7, background: '#f8fffb', minWidth: 0 }}>
|
||||
<SmallLabel>{t('professionalTaskExpansion.canaryDeliveryRehearsalTitle')}</SmallLabel>
|
||||
<p style={{ margin: '6px 0 8px', fontFamily: "'DM Mono', monospace", fontSize: 10, lineHeight: 1.5, color: '#375446', overflowWrap: 'anywhere' }}>
|
||||
{professionalTaskCanaryDeliveryRehearsal.rehearsal_id} · {professionalTaskCanaryDeliveryRehearsal.status}
|
||||
</p>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 8 }}>
|
||||
<Chip value={t('professionalTaskExpansion.labels.rehearsalReady', { value: String(professionalTaskCanaryDeliveryRehearsal.rehearsal_ready) })} />
|
||||
<Chip value={t('professionalTaskExpansion.labels.selectedMessage', { value: professionalTaskCanaryDeliveryRehearsal.selected_message_type })} muted />
|
||||
<Chip value={t('professionalTaskExpansion.labels.targetRoom', { value: professionalTaskCanaryDeliveryRehearsal.target_room_env })} muted />
|
||||
<Chip value={t('professionalTaskExpansion.labels.valueVisible', { value: String(professionalTaskCanaryDeliveryRehearsal.target_room_value_visible) })} muted />
|
||||
<Chip value={t('professionalTaskExpansion.labels.dedup', { value: professionalTaskCanaryDeliveryRehearsal.dedup_key })} muted />
|
||||
<Chip value={t('professionalTaskExpansion.labels.previewHash', { value: professionalTaskCanaryDeliveryRehearsal.sanitized_preview_hash })} muted />
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)', gap: 8 }} className="automation-inventory-live-read-grid">
|
||||
<div style={{ padding: 8, borderRadius: 6, background: '#fff', border: '0.5px solid #c7e7d4', display: 'flex', flexDirection: 'column', gap: 6, minWidth: 0 }}>
|
||||
<SmallLabel>{t('professionalTaskExpansion.rehearsalEnvelopeTitle')}</SmallLabel>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={t('professionalTaskExpansion.labels.queueWrites', { value: String(professionalTaskCanaryDeliveryRehearsal.gateway_envelope_preview.queue_write_enabled) })} muted />
|
||||
<Chip value={t('professionalTaskExpansion.labels.botCalls', { value: String(professionalTaskCanaryDeliveryRehearsal.gateway_envelope_preview.bot_api_call_enabled) })} muted />
|
||||
<Chip value={t('professionalTaskExpansion.labels.send', { value: String(professionalTaskCanaryDeliveryRehearsal.gateway_envelope_preview.telegram_send_enabled) })} muted />
|
||||
<Chip value={t('professionalTaskExpansion.labels.receiptWrite', { value: String(professionalTaskCanaryDeliveryRehearsal.gateway_envelope_preview.delivery_receipt_write_enabled) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ padding: 8, borderRadius: 6, background: '#fff', border: '0.5px solid #c7e7d4', display: 'flex', flexDirection: 'column', gap: 6, minWidth: 0 }}>
|
||||
<SmallLabel>{t('professionalTaskExpansion.rehearsalReadbackTitle')}</SmallLabel>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={t('professionalTaskExpansion.labels.owner', { value: professionalTaskCanaryDeliveryRehearsal.readback_drill.owner_agent })} muted />
|
||||
<Chip value={t('professionalTaskExpansion.labels.completedChecks', { done: professionalTaskCanaryDeliveryRehearsal.readback_drill.completed_check_count, total: professionalTaskCanaryDeliveryRehearsal.readback_drill.required_checks.length })} />
|
||||
<Chip value={t('professionalTaskExpansion.labels.failedChecks', { count: professionalTaskCanaryDeliveryRehearsal.readback_drill.failed_check_count })} muted />
|
||||
<Chip value={t('professionalTaskExpansion.labels.receiptWrite', { value: String(professionalTaskCanaryDeliveryRehearsal.readback_drill.production_receipt_write_enabled) })} muted />
|
||||
<Chip value={t('professionalTaskExpansion.labels.liveReadback', { value: String(professionalTaskCanaryDeliveryRehearsal.readback_drill.live_receipt_readback_enabled) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 8, marginTop: 8 }}>
|
||||
{professionalTaskCanaryDeliveryRehearsal.dry_run_steps.map(step => (
|
||||
<div key={step} style={{ padding: 8, borderRadius: 6, background: '#eef8f4', fontFamily: "'DM Mono', monospace", fontSize: 10, lineHeight: 1.45, color: '#176d8a', overflowWrap: 'anywhere' }}>
|
||||
{step}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 8, marginTop: 8 }}>
|
||||
{professionalTaskCanaryDeliveryRehearsal.stop_conditions.slice(0, 7).map(condition => (
|
||||
<div key={condition} style={{ padding: 8, borderRadius: 6, background: '#fff7ed', fontFamily: "'DM Mono', monospace", fontSize: 10, lineHeight: 1.45, color: '#7a4a20', overflowWrap: 'anywhere' }}>
|
||||
{t('professionalTaskExpansion.labels.stopCondition', { value: condition })}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SmallLabel>{t('professionalTaskExpansion.tasksTitle')}</SmallLabel>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{visibleProfessionalTasks.map(task => {
|
||||
|
||||
@@ -1429,8 +1429,8 @@ export interface AiAgentProfessionalTaskExpansionSnapshot {
|
||||
program_status: {
|
||||
overall_completion_percent: number
|
||||
current_priority: 'P0' | 'P1' | 'P2' | 'P3'
|
||||
current_task_id: 'P2-405D'
|
||||
next_task_id: 'P2-405E'
|
||||
current_task_id: 'P2-405E'
|
||||
next_task_id: 'P2-405F'
|
||||
read_only_mode: true
|
||||
runtime_authority: 'professional_task_expansion_and_telegram_bridge_read_only_no_send'
|
||||
status_note: string
|
||||
@@ -1645,6 +1645,54 @@ export interface AiAgentProfessionalTaskExpansionSnapshot {
|
||||
}
|
||||
delivery_decision_log: unknown[]
|
||||
}
|
||||
canary_delivery_rehearsal: {
|
||||
rehearsal_id: string
|
||||
status: string
|
||||
rehearsal_ready: boolean
|
||||
selected_message_type: string
|
||||
selected_preview_id: string
|
||||
selected_receipt_expectation_id: string
|
||||
target_room_alias: string
|
||||
target_room_env: string
|
||||
target_room_value_visible: boolean
|
||||
dry_run_window: string
|
||||
preview_hash_algorithm: string
|
||||
sanitized_preview_hash: string
|
||||
dedup_key: string
|
||||
gateway_envelope_preview: {
|
||||
message_type: string
|
||||
target_room_env_ref: string
|
||||
dedup_key: string
|
||||
preview_hash: string
|
||||
risk_tier: string
|
||||
queue_write_enabled: boolean
|
||||
bot_api_call_enabled: boolean
|
||||
telegram_send_enabled: boolean
|
||||
delivery_receipt_write_enabled: boolean
|
||||
}
|
||||
dry_run_steps: string[]
|
||||
readback_drill: {
|
||||
owner_agent: string
|
||||
required_checks: string[]
|
||||
completed_check_count: number
|
||||
failed_check_count: number
|
||||
production_receipt_write_enabled: boolean
|
||||
live_receipt_readback_enabled: boolean
|
||||
}
|
||||
stop_conditions: string[]
|
||||
rollback_mute_controls: string[]
|
||||
execution_flags: {
|
||||
live_delivery_enabled: boolean
|
||||
gateway_queue_write_enabled: boolean
|
||||
bot_api_call_enabled: boolean
|
||||
telegram_send_enabled: boolean
|
||||
delivery_receipt_write_enabled: boolean
|
||||
production_write_enabled: boolean
|
||||
secret_read_enabled: boolean
|
||||
paid_api_enabled: boolean
|
||||
}
|
||||
next_gate: string
|
||||
}
|
||||
no_send_preview_completion_percent: number
|
||||
canary_approval_package_completion_percent: number
|
||||
canary_send_approval_packet_ready: boolean
|
||||
@@ -1655,6 +1703,8 @@ export interface AiAgentProfessionalTaskExpansionSnapshot {
|
||||
canary_delivery_approved: boolean
|
||||
canary_delivery_attempt_allowed: boolean
|
||||
canary_delivery_gate_completion_percent: number
|
||||
canary_delivery_rehearsal_ready: boolean
|
||||
canary_delivery_rehearsal_completion_percent: number
|
||||
}
|
||||
professional_task_domains: Array<{
|
||||
domain_id: string
|
||||
@@ -1751,6 +1801,17 @@ export interface AiAgentProfessionalTaskExpansionSnapshot {
|
||||
canary_delivery_bot_api_call_enabled_count: number
|
||||
canary_delivery_secret_read_enabled_count: number
|
||||
canary_delivery_paid_api_enabled_count: number
|
||||
canary_delivery_rehearsal_count: number
|
||||
canary_delivery_rehearsal_step_count: number
|
||||
canary_delivery_rehearsal_readback_check_count: number
|
||||
canary_delivery_rehearsal_stop_condition_count: number
|
||||
canary_delivery_rehearsal_rollback_mute_control_count: number
|
||||
canary_delivery_rehearsal_completed_check_count: number
|
||||
canary_delivery_rehearsal_failed_check_count: number
|
||||
canary_delivery_rehearsal_live_send_enabled_count: number
|
||||
canary_delivery_rehearsal_gateway_queue_write_enabled_count: number
|
||||
canary_delivery_rehearsal_bot_api_call_enabled_count: number
|
||||
canary_delivery_rehearsal_receipt_write_enabled_count: number
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
## 2026-06-18|P2-405E / P2-406A AI Agent Telegram 派送演練與前段主看板
|
||||
|
||||
**背景**:統帥已明確指出 Telegram 告警與日週月報不能停在「報表都是 0」或「批准後沒有自動化」,也不能讓日報、週報、月報埋在長頁面後段。既有 P2-405D 已把 Canary Delivery Gate、必填欄位、preflight、hold reason 與 rollback / mute 控制固定;既有 P2-111 也已有日報、週報、月報、failure-only 摘要與讀報回執的實發批准包。本階段一方面把下一步推進成可重放的 dry-run delivery rehearsal,另一方面把 P2-111 報告派送批准包拉到治理頁前段,讓 operator 能看見單一訊息如何被選定、如何形成 Gateway envelope preview、如何由 Hermes 做 receipt readback drill、哪些條件會停止,以及報告會送往哪個 TG 戰情室。此段仍不實發 Telegram、不寫 Gateway queue、不呼叫 Bot API。
|
||||
|
||||
**完成內容**:
|
||||
- 新增 committed snapshot `docs/evaluations/ai_agent_professional_task_expansion_2026-06-18_1200_p2_405e.json`,current `P2-405E`、next `P2-405F`、completion `98%`。
|
||||
- `telegram_runtime_bridge.canary_delivery_rehearsal` 固定 `daily_agent_workload_digest` 作為第一個 dry-run rehearsal 訊息,目標只顯示 `SRE_GROUP_CHAT_ID` env ref,不顯示 chat id value。
|
||||
- Rehearsal 固定 preview-only hash、single-use dedup key、Gateway envelope preview、6 個 dry-run step、8 個 readback check、7 個 stop condition、5 個 rollback / mute control。
|
||||
- API service guard 強制 rehearsal 的 live delivery、Gateway queue write、Bot API call、Telegram send、receipt write、production write、secret read、paid API 全部維持 `false / 0`。
|
||||
- Governance automation inventory 的 P2-405 區塊新增 rehearsal KPI 與卡片,直接顯示 selected message、target env、preview hash、dedup key、readback owner、completed / failed checks、next gate。
|
||||
- Governance automation inventory 在日週月報主看板下方新增「Telegram / TG Bot 日週月報派送演練」主看板。
|
||||
- P2-406A 主看板直接顯示正式目標 `AwoooI SRE 戰情室`、P2-111 實發批准包、下一關 P2-112、5 份 delivery approval packet、4 個路由閘門、4 個 no-send 回執演練、需審核數、Telegram 實發數與 live write 數。
|
||||
- P2-406A 主看板列出 `AI Agent 日報實發批准包`、`AI Agent 週報實發批准包`、`AI Agent 月報實發批准包`、`失敗限定摘要批准包`、`讀報回執 readback 批准包`,並保留 owner agent、risk tier、status 與 no-send 狀態。
|
||||
- i18n 兩份 locale 均使用繁體中文鏡像;前端仍透過既有 redaction helper 遮蔽內部協作、raw prompt、raw payload、authorization header 與 secret 類字串。
|
||||
|
||||
**完成度同步**:
|
||||
- P2-405E Telegram Canary Dry-run Delivery Rehearsal:本地實作 `100%`,待 Gitea CD / production verification。
|
||||
- P2-406A 日週月報 Telegram 派送演練主看板:本地實作 `100%`,待 Gitea CD / production verification。
|
||||
- AI Agent 專業任務擴展與 Telegram Runtime Bridge:`96% -> 98%`。
|
||||
- Telegram 實發、Gateway queue 寫入、Bot API call、delivery receipt production write、AI analysis runtime、中低風險 auto worker、production optimization write:全部仍維持 `0 / false`。
|
||||
|
||||
**邊界**:本段不送 Telegram、不寫 Gateway queue、不呼叫 Bot API、不寫讀報回執、不啟動排程、不啟動 AI analysis runtime、不啟動中低風險自動處理、不讀 secret、不新增批准或發送按鈕;不得把 dry-run rehearsal 解讀成 runtime gate 已開啟。
|
||||
|
||||
## 2026-06-16|IwoooS CD / Runner / Secret 回讀 Gate 正式部署驗證
|
||||
|
||||
**背景**:上一段 CD / Runner / Secret 注入事故後回讀 gate 已完成 repo 內 artifact / guard / 前台 marker,但一度被 CD run `3071` 的 Docker build lock timeout 擋住,不能宣告 production 完成。後續另一個 Session 記錄 empty lock cleanup evidence,並以 `97b66a0e` 前端 locale commit 觸發正式 CD;本視窗只做只讀 Actions / production 回讀與 LOGBOOK 同步,未 SSH、未 Docker / host live write、未 workflow dispatch、未改 runner 或 repository secret。
|
||||
|
||||
@@ -15,11 +15,19 @@
|
||||
| OpenClaw / Hermes / NemoTron 主動溝通、學習與成長證據 | 100% | P2-401A 到 P2-144 已完成只讀證據面、runtime / report / result-capture gates、no-write readback、promotion review、writer implementation review、writer dry-run fixture、writer dry-run readback、owner promotion execution gate、owner-approved execution rehearsal、owner acceptance / maintenance window gate、owner acceptance readback / preflight hold、owner-approved preflight release package、owner-approved release readiness readback、owner release approval gate、post-release verifier / rollback gate、final release candidate readback、release authorization hold / readback gate、release verifier preflight / owner review packet、release decision hold / readback、release decision next handoff、release decision input prep、12-Agent War Room、owner response 預檢與 owner response 回讀;P2-141 基線與 S4.9 owner release packet 補強皆已正式驗證,P2-142 12-Agent War Room 已完成 production readback 與 desktop / mobile smoke,P2-143 owner response 預檢已完成 production readback 與 in-app browser smoke,P2-144 owner response 回讀已完成 production API readback 與 desktop / mobile smoke。runtime worker、DB migration、production Redis consumer group、canonical runtime readback、live query、runtime score、result capture write、Telegram 實發、delivery receipt E2E、live report delivery、reviewer queue write、Gateway queue write、AI analysis runtime、中低風險 auto worker、KM / LOGBOOK / audit DB / timeline / PlayBook trust 寫入、SDK / 付費服務仍未開 gate | `ai_agent_result_capture_release_decision_owner_response_readback_v1`、`GET /api/v1/agents/agent-result-capture-release-decision-owner-response-readback`、`docs/evaluations/ai_agent_result_capture_release_decision_owner_response_readback_2026-06-14.json`、feature commit `8795f100`、deploy marker `ac938037`、Gitea code-review `2965` / CD `2964` success、5 個回覆讀回 lane、18 個 owner 必填欄位、6 個 readback validation check、6 個 rejection guard、5 個 operator action、等待外部回覆 `5`、未收件 lane `5`、正式寫入 / 發送 `0`;P2-142 feature commit `5de4b3f3`、deploy marker `1a2c9e36`、Gitea CD run `4232` success、production API readback、desktop / mobile in-app browser smoke;P2-143 feature commit `755b0a8d`、deploy marker `667d6329`、Gitea code-review `2961` / CD `2960` success、production API readback、desktop / mobile in-app browser smoke;MASTER §3.2.1b / §3.2.1d / §3.4.3 |
|
||||
| AI Agent 主動營運委派與版本生命週期 | 100% | P2-402A / P2-402B / P2-402C / P2-402D / P2-402E / P2-402F / P2-402G 已完成;已建立 repo-only 版本新鮮度快照、工具採用批准包、Telegram action-required digest policy、Gitea PR 草案 lane、host / K3s / stateful 版本只讀盤點、API 與 governance UI。定期排程、外部版本查詢、工具安裝、CI 變更、套件升級、主機更新、container pull、實際 PR creation、auto merge、Telegram 實發、SSH、kubectl、重啟仍未開 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`、`ai_agent_gitea_pr_draft_lane_v1`、`ai_agent_host_stateful_version_inventory_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`、`GET /api/v1/agents/agent-gitea-pr-draft-lane`、`GET /api/v1/agents/agent-host-stateful-version-inventory`、`/zh-TW/governance?tab=automation-inventory`、MASTER §3.2.1c |
|
||||
| 12-Agent War Room 編組 | 72% | 12 個邏輯工位與分批派工規則已正式部署;OpenClaw / Hermes / NemoTron / SRE / Security / DevOps / Data/DR / Supply Chain / Product/UI / QA / Market / Telegram 共 12 份只讀審查已回收;schema / committed snapshot / API / tests / governance UI 區塊 / production API readback / desktop + mobile in-app browser smoke 已完成;runtime writer、Telegram send、Bot API、production write 仍未批准 | `ai_agent_12_agent_war_room_v1`、`docs/evaluations/ai_agent_12_agent_war_room_2026-06-14.json`、`GET /api/v1/agents/agent-12-agent-war-room`、feature commit `5de4b3f3`、deploy marker `1a2c9e36`、Gitea CD run `4232` success、`/zh-TW/governance?tab=automation-inventory`、12 份 Codex sub-agent 只讀回饋 |
|
||||
| AI Agent 專業任務擴展與 Telegram Runtime Bridge | 96% | P2-405D 已完成只讀契約、正式 API、治理頁 P2-405D 卡片、6 種 Telegram no-send preview、6 個 dedup key、6 組 receipt expectation、1 份 canary approval package、1 份 canary send approval packet、1 份 canary delivery gate、8 個交付必填欄位、8 個 preflight check、7 個 hold reason、7 個 readback check、5 個 rollback / mute control;24 類專業任務、8 個領域、5 段 Telegram bridge、6 種訊息類型、MCP/RAG stack、日報 / 週報 / 月報 / action-required 報告契約已固定;Telegram 實發、Gateway queue、Bot API、delivery receipt production write、secret read、paid API、host write、kubectl action 仍全部關閉 | `ai_agent_professional_task_expansion_v1`、`docs/evaluations/ai_agent_professional_task_expansion_2026-06-16_1108_p2_405d.json`、`GET /api/v1/agents/agent-professional-task-expansion`、`/zh-TW/governance?tab=automation-inventory`、`docs/ai/AI_AGENT_PROFESSIONAL_TASK_EXPANSION_2026-06-15.md`、需批准任務 `19`、no-send preview `6`、dedup key `6`、receipt expectation `6`、canary package `1`、canary send approval packet `1`、delivery gate `1`、交付欄位 `8`、preflight `8`、hold reason `7`、preview / canary / delivery live write `0`;下一步 P2-405E canary dry-run delivery rehearsal |
|
||||
| AI Agent 專業任務擴展與 Telegram Runtime Bridge | 98% | P2-405E 已完成只讀契約、正式 API 候選、治理頁 P2-405E 乾跑派送演練卡、6 種 Telegram no-send preview、6 個 dedup key、6 組 receipt expectation、1 份 canary approval package、1 份 canary send approval packet、1 份 canary delivery gate、1 份 canary dry-run delivery rehearsal、6 個乾跑步驟、8 個 receipt readback check、7 個 stop condition、5 個 rollback / mute control;P2-406A 已把 P2-111 日報 / 週報 / 月報實發批准包、AwoooI SRE 戰情室 route、TG Bot / Gateway / receipt / AI analysis 邊界拉到治理頁前段主看板;24 類專業任務、8 個領域、5 段 Telegram bridge、6 種訊息類型、MCP/RAG stack、日報 / 週報 / 月報 / action-required 報告契約已固定;Telegram 實發、Gateway queue、Bot API、delivery receipt production write、secret read、paid API、host write、kubectl action 仍全部關閉 | `ai_agent_professional_task_expansion_v1`、`docs/evaluations/ai_agent_professional_task_expansion_2026-06-18_1200_p2_405e.json`、`GET /api/v1/agents/agent-professional-task-expansion`、`GET /api/v1/agents/agent-report-live-delivery-approval-package`、`/zh-TW/governance?tab=automation-inventory`、`docs/ai/AI_AGENT_PROFESSIONAL_TASK_EXPANSION_2026-06-15.md`、需批准任務 `19`、no-send preview `6`、dedup key `6`、receipt expectation `6`、canary package `1`、canary send approval packet `1`、delivery gate `1`、dry-run rehearsal `1`、P2-111 delivery approval packet `5`、route gate `4`、no-send receipt `4`、交付欄位 `8`、preflight `8`、hold reason `7`、preview / canary / delivery / rehearsal live write `0`;下一步 P2-405F / P2-406B receipt readback owner review |
|
||||
| Owner response 預檢與拒收邊界 | 100% | P2-143 已完成正式部署與 production readback;承接 P2-141 input prep 與 P2-142 War Room,只建立 owner / verifier / rollback / maintenance / live-apply 五類外部回覆的 intake 預檢、必填欄位與拒收規則;正式 owner response 尚未收到、未接受、未寫入 | `ai_agent_result_capture_release_decision_owner_response_preflight_v1`、`GET /api/v1/agents/agent-result-capture-release-decision-owner-response-preflight`、feature commit `755b0a8d`、deploy marker `667d6329`、Gitea code-review `2961` / CD `2960` success、5 個 response intake lane、18 個 required owner field、6 個 validation check、6 個 rejection guard、5 個 operator action;owner response received / accepted / redacted payload / reviewer queue / Gateway / Telegram / Bot API / production write / secret read / destructive operation 全為 `0` |
|
||||
| Owner response 回讀狀態 | 100% | P2-144 已完成正式部署與 production readback;承接 P2-143 preflight,只讀回五類外部回覆仍未收到、未接受、未拒絕、未保存 | `ai_agent_result_capture_release_decision_owner_response_readback_v1`、`GET /api/v1/agents/agent-result-capture-release-decision-owner-response-readback`、feature commit `8795f100`、deploy marker `ac938037`、Gitea code-review `2965` / CD `2964` success、5 個 response readback lane、18 個 required owner field、6 個 readback validation check、6 個 readback rejection guard、5 個 operator action、waiting external response `5`、no external response received `5`;owner response received / accepted / redacted payload / reviewer queue / Gateway / Telegram / Bot API / production write / secret read / destructive operation 全為 `0` |
|
||||
| 本工作清單與分析報告 | 100% | 已完成 | 本 MD 文件 |
|
||||
|
||||
### 2026-06-18 12:00 狀態同步
|
||||
|
||||
- `P2-405E` AI Agent TG Canary 乾跑派送演練已本地完成:新增 `docs/evaluations/ai_agent_professional_task_expansion_2026-06-18_1200_p2_405e.json`,current `P2-405E`、next `P2-405F`、completion `98`。
|
||||
- P2-405E 固定 1 份 canary dry-run delivery rehearsal、6 個 dry-run step、8 個 receipt readback check、7 個 stop condition、5 個 rollback / mute control。
|
||||
- 治理頁 `automation-inventory` 已顯示 P2-405E 乾跑派送演練、Gateway envelope 演練、回執讀回演練、dry-run step、stop condition、queue / Bot API / Telegram send / receipt write 狀態。
|
||||
- P2-406A 前段主看板同步顯示 P2-111 日報 / 週報 / 月報實發批准包、AwoooI SRE 戰情室 route、5 份 delivery packet、4 個 route gate、4 個 no-send receipt。
|
||||
- Telegram send、Gateway queue write、Bot API call、delivery receipt production write、secret read、paid API、host write、kubectl action、production write 全部仍為 `0 / false`;P2-405F / P2-406B 才能進入 receipt readback owner review,且仍不得實發。
|
||||
|
||||
### 2026-06-16 11:08 狀態同步
|
||||
|
||||
- `P2-405D` AI Agent TG Canary Delivery Gate 已本地完成:新增 `docs/evaluations/ai_agent_professional_task_expansion_2026-06-16_1108_p2_405d.json`,current `P2-405D`、next `P2-405E`、completion `96`。
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# AI Agent 專業任務擴展與 Telegram Runtime Bridge 工作報告
|
||||
|
||||
> 日期:2026-06-16(台北時間)
|
||||
> 狀態:P2-405D 已完成 Telegram Canary Delivery Gate、8 個交付必填欄位、8 個 preflight check、7 個 hold reason、7 個 readback check、5 個 rollback / mute 控制、API guard、測試與治理頁可視化;Telegram 實發仍未啟用。
|
||||
> 日期:2026-06-18(台北時間)
|
||||
> 狀態:P2-405E 已完成 Telegram Canary Dry-run Delivery Rehearsal、6 個 rehearsal step、8 個 readback check、7 個 stop condition、5 個 rollback / mute 控制、API guard、測試與治理頁可視化;Telegram 實發仍未啟用。
|
||||
> 事實來源:`ai_agent_professional_task_expansion_v1`
|
||||
|
||||
## 1. 結論
|
||||
|
||||
本輪把「AI Agent 還能處理哪些專業工作」正式產品化成 24 類專業任務,並把 Telegram 群組 / TG Bot 整合拆成 5 段啟動前閘門。P2-405D 進一步把第一次 Canary delivery 前必須由統帥確認的交付欄位、preflight、hold reason、rollback / mute 與 readback plan 顯示到治理頁。
|
||||
本輪把「AI Agent 還能處理哪些專業工作」正式產品化成 24 類專業任務,並把 Telegram 群組 / TG Bot 整合拆成 5 段啟動前閘門。P2-405D 已把第一次 Canary delivery 前必須由統帥確認的交付欄位、preflight、hold reason、rollback / mute 與 readback plan 顯示到治理頁;P2-405E 進一步把第一個 `daily_agent_workload_digest` dry-run delivery rehearsal 固定成可重放證據,包含 preview hash、dedup key、Gateway envelope preview、Hermes receipt readback drill 與停止條件。
|
||||
|
||||
這不是直接讓 AI Agent 發 Telegram 或改 production;目前只允許 no-send preview、queue preview readback、owner review、canary approval package、canary send approval packet 與 canary delivery gate。真正送到 **AwoooI SRE 戰情室** 必須先通過統帥明確批准、approved canary、dedup、receipt、redaction、OpenClaw 仲裁、Security gate 與 QA verifier。
|
||||
這不是直接讓 AI Agent 發 Telegram 或改 production;目前只允許 no-send preview、queue preview readback、owner review、canary approval package、canary send approval packet、canary delivery gate 與 dry-run delivery rehearsal。真正送到 **AwoooI SRE 戰情室** 必須先通過 owner-approved P2-405F live canary approval、dedup、receipt、redaction、OpenClaw 仲裁、Security gate 與 QA verifier。
|
||||
|
||||
## 2. 完成度
|
||||
|
||||
@@ -19,8 +19,9 @@
|
||||
| Telegram no-send 訊息預覽 | 100% | 6 種訊息預覽、6 個 dedup key、6 組 receipt expectation、1 份 canary approval package 已固定 |
|
||||
| Canary 發送批准包 | 100% | 1 份 canary send approval packet、7 個批准欄位、6 個停止條件、5 步 mute / rollback、6 個 receipt readback check 已固定 |
|
||||
| Canary Delivery Gate | 100% | 1 份 delivery gate、8 個交付必填欄位、8 個 preflight、7 個 hold reason、7 個 readback check、5 個 rollback / mute 控制已固定 |
|
||||
| Canary Dry-run Delivery Rehearsal | 100% | 1 份 dry-run rehearsal、6 個 step、8 個 readback check、7 個 stop condition、5 個 rollback / mute 控制已固定 |
|
||||
| API / loader | 100% | `GET /api/v1/agents/agent-professional-task-expansion` 只讀輸出 |
|
||||
| 治理頁可視化 | 100% | `/zh-TW/governance?tab=automation-inventory` 顯示任務、風險、TG bridge、preview、dedup、receipt、canary、delivery gate 與 live/send/write=0 |
|
||||
| 治理頁可視化 | 100% | `/zh-TW/governance?tab=automation-inventory` 顯示任務、風險、TG bridge、preview、dedup、receipt、canary、delivery gate、rehearsal 與 live/send/write=0 |
|
||||
| Telegram 實發 | 0% | `telegram_send_count=0`、`bot_api_call_count=0`、`gateway_queue_write_count=0` |
|
||||
| Runtime 自動優化 | 0% | production write、host write、kubectl、paid API、secret read 全部維持 0 |
|
||||
|
||||
@@ -92,7 +93,22 @@ Canary 發送批准包固定 6 個停止條件、5 步 mute / rollback plan、6
|
||||
|
||||
Canary delivery gate 固定 8 個 preflight check、7 個 hold reason、7 個 readback check 與 5 個 rollback / mute control;`live_delivery_enabled`、`gateway_queue_write_enabled`、`bot_api_call_enabled`、`delivery_receipt_write_enabled`、`production_write_enabled`、`secret_read_enabled`、`paid_api_enabled` 全部仍為 `false`。
|
||||
|
||||
## 8. 專業任務總覽
|
||||
## 8. P2-405E Canary Dry-run Delivery Rehearsal
|
||||
|
||||
目前 canary delivery rehearsal 狀態為 `ready_no_send_rehearsal`,`rehearsal_ready=true`,選定 `daily_agent_workload_digest` 作為第一個 dry-run 訊息。此 rehearsal 只產生 preview hash、dedup key 與 Gateway envelope preview,不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 production receipt。
|
||||
|
||||
| 項目 | 值 | 邊界 |
|
||||
|---|---|---|
|
||||
| selected message | `daily_agent_workload_digest` | 只允許單一訊息型別 |
|
||||
| selected preview | `p2_405b_preview_daily_agent_workload_digest_v1` | 必須對應 no-send preview |
|
||||
| target room | `SRE_GROUP_CHAT_ID` | 只顯示 env ref,不顯示 chat id value |
|
||||
| dedup key | `awoooi:agent-report:daily:2026-06-18:v1` | 單一 rehearsal window 使用 |
|
||||
| readback owner | Hermes | 只做 dry-run readback drill |
|
||||
| completed / failed checks | `8 / 0` | 失敗即回到 no-send preview |
|
||||
|
||||
Rehearsal 固定 6 個 dry-run step、8 個 readback check、7 個 stop condition 與 5 個 rollback / mute control;`live_delivery_enabled`、`gateway_queue_write_enabled`、`bot_api_call_enabled`、`telegram_send_enabled`、`delivery_receipt_write_enabled`、`production_write_enabled`、`secret_read_enabled`、`paid_api_enabled` 全部仍為 `false`。
|
||||
|
||||
## 9. 專業任務總覽
|
||||
|
||||
| 領域 | 任務數 | 代表任務 | 主責 |
|
||||
|---|---:|---|---|
|
||||
@@ -105,7 +121,7 @@ Canary delivery gate 固定 8 個 preflight check、7 個 hold reason、7 個 re
|
||||
| AI Governance / Replay / Market | 4 | market watch、NemoTron replay、cost forecast、runbook/postmortem | OpenClaw / NemoTron / Hermes |
|
||||
| Telegram / Reports / Receipts | 3 | digest preview、report truth gate、post-action verifier | Telegram Ops / Hermes / OpenClaw |
|
||||
|
||||
## 9. 專業能力層級
|
||||
## 10. 專業能力層級
|
||||
|
||||
| 層級 | AI Agent 可自動做 | Gate |
|
||||
|---|---|---|
|
||||
@@ -114,7 +130,7 @@ Canary delivery gate 固定 8 個 preflight check、7 個 hold reason、7 個 re
|
||||
| 高風險 | 只產批准包、rollback plan、failure-only digest 草案 | 統帥批准 |
|
||||
| Critical | production write、kubectl、ArgoCD sync、Telegram 實發、secret、restore、host write | 預設 blocked |
|
||||
|
||||
## 10. MCP / RAG
|
||||
## 11. MCP / RAG
|
||||
|
||||
首批 MCP:Gitea、Browser、Observability、Telegram Gateway、Package Registry、Database Readonly、Backup Status、ArgoCD Readonly、HTTP Probe、Fixture Store。
|
||||
|
||||
@@ -122,7 +138,7 @@ Canary delivery gate 固定 8 個 preflight check、7 個 hold reason、7 個 re
|
||||
|
||||
成長指標:KM entries、PlayBook updates、recommendations、replay score delta、blocked action prevented count、receipt missing count。
|
||||
|
||||
## 11. 邊界
|
||||
## 12. 邊界
|
||||
|
||||
- 不直接發 Telegram。
|
||||
- 不寫 Telegram Gateway queue。
|
||||
@@ -131,9 +147,9 @@ Canary delivery gate 固定 8 個 preflight check、7 個 hold reason、7 個 re
|
||||
- 不把工作視窗對話、未遮罩提示、私人推理或未遮罩 runtime payload 放進前端或 Telegram。
|
||||
- 不做 production write、host write、kubectl、ArgoCD sync、restore、rollback、paid API、SDK install。
|
||||
|
||||
## 12. 下一步
|
||||
## 13. 下一步
|
||||
|
||||
1. P2-405E:統帥明確批准 canary delivery 欄位、單一訊息類型、時間窗、目標 env ref、receipt readback owner 與停止條件後,才進入受控 dry-run delivery rehearsal。
|
||||
2. P2-405F:canary 通過後才開日報 / 週報 / 月報 digest delivery。
|
||||
3. P2-405G:Action-required digest 只對 failure / high-risk / approval-required 事件開啟。
|
||||
4. P2-405G:把 receipt readback 與 report status board 串起來,但仍需 canary gate 後才能寫正式 receipt。
|
||||
1. P2-405F:以 P2-405E rehearsal readback 為證據,產出 owner-approved single canary live delivery approval package。
|
||||
2. P2-405G:canary 通過後才開日報 / 週報 / 月報 digest delivery。
|
||||
3. P2-405H:Action-required digest 只對 failure / high-risk / approval-required 事件開啟。
|
||||
4. P2-405H:把 receipt readback 與 report status board 串起來,但仍需 canary gate 後才能寫正式 receipt。
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -46,10 +46,10 @@
|
||||
]
|
||||
},
|
||||
"current_task_id": {
|
||||
"const": "P2-405D"
|
||||
"const": "P2-405E"
|
||||
},
|
||||
"next_task_id": {
|
||||
"const": "P2-405E"
|
||||
"const": "P2-405F"
|
||||
},
|
||||
"overall_completion_percent": {
|
||||
"type": "integer",
|
||||
@@ -98,7 +98,8 @@
|
||||
"receipt_expectations",
|
||||
"canary_approval_package",
|
||||
"canary_send_approval_packet",
|
||||
"canary_delivery_gate"
|
||||
"canary_delivery_gate",
|
||||
"canary_delivery_rehearsal"
|
||||
],
|
||||
"properties": {
|
||||
"canonical_room": {
|
||||
@@ -614,6 +615,101 @@
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
"canary_delivery_rehearsal": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"rehearsal_id",
|
||||
"status",
|
||||
"rehearsal_ready",
|
||||
"selected_message_type",
|
||||
"selected_preview_id",
|
||||
"selected_receipt_expectation_id",
|
||||
"target_room_env",
|
||||
"target_room_value_visible",
|
||||
"sanitized_preview_hash",
|
||||
"dedup_key",
|
||||
"gateway_envelope_preview",
|
||||
"dry_run_steps",
|
||||
"readback_drill",
|
||||
"stop_conditions",
|
||||
"rollback_mute_controls",
|
||||
"execution_flags",
|
||||
"next_gate"
|
||||
],
|
||||
"properties": {
|
||||
"status": {
|
||||
"const": "ready_no_send_rehearsal"
|
||||
},
|
||||
"rehearsal_ready": {
|
||||
"const": true
|
||||
},
|
||||
"selected_message_type": {
|
||||
"const": "daily_agent_workload_digest"
|
||||
},
|
||||
"selected_preview_id": {
|
||||
"const": "p2_405b_preview_daily_agent_workload_digest_v1"
|
||||
},
|
||||
"selected_receipt_expectation_id": {
|
||||
"const": "p2_405b_receipt_daily_agent_workload_digest_v1"
|
||||
},
|
||||
"target_room_env": {
|
||||
"const": "SRE_GROUP_CHAT_ID"
|
||||
},
|
||||
"target_room_value_visible": {
|
||||
"const": false
|
||||
},
|
||||
"dry_run_steps": {
|
||||
"type": "array",
|
||||
"minItems": 6,
|
||||
"maxItems": 6
|
||||
},
|
||||
"readback_drill": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"owner_agent",
|
||||
"required_checks",
|
||||
"completed_check_count",
|
||||
"failed_check_count",
|
||||
"production_receipt_write_enabled",
|
||||
"live_receipt_readback_enabled"
|
||||
],
|
||||
"properties": {
|
||||
"owner_agent": {
|
||||
"const": "hermes"
|
||||
},
|
||||
"required_checks": {
|
||||
"type": "array",
|
||||
"minItems": 8,
|
||||
"maxItems": 8
|
||||
},
|
||||
"completed_check_count": {
|
||||
"const": 8
|
||||
},
|
||||
"failed_check_count": {
|
||||
"const": 0
|
||||
},
|
||||
"production_receipt_write_enabled": {
|
||||
"const": false
|
||||
},
|
||||
"live_receipt_readback_enabled": {
|
||||
"const": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
"stop_conditions": {
|
||||
"type": "array",
|
||||
"minItems": 7,
|
||||
"maxItems": 7
|
||||
},
|
||||
"rollback_mute_controls": {
|
||||
"type": "array",
|
||||
"minItems": 5,
|
||||
"maxItems": 5
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
@@ -780,7 +876,18 @@
|
||||
"canary_delivery_gateway_queue_write_enabled_count",
|
||||
"canary_delivery_bot_api_call_enabled_count",
|
||||
"canary_delivery_secret_read_enabled_count",
|
||||
"canary_delivery_paid_api_enabled_count"
|
||||
"canary_delivery_paid_api_enabled_count",
|
||||
"canary_delivery_rehearsal_count",
|
||||
"canary_delivery_rehearsal_step_count",
|
||||
"canary_delivery_rehearsal_readback_check_count",
|
||||
"canary_delivery_rehearsal_stop_condition_count",
|
||||
"canary_delivery_rehearsal_rollback_mute_control_count",
|
||||
"canary_delivery_rehearsal_completed_check_count",
|
||||
"canary_delivery_rehearsal_failed_check_count",
|
||||
"canary_delivery_rehearsal_live_send_enabled_count",
|
||||
"canary_delivery_rehearsal_gateway_queue_write_enabled_count",
|
||||
"canary_delivery_rehearsal_bot_api_call_enabled_count",
|
||||
"canary_delivery_rehearsal_receipt_write_enabled_count"
|
||||
],
|
||||
"properties": {
|
||||
"professional_task_count": {
|
||||
@@ -944,6 +1051,39 @@
|
||||
},
|
||||
"canary_delivery_paid_api_enabled_count": {
|
||||
"const": 0
|
||||
},
|
||||
"canary_delivery_rehearsal_count": {
|
||||
"const": 1
|
||||
},
|
||||
"canary_delivery_rehearsal_step_count": {
|
||||
"const": 6
|
||||
},
|
||||
"canary_delivery_rehearsal_readback_check_count": {
|
||||
"const": 8
|
||||
},
|
||||
"canary_delivery_rehearsal_stop_condition_count": {
|
||||
"const": 7
|
||||
},
|
||||
"canary_delivery_rehearsal_rollback_mute_control_count": {
|
||||
"const": 5
|
||||
},
|
||||
"canary_delivery_rehearsal_completed_check_count": {
|
||||
"const": 8
|
||||
},
|
||||
"canary_delivery_rehearsal_failed_check_count": {
|
||||
"const": 0
|
||||
},
|
||||
"canary_delivery_rehearsal_live_send_enabled_count": {
|
||||
"const": 0
|
||||
},
|
||||
"canary_delivery_rehearsal_gateway_queue_write_enabled_count": {
|
||||
"const": 0
|
||||
},
|
||||
"canary_delivery_rehearsal_bot_api_call_enabled_count": {
|
||||
"const": 0
|
||||
},
|
||||
"canary_delivery_rehearsal_receipt_write_enabled_count": {
|
||||
"const": 0
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
|
||||
Reference in New Issue
Block a user