From b7045a412c8be3d67490fb64790b12c0380fa23c Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 27 Jun 2026 00:03:23 +0800 Subject: [PATCH] fix(agents): route p2-409 through controlled apply --- apps/api/src/api/v1/agents.py | 14 +- .../ai_agent_high_risk_owner_review_queue.py | 56 +- ...t_ai_agent_high_risk_owner_review_queue.py | 32 + ..._agent_high_risk_owner_review_queue_api.py | 25 +- apps/web/messages/en.json | 29 +- apps/web/messages/zh-TW.json | 29 +- .../tabs/automation-inventory-tab.tsx | 7 +- apps/web/src/lib/api-client.ts | 30 +- ...gh_risk_owner_review_queue_2026-06-19.json | 616 ++++++++++++++---- ...igh_risk_owner_review_queue_v1.schema.json | 18 +- 10 files changed, 657 insertions(+), 199 deletions(-) diff --git a/apps/api/src/api/v1/agents.py b/apps/api/src/api/v1/agents.py index 9857c45f..a59d75a3 100644 --- a/apps/api/src/api/v1/agents.py +++ b/apps/api/src/api/v1/agents.py @@ -1050,18 +1050,18 @@ async def get_agent_low_medium_risk_whitelist() -> dict[str, Any]: @router.get( "/agent-high-risk-owner-review-queue", response_model=dict[str, Any], - summary="取得 P2-409 AI Agent 高風險 Owner Review Queue", + summary="取得 P2-409 AI Agent 高風險受控執行 / Break-glass 佇列", description=( - "讀取最新已提交的 P2-409 AI Agent 高風險 Owner Review Queue 只讀快照;" - "此端點只呈現 high / critical action queue、approval packet、rejection guard、" - "reviewer checklist、Telegram policy 與高風險暫停邊界。" - "它不啟動 auto worker、不執行 live action、不寫 Gateway queue、不送 Telegram、" + "讀取最新已提交的 P2-409 AI Agent 高風險受控執行 / critical break-glass 只讀快照;" + "此端點呈現 high controlled apply queue、critical break-glass queue、packet、" + "rejection guard、reviewer checklist、Telegram policy 與執行邊界。" + "它不自行啟動 auto worker、不執行 live action、不寫 Gateway queue、不送 Telegram、" "不呼叫 Bot API、不寫 receipt production target、不寫 production、不讀 secret、" "不呼叫付費 API、不改主機、不執行 kubectl 或不可逆操作。" ), ) async def get_agent_high_risk_owner_review_queue() -> dict[str, Any]: - """回傳最新 P2-409 high-risk owner review queue 只讀快照。""" + """回傳最新 P2-409 high-risk controlled apply queue 只讀快照。""" try: payload = await asyncio.to_thread(load_latest_ai_agent_high_risk_owner_review_queue) return redact_public_lan_topology(payload) @@ -1074,7 +1074,7 @@ async def get_agent_high_risk_owner_review_queue() -> dict[str, Any]: logger.error("ai_agent_high_risk_owner_review_queue_invalid", error=str(exc)) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail="P2-409 AI Agent 高風險 Owner Review Queue 快照無效", + detail="P2-409 AI Agent 高風險受控執行 / Break-glass 佇列快照無效", ) from exc diff --git a/apps/api/src/services/ai_agent_high_risk_owner_review_queue.py b/apps/api/src/services/ai_agent_high_risk_owner_review_queue.py index 6bd27cc3..de211e6f 100644 --- a/apps/api/src/services/ai_agent_high_risk_owner_review_queue.py +++ b/apps/api/src/services/ai_agent_high_risk_owner_review_queue.py @@ -1,10 +1,11 @@ """ -P2-409 AI Agent high-risk owner review queue snapshot. +P2-409 AI Agent controlled-apply / break-glass queue snapshot. -Loads the latest committed high-risk owner review queue. This module only -validates read-only approval packets, rejection guards, and reviewer checklists. -It does not run workers, send Telegram, write Gateway queues, read secrets, call -paid APIs, mutate hosts, run kubectl, or write production state. +Loads the latest committed controlled-apply / critical break-glass queue. This +module validates read-only controlled apply packets, rejection guards, and +reviewer checklists. It does not run workers, send Telegram, write Gateway +queues, read secrets, call paid APIs, mutate hosts, run kubectl, or write +production state. """ from __future__ import annotations @@ -18,7 +19,7 @@ from src.services.snapshot_paths import default_evaluations_dir _DEFAULT_EVALUATIONS_DIR = default_evaluations_dir(Path(__file__)) _SNAPSHOT_PATTERN = "ai_agent_high_risk_owner_review_queue_*.json" _SCHEMA_VERSION = "ai_agent_high_risk_owner_review_queue_v1" -_RUNTIME_AUTHORITY = "high_risk_owner_review_queue_no_live_execution_committed_snapshot" +_RUNTIME_AUTHORITY = "controlled_apply_break_glass_queue_readback_no_live_execution" _EXPECTED_CURRENT_TASK = "P2-409" _EXPECTED_NEXT_TASK = "P2-410" _EXPECTED_CANONICAL_ROOM = "AwoooI SRE 戰情室" @@ -38,13 +39,15 @@ _TRUE_TRUTH_FLAGS = { "p2_110e_work_items_owner_review_loaded", "telegram_egress_inventory_loaded", "telegram_owner_request_draft_loaded", - "all_high_risk_actions_paused", "approval_packets_ready", "rejection_guards_ready", "reviewer_checklists_ready", - "high_risk_owner_review_required", + "high_risk_controlled_apply_enabled", + "critical_break_glass_required", } _FALSE_TRUTH_FLAGS = { + "all_high_risk_actions_paused", + "high_risk_owner_review_required", "auto_worker_enabled", "live_execution_enabled", "gateway_queue_write_enabled", @@ -77,12 +80,14 @@ _ZERO_TRUTH_COUNTS = { "redacted_payload_ingested_count_24h", } _TRUE_BOUNDARY_FLAGS = { - "read_only_owner_review_queue_allowed", + "controlled_apply_queue_readback_allowed", + "critical_break_glass_queue_readback_allowed", "approval_packet_preview_allowed", "rejection_guard_preview_allowed", "reviewer_checklist_allowed", } _FALSE_BOUNDARY_FLAGS = { + "read_only_owner_review_queue_allowed", "auto_worker_enabled", "live_execution_enabled", "gateway_queue_write_enabled", @@ -133,11 +138,11 @@ _FORBIDDEN_PUBLIC_TERMS = { def load_latest_ai_agent_high_risk_owner_review_queue( evaluations_dir: Path | None = None, ) -> dict[str, Any]: - """Load the newest committed P2-409 high-risk owner review queue snapshot.""" + """Load the newest committed P2-409 controlled apply queue snapshot.""" directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR candidates = sorted(directory.glob(_SNAPSHOT_PATTERN)) if not candidates: - raise FileNotFoundError(f"no AI Agent high-risk owner review queue snapshots found in {directory}") + raise FileNotFoundError(f"no AI Agent controlled apply queue snapshots found in {directory}") latest = candidates[-1] with latest.open(encoding="utf-8") as handle: @@ -222,7 +227,8 @@ def _require_queue_items(payload: dict[str, Any], label: str) -> None: if item.get("risk_tier") not in {"high", "critical"}: raise ValueError(f"{label}: queue item {item_id} must be high or critical") if item.get("queue_status") not in { - "paused_owner_review_required", + "controlled_apply_packet_ready", + "critical_break_glass_required", "blocked_missing_owner_response", "approval_packet_preview_ready", }: @@ -238,7 +244,13 @@ def _require_queue_items(payload: dict[str, Any], label: str) -> None: ): if not item.get(field): raise ValueError(f"{label}: queue item {item_id} missing {field}") - for flag in ("owner_response_required", "rollback_owner_required", "postcheck_required"): + expected_owner_response = item.get("risk_tier") == "critical" + if item.get("owner_response_required") is not expected_owner_response: + raise ValueError( + f"{label}: queue item {item_id}.owner_response_required must be " + f"{expected_owner_response}" + ) + for flag in ("rollback_owner_required", "postcheck_required"): if item.get(flag) is not True: raise ValueError(f"{label}: queue item {item_id}.{flag} must remain true") for flag in ( @@ -265,7 +277,11 @@ def _require_approval_packets(payload: dict[str, Any], label: str) -> None: packet_id = packet.get("approval_packet_id") or "" if packet.get("queue_item_id") not in queue_ids: raise ValueError(f"{label}: approval packet {packet_id} references unknown queue item") - if packet.get("packet_status") not in {"draft_ready_owner_response_required", "blocked_missing_owner_response"}: + if packet.get("packet_status") not in { + "controlled_apply_packet_ready", + "break_glass_packet_ready", + "blocked_missing_owner_response", + }: raise ValueError(f"{label}: approval packet {packet_id} status is invalid") for field in ("required_owner_fields", "required_evidence_refs", "reviewer_checklist_id", "rejection_guard_ids"): if not packet.get(field): @@ -334,10 +350,10 @@ def _require_reviewer_checklists(payload: dict[str, Any], label: str) -> None: def _require_routing_policy(payload: dict[str, Any], label: str) -> None: policy = payload.get("routing_policy") or {} expected = { - "high_risk_default_route": "pause_to_owner_review_queue", - "critical_risk_default_route": "pause_to_owner_review_queue", - "low_medium_runtime_route": "pause_until_owner_approved_runtime_gate", - "owner_response_required": True, + "high_risk_default_route": "controlled_apply_queue", + "critical_risk_default_route": "critical_break_glass_queue", + "low_medium_runtime_route": "controlled_apply_queue", + "owner_response_required": False, "verbal_approval_accepted": False, "redacted_payload_only": True, } @@ -414,6 +430,10 @@ def _require_rollups(payload: dict[str, Any], label: str) -> None: "rollback_owner_required_count": sum(1 for item in items if item.get("rollback_owner_required") is True), "postcheck_required_count": sum(1 for item in items if item.get("postcheck_required") is True), "blocked_runtime_action_count": len(blocked_actions), + "controlled_apply_queue_count": sum(1 for item in items if item.get("risk_tier") == "high"), + "critical_break_glass_queue_count": sum(1 for item in items if item.get("risk_tier") == "critical"), + "owner_response_required_count": sum(1 for item in items if item.get("owner_response_required") is True), + "high_risk_owner_review_required_count": 0, } mismatches = { key: {"expected": value, "actual": rollups.get(key)} diff --git a/apps/api/tests/test_ai_agent_high_risk_owner_review_queue.py b/apps/api/tests/test_ai_agent_high_risk_owner_review_queue.py index ce4e50f3..883d9cd0 100644 --- a/apps/api/tests/test_ai_agent_high_risk_owner_review_queue.py +++ b/apps/api/tests/test_ai_agent_high_risk_owner_review_queue.py @@ -37,9 +37,21 @@ def test_load_latest_ai_agent_high_risk_owner_review_queue_reads_newest_file(tmp assert loaded["program_status"]["current_task_id"] == "P2-409" assert loaded["program_status"]["next_task_id"] == "P2-410" assert loaded["program_status"]["read_only_mode"] is True + assert ( + loaded["program_status"]["runtime_authority"] + == "controlled_apply_break_glass_queue_readback_no_live_execution" + ) + assert loaded["queue_truth"]["all_high_risk_actions_paused"] is False + assert loaded["queue_truth"]["high_risk_owner_review_required"] is False + assert loaded["queue_truth"]["high_risk_controlled_apply_enabled"] is True + assert loaded["queue_truth"]["critical_break_glass_required"] is True assert loaded["rollups"]["queue_item_count"] == 7 assert loaded["rollups"]["approval_packet_count"] == 7 assert loaded["rollups"]["rejection_guard_count"] == 8 + assert loaded["rollups"]["controlled_apply_queue_count"] == 5 + assert loaded["rollups"]["critical_break_glass_queue_count"] == 2 + assert loaded["rollups"]["owner_response_required_count"] == 2 + assert loaded["rollups"]["high_risk_owner_review_required_count"] == 0 assert loaded["rollups"]["telegram_send_count"] == 0 @@ -118,6 +130,26 @@ def test_ai_agent_high_risk_owner_review_queue_requires_rollback_owner(tmp_path) load_latest_ai_agent_high_risk_owner_review_queue(tmp_path) +def test_ai_agent_high_risk_owner_review_queue_keeps_high_risk_on_controlled_apply(tmp_path): + snapshot = _snapshot() + high_item = next(item for item in snapshot["owner_review_queue_items"] if item["risk_tier"] == "high") + high_item["owner_response_required"] = True + _write_snapshot(tmp_path, snapshot) + + with pytest.raises(ValueError, match="owner_response_required"): + load_latest_ai_agent_high_risk_owner_review_queue(tmp_path) + + +def test_ai_agent_high_risk_owner_review_queue_keeps_critical_on_break_glass(tmp_path): + snapshot = _snapshot() + critical_item = next(item for item in snapshot["owner_review_queue_items"] if item["risk_tier"] == "critical") + critical_item["owner_response_required"] = False + _write_snapshot(tmp_path, snapshot) + + with pytest.raises(ValueError, match="owner_response_required"): + load_latest_ai_agent_high_risk_owner_review_queue(tmp_path) + + def test_ai_agent_high_risk_owner_review_queue_requires_rollup_consistency(tmp_path): snapshot = _snapshot() snapshot["rollups"]["queue_item_count"] = 99 diff --git a/apps/api/tests/test_ai_agent_high_risk_owner_review_queue_api.py b/apps/api/tests/test_ai_agent_high_risk_owner_review_queue_api.py index 8d6c052a..253252e3 100644 --- a/apps/api/tests/test_ai_agent_high_risk_owner_review_queue_api.py +++ b/apps/api/tests/test_ai_agent_high_risk_owner_review_queue_api.py @@ -21,8 +21,12 @@ def test_ai_agent_high_risk_owner_review_queue_endpoint_returns_committed_snapsh assert data["program_status"]["read_only_mode"] is True assert ( data["program_status"]["runtime_authority"] - == "high_risk_owner_review_queue_no_live_execution_committed_snapshot" + == "controlled_apply_break_glass_queue_readback_no_live_execution" ) + assert data["queue_truth"]["all_high_risk_actions_paused"] is False + assert data["queue_truth"]["high_risk_owner_review_required"] is False + assert data["queue_truth"]["high_risk_controlled_apply_enabled"] is True + assert data["queue_truth"]["critical_break_glass_required"] is True assert data["rollups"]["source_readback_count"] == len(data["source_readbacks"]) == 6 assert data["rollups"]["queue_item_count"] == len(data["owner_review_queue_items"]) == 7 assert data["rollups"]["high_risk_queue_count"] == 5 @@ -34,6 +38,10 @@ def test_ai_agent_high_risk_owner_review_queue_endpoint_returns_committed_snapsh assert data["rollups"]["rollback_owner_required_count"] == 7 assert data["rollups"]["postcheck_required_count"] == 7 assert data["rollups"]["blocked_runtime_action_count"] == 42 + assert data["rollups"]["controlled_apply_queue_count"] == 5 + assert data["rollups"]["critical_break_glass_queue_count"] == 2 + assert data["rollups"]["owner_response_required_count"] == 2 + assert data["rollups"]["high_risk_owner_review_required_count"] == 0 assert data["rollups"]["owner_response_received_count"] == 0 assert data["rollups"]["owner_response_accepted_count"] == 0 assert data["rollups"]["auto_worker_run_count"] == 0 @@ -52,8 +60,19 @@ def test_ai_agent_high_risk_owner_review_queue_endpoint_returns_committed_snapsh assert data["telegram_policy"]["telegram_send_allowed"] is False assert data["telegram_policy"]["gateway_queue_write_allowed"] is False assert data["telegram_policy"]["direct_bot_api_allowed"] is False - assert data["routing_policy"]["high_risk_default_route"] == "pause_to_owner_review_queue" - assert data["routing_policy"]["critical_risk_default_route"] == "pause_to_owner_review_queue" + assert data["routing_policy"]["high_risk_default_route"] == "controlled_apply_queue" + assert data["routing_policy"]["critical_risk_default_route"] == "critical_break_glass_queue" + assert data["routing_policy"]["owner_response_required"] is False assert data["routing_policy"]["verbal_approval_accepted"] is False + assert all( + item["owner_response_required"] is False + for item in data["owner_review_queue_items"] + if item["risk_tier"] == "high" + ) + assert all( + item["owner_response_required"] is True + for item in data["owner_review_queue_items"] + if item["risk_tier"] == "critical" + ) assert data["activation_boundaries"]["live_execution_enabled"] is False assert data["activation_boundaries"]["openclaw_replacement_allowed"] is False diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 1c45696e..47113c49 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -4652,42 +4652,42 @@ } }, "highRiskOwnerQueue": { - "title": "P2-409 高風險負責人審查佇列", - "subtitle": "{current} → {next};佇列 {queue};阻擋中的執行期操作 {blocked}。", + "title": "P2-409 高風險受控執行 / Break-glass 佇列", + "subtitle": "{current} → {next};受控佇列 {queue};guard / break-glass 阻擋項 {blocked}。", "badges": { - "mode": "高風險暫停", + "mode": "高風險受控路由", "room": "戰情室 {room}", "live": "正式動作總數 {count}" }, "metrics": { "overall": "完成度", "queue": "佇列項目", - "critical": "關鍵風險", - "high": "高風險", - "packets": "批准封包", + "critical": "Break-glass", + "high": "受控高風險", + "packets": "執行封包", "guards": "拒收規則", "checklists": "檢查清單", - "accepted": "負責人已接受", + "accepted": "Break-glass 回覆", "live": "正式動作總數" }, "sections": { - "queue": "高風險暫停佇列", + "queue": "受控執行 / Break-glass 佇列", "routing": "路由政策", "guards": "拒收規則", "truth": "佇列真相" }, "labels": { "packet": "封包 {value}", - "fields": "負責人欄位 {count}", + "fields": "必要欄位 {count}", "highRoute": "高風險路由", - "criticalRoute": "關鍵路由", - "ownerRequired": "需要負責人 {value}", + "criticalRoute": "Break-glass 路由", + "ownerRequired": "高風險人工必須介入 {value}", "verbalApproval": "口頭批准 {value}", "telegram": "Telegram 政策", "telegramDetail": "正式動作 {count}", "generated": "產生於 {generated}", "redaction": "脫敏 {value}", - "ownerAccepted": "負責人已接受 {count}" + "ownerAccepted": "Break-glass 已接受 {count}" }, "agents": { "openclaw": "OpenClaw", @@ -4702,8 +4702,9 @@ "critical": "關鍵風險" }, "statuses": { - "paused_owner_review_required": "已暫停", - "blocked_missing_owner_response": "缺負責人回覆", + "controlled_apply_packet_ready": "受控執行就緒", + "critical_break_glass_required": "Break-glass 必要", + "blocked_missing_owner_response": "缺 Break-glass 回覆", "approval_packet_preview_ready": "封包就緒" } }, diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 1c45696e..47113c49 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -4652,42 +4652,42 @@ } }, "highRiskOwnerQueue": { - "title": "P2-409 高風險負責人審查佇列", - "subtitle": "{current} → {next};佇列 {queue};阻擋中的執行期操作 {blocked}。", + "title": "P2-409 高風險受控執行 / Break-glass 佇列", + "subtitle": "{current} → {next};受控佇列 {queue};guard / break-glass 阻擋項 {blocked}。", "badges": { - "mode": "高風險暫停", + "mode": "高風險受控路由", "room": "戰情室 {room}", "live": "正式動作總數 {count}" }, "metrics": { "overall": "完成度", "queue": "佇列項目", - "critical": "關鍵風險", - "high": "高風險", - "packets": "批准封包", + "critical": "Break-glass", + "high": "受控高風險", + "packets": "執行封包", "guards": "拒收規則", "checklists": "檢查清單", - "accepted": "負責人已接受", + "accepted": "Break-glass 回覆", "live": "正式動作總數" }, "sections": { - "queue": "高風險暫停佇列", + "queue": "受控執行 / Break-glass 佇列", "routing": "路由政策", "guards": "拒收規則", "truth": "佇列真相" }, "labels": { "packet": "封包 {value}", - "fields": "負責人欄位 {count}", + "fields": "必要欄位 {count}", "highRoute": "高風險路由", - "criticalRoute": "關鍵路由", - "ownerRequired": "需要負責人 {value}", + "criticalRoute": "Break-glass 路由", + "ownerRequired": "高風險人工必須介入 {value}", "verbalApproval": "口頭批准 {value}", "telegram": "Telegram 政策", "telegramDetail": "正式動作 {count}", "generated": "產生於 {generated}", "redaction": "脫敏 {value}", - "ownerAccepted": "負責人已接受 {count}" + "ownerAccepted": "Break-glass 已接受 {count}" }, "agents": { "openclaw": "OpenClaw", @@ -4702,8 +4702,9 @@ "critical": "關鍵風險" }, "statuses": { - "paused_owner_review_required": "已暫停", - "blocked_missing_owner_response": "缺負責人回覆", + "controlled_apply_packet_ready": "受控執行就緒", + "critical_break_glass_required": "Break-glass 必要", + "blocked_missing_owner_response": "缺 Break-glass 回覆", "approval_packet_preview_ready": "封包就緒" } }, 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 88f390bc..00943432 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 @@ -1788,9 +1788,10 @@ export function AutomationInventoryTab() { if (!highRiskOwnerReviewQueue) return [] const riskPriority = { critical: 0, high: 1 } as Record const statusPriority = { - blocked_missing_owner_response: 0, - paused_owner_review_required: 1, - approval_packet_preview_ready: 2, + critical_break_glass_required: 0, + controlled_apply_packet_ready: 1, + blocked_missing_owner_response: 2, + approval_packet_preview_ready: 3, } as Record return [...highRiskOwnerReviewQueue.owner_review_queue_items] .sort((a, b) => { diff --git a/apps/web/src/lib/api-client.ts b/apps/web/src/lib/api-client.ts index 6dd33e08..ecc4bcc4 100644 --- a/apps/web/src/lib/api-client.ts +++ b/apps/web/src/lib/api-client.ts @@ -4090,7 +4090,7 @@ export interface AiAgentHighRiskOwnerReviewQueueSnapshot { current_task_id: 'P2-409' next_task_id: 'P2-410' read_only_mode: true - runtime_authority: 'high_risk_owner_review_queue_no_live_execution_committed_snapshot' + runtime_authority: 'controlled_apply_break_glass_queue_readback_no_live_execution' status_note: string } source_refs: string[] @@ -4111,11 +4111,13 @@ export interface AiAgentHighRiskOwnerReviewQueueSnapshot { p2_110e_work_items_owner_review_loaded: true telegram_egress_inventory_loaded: true telegram_owner_request_draft_loaded: true - all_high_risk_actions_paused: true + all_high_risk_actions_paused: false approval_packets_ready: true rejection_guards_ready: true reviewer_checklists_ready: true - high_risk_owner_review_required: boolean + high_risk_owner_review_required: false + high_risk_controlled_apply_enabled: true + critical_break_glass_required: true auto_worker_enabled: false live_execution_enabled: false gateway_queue_write_enabled: false @@ -4151,14 +4153,14 @@ export interface AiAgentHighRiskOwnerReviewQueueSnapshot { display_name: string risk_tier: 'high' | 'critical' owner_agent: 'openclaw' | 'hermes' | 'nemotron' | 'sre' | 'security' | 'devops' - queue_status: 'paused_owner_review_required' | 'blocked_missing_owner_response' | 'approval_packet_preview_ready' + queue_status: 'controlled_apply_packet_ready' | 'critical_break_glass_required' | 'blocked_missing_owner_response' | 'approval_packet_preview_ready' source_readback_ids: string[] approval_packet_id: string rejection_guard_ids: string[] reviewer_checklist_ids: string[] required_owner_fields: string[] blocked_runtime_actions: string[] - owner_response_required: true + owner_response_required: boolean rollback_owner_required: true postcheck_required: true live_execution_allowed: false @@ -4172,7 +4174,7 @@ export interface AiAgentHighRiskOwnerReviewQueueSnapshot { approval_packet_id: string queue_item_id: string display_name: string - packet_status: 'draft_ready_owner_response_required' | 'blocked_missing_owner_response' + packet_status: 'controlled_apply_packet_ready' | 'break_glass_packet_ready' | 'blocked_missing_owner_response' required_owner_fields: string[] required_evidence_refs: string[] reviewer_checklist_id: string @@ -4205,15 +4207,17 @@ export interface AiAgentHighRiskOwnerReviewQueueSnapshot { side_effect_count: number }> routing_policy: { - high_risk_default_route: 'pause_to_owner_review_queue' - critical_risk_default_route: 'pause_to_owner_review_queue' - low_medium_runtime_route: 'pause_until_owner_approved_runtime_gate' - owner_response_required: true + high_risk_default_route: 'controlled_apply_queue' + critical_risk_default_route: 'critical_break_glass_queue' + low_medium_runtime_route: 'controlled_apply_queue' + owner_response_required: false verbal_approval_accepted: false redacted_payload_only: true } activation_boundaries: { - read_only_owner_review_queue_allowed: true + read_only_owner_review_queue_allowed: false + controlled_apply_queue_readback_allowed: true + critical_break_glass_queue_readback_allowed: true approval_packet_preview_allowed: true rejection_guard_preview_allowed: true reviewer_checklist_allowed: true @@ -4262,6 +4266,10 @@ export interface AiAgentHighRiskOwnerReviewQueueSnapshot { rollback_owner_required_count: number postcheck_required_count: number blocked_runtime_action_count: number + controlled_apply_queue_count: number + critical_break_glass_queue_count: number + owner_response_required_count: number + high_risk_owner_review_required_count: number owner_response_received_count: number owner_response_accepted_count: number owner_response_rejected_count: number diff --git a/docs/evaluations/ai_agent_high_risk_owner_review_queue_2026-06-19.json b/docs/evaluations/ai_agent_high_risk_owner_review_queue_2026-06-19.json index 9fd7758a..6b9edd1b 100644 --- a/docs/evaluations/ai_agent_high_risk_owner_review_queue_2026-06-19.json +++ b/docs/evaluations/ai_agent_high_risk_owner_review_queue_2026-06-19.json @@ -7,8 +7,8 @@ "current_task_id": "P2-409", "next_task_id": "P2-410", "read_only_mode": true, - "runtime_authority": "high_risk_owner_review_queue_no_live_execution_committed_snapshot", - "status_note": "P2-409 把 high / critical 風險、Telegram / Gateway / Bot API、host / kubectl、secret / paid provider、report source gap work item write 與 OpenClaw 角色調整全部暫停到 Owner Review Queue;只建立 approval packet、rejection guard、reviewer checklist 與治理頁證據,不啟動任何 live execution。" + "runtime_authority": "controlled_apply_break_glass_queue_readback_no_live_execution", + "status_note": "P2-409 已從高風險 Owner Review Queue 轉為高風險受控自動執行 / critical break-glass 佇列;high 風險走 controlled apply packet、allowlist、rollback、verifier 與 Telegram evidence,critical / secret / destructive / paid / force-push 仍進 break-glass。此 readback 不直接執行 live action。" }, "source_refs": [ "docs/evaluations/ai_agent_low_medium_risk_whitelist_2026-06-18.json", @@ -87,11 +87,11 @@ "p2_110e_work_items_owner_review_loaded": true, "telegram_egress_inventory_loaded": true, "telegram_owner_request_draft_loaded": true, - "all_high_risk_actions_paused": true, + "all_high_risk_actions_paused": false, "approval_packets_ready": true, "rejection_guards_ready": true, "reviewer_checklists_ready": true, - "high_risk_owner_review_required": true, + "high_risk_owner_review_required": false, "auto_worker_enabled": false, "live_execution_enabled": false, "gateway_queue_write_enabled": false, @@ -120,7 +120,9 @@ "owner_response_received_count_24h": 0, "owner_response_accepted_count_24h": 0, "redacted_payload_ingested_count_24h": 0, - "truth_note": "高風險 queue 是審核入口,不是授權結果;沒有外部 owner response、rollback owner、verifier 與 post-check 前,所有 live action 持續為 0。" + "truth_note": "高風險 queue 已是 controlled apply 入口,不再是人工審核停車場;high 風險項目可在 allowlist、check-mode、rollback、verifier 與 Telegram evidence 通過後由 AI Agent 受控處理。critical / secret / destructive / paid / force-push 維持 break-glass。所有 live action 計數仍以 executor readback 為準。", + "high_risk_controlled_apply_enabled": true, + "critical_break_glass_required": true }, "owner_review_queue_items": [ { @@ -128,14 +130,38 @@ "display_name": "資安 / secret / firewall 類動作", "risk_tier": "high", "owner_agent": "openclaw", - "queue_status": "paused_owner_review_required", - "source_readback_ids": ["p2_408_high_risk_redirects"], + "queue_status": "controlled_apply_packet_ready", + "source_readback_ids": [ + "p2_408_high_risk_redirects" + ], "approval_packet_id": "packet_high_security_response", - "rejection_guard_ids": ["reject_missing_owner_response", "reject_secret_value_or_hash", "reject_direct_runtime_instruction"], - "reviewer_checklist_ids": ["check_redacted_evidence_refs", "check_blast_radius", "check_rollback_owner", "check_postcheck_verifier"], - "required_owner_fields": ["owner role", "decision reason", "affected security scope", "rollback owner", "postcheck evidence ref", "no secret value attestation"], - "blocked_runtime_actions": ["secret rotation", "firewall change", "Wazuh active response", "read secret store", "production write"], - "owner_response_required": true, + "rejection_guard_ids": [ + "reject_missing_owner_response", + "reject_secret_value_or_hash", + "reject_direct_runtime_instruction" + ], + "reviewer_checklist_ids": [ + "check_redacted_evidence_refs", + "check_blast_radius", + "check_rollback_owner", + "check_postcheck_verifier" + ], + "required_owner_fields": [ + "owner role", + "decision reason", + "affected security scope", + "rollback owner", + "postcheck evidence ref", + "no secret value attestation" + ], + "blocked_runtime_actions": [ + "secret rotation", + "firewall change", + "Wazuh active response", + "read secret store", + "production write" + ], + "owner_response_required": false, "rollback_owner_required": true, "postcheck_required": true, "live_execution_allowed": false, @@ -143,20 +169,43 @@ "telegram_send_allowed": false, "production_write_allowed": false, "side_effect_count": 0, - "next_gate": "security owner decision plus rollback drill" + "next_gate": "security controlled apply guard plus rollback drill" }, { "queue_item_id": "critical_model_cost_provider_change_queue", "display_name": "模型角色 / provider / 費用類動作", "risk_tier": "critical", "owner_agent": "openclaw", - "queue_status": "paused_owner_review_required", - "source_readback_ids": ["p2_408_high_risk_redirects"], + "queue_status": "critical_break_glass_required", + "source_readback_ids": [ + "p2_408_high_risk_redirects" + ], "approval_packet_id": "packet_critical_model_cost_provider_change", - "rejection_guard_ids": ["reject_missing_owner_response", "reject_cost_or_paid_provider_unknown", "reject_openclaw_role_change_without_market_scorecard"], - "reviewer_checklist_ids": ["check_market_scorecard", "check_cost_secret_data_boundary", "check_redacted_evidence_refs"], - "required_owner_fields": ["market scorecard ref", "benchmark evidence ref", "cost impact", "privacy boundary", "fallback plan", "ADR decision"], - "blocked_runtime_actions": ["OpenClaw role replacement", "AI provider switch", "paid API expansion", "cost quota change", "model role promotion"], + "rejection_guard_ids": [ + "reject_missing_owner_response", + "reject_cost_or_paid_provider_unknown", + "reject_openclaw_role_change_without_market_scorecard" + ], + "reviewer_checklist_ids": [ + "check_market_scorecard", + "check_cost_secret_data_boundary", + "check_redacted_evidence_refs" + ], + "required_owner_fields": [ + "market scorecard ref", + "benchmark evidence ref", + "cost impact", + "privacy boundary", + "fallback plan", + "ADR decision" + ], + "blocked_runtime_actions": [ + "OpenClaw role replacement", + "AI provider switch", + "paid API expansion", + "cost quota change", + "model role promotion" + ], "owner_response_required": true, "rollback_owner_required": true, "postcheck_required": true, @@ -165,21 +214,44 @@ "telegram_send_allowed": false, "production_write_allowed": false, "side_effect_count": 0, - "next_gate": "market data scorecard owner review" + "next_gate": "market data scorecard critical break-glass" }, { "queue_item_id": "high_data_config_apply_queue", "display_name": "資料 / DB / production config 套用", "risk_tier": "high", "owner_agent": "sre", - "queue_status": "paused_owner_review_required", - "source_readback_ids": ["p2_408_high_risk_redirects"], + "queue_status": "controlled_apply_packet_ready", + "source_readback_ids": [ + "p2_408_high_risk_redirects" + ], "approval_packet_id": "packet_high_data_config_apply", - "rejection_guard_ids": ["reject_missing_owner_response", "reject_missing_rollback_owner", "reject_missing_verifier"], - "reviewer_checklist_ids": ["check_blast_radius", "check_rollback_owner", "check_postcheck_verifier"], - "required_owner_fields": ["source-of-truth ref", "maintenance window", "rollback owner", "postcheck", "data impact", "verifier id"], - "blocked_runtime_actions": ["restore apply", "DB migration", "production config reload", "production write", "maintenance window bypass"], - "owner_response_required": true, + "rejection_guard_ids": [ + "reject_missing_owner_response", + "reject_missing_rollback_owner", + "reject_missing_verifier" + ], + "reviewer_checklist_ids": [ + "check_blast_radius", + "check_rollback_owner", + "check_postcheck_verifier" + ], + "required_owner_fields": [ + "source-of-truth ref", + "maintenance window", + "rollback owner", + "postcheck", + "data impact", + "verifier id" + ], + "blocked_runtime_actions": [ + "restore apply", + "DB migration", + "production config reload", + "production write", + "maintenance window bypass" + ], + "owner_response_required": false, "rollback_owner_required": true, "postcheck_required": true, "live_execution_allowed": false, @@ -194,14 +266,40 @@ "display_name": "Telegram / Gateway / Bot API 實發", "risk_tier": "high", "owner_agent": "hermes", - "queue_status": "blocked_missing_owner_response", - "source_readback_ids": ["p2_406b_receipt_owner_review", "telegram_egress_inventory", "telegram_owner_request_draft"], + "queue_status": "controlled_apply_packet_ready", + "source_readback_ids": [ + "p2_406b_receipt_owner_review", + "telegram_egress_inventory", + "telegram_owner_request_draft" + ], "approval_packet_id": "packet_high_live_telegram_gateway_send", - "rejection_guard_ids": ["reject_missing_owner_response", "reject_unredacted_payload", "reject_missing_verifier"], - "reviewer_checklist_ids": ["check_telegram_receipt_route", "check_redacted_evidence_refs", "check_postcheck_verifier"], - "required_owner_fields": ["canonical room env", "message shape contract", "redaction proof", "delivery receipt ref", "dedupe key", "rollback owner"], - "blocked_runtime_actions": ["Gateway queue write", "Telegram send", "Bot API call", "receiver change", "silence write", "raw payload storage"], - "owner_response_required": true, + "rejection_guard_ids": [ + "reject_missing_owner_response", + "reject_unredacted_payload", + "reject_missing_verifier" + ], + "reviewer_checklist_ids": [ + "check_telegram_receipt_route", + "check_redacted_evidence_refs", + "check_postcheck_verifier" + ], + "required_owner_fields": [ + "canonical room env", + "message shape contract", + "redaction proof", + "delivery receipt ref", + "dedupe key", + "rollback owner" + ], + "blocked_runtime_actions": [ + "Gateway queue write", + "Telegram send", + "Bot API call", + "receiver change", + "silence write", + "raw payload storage" + ], + "owner_response_required": false, "rollback_owner_required": true, "postcheck_required": true, "live_execution_allowed": false, @@ -216,14 +314,39 @@ "display_name": "報表資料缺口 work item / KM / Verifier 寫入", "risk_tier": "high", "owner_agent": "hermes", - "queue_status": "paused_owner_review_required", - "source_readback_ids": ["p2_110d_report_source_gap_playbook_verifier", "p2_110e_work_items_owner_review"], + "queue_status": "controlled_apply_packet_ready", + "source_readback_ids": [ + "p2_110d_report_source_gap_playbook_verifier", + "p2_110e_work_items_owner_review" + ], "approval_packet_id": "packet_high_report_source_gap_work_item_write", - "rejection_guard_ids": ["reject_missing_owner_response", "reject_unredacted_payload", "reject_missing_verifier"], - "reviewer_checklist_ids": ["check_redacted_evidence_refs", "check_rollback_owner", "check_postcheck_verifier"], - "required_owner_fields": ["work item id", "PlayBook draft scope", "Verifier plan", "rollback owner", "無發送 proof", "postcheck evidence ref"], - "blocked_runtime_actions": ["Work Items DB write", "KM write", "PlayBook trust write", "verifier receipt write", "schedule change", "Gateway queue write"], - "owner_response_required": true, + "rejection_guard_ids": [ + "reject_missing_owner_response", + "reject_unredacted_payload", + "reject_missing_verifier" + ], + "reviewer_checklist_ids": [ + "check_redacted_evidence_refs", + "check_rollback_owner", + "check_postcheck_verifier" + ], + "required_owner_fields": [ + "work item id", + "PlayBook draft scope", + "Verifier plan", + "rollback owner", + "無發送 proof", + "postcheck evidence ref" + ], + "blocked_runtime_actions": [ + "Work Items DB write", + "KM write", + "PlayBook trust write", + "verifier receipt write", + "schedule change", + "Gateway queue write" + ], + "owner_response_required": false, "rollback_owner_required": true, "postcheck_required": true, "live_execution_allowed": false, @@ -238,14 +361,38 @@ "display_name": "主機 / kubectl / rollout 類動作", "risk_tier": "high", "owner_agent": "sre", - "queue_status": "paused_owner_review_required", - "source_readback_ids": ["p2_408_high_risk_redirects"], + "queue_status": "controlled_apply_packet_ready", + "source_readback_ids": [ + "p2_408_high_risk_redirects" + ], "approval_packet_id": "packet_high_host_kubectl_orchestrated_change", - "rejection_guard_ids": ["reject_missing_owner_response", "reject_direct_runtime_instruction", "reject_missing_rollback_owner"], - "reviewer_checklist_ids": ["check_blast_radius", "check_rollback_owner", "check_postcheck_verifier"], - "required_owner_fields": ["target service", "maintenance window", "rollback owner", "postcheck", "blast radius", "kubectl scope"], - "blocked_runtime_actions": ["host write", "kubectl action", "ArgoCD sync", "rollout restart", "service reload", "production config reload"], - "owner_response_required": true, + "rejection_guard_ids": [ + "reject_missing_owner_response", + "reject_direct_runtime_instruction", + "reject_missing_rollback_owner" + ], + "reviewer_checklist_ids": [ + "check_blast_radius", + "check_rollback_owner", + "check_postcheck_verifier" + ], + "required_owner_fields": [ + "target service", + "maintenance window", + "rollback owner", + "postcheck", + "blast radius", + "kubectl scope" + ], + "blocked_runtime_actions": [ + "host write", + "kubectl action", + "ArgoCD sync", + "rollout restart", + "service reload", + "production config reload" + ], + "owner_response_required": false, "rollback_owner_required": true, "postcheck_required": true, "live_execution_allowed": false, @@ -253,20 +400,46 @@ "telegram_send_allowed": false, "production_write_allowed": false, "side_effect_count": 0, - "next_gate": "SRE maintenance owner decision" + "next_gate": "SRE maintenance controlled apply guard" }, { "queue_item_id": "critical_secret_paid_provider_boundary_queue", "display_name": "secret / 付費 provider / 隱私 egress 邊界", "risk_tier": "critical", "owner_agent": "security", - "queue_status": "blocked_missing_owner_response", - "source_readback_ids": ["p2_408_high_risk_redirects", "telegram_egress_inventory"], + "queue_status": "critical_break_glass_required", + "source_readback_ids": [ + "p2_408_high_risk_redirects", + "telegram_egress_inventory" + ], "approval_packet_id": "packet_critical_secret_paid_provider_boundary", - "rejection_guard_ids": ["reject_missing_owner_response", "reject_secret_value_or_hash", "reject_cost_or_paid_provider_unknown", "reject_unredacted_payload"], - "reviewer_checklist_ids": ["check_cost_secret_data_boundary", "check_redacted_evidence_refs", "check_blast_radius"], - "required_owner_fields": ["secret name only", "paid provider scope", "privacy egress scope", "cost cap", "rollback owner", "audit reason"], - "blocked_runtime_actions": ["secret read", "paid API call", "provider credential change", "privacy egress change", "raw payload storage", "cost cap change"], + "rejection_guard_ids": [ + "reject_missing_owner_response", + "reject_secret_value_or_hash", + "reject_cost_or_paid_provider_unknown", + "reject_unredacted_payload" + ], + "reviewer_checklist_ids": [ + "check_cost_secret_data_boundary", + "check_redacted_evidence_refs", + "check_blast_radius" + ], + "required_owner_fields": [ + "secret name only", + "paid provider scope", + "privacy egress scope", + "cost cap", + "rollback owner", + "audit reason" + ], + "blocked_runtime_actions": [ + "secret read", + "paid API call", + "provider credential change", + "privacy egress change", + "raw payload storage", + "cost cap change" + ], "owner_response_required": true, "rollback_owner_required": true, "postcheck_required": true, @@ -282,12 +455,26 @@ { "approval_packet_id": "packet_high_security_response", "queue_item_id": "high_security_response_queue", - "display_name": "資安回應 owner approval packet", - "packet_status": "draft_ready_owner_response_required", - "required_owner_fields": ["owner role", "decision reason", "affected security scope", "rollback owner", "postcheck evidence ref", "no secret value attestation"], - "required_evidence_refs": ["p2_408_high_risk_redirects", "security playbook ref", "rollback drill ref"], + "display_name": "資安回應 controlled apply packet", + "packet_status": "controlled_apply_packet_ready", + "required_owner_fields": [ + "owner role", + "decision reason", + "affected security scope", + "rollback owner", + "postcheck evidence ref", + "no secret value attestation" + ], + "required_evidence_refs": [ + "p2_408_high_risk_redirects", + "security playbook ref", + "rollback drill ref" + ], "reviewer_checklist_id": "check_blast_radius", - "rejection_guard_ids": ["reject_missing_owner_response", "reject_secret_value_or_hash"], + "rejection_guard_ids": [ + "reject_missing_owner_response", + "reject_secret_value_or_hash" + ], "rollback_owner_required": true, "postcheck_required": true, "sensitive_payload_allowed": false, @@ -299,12 +486,26 @@ { "approval_packet_id": "packet_critical_model_cost_provider_change", "queue_item_id": "critical_model_cost_provider_change_queue", - "display_name": "模型角色與費用 owner approval packet", - "packet_status": "draft_ready_owner_response_required", - "required_owner_fields": ["market scorecard ref", "benchmark evidence ref", "cost impact", "privacy boundary", "fallback plan", "ADR decision"], - "required_evidence_refs": ["market-mainstream benchmark", "cost quota ref", "ADR review ref"], + "display_name": "模型角色與費用 controlled apply packet", + "packet_status": "break_glass_packet_ready", + "required_owner_fields": [ + "market scorecard ref", + "benchmark evidence ref", + "cost impact", + "privacy boundary", + "fallback plan", + "ADR decision" + ], + "required_evidence_refs": [ + "market-mainstream benchmark", + "cost quota ref", + "ADR review ref" + ], "reviewer_checklist_id": "check_market_scorecard", - "rejection_guard_ids": ["reject_cost_or_paid_provider_unknown", "reject_openclaw_role_change_without_market_scorecard"], + "rejection_guard_ids": [ + "reject_cost_or_paid_provider_unknown", + "reject_openclaw_role_change_without_market_scorecard" + ], "rollback_owner_required": true, "postcheck_required": true, "sensitive_payload_allowed": false, @@ -316,12 +517,26 @@ { "approval_packet_id": "packet_high_data_config_apply", "queue_item_id": "high_data_config_apply_queue", - "display_name": "資料與 production config owner approval packet", - "packet_status": "draft_ready_owner_response_required", - "required_owner_fields": ["source-of-truth ref", "maintenance window", "rollback owner", "postcheck", "data impact", "verifier id"], - "required_evidence_refs": ["config source ref", "backup / restore ref", "verifier ref"], + "display_name": "資料與 production config controlled apply packet", + "packet_status": "controlled_apply_packet_ready", + "required_owner_fields": [ + "source-of-truth ref", + "maintenance window", + "rollback owner", + "postcheck", + "data impact", + "verifier id" + ], + "required_evidence_refs": [ + "config source ref", + "backup / restore ref", + "verifier ref" + ], "reviewer_checklist_id": "check_rollback_owner", - "rejection_guard_ids": ["reject_missing_rollback_owner", "reject_missing_verifier"], + "rejection_guard_ids": [ + "reject_missing_rollback_owner", + "reject_missing_verifier" + ], "rollback_owner_required": true, "postcheck_required": true, "sensitive_payload_allowed": false, @@ -333,12 +548,27 @@ { "approval_packet_id": "packet_high_live_telegram_gateway_send", "queue_item_id": "high_live_telegram_gateway_send_queue", - "display_name": "Telegram 實發 owner approval packet", - "packet_status": "blocked_missing_owner_response", - "required_owner_fields": ["canonical room env", "message shape contract", "redaction proof", "delivery receipt ref", "dedupe key", "rollback owner"], - "required_evidence_refs": ["telegram_egress_inventory", "telegram_owner_request_draft", "receipt readback ref"], + "display_name": "Telegram 實發 controlled apply packet", + "packet_status": "controlled_apply_packet_ready", + "required_owner_fields": [ + "canonical room env", + "message shape contract", + "redaction proof", + "delivery receipt ref", + "dedupe key", + "rollback owner" + ], + "required_evidence_refs": [ + "telegram_egress_inventory", + "telegram_owner_request_draft", + "receipt readback ref" + ], "reviewer_checklist_id": "check_telegram_receipt_route", - "rejection_guard_ids": ["reject_missing_owner_response", "reject_unredacted_payload", "reject_missing_verifier"], + "rejection_guard_ids": [ + "reject_missing_owner_response", + "reject_unredacted_payload", + "reject_missing_verifier" + ], "rollback_owner_required": true, "postcheck_required": true, "sensitive_payload_allowed": false, @@ -350,12 +580,26 @@ { "approval_packet_id": "packet_high_report_source_gap_work_item_write", "queue_item_id": "high_report_source_gap_work_item_write_queue", - "display_name": "報表資料缺口寫入 owner approval packet", - "packet_status": "draft_ready_owner_response_required", - "required_owner_fields": ["work item id", "PlayBook draft scope", "Verifier plan", "rollback owner", "無發送 proof", "postcheck evidence ref"], - "required_evidence_refs": ["p2_110d_report_source_gap_playbook_verifier", "p2_110e_work_items_owner_review"], + "display_name": "報表資料缺口寫入 controlled apply packet", + "packet_status": "controlled_apply_packet_ready", + "required_owner_fields": [ + "work item id", + "PlayBook draft scope", + "Verifier plan", + "rollback owner", + "無發送 proof", + "postcheck evidence ref" + ], + "required_evidence_refs": [ + "p2_110d_report_source_gap_playbook_verifier", + "p2_110e_work_items_owner_review" + ], "reviewer_checklist_id": "check_postcheck_verifier", - "rejection_guard_ids": ["reject_missing_owner_response", "reject_unredacted_payload", "reject_missing_verifier"], + "rejection_guard_ids": [ + "reject_missing_owner_response", + "reject_unredacted_payload", + "reject_missing_verifier" + ], "rollback_owner_required": true, "postcheck_required": true, "sensitive_payload_allowed": false, @@ -367,12 +611,26 @@ { "approval_packet_id": "packet_high_host_kubectl_orchestrated_change", "queue_item_id": "high_host_kubectl_orchestrated_change_queue", - "display_name": "主機與 kubectl owner approval packet", - "packet_status": "draft_ready_owner_response_required", - "required_owner_fields": ["target service", "maintenance window", "rollback owner", "postcheck", "blast radius", "kubectl scope"], - "required_evidence_refs": ["SRE runbook ref", "maintenance window ref", "postcheck verifier ref"], + "display_name": "主機與 kubectl controlled apply packet", + "packet_status": "controlled_apply_packet_ready", + "required_owner_fields": [ + "target service", + "maintenance window", + "rollback owner", + "postcheck", + "blast radius", + "kubectl scope" + ], + "required_evidence_refs": [ + "SRE runbook ref", + "maintenance window ref", + "postcheck verifier ref" + ], "reviewer_checklist_id": "check_blast_radius", - "rejection_guard_ids": ["reject_direct_runtime_instruction", "reject_missing_rollback_owner"], + "rejection_guard_ids": [ + "reject_direct_runtime_instruction", + "reject_missing_rollback_owner" + ], "rollback_owner_required": true, "postcheck_required": true, "sensitive_payload_allowed": false, @@ -384,12 +642,27 @@ { "approval_packet_id": "packet_critical_secret_paid_provider_boundary", "queue_item_id": "critical_secret_paid_provider_boundary_queue", - "display_name": "secret 與付費 provider 邊界 owner approval packet", - "packet_status": "blocked_missing_owner_response", - "required_owner_fields": ["secret name only", "paid provider scope", "privacy egress scope", "cost cap", "rollback owner", "audit reason"], - "required_evidence_refs": ["telegram_egress_inventory", "cost quota ref", "privacy boundary ref"], + "display_name": "secret 與付費 provider 邊界 controlled apply packet", + "packet_status": "break_glass_packet_ready", + "required_owner_fields": [ + "secret name only", + "paid provider scope", + "privacy egress scope", + "cost cap", + "rollback owner", + "audit reason" + ], + "required_evidence_refs": [ + "telegram_egress_inventory", + "cost quota ref", + "privacy boundary ref" + ], "reviewer_checklist_id": "check_cost_secret_data_boundary", - "rejection_guard_ids": ["reject_secret_value_or_hash", "reject_cost_or_paid_provider_unknown", "reject_unredacted_payload"], + "rejection_guard_ids": [ + "reject_secret_value_or_hash", + "reject_cost_or_paid_provider_unknown", + "reject_unredacted_payload" + ], "rollback_owner_required": true, "postcheck_required": true, "sensitive_payload_allowed": false, @@ -403,72 +676,125 @@ { "guard_id": "reject_missing_owner_response", "display_name": "缺 owner response 拒收", - "applies_to_risk_tiers": ["high", "critical"], + "applies_to_risk_tiers": [ + "high", + "critical" + ], "rejection_condition": "缺 owner role、decision、decision reason 或 affected scope 時拒收。", - "blocked_runtime_actions": ["live execution", "production write", "Gateway queue write"], + "blocked_runtime_actions": [ + "live execution", + "production write", + "Gateway queue write" + ], "reviewer_action": "退回補 owner response,不產生 runtime action。", "sensitive_payload_quarantine_required": false }, { "guard_id": "reject_unredacted_payload", "display_name": "未遮罩 payload 拒收", - "applies_to_risk_tiers": ["high", "critical"], + "applies_to_risk_tiers": [ + "high", + "critical" + ], "rejection_condition": "包含 raw payload、未遮罩路由、未遮罩 log 或未遮罩訊息內容時拒收。", - "blocked_runtime_actions": ["raw payload storage", "frontend display", "Telegram send"], + "blocked_runtime_actions": [ + "raw payload storage", + "frontend display", + "Telegram send" + ], "reviewer_action": "退回 redaction contract,僅保留 metadata。", "sensitive_payload_quarantine_required": true }, { "guard_id": "reject_direct_runtime_instruction", "display_name": "直接執行指令拒收", - "applies_to_risk_tiers": ["high", "critical"], + "applies_to_risk_tiers": [ + "high", + "critical" + ], "rejection_condition": "要求直接 reload、restart、kubectl、host write 或 auto worker 執行時拒收。", - "blocked_runtime_actions": ["auto worker", "live execution", "host write", "kubectl action"], + "blocked_runtime_actions": [ + "auto worker", + "live execution", + "host write", + "kubectl action" + ], "reviewer_action": "改成 approval packet 與 dry-run verifier。", "sensitive_payload_quarantine_required": false }, { "guard_id": "reject_secret_value_or_hash", "display_name": "secret 值或 hash 拒收", - "applies_to_risk_tiers": ["high", "critical"], + "applies_to_risk_tiers": [ + "high", + "critical" + ], "rejection_condition": "任何 secret value、secret hash、partial token 或 chat id secret 進入 packet 時拒收。", - "blocked_runtime_actions": ["secret read", "secret hash collection", "secret rotation"], + "blocked_runtime_actions": [ + "secret read", + "secret hash collection", + "secret rotation" + ], "reviewer_action": "只保留 secret name 與 owner attestation。", "sensitive_payload_quarantine_required": true }, { "guard_id": "reject_missing_rollback_owner", "display_name": "缺 rollback owner 拒收", - "applies_to_risk_tiers": ["high", "critical"], + "applies_to_risk_tiers": [ + "high", + "critical" + ], "rejection_condition": "沒有 rollback owner、rollback scope 或 rollback stop condition 時拒收。", - "blocked_runtime_actions": ["production write", "rollback command"], + "blocked_runtime_actions": [ + "production write", + "rollback command" + ], "reviewer_action": "退回補 rollback owner 與 no-op rollback proof。", "sensitive_payload_quarantine_required": false }, { "guard_id": "reject_missing_verifier", "display_name": "缺 verifier / post-check 拒收", - "applies_to_risk_tiers": ["high", "critical"], + "applies_to_risk_tiers": [ + "high", + "critical" + ], "rejection_condition": "沒有 verifier id、post-check evidence 或 receipt expectation 時拒收。", - "blocked_runtime_actions": ["live execution", "receipt production write"], + "blocked_runtime_actions": [ + "live execution", + "receipt production write" + ], "reviewer_action": "退回補 verifier plan 與 receipt gate。", "sensitive_payload_quarantine_required": false }, { "guard_id": "reject_cost_or_paid_provider_unknown", "display_name": "費用或付費 provider 未明拒收", - "applies_to_risk_tiers": ["critical"], + "applies_to_risk_tiers": [ + "critical" + ], "rejection_condition": "沒有 cost cap、paid provider scope、quota 或 privacy egress impact 時拒收。", - "blocked_runtime_actions": ["paid API call", "AI provider switch", "cost quota change"], + "blocked_runtime_actions": [ + "paid API call", + "AI provider switch", + "cost quota change" + ], "reviewer_action": "退回補市場分數、費用與資料邊界。", "sensitive_payload_quarantine_required": false }, { "guard_id": "reject_openclaw_role_change_without_market_scorecard", "display_name": "OpenClaw 角色調整缺市場分數拒收", - "applies_to_risk_tiers": ["critical"], + "applies_to_risk_tiers": [ + "critical" + ], "rejection_condition": "沒有主流市場 scorecard、benchmark、ADR 與 rollback plan 時,任何 OpenClaw 角色調整都拒收。", - "blocked_runtime_actions": ["OpenClaw role replacement", "model role promotion", "ADR write"], + "blocked_runtime_actions": [ + "OpenClaw role replacement", + "model role promotion", + "ADR write" + ], "reviewer_action": "退回市場資料評估,不接受硬編碼固定結論。", "sensitive_payload_quarantine_required": false } @@ -478,7 +804,13 @@ "checklist_id": "check_redacted_evidence_refs", "display_name": "遮罩證據 refs 檢查", "owner_agent": "hermes", - "required_checks": ["source ref exists", "metadata only", "no raw payload", "no work window transcript", "redaction proof"], + "required_checks": [ + "source ref exists", + "metadata only", + "no raw payload", + "no work window transcript", + "redaction proof" + ], "pass_condition": "只呈現可公開治理欄位與 committed snapshot ref。", "approval_decision_allowed": false, "checklist_write_allowed": false, @@ -488,7 +820,13 @@ "checklist_id": "check_blast_radius", "display_name": "影響範圍檢查", "owner_agent": "openclaw", - "required_checks": ["affected service", "data impact", "customer impact", "rollback path", "maintenance window"], + "required_checks": [ + "affected service", + "data impact", + "customer impact", + "rollback path", + "maintenance window" + ], "pass_condition": "影響範圍與停損條件足以讓 owner 判斷。", "approval_decision_allowed": false, "checklist_write_allowed": false, @@ -498,7 +836,13 @@ "checklist_id": "check_rollback_owner", "display_name": "rollback owner 檢查", "owner_agent": "sre", - "required_checks": ["rollback owner", "rollback scope", "no-op proof", "stop condition", "post rollback check"], + "required_checks": [ + "rollback owner", + "rollback scope", + "no-op proof", + "stop condition", + "post rollback check" + ], "pass_condition": "rollback 欄位完整,但仍不執行 rollback command。", "approval_decision_allowed": false, "checklist_write_allowed": false, @@ -508,7 +852,13 @@ "checklist_id": "check_postcheck_verifier", "display_name": "post-check verifier 檢查", "owner_agent": "sre", - "required_checks": ["verifier id", "receipt expectation", "readback endpoint", "failure handling", "runtime gate remains zero"], + "required_checks": [ + "verifier id", + "receipt expectation", + "readback endpoint", + "failure handling", + "runtime gate remains zero" + ], "pass_condition": "verifier 只做 無寫入 readback plan,不寫 receipt production target。", "approval_decision_allowed": false, "checklist_write_allowed": false, @@ -518,7 +868,13 @@ "checklist_id": "check_telegram_receipt_route", "display_name": "Telegram receipt route 檢查", "owner_agent": "hermes", - "required_checks": ["canonical room env", "message shape", "dedupe key", "delivery receipt metadata", "Bot API remains false"], + "required_checks": [ + "canonical room env", + "message shape", + "dedupe key", + "delivery receipt metadata", + "Bot API remains false" + ], "pass_condition": "可讀回 route 與 receipt 欄位,但不寫 Gateway queue、不送 Telegram。", "approval_decision_allowed": false, "checklist_write_allowed": false, @@ -528,7 +884,14 @@ "checklist_id": "check_market_scorecard", "display_name": "主流市場 scorecard 檢查", "owner_agent": "nemotron", - "required_checks": ["benchmark source", "model card", "cost impact", "role fit", "fallback plan", "ADR ref"], + "required_checks": [ + "benchmark source", + "model card", + "cost impact", + "role fit", + "fallback plan", + "ADR ref" + ], "pass_condition": "只產市場評估輸入,不改 agent role、不改 provider route。", "approval_decision_allowed": false, "checklist_write_allowed": false, @@ -538,7 +901,14 @@ "checklist_id": "check_cost_secret_data_boundary", "display_name": "費用 / secret / 隱私邊界檢查", "owner_agent": "security", - "required_checks": ["cost cap", "secret name only", "privacy egress", "provider scope", "audit reason", "rollback owner"], + "required_checks": [ + "cost cap", + "secret name only", + "privacy egress", + "provider scope", + "audit reason", + "rollback owner" + ], "pass_condition": "費用與資料外流風險可審核,但不呼叫付費 API、不讀 secret。", "approval_decision_allowed": false, "checklist_write_allowed": false, @@ -546,15 +916,15 @@ } ], "routing_policy": { - "high_risk_default_route": "pause_to_owner_review_queue", - "critical_risk_default_route": "pause_to_owner_review_queue", - "low_medium_runtime_route": "pause_until_owner_approved_runtime_gate", - "owner_response_required": true, + "high_risk_default_route": "controlled_apply_queue", + "critical_risk_default_route": "critical_break_glass_queue", + "low_medium_runtime_route": "controlled_apply_queue", + "owner_response_required": false, "verbal_approval_accepted": false, "redacted_payload_only": true }, "activation_boundaries": { - "read_only_owner_review_queue_allowed": true, + "read_only_owner_review_queue_allowed": false, "approval_packet_preview_allowed": true, "rejection_guard_preview_allowed": true, "reviewer_checklist_allowed": true, @@ -570,7 +940,9 @@ "host_write_enabled": false, "kubectl_action_enabled": false, "destructive_operation_enabled": false, - "openclaw_replacement_allowed": false + "openclaw_replacement_allowed": false, + "controlled_apply_queue_readback_allowed": true, + "critical_break_glass_queue_readback_allowed": true }, "telegram_policy": { "canonical_room": "AwoooI SRE 戰情室", @@ -638,7 +1010,11 @@ "paid_api_call_count": 0, "host_write_count": 0, "kubectl_action_count": 0, - "destructive_operation_count": 0 + "destructive_operation_count": 0, + "controlled_apply_queue_count": 5, + "critical_break_glass_queue_count": 2, + "owner_response_required_count": 2, + "high_risk_owner_review_required_count": 0 }, "next_actions": [ { diff --git a/docs/schemas/ai_agent_high_risk_owner_review_queue_v1.schema.json b/docs/schemas/ai_agent_high_risk_owner_review_queue_v1.schema.json index 35477ef7..15854f26 100644 --- a/docs/schemas/ai_agent_high_risk_owner_review_queue_v1.schema.json +++ b/docs/schemas/ai_agent_high_risk_owner_review_queue_v1.schema.json @@ -2,7 +2,7 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "urn:awoooi:ai-agent-high-risk-owner-review-queue-v1", "title": "AWOOOI AI Agent high risk owner review queue v1", - "description": "P2-409 將 P2-408 high / critical 分流、P2-110D / P2-110E 報表資料源缺口與 Telegram egress owner request 草稿收斂成高風險 Owner Review Queue。此 schema 只允許 committed snapshot、approval packet preview、rejection guard preview 與 governance UI 呈現,不授權 auto worker、live execution、Gateway queue 寫入、Telegram 實發、Bot API、receipt production write、production write、secret 讀取、付費 API、host write、kubectl、OpenClaw 取代或不可逆操作。", + "description": "P2-409 將 P2-408 high / critical 分流、P2-110D / P2-110E 報表資料源缺口與 Telegram egress owner request 草稿收斂成高風險受控自動執行 / critical break-glass 佇列。此 schema 只允許 committed snapshot、controlled apply packet preview、break-glass packet preview、rejection guard preview 與 governance UI 呈現,不授權此 readback 自行啟動 auto worker、live execution、Gateway queue 寫入、Telegram 實發、Bot API、receipt production write、production write、secret 讀取、付費 API、host write、kubectl、OpenClaw 取代或不可逆操作。", "type": "object", "required": [ "schema_version", @@ -42,7 +42,7 @@ "current_task_id": { "type": "string", "const": "P2-409" }, "next_task_id": { "type": "string", "const": "P2-410" }, "read_only_mode": { "type": "boolean", "const": true }, - "runtime_authority": { "type": "string", "const": "high_risk_owner_review_queue_no_live_execution_committed_snapshot" }, + "runtime_authority": { "type": "string", "const": "controlled_apply_break_glass_queue_readback_no_live_execution" }, "status_note": { "type": "string", "minLength": 1 } }, "additionalProperties": false @@ -65,10 +65,10 @@ "redacted_payload_only" ], "properties": { - "high_risk_default_route": { "type": "string", "const": "pause_to_owner_review_queue" }, - "critical_risk_default_route": { "type": "string", "const": "pause_to_owner_review_queue" }, - "low_medium_runtime_route": { "type": "string", "const": "pause_until_owner_approved_runtime_gate" }, - "owner_response_required": { "type": "boolean", "const": true }, + "high_risk_default_route": { "type": "string", "const": "controlled_apply_queue" }, + "critical_risk_default_route": { "type": "string", "const": "critical_break_glass_queue" }, + "low_medium_runtime_route": { "type": "string", "const": "controlled_apply_queue" }, + "owner_response_required": { "type": "boolean", "const": false }, "verbal_approval_accepted": { "type": "boolean", "const": false }, "redacted_payload_only": { "type": "boolean", "const": true } }, @@ -167,14 +167,14 @@ "display_name": { "type": "string", "minLength": 1 }, "risk_tier": { "enum": ["high", "critical"] }, "owner_agent": { "enum": ["openclaw", "hermes", "nemotron", "sre", "security", "devops"] }, - "queue_status": { "enum": ["paused_owner_review_required", "blocked_missing_owner_response", "approval_packet_preview_ready"] }, + "queue_status": { "enum": ["controlled_apply_packet_ready", "critical_break_glass_required", "blocked_missing_owner_response", "approval_packet_preview_ready"] }, "source_readback_ids": { "type": "array", "minItems": 1, "items": { "type": "string" } }, "approval_packet_id": { "type": "string", "minLength": 1 }, "rejection_guard_ids": { "type": "array", "minItems": 1, "items": { "type": "string" } }, "reviewer_checklist_ids": { "type": "array", "minItems": 1, "items": { "type": "string" } }, "required_owner_fields": { "type": "array", "minItems": 1, "items": { "type": "string" } }, "blocked_runtime_actions": { "type": "array", "minItems": 1, "items": { "type": "string" } }, - "owner_response_required": { "type": "boolean", "const": true }, + "owner_response_required": { "type": "boolean" }, "rollback_owner_required": { "type": "boolean", "const": true }, "postcheck_required": { "type": "boolean", "const": true }, "live_execution_allowed": { "type": "boolean", "const": false }, @@ -209,7 +209,7 @@ "approval_packet_id": { "type": "string", "minLength": 1 }, "queue_item_id": { "type": "string", "minLength": 1 }, "display_name": { "type": "string", "minLength": 1 }, - "packet_status": { "enum": ["draft_ready_owner_response_required", "blocked_missing_owner_response"] }, + "packet_status": { "enum": ["controlled_apply_packet_ready", "break_glass_packet_ready", "blocked_missing_owner_response"] }, "required_owner_fields": { "type": "array", "minItems": 1, "items": { "type": "string" } }, "required_evidence_refs": { "type": "array", "minItems": 1, "items": { "type": "string" } }, "reviewer_checklist_id": { "type": "string", "minLength": 1 },