2/5" in report
assert "resolution_stats" in report
assert "KM: draft_ready 3/4" in report
assert "Verifier: source_health_ready 1/2" in report
- assert "不代表已授權發送或自動修復" in report
+ assert "AI Agent 受控接手" in report
+
+ def test_weekly_and_monthly_report_schedule_helpers_return_positive_seconds(self):
+ assert _seconds_until_next_report() > 0
+ assert _seconds_until_next_weekly_report() > 0
+ assert _seconds_until_next_monthly_report() > 0
def test_sre_digest_preview_contains_assets_and_boundaries(self):
"""SRE 戰情室 digest 應收斂缺口、資產與 no-send 邊界"""
diff --git a/apps/api/tests/test_weekly_report_preview_api.py b/apps/api/tests/test_weekly_report_preview_api.py
index 4816f78c8..77047fb98 100644
--- a/apps/api/tests/test_weekly_report_preview_api.py
+++ b/apps/api/tests/test_weekly_report_preview_api.py
@@ -50,7 +50,7 @@ def test_weekly_report_preview_exposes_source_health_no_send_preview():
assert "不自動改排程" in preview
-def test_monthly_report_preview_exposes_source_health_no_send_preview():
+def test_monthly_report_preview_exposes_source_health_and_gateway_delivery():
client = TestClient(app)
response = client.get("/api/v1/stats/monthly/preview")
@@ -65,11 +65,11 @@ def test_monthly_report_preview_exposes_source_health_no_send_preview():
assert "formatted_preview" in data
preview = data["formatted_preview"]
- assert "月報 no-send preview" in preview
+ assert "AWOOOI 月報" in preview
assert "報表資料源 / 沉澱" in preview
assert f"來源: {data['source_ok_count']}/{data['source_total_count']}" in preview
- assert "實發: 0" in preview
- assert "不代表已授權發送或自動修復" in preview
+ assert "Telegram Gateway" in preview
+ assert "AI Agent 受控接手" in preview
def test_sre_digest_preview_exposes_source_health_no_send_preview():
diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json
index 145f07f50..cf73e7172 100644
--- a/apps/web/messages/en.json
+++ b/apps/web/messages/en.json
@@ -1866,10 +1866,16 @@
"needsHumanYes": "需要",
"needsHumanNo": "不需要",
"stateLabels": {
- "verificationDegradedManualRequired": "驗證退化,需人工確認"
+ "verificationDegradedManualRequired": "驗證退化,AI 進入 verifier / rollback",
+ "verificationDegradedAiVerifierRequired": "驗證退化,AI 進入 verifier / rollback",
+ "diagnosticOnlyAiRepairRequired": "只完成診斷,AI 補修復候選",
+ "noActionAiCandidateRequired": "未找到修復候選,AI 補 PlayBook"
},
"nextActionLabels": {
- "manualVerifyOrRepair": "人工確認修復狀態;需要時重新送審修復"
+ "manualVerifyOrRepair": "AI 執行 verifier 或 rollback 判定",
+ "runVerifierOrRollbackCandidate": "AI 執行 verifier 或 rollback 判定",
+ "autoGenerateRepairCandidate": "AI 從診斷證據產生修復候選",
+ "autoRepairBlockerConnector": "AI 修復 blocker / connector 後重試"
},
"reasonLabels": {
"incidentOpenAfterSuccessfulExecution": "自動執行已完成,但 Incident仍開啟"
@@ -3681,6 +3687,41 @@
"runwayTitle": "AI Agents 專業執行跑道",
"runwayBadge": "只讀 / 乾跑 / 審核 / 回寫",
"runwaySummary": "可無寫入推進 {noWrite} 類;正式執行 {runtime}、Telegram 發送 {sends}、production 寫入 {writes} 仍依 gate。",
+ "currentAutonomy": {
+ "title": "目前有效自主化控制層",
+ "policyTitle": "目前執行政策",
+ "runtimeTitle": "Worker / Gateway 開關",
+ "executorTitle": "Executor 收據鏈",
+ "overrideTitle": "舊規範覆寫",
+ "hardBlockerTitle": "仍維持硬阻擋",
+ "hardBlockerDetail": "需 break-glass 或專案級合約,不由一般自動化靜默執行。",
+ "badges": {
+ "override": "舊 no-send / no-live 已覆寫",
+ "gateway": "Telegram Gateway"
+ },
+ "metrics": {
+ "completion": "目前完成度",
+ "riskTiers": "自動風險層",
+ "reports": "日週月報",
+ "gateway": "Gateway 派送",
+ "executor": "Executor 收據",
+ "hardBlockers": "硬阻擋"
+ },
+ "policy": {
+ "low": "低風險",
+ "medium": "中風險",
+ "high": "高風險",
+ "noOwnerReview": "低/中/高人工 gate={value}",
+ "verifier": "post-apply verifier={value}",
+ "km": "KM / PlayBook 回寫={value}"
+ },
+ "runtime": {
+ "checkMode": "Ansible check-mode worker",
+ "apply": "Controlled apply",
+ "botApi": "Direct Bot API",
+ "gatewayOnly": "只允許既有 Telegram Gateway,不暴露 token / chat id。"
+ }
+ },
"runway": {
"readOnlyInvestigation": {
"label": "主動巡檢與證據蒐集",
@@ -9755,12 +9796,12 @@
"verify_git_baseline_then_mark_adopted": "驗證 Git baseline 後標記採納",
"operator_review_handoff_and_execute_manual_plan": "Operator review交接並執行人工方案",
"run_verification_scan_then_record_result": "執行驗證掃描並記錄結果",
- "open_manual_investigation_with_failed_verification": "建立人工調查並附上失敗驗證",
+ "open_manual_investigation_with_failed_verification": "建立 AI verifier / rollback 調查並附上失敗驗證",
"verify_k8s_matches_git_baseline": "驗證 K8s與Git baseline 一致",
"confirm_no_repeat_after_rollback": "確認回滾後不再重複",
"monitor_for_recurrence": "監控是否復發",
"retry_pr_lookup_then_review_drift": "重試 PR 查詢後 review drift",
- "manual_investigation_or_ansible_check_mode": "人工調查或Ansible check-mode",
+ "manual_investigation_or_ansible_check_mode": "AI 調查或 Ansible check-mode",
"unknown": "未知"
},
"pr": {
@@ -10669,11 +10710,15 @@
"nextActions": {
"openApplyGateWorkItem": "開啟 apply gate 工作項,審查 Verifier 與 KM 回寫",
"reviewOwnerReleasePacket": "審查 owner 放行包、執行窗口、rollback 與回寫責任",
- "manualReviewNoActionDecision": "人工判斷是否接手或關閉事件",
+ "manualReviewNoActionDecision": "AI 補齊 evidence / PlayBook 後判定是否關閉事件",
"ownerReviewRepairCandidateDraft": "審查修復候選草案、rollback 與 verifier",
"collectRepairEvidence": "補齊修復證據或建立專屬 PlayBook",
- "manualInvestigation": "人工調查卡點並補證據",
- "reviewVerifier": "執行或審查修復後 verifier",
+ "manualInvestigation": "AI 調查卡點並補證據",
+ "autoGenerateRepairCandidate": "AI 從診斷證據產生修復候選",
+ "autoVerifyOrRollback": "AI 執行 verifier 或 rollback 判定",
+ "autoRepairBlockerConnector": "AI 修復 blocker / connector 後重試",
+ "autoGenerateRepairOrBreakGlass": "AI 產生修復包;硬阻擋才 break-glass",
+ "reviewVerifier": "執行修復後 verifier",
"monitorRegression": "持續觀察是否復發",
"collectEvidenceOrWait": "補收證據或等待下一筆 recurrence",
"collectMaintenanceRollback": "補齊維護窗口與 rollback owner",
@@ -11272,7 +11317,7 @@
"nextActions": {
"openApplyGateWorkItem": "開啟 apply gate 工作項,審查 Verifier 與 KM 回寫",
"ownerReviewRepairCandidateDraft": "審查修復候選草案、rollback 與 verifier",
- "manualReviewNoActionDecision": "人工判斷是否接手或關閉事件"
+ "manualReviewNoActionDecision": "AI 補齊 evidence / PlayBook 後判定是否關閉事件"
},
"items": {
"km": "KM",
diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json
index 145f07f50..cf73e7172 100644
--- a/apps/web/messages/zh-TW.json
+++ b/apps/web/messages/zh-TW.json
@@ -1866,10 +1866,16 @@
"needsHumanYes": "需要",
"needsHumanNo": "不需要",
"stateLabels": {
- "verificationDegradedManualRequired": "驗證退化,需人工確認"
+ "verificationDegradedManualRequired": "驗證退化,AI 進入 verifier / rollback",
+ "verificationDegradedAiVerifierRequired": "驗證退化,AI 進入 verifier / rollback",
+ "diagnosticOnlyAiRepairRequired": "只完成診斷,AI 補修復候選",
+ "noActionAiCandidateRequired": "未找到修復候選,AI 補 PlayBook"
},
"nextActionLabels": {
- "manualVerifyOrRepair": "人工確認修復狀態;需要時重新送審修復"
+ "manualVerifyOrRepair": "AI 執行 verifier 或 rollback 判定",
+ "runVerifierOrRollbackCandidate": "AI 執行 verifier 或 rollback 判定",
+ "autoGenerateRepairCandidate": "AI 從診斷證據產生修復候選",
+ "autoRepairBlockerConnector": "AI 修復 blocker / connector 後重試"
},
"reasonLabels": {
"incidentOpenAfterSuccessfulExecution": "自動執行已完成,但 Incident仍開啟"
@@ -3681,6 +3687,41 @@
"runwayTitle": "AI Agents 專業執行跑道",
"runwayBadge": "只讀 / 乾跑 / 審核 / 回寫",
"runwaySummary": "可無寫入推進 {noWrite} 類;正式執行 {runtime}、Telegram 發送 {sends}、production 寫入 {writes} 仍依 gate。",
+ "currentAutonomy": {
+ "title": "目前有效自主化控制層",
+ "policyTitle": "目前執行政策",
+ "runtimeTitle": "Worker / Gateway 開關",
+ "executorTitle": "Executor 收據鏈",
+ "overrideTitle": "舊規範覆寫",
+ "hardBlockerTitle": "仍維持硬阻擋",
+ "hardBlockerDetail": "需 break-glass 或專案級合約,不由一般自動化靜默執行。",
+ "badges": {
+ "override": "舊 no-send / no-live 已覆寫",
+ "gateway": "Telegram Gateway"
+ },
+ "metrics": {
+ "completion": "目前完成度",
+ "riskTiers": "自動風險層",
+ "reports": "日週月報",
+ "gateway": "Gateway 派送",
+ "executor": "Executor 收據",
+ "hardBlockers": "硬阻擋"
+ },
+ "policy": {
+ "low": "低風險",
+ "medium": "中風險",
+ "high": "高風險",
+ "noOwnerReview": "低/中/高人工 gate={value}",
+ "verifier": "post-apply verifier={value}",
+ "km": "KM / PlayBook 回寫={value}"
+ },
+ "runtime": {
+ "checkMode": "Ansible check-mode worker",
+ "apply": "Controlled apply",
+ "botApi": "Direct Bot API",
+ "gatewayOnly": "只允許既有 Telegram Gateway,不暴露 token / chat id。"
+ }
+ },
"runway": {
"readOnlyInvestigation": {
"label": "主動巡檢與證據蒐集",
@@ -9755,12 +9796,12 @@
"verify_git_baseline_then_mark_adopted": "驗證 Git baseline 後標記採納",
"operator_review_handoff_and_execute_manual_plan": "Operator review交接並執行人工方案",
"run_verification_scan_then_record_result": "執行驗證掃描並記錄結果",
- "open_manual_investigation_with_failed_verification": "建立人工調查並附上失敗驗證",
+ "open_manual_investigation_with_failed_verification": "建立 AI verifier / rollback 調查並附上失敗驗證",
"verify_k8s_matches_git_baseline": "驗證 K8s與Git baseline 一致",
"confirm_no_repeat_after_rollback": "確認回滾後不再重複",
"monitor_for_recurrence": "監控是否復發",
"retry_pr_lookup_then_review_drift": "重試 PR 查詢後 review drift",
- "manual_investigation_or_ansible_check_mode": "人工調查或Ansible check-mode",
+ "manual_investigation_or_ansible_check_mode": "AI 調查或 Ansible check-mode",
"unknown": "未知"
},
"pr": {
@@ -10669,11 +10710,15 @@
"nextActions": {
"openApplyGateWorkItem": "開啟 apply gate 工作項,審查 Verifier 與 KM 回寫",
"reviewOwnerReleasePacket": "審查 owner 放行包、執行窗口、rollback 與回寫責任",
- "manualReviewNoActionDecision": "人工判斷是否接手或關閉事件",
+ "manualReviewNoActionDecision": "AI 補齊 evidence / PlayBook 後判定是否關閉事件",
"ownerReviewRepairCandidateDraft": "審查修復候選草案、rollback 與 verifier",
"collectRepairEvidence": "補齊修復證據或建立專屬 PlayBook",
- "manualInvestigation": "人工調查卡點並補證據",
- "reviewVerifier": "執行或審查修復後 verifier",
+ "manualInvestigation": "AI 調查卡點並補證據",
+ "autoGenerateRepairCandidate": "AI 從診斷證據產生修復候選",
+ "autoVerifyOrRollback": "AI 執行 verifier 或 rollback 判定",
+ "autoRepairBlockerConnector": "AI 修復 blocker / connector 後重試",
+ "autoGenerateRepairOrBreakGlass": "AI 產生修復包;硬阻擋才 break-glass",
+ "reviewVerifier": "執行修復後 verifier",
"monitorRegression": "持續觀察是否復發",
"collectEvidenceOrWait": "補收證據或等待下一筆 recurrence",
"collectMaintenanceRollback": "補齊維護窗口與 rollback owner",
@@ -11272,7 +11317,7 @@
"nextActions": {
"openApplyGateWorkItem": "開啟 apply gate 工作項,審查 Verifier 與 KM 回寫",
"ownerReviewRepairCandidateDraft": "審查修復候選草案、rollback 與 verifier",
- "manualReviewNoActionDecision": "人工判斷是否接手或關閉事件"
+ "manualReviewNoActionDecision": "AI 補齊 evidence / PlayBook 後判定是否關閉事件"
},
"items": {
"km": "KM",
diff --git a/apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx b/apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx
index 93984bf68..c7edac744 100644
--- a/apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx
+++ b/apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx
@@ -45,6 +45,7 @@ import { redactPublicIdentifier } from '@/lib/public-security-redaction'
import {
apiClient,
type AiAgent12AgentWarRoomSnapshot,
+ type AiAgentAutonomousRuntimeControlSnapshot,
type AiAgentProfessionalTaskExpansionSnapshot,
type AiAgentReceiptReadbackOwnerReviewSnapshot,
type AiAgentReportNoWriteAnalysisRuntimeSnapshot,
@@ -849,6 +850,7 @@ function GateMatrixRow({
export function AutomationInventoryTab() {
const t = useTranslations('governance.automationInventory')
const [snapshot, setSnapshot] = useState