From d41b1a383e88d9b73d77052b00755ea5907a7dc3 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 14 Jun 2026 11:43:03 +0800 Subject: [PATCH] =?UTF-8?q?feat(governance):=20=E6=96=B0=E5=A2=9E=20releas?= =?UTF-8?q?e=20decision=20readback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/api/src/api/v1/agents.py | 34 + ...esult_capture_release_decision_readback.py | 345 +++++++++ ...esult_capture_release_decision_readback.py | 124 ++++ ...t_capture_release_decision_readback_api.py | 39 + apps/web/messages/en.json | 37 + apps/web/messages/zh-TW.json | 37 + .../tabs/automation-inventory-tab.tsx | 203 +++++- apps/web/src/lib/api-client.ts | 228 ++++++ docs/LOGBOOK.md | 24 + ...AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md | 12 +- ..._release_decision_readback_2026-06-14.json | 674 ++++++++++++++++++ ...e_release_decision_readback_v1.schema.json | 118 +++ ...-04-15-MASTER-ai-autonomous-flywheel-v2.md | 10 +- 13 files changed, 1880 insertions(+), 5 deletions(-) create mode 100644 apps/api/src/services/ai_agent_result_capture_release_decision_readback.py create mode 100644 apps/api/tests/test_ai_agent_result_capture_release_decision_readback.py create mode 100644 apps/api/tests/test_ai_agent_result_capture_release_decision_readback_api.py create mode 100644 docs/evaluations/ai_agent_result_capture_release_decision_readback_2026-06-14.json create mode 100644 docs/schemas/ai_agent_result_capture_release_decision_readback_v1.schema.json diff --git a/apps/api/src/api/v1/agents.py b/apps/api/src/api/v1/agents.py index 9e1bb31fa..3e87109a1 100644 --- a/apps/api/src/api/v1/agents.py +++ b/apps/api/src/api/v1/agents.py @@ -124,6 +124,9 @@ from src.services.ai_agent_result_capture_no_write_readback import ( from src.services.ai_agent_result_capture_release_decision_hold import ( load_latest_ai_agent_result_capture_release_decision_hold, ) +from src.services.ai_agent_result_capture_release_decision_readback import ( + load_latest_ai_agent_result_capture_release_decision_readback, +) from src.services.ai_agent_result_capture_owner_promotion_review import ( load_latest_ai_agent_result_capture_owner_promotion_review, ) @@ -2291,6 +2294,37 @@ async def get_agent_result_capture_release_decision_hold() -> dict[str, Any]: ) from exc +@router.get( + "/agent-result-capture-release-decision-readback", + response_model=dict[str, Any], + summary="取得 AI Agent result capture release decision readback", + description=( + "讀取最新已提交的 P2-139 release decision readback;" + "此端點只回讀 P2-138 release decision hold 後的釋出、負責人、驗證器、回滾、" + "維護窗口與正式套用決策狀態," + "不把 hold 視為決策通過、不授權 owner release、不核發 release authorization、" + "不寫 reviewer queue、Gateway queue、receipt、result capture、learning 或 PlayBook trust," + "不送 Telegram、不呼叫 Bot API、不讀 secret、不執行 production 寫入。" + ), +) +async def get_agent_result_capture_release_decision_readback() -> dict[str, Any]: + """Return the latest read-only release decision readback.""" + try: + payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_release_decision_readback) + return redact_public_lan_topology(payload) + except FileNotFoundError as exc: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=str(exc), + ) from exc + except (json.JSONDecodeError, ValueError) as exc: + logger.error("ai_agent_result_capture_release_decision_readback_invalid", error=str(exc)) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="AI Agent result capture release decision readback 無效", + ) from exc + + @router.get( "/agent-owner-approved-fixture-dry-run", response_model=dict[str, Any], diff --git a/apps/api/src/services/ai_agent_result_capture_release_decision_readback.py b/apps/api/src/services/ai_agent_result_capture_release_decision_readback.py new file mode 100644 index 000000000..8696c4cda --- /dev/null +++ b/apps/api/src/services/ai_agent_result_capture_release_decision_readback.py @@ -0,0 +1,345 @@ +""" +AI Agent result capture release decision readback snapshot. + +Loads the latest committed P2-139 release decision readback. This module only +reads committed evidence from P2-138 release decision hold; it never treats a +hold as a passed decision, grants release authorization, writes reviewer / +Gateway queues, sends Telegram messages, writes result capture, writes learning +records, updates PlayBook trust, reads secrets, writes production targets, or +performs destructive operations. +""" + +from __future__ import annotations + +import json +import re +from pathlib import Path +from typing import Any + +from src.services.snapshot_paths import default_evaluations_dir + +_DEFAULT_EVALUATIONS_DIR = default_evaluations_dir(Path(__file__)) +_SNAPSHOT_PATTERN = "ai_agent_result_capture_release_decision_readback_*.json" +_SCHEMA_VERSION = "ai_agent_result_capture_release_decision_readback_v1" +_RUNTIME_AUTHORITY = "result_capture_release_decision_readback_only_no_live_write" + + +def load_latest_ai_agent_result_capture_release_decision_readback( + evaluations_dir: Path | None = None, +) -> dict[str, Any]: + """Load the newest committed release decision readback.""" + directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR + candidates = sorted(directory.glob(_SNAPSHOT_PATTERN)) + if not candidates: + raise FileNotFoundError(f"no AI Agent result capture release decision readback snapshots found in {directory}") + + latest = candidates[-1] + with latest.open(encoding="utf-8") as handle: + payload = json.load(handle) + + if not isinstance(payload, dict): + raise ValueError(f"{latest}: expected JSON object") + + label = str(latest) + _require_schema(payload, label) + _require_prior(payload, label) + _require_truth(payload, label) + _require_readback_groups(payload, label) + _require_blocked_transitions(payload, label) + _require_actions(payload, label) + _require_display_redaction(payload, label) + _require_no_forbidden_display_terms(payload, label) + _require_rollup_consistency(payload, label) + return payload + + +def _require_schema(payload: dict[str, Any], label: str) -> None: + if payload.get("schema_version") != _SCHEMA_VERSION: + raise ValueError(f"{label}: expected schema_version={_SCHEMA_VERSION}") + status = payload.get("program_status") or {} + expected = { + "current_priority": "P2", + "current_task_id": "P2-139", + "next_task_id": "P2-140", + "read_only_mode": True, + "runtime_authority": _RUNTIME_AUTHORITY, + "overall_completion_percent": 100, + } + mismatches = _mismatches(status, expected) + if mismatches: + raise ValueError(f"{label}: program_status mismatch: {mismatches}") + if not status.get("status_note"): + raise ValueError(f"{label}: program_status.status_note is required") + + +def _require_prior(payload: dict[str, Any], label: str) -> None: + prior = payload.get("prior_release_decision_hold") or {} + expected = { + "schema_version": "ai_agent_result_capture_release_decision_hold_v1", + "release_decision_hold_count": 5, + "owner_decision_hold_count": 5, + "verifier_decision_hold_count": 5, + "rollback_decision_hold_count": 5, + "maintenance_window_decision_hold_count": 5, + "live_apply_decision_hold_count": 5, + "blocked_decision_transition_count": 6, + "operator_action_count": 5, + "approval_required_total": 12, + "blocked_total": 12, + } + expected.update(_zero_count_expectations()) + mismatches = _mismatches(prior, expected) + if mismatches: + raise ValueError(f"{label}: prior_release_decision_hold mismatch: {mismatches}") + if not prior.get("readiness_note"): + raise ValueError(f"{label}: prior_release_decision_hold.readiness_note is required") + + +def _require_truth(payload: dict[str, Any], label: str) -> None: + truth = payload.get("release_decision_readback_truth") or {} + required_true = { + "p2_138_release_decision_hold_loaded", + "release_decision_readback_ready", + "owner_decision_still_required", + "verifier_decision_still_required", + "rollback_decision_still_required", + "maintenance_window_decision_still_required", + "live_apply_decision_still_required", + "redaction_review_still_required", + "release_decision_readback_only", + } + missing = sorted(field for field in required_true if truth.get(field) is not True) + if missing: + raise ValueError(f"{label}: release decision readback flags must remain true: {missing}") + + required_false = { + "owner_release_authorized", + "owner_release_approved", + "owner_review_approved", + "owner_decision_approved", + "verifier_decision_approved", + "maintenance_window_approved", + "rollback_owner_confirmed", + "post_release_verifier_ready", + "final_release_candidate_approved", + "final_release_candidate_passed", + "release_decision_passed", + "release_authorization_granted", + "release_authorization_passed", + "rollback_release_passed", + "live_apply_release_passed", + "writer_apply_enabled", + "execution_apply_enabled", + "receipt_write_enabled", + "reviewer_queue_write_enabled", + "gateway_queue_write_enabled", + "telegram_send_enabled", + "bot_api_call_enabled", + "report_receipt_write_enabled", + "result_capture_write_enabled", + "learning_write_enabled", + "playbook_trust_write_enabled", + "production_write_enabled", + "secret_read_enabled", + "destructive_operation_enabled", + } + unsafe = sorted(field for field in required_false if truth.get(field) is not False) + if unsafe: + raise ValueError(f"{label}: release decision readback live/send/write flags must remain false: {unsafe}") + + non_zero = sorted(field for field in _zero_count_expectations() if truth.get(field) != 0) + if non_zero: + raise ValueError(f"{label}: release decision readback live counters must remain zero: {non_zero}") + if not truth.get("truth_note"): + raise ValueError(f"{label}: release_decision_readback_truth.truth_note is required") + + +def _require_readback_groups(payload: dict[str, Any], label: str) -> None: + groups = { + "release_decision_readbacks": ("readback_id", "release_decision_readback", "release decision readbacks"), + "owner_decision_readbacks": ("readback_id", "owner_decision_readback", "owner decision readbacks"), + "verifier_decision_readbacks": ("readback_id", "verifier_decision_readback", "verifier decision readbacks"), + "rollback_decision_readbacks": ("readback_id", "rollback_decision_readback", "rollback decision readbacks"), + "maintenance_window_decision_readbacks": ("readback_id", "maintenance_window_decision_readback", "maintenance window decision readbacks"), + "live_apply_decision_readbacks": ("readback_id", "live_apply_decision_readback", "live apply decision readbacks"), + } + for field, (id_field, mode, group_name) in groups.items(): + items = payload.get(field) or [] + _require_ids(items, id_field, _expected_ids(mode), label, group_name) + for item in items: + item_id = item.get(id_field) + if item.get("readback_mode") != mode: + raise ValueError(f"{label}: {group_name} {item_id} mode is invalid") + if item.get("readback_status") not in {"readback_complete", "approval_required", "blocked_by_policy"}: + raise ValueError(f"{label}: {group_name} {item_id} readback_status is invalid") + if not item.get("readback_summary"): + raise ValueError(f"{label}: {group_name} {item_id}.readback_summary is required") + if item.get("release_decision_passed") is not False: + raise ValueError(f"{label}: {group_name} {item_id} must keep release_decision_passed=false") + if item.get("release_authorization_granted") is not False: + raise ValueError(f"{label}: {group_name} {item_id} must keep release_authorization_granted=false") + if item.get("runtime_write_allowed") is not False: + raise ValueError(f"{label}: {group_name} {item_id} must keep runtime_write_allowed=false") + if item.get("telegram_send_allowed") is not False: + raise ValueError(f"{label}: {group_name} {item_id} must keep telegram_send_allowed=false") + if "evidence_hash" in item and not _is_redacted_sha256(item.get("evidence_hash")): + raise ValueError(f"{label}: {group_name} {item_id}.evidence_hash must be redacted sha256") + + +def _require_blocked_transitions(payload: dict[str, Any], label: str) -> None: + items = payload.get("blocked_readback_transitions") or [] + _require_count(items, 6, label, "blocked readback transitions") + for item in items: + item_id = item.get("transition_id") + if item.get("runtime_write_allowed") is not False: + raise ValueError(f"{label}: blocked readback transition {item_id} must keep runtime_write_allowed=false") + if item.get("status") not in {"blocked_by_policy", "approval_required"}: + raise ValueError(f"{label}: blocked readback transition {item_id} status is invalid") + if not item.get("reason"): + raise ValueError(f"{label}: blocked readback transition {item_id}.reason is required") + + +def _require_actions(payload: dict[str, Any], label: str) -> None: + items = payload.get("operator_actions") or [] + _require_count(items, 5, label, "operator actions") + for item in items: + item_id = item.get("action_id") + if item.get("runtime_write_allowed") is not False: + raise ValueError(f"{label}: operator action {item_id} must keep runtime_write_allowed=false") + if item.get("status") not in {"ready_for_operator_review", "approval_required"}: + raise ValueError(f"{label}: operator action {item_id} status is invalid") + if not item.get("operator_instruction"): + raise ValueError(f"{label}: operator action {item_id}.operator_instruction is required") + + +def _require_display_redaction(payload: dict[str, Any], label: str) -> None: + contract = payload.get("display_redaction_contract") or {} + expected = { + "redaction_required": True, + "raw_prompt_display_allowed": False, + "private_reasoning_display_allowed": False, + "secret_value_display_allowed": False, + "raw_runtime_payload_display_allowed": False, + "internal_collaboration_content_display_allowed": False, + } + mismatches = _mismatches(contract, expected) + if mismatches: + raise ValueError(f"{label}: display_redaction_contract mismatch: {mismatches}") + if not contract.get("frontend_display_policy"): + raise ValueError(f"{label}: display_redaction_contract.frontend_display_policy is required") + + +def _require_rollup_consistency(payload: dict[str, Any], label: str) -> None: + rollups = payload.get("rollups") or {} + expected = { + "release_decision_readback_count": len(payload.get("release_decision_readbacks") or []), + "owner_decision_readback_count": len(payload.get("owner_decision_readbacks") or []), + "verifier_decision_readback_count": len(payload.get("verifier_decision_readbacks") or []), + "rollback_decision_readback_count": len(payload.get("rollback_decision_readbacks") or []), + "maintenance_window_decision_readback_count": len(payload.get("maintenance_window_decision_readbacks") or []), + "live_apply_decision_readback_count": len(payload.get("live_apply_decision_readbacks") or []), + "blocked_readback_transition_count": len(payload.get("blocked_readback_transitions") or []), + "operator_action_count": len(payload.get("operator_actions") or []), + } + expected.update(_zero_count_expectations()) + mismatches = _mismatches(rollups, expected) + if mismatches: + raise ValueError(f"{label}: rollups mismatch: {mismatches}") + + +def _require_no_forbidden_display_terms(payload: Any, label: str) -> None: + forbidden = { + "work_window_transcript", + "internal_collaboration_transcript", + "raw_prompt", + "private_reasoning", + "chain_of_thought", + "authorization_header", + "secret_value", + } + found = sorted(term for term in forbidden if _contains_term(payload, term)) + if found: + raise ValueError(f"{label}: forbidden display terms leaked: {found}") + + +def _contains_term(value: Any, term: str) -> bool: + if isinstance(value, str): + return term.lower() in value.lower() + if isinstance(value, dict): + return any(_contains_term(child, term) for child in value.values()) + if isinstance(value, list): + return any(_contains_term(child, term) for child in value) + return False + + +def _zero_count_expectations() -> dict[str, int]: + return { + "owner_release_authorized_count": 0, + "owner_release_approved_count": 0, + "owner_review_approved_count": 0, + "owner_decision_approved_count": 0, + "verifier_decision_approved_count": 0, + "maintenance_window_approved_count": 0, + "rollback_owner_confirmed_count": 0, + "post_release_verifier_ready_count": 0, + "final_release_candidate_approved_count": 0, + "final_release_candidate_pass_count": 0, + "release_decision_pass_count": 0, + "release_authorization_granted_count": 0, + "release_authorization_pass_count": 0, + "rollback_release_pass_count": 0, + "live_apply_release_pass_count": 0, + "writer_apply_count": 0, + "execution_apply_count": 0, + "receipt_write_count": 0, + "reviewer_queue_write_count": 0, + "gateway_queue_write_count": 0, + "telegram_send_count": 0, + "bot_api_call_count": 0, + "report_receipt_write_count": 0, + "result_capture_write_count": 0, + "learning_write_count": 0, + "playbook_trust_write_count": 0, + "production_write_count": 0, + "secret_read_count": 0, + "destructive_operation_count": 0, + } + + +def _expected_ids(mode: str) -> set[str]: + return { + f"{mode}_result_capture", + f"{mode}_learning", + f"{mode}_playbook_trust", + f"{mode}_reviewer_queue", + f"{mode}_gateway_queue", + } + + +def _require_ids( + items: list[dict[str, Any]], + field: str, + expected_ids: set[str], + label: str, + group_name: str, +) -> None: + actual_ids = {str(item.get(field)) for item in items} + if actual_ids != expected_ids: + raise ValueError(f"{label}: {group_name} ids mismatch: expected={sorted(expected_ids)} actual={sorted(actual_ids)}") + + +def _require_count(items: list[Any], expected: int, label: str, group_name: str) -> None: + if len(items) != expected: + raise ValueError(f"{label}: expected {expected} {group_name}, got {len(items)}") + + +def _is_redacted_sha256(value: Any) -> bool: + return isinstance(value, str) and re.fullmatch(r"sha256:[0-9a-f]{64}", value) is not None + + +def _mismatches(payload: dict[str, Any], expected: dict[str, Any]) -> dict[str, dict[str, Any]]: + return { + key: {"expected": expected_value, "actual": payload.get(key)} + for key, expected_value in expected.items() + if payload.get(key) != expected_value + } diff --git a/apps/api/tests/test_ai_agent_result_capture_release_decision_readback.py b/apps/api/tests/test_ai_agent_result_capture_release_decision_readback.py new file mode 100644 index 000000000..c5b8be809 --- /dev/null +++ b/apps/api/tests/test_ai_agent_result_capture_release_decision_readback.py @@ -0,0 +1,124 @@ +from __future__ import annotations + +import copy +import json +from pathlib import Path + +import pytest + +from src.services.ai_agent_result_capture_release_decision_readback import ( + load_latest_ai_agent_result_capture_release_decision_readback, +) + + +def test_load_latest_release_decision_readback_snapshot() -> None: + snapshot = load_latest_ai_agent_result_capture_release_decision_readback() + + assert snapshot["schema_version"] == "ai_agent_result_capture_release_decision_readback_v1" + assert snapshot["program_status"]["current_task_id"] == "P2-139" + assert snapshot["program_status"]["next_task_id"] == "P2-140" + assert snapshot["program_status"]["overall_completion_percent"] == 100 + assert snapshot["program_status"]["runtime_authority"] == "result_capture_release_decision_readback_only_no_live_write" + + rollups = snapshot["rollups"] + assert rollups["release_decision_readback_count"] == 5 + assert rollups["owner_decision_readback_count"] == 5 + assert rollups["verifier_decision_readback_count"] == 5 + assert rollups["rollback_decision_readback_count"] == 5 + assert rollups["maintenance_window_decision_readback_count"] == 5 + assert rollups["live_apply_decision_readback_count"] == 5 + assert rollups["blocked_readback_transition_count"] == 6 + assert rollups["operator_action_count"] == 5 + assert ( + rollups["approval_required_release_decision_count"] + + rollups["approval_required_owner_decision_count"] + + rollups["approval_required_verifier_decision_count"] + + rollups["approval_required_rollback_decision_count"] + + rollups["approval_required_maintenance_window_decision_count"] + + rollups["approval_required_live_apply_decision_count"] + ) == 12 + assert ( + rollups["blocked_release_decision_count"] + + rollups["blocked_owner_decision_count"] + + rollups["blocked_verifier_decision_count"] + + rollups["blocked_rollback_decision_count"] + + rollups["blocked_maintenance_window_decision_count"] + + rollups["blocked_live_apply_decision_count"] + + rollups["critical_blocker_count"] + ) == 12 + + assert rollups["owner_release_authorized_count"] == 0 + assert rollups["owner_decision_approved_count"] == 0 + assert rollups["maintenance_window_approved_count"] == 0 + assert rollups["release_decision_pass_count"] == 0 + assert rollups["release_authorization_granted_count"] == 0 + assert rollups["reviewer_queue_write_count"] == 0 + assert rollups["gateway_queue_write_count"] == 0 + assert rollups["telegram_send_count"] == 0 + assert rollups["result_capture_write_count"] == 0 + assert rollups["learning_write_count"] == 0 + assert rollups["playbook_trust_write_count"] == 0 + assert rollups["production_write_count"] == 0 + + +def test_release_decision_readback_truth_keeps_all_live_paths_closed() -> None: + snapshot = load_latest_ai_agent_result_capture_release_decision_readback() + truth = snapshot["release_decision_readback_truth"] + + assert truth["p2_138_release_decision_hold_loaded"] is True + assert truth["release_decision_readback_ready"] is True + assert truth["owner_decision_still_required"] is True + assert truth["maintenance_window_decision_still_required"] is True + assert truth["release_decision_readback_only"] is True + assert truth["owner_release_authorized"] is False + assert truth["owner_decision_approved"] is False + assert truth["maintenance_window_approved"] is False + assert truth["release_decision_passed"] is False + assert truth["release_authorization_granted"] is False + assert truth["reviewer_queue_write_enabled"] is False + assert truth["gateway_queue_write_enabled"] is False + assert truth["telegram_send_enabled"] is False + assert truth["production_write_enabled"] is False + assert truth["secret_read_enabled"] is False + assert truth["destructive_operation_enabled"] is False + + +def test_rejects_release_decision_passed(tmp_path: Path) -> None: + snapshot = copy.deepcopy(load_latest_ai_agent_result_capture_release_decision_readback()) + snapshot["release_decision_readbacks"][0]["release_decision_passed"] = True + _write_snapshot(tmp_path, snapshot) + + with pytest.raises(ValueError, match="must keep release_decision_passed=false"): + load_latest_ai_agent_result_capture_release_decision_readback(tmp_path) + + +def test_rejects_release_authorization_granted(tmp_path: Path) -> None: + snapshot = copy.deepcopy(load_latest_ai_agent_result_capture_release_decision_readback()) + snapshot["owner_decision_readbacks"][0]["release_authorization_granted"] = True + _write_snapshot(tmp_path, snapshot) + + with pytest.raises(ValueError, match="must keep release_authorization_granted=false"): + load_latest_ai_agent_result_capture_release_decision_readback(tmp_path) + + +def test_rejects_queue_write_drift(tmp_path: Path) -> None: + snapshot = copy.deepcopy(load_latest_ai_agent_result_capture_release_decision_readback()) + snapshot["rollups"]["gateway_queue_write_count"] = 1 + _write_snapshot(tmp_path, snapshot) + + with pytest.raises(ValueError, match="rollups mismatch"): + load_latest_ai_agent_result_capture_release_decision_readback(tmp_path) + + +def test_rejects_forbidden_display_terms(tmp_path: Path) -> None: + snapshot = copy.deepcopy(load_latest_ai_agent_result_capture_release_decision_readback()) + snapshot["operator_actions"][0]["operator_instruction"] = "不要顯示 raw_prompt" + _write_snapshot(tmp_path, snapshot) + + with pytest.raises(ValueError, match="forbidden display terms leaked"): + load_latest_ai_agent_result_capture_release_decision_readback(tmp_path) + + +def _write_snapshot(directory: Path, payload: dict) -> None: + path = directory / "ai_agent_result_capture_release_decision_readback_2099-01-01.json" + path.write_text(json.dumps(payload, ensure_ascii=False), encoding="utf-8") diff --git a/apps/api/tests/test_ai_agent_result_capture_release_decision_readback_api.py b/apps/api/tests/test_ai_agent_result_capture_release_decision_readback_api.py new file mode 100644 index 000000000..490155f49 --- /dev/null +++ b/apps/api/tests/test_ai_agent_result_capture_release_decision_readback_api.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +from fastapi.testclient import TestClient + +from src.main import app + + +def test_release_decision_readback_endpoint() -> None: + client = TestClient(app) + + response = client.get("/api/v1/agents/agent-result-capture-release-decision-readback") + + assert response.status_code == 200 + payload = response.json() + assert payload["schema_version"] == "ai_agent_result_capture_release_decision_readback_v1" + assert payload["program_status"]["current_task_id"] == "P2-139" + assert payload["program_status"]["next_task_id"] == "P2-140" + assert payload["program_status"]["overall_completion_percent"] == 100 + assert payload["program_status"]["runtime_authority"] == "result_capture_release_decision_readback_only_no_live_write" + assert payload["prior_release_decision_hold"]["schema_version"] == "ai_agent_result_capture_release_decision_hold_v1" + assert payload["rollups"]["release_decision_readback_count"] == 5 + assert payload["rollups"]["owner_decision_readback_count"] == 5 + assert payload["rollups"]["verifier_decision_readback_count"] == 5 + assert payload["rollups"]["rollback_decision_readback_count"] == 5 + assert payload["rollups"]["maintenance_window_decision_readback_count"] == 5 + assert payload["rollups"]["live_apply_decision_readback_count"] == 5 + assert payload["rollups"]["blocked_readback_transition_count"] == 6 + assert payload["rollups"]["operator_action_count"] == 5 + assert payload["rollups"]["owner_release_authorized_count"] == 0 + assert payload["rollups"]["owner_review_approved_count"] == 0 + assert payload["rollups"]["owner_decision_approved_count"] == 0 + assert payload["rollups"]["maintenance_window_approved_count"] == 0 + assert payload["rollups"]["release_decision_pass_count"] == 0 + assert payload["rollups"]["release_authorization_granted_count"] == 0 + assert payload["rollups"]["release_authorization_pass_count"] == 0 + assert payload["rollups"]["reviewer_queue_write_count"] == 0 + assert payload["rollups"]["gateway_queue_write_count"] == 0 + assert payload["rollups"]["telegram_send_count"] == 0 + assert payload["rollups"]["production_write_count"] == 0 diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index d06982a50..deebe5906 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -6185,6 +6185,43 @@ "runtimeWriteAllowed": "runtime 寫入允許={value}" } }, + "resultCaptureReleaseDecisionReadback": { + "title": "P2-139 釋出決策讀回關卡", + "source": "產生 {generated};目前 {current};下一步 {next}", + "priorTitle": "前一關釋出決策保留", + "truthTitle": "釋出決策讀回真相", + "metrics": { + "overall": "完成度", + "releaseReadbacks": "釋出決策讀回", + "ownerReadbacks": "負責人決策讀回", + "verifierReadbacks": "驗證器決策讀回", + "rollbackReadbacks": "回滾決策讀回", + "maintenanceReadbacks": "維護窗口決策讀回", + "liveApplyReadbacks": "正式套用讀回", + "blockers": "已阻擋讀回", + "actions": "操作選項", + "approvalRequired": "需批准", + "blocked": "阻擋", + "liveWrites": "正式寫入 / 發送" + }, + "flags": { + "p2Loaded": "已載入 P2-138={value}", + "readbackReady": "釋出決策讀回已就緒={value}", + "maintenanceStillRequired": "維護窗口仍需決策={value}", + "liveApplyStillRequired": "正式套用仍需決策={value}" + }, + "labels": { + "ownerReleaseAuthorized": "負責人釋出授權={value}", + "ownerDecisionApproved": "負責人決策通過={value}", + "decisionPassed": "釋出決策通過={value}", + "authorizationGranted": "釋出授權已核發={value}", + "gatewayWrites": "Gateway 寫入={value}", + "telegramSends": "Telegram 送出={value}", + "productionWrites": "正式寫入={value}", + "runtimeWriteAllowed": "runtime 寫入允許={value}", + "telegramSendAllowed": "Telegram 發送允許={value}" + } + }, "resultCaptureReleaseVerifierOwnerReviewPacket": { "title": "P2-137 釋出驗證器負責人審查包", "source": "產生 {generated};目前 {current};下一步 {next}", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index d06982a50..deebe5906 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -6185,6 +6185,43 @@ "runtimeWriteAllowed": "runtime 寫入允許={value}" } }, + "resultCaptureReleaseDecisionReadback": { + "title": "P2-139 釋出決策讀回關卡", + "source": "產生 {generated};目前 {current};下一步 {next}", + "priorTitle": "前一關釋出決策保留", + "truthTitle": "釋出決策讀回真相", + "metrics": { + "overall": "完成度", + "releaseReadbacks": "釋出決策讀回", + "ownerReadbacks": "負責人決策讀回", + "verifierReadbacks": "驗證器決策讀回", + "rollbackReadbacks": "回滾決策讀回", + "maintenanceReadbacks": "維護窗口決策讀回", + "liveApplyReadbacks": "正式套用讀回", + "blockers": "已阻擋讀回", + "actions": "操作選項", + "approvalRequired": "需批准", + "blocked": "阻擋", + "liveWrites": "正式寫入 / 發送" + }, + "flags": { + "p2Loaded": "已載入 P2-138={value}", + "readbackReady": "釋出決策讀回已就緒={value}", + "maintenanceStillRequired": "維護窗口仍需決策={value}", + "liveApplyStillRequired": "正式套用仍需決策={value}" + }, + "labels": { + "ownerReleaseAuthorized": "負責人釋出授權={value}", + "ownerDecisionApproved": "負責人決策通過={value}", + "decisionPassed": "釋出決策通過={value}", + "authorizationGranted": "釋出授權已核發={value}", + "gatewayWrites": "Gateway 寫入={value}", + "telegramSends": "Telegram 送出={value}", + "productionWrites": "正式寫入={value}", + "runtimeWriteAllowed": "runtime 寫入允許={value}", + "telegramSendAllowed": "Telegram 發送允許={value}" + } + }, "resultCaptureReleaseVerifierOwnerReviewPacket": { "title": "P2-137 釋出驗證器負責人審查包", "source": "產生 {generated};目前 {current};下一步 {next}", 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 3d8c7a4f2..0b80e6d66 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 @@ -14,6 +14,7 @@ import { Archive, BellOff, BellRing, + BookOpenCheck, Boxes, CalendarClock, Database, @@ -86,6 +87,7 @@ import { type AiAgentResultCaptureReleaseAuthorizationHoldSnapshot, type AiAgentResultCaptureReleaseAuthorizationReadbackGateSnapshot, type AiAgentResultCaptureReleaseDecisionHoldSnapshot, + type AiAgentResultCaptureReleaseDecisionReadbackSnapshot, type AiAgentResultCaptureReleaseVerifierPreflightGateSnapshot, type AiAgentResultCaptureReleaseVerifierOwnerReviewPacketSnapshot, type AiAgentResultCaptureWriterImplementationReviewSnapshot, @@ -497,6 +499,7 @@ export function AutomationInventoryTab() { const [resultCaptureReleaseVerifierPreflightGate, setResultCaptureReleaseVerifierPreflightGate] = useState(null) const [resultCaptureReleaseVerifierOwnerReviewPacket, setResultCaptureReleaseVerifierOwnerReviewPacket] = useState(null) const [resultCaptureReleaseDecisionHold, setResultCaptureReleaseDecisionHold] = useState(null) + const [resultCaptureReleaseDecisionReadback, setResultCaptureReleaseDecisionReadback] = useState(null) const [reportTruthActionabilityReview, setReportTruthActionabilityReview] = useState(null) const [ownerDryRunPackage, setOwnerDryRunPackage] = useState(null) const [hostStatefulInventory, setHostStatefulInventory] = useState(null) @@ -572,6 +575,7 @@ export function AutomationInventoryTab() { apiClient.getAiAgentResultCaptureReleaseVerifierPreflightGate(), apiClient.getAiAgentResultCaptureReleaseVerifierOwnerReviewPacket(), apiClient.getAiAgentResultCaptureReleaseDecisionHold(), + apiClient.getAiAgentResultCaptureReleaseDecisionReadback(), apiClient.getAiAgentReportTruthActionabilityReview(), apiClient.getAiAgentOwnerApprovedFixtureDryRun(), apiClient.getAiAgentHostStatefulVersionInventory(), @@ -646,6 +650,7 @@ export function AutomationInventoryTab() { resultCaptureReleaseVerifierPreflightGateResult, resultCaptureReleaseVerifierOwnerReviewPacketResult, resultCaptureReleaseDecisionHoldResult, + resultCaptureReleaseDecisionReadbackResult, reportTruthActionabilityReviewResult, ownerDryRunPackageResult, hostStatefulInventoryResult, @@ -717,6 +722,7 @@ export function AutomationInventoryTab() { setResultCaptureReleaseVerifierPreflightGate(resultCaptureReleaseVerifierPreflightGateResult.status === 'fulfilled' ? resultCaptureReleaseVerifierPreflightGateResult.value : null) setResultCaptureReleaseVerifierOwnerReviewPacket(resultCaptureReleaseVerifierOwnerReviewPacketResult.status === 'fulfilled' ? resultCaptureReleaseVerifierOwnerReviewPacketResult.value : null) setResultCaptureReleaseDecisionHold(resultCaptureReleaseDecisionHoldResult.status === 'fulfilled' ? resultCaptureReleaseDecisionHoldResult.value : null) + setResultCaptureReleaseDecisionReadback(resultCaptureReleaseDecisionReadbackResult.status === 'fulfilled' ? resultCaptureReleaseDecisionReadbackResult.value : null) setReportTruthActionabilityReview(reportTruthActionabilityReviewResult.status === 'fulfilled' ? reportTruthActionabilityReviewResult.value : null) setOwnerDryRunPackage(ownerDryRunPackageResult.status === 'fulfilled' ? ownerDryRunPackageResult.value : null) setHostStatefulInventory(hostStatefulInventoryResult.status === 'fulfilled' ? hostStatefulInventoryResult.value : null) @@ -786,6 +792,7 @@ export function AutomationInventoryTab() { resultCaptureReleaseVerifierPreflightGateResult, resultCaptureReleaseVerifierOwnerReviewPacketResult, resultCaptureReleaseDecisionHoldResult, + resultCaptureReleaseDecisionReadbackResult, reportTruthActionabilityReviewResult, ownerDryRunPackageResult, hostStatefulInventoryResult, @@ -2028,7 +2035,7 @@ export function AutomationInventoryTab() { ) } - if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !proactiveOperations || !interactionLearningProof || !liveReadModelGate || !redisDryRunGate || !learningWritebackPackage || !telegramReceiptPackage || !ownerApprovedLearningDryRun || !runtimeWriteGateReview || !postWriteVerifierPackage || !runtimeVerifierEvidenceReview || !reportAutomationReview || !reportStatusBoard || !reportRuntimeReadiness || !reportRuntimeDryRun || !reportRuntimeFixtureReadback || !runtimeWorkerShadowGate || !operationPermissionModel || !candidateOperationDryRunEvidence || !taskResultAuditTrail || !matchedPlaybookLearningGap || !criticReviewerResultCapture || !ownerApprovedResultCaptureDryRun || !ownerApprovedResultCaptureReadback || !runtimeReadbackApprovalPackage || !runtimeReadbackImplementationReview || !reportLiveDeliveryApprovalPackage || !runtimeReadbackFixtureApproval || !runtimeReadbackPromotionGate || !ownerApprovedFixturePromotionGate || !canonicalRuntimeReadbackOwnerAcceptance || !failureReceiptNoSendReplay || !reviewerQueueNoWriteReadback || !resultCaptureNoWriteReadback || !resultCapturePromotionApprovalGate || !ownerApprovedResultCapturePromotionDryRun || !resultCaptureWriteGateReview || !resultCaptureWriterImplementationReview || !resultCaptureWriterDryRunFixture || !resultCaptureWriterDryRunReadback || !resultCaptureOwnerPromotionReview || !resultCaptureOwnerApprovedExecutionRehearsal || !resultCaptureOwnerAcceptanceMaintenanceGate || !resultCaptureOwnerAcceptanceReadbackPreflightHold || !resultCaptureOwnerApprovedPreflightReleasePackage || !resultCaptureOwnerApprovedReleaseReadinessReadback || !resultCaptureOwnerReleaseApprovalGate || !resultCapturePostReleaseVerifierRollbackGate || !resultCaptureFinalReleaseCandidateReadback || !resultCaptureReleaseAuthorizationHold || !resultCaptureReleaseAuthorizationReadbackGate || !resultCaptureReleaseVerifierPreflightGate || !resultCaptureReleaseVerifierOwnerReviewPacket || !resultCaptureReleaseDecisionHold || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) { + if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !proactiveOperations || !interactionLearningProof || !liveReadModelGate || !redisDryRunGate || !learningWritebackPackage || !telegramReceiptPackage || !ownerApprovedLearningDryRun || !runtimeWriteGateReview || !postWriteVerifierPackage || !runtimeVerifierEvidenceReview || !reportAutomationReview || !reportStatusBoard || !reportRuntimeReadiness || !reportRuntimeDryRun || !reportRuntimeFixtureReadback || !runtimeWorkerShadowGate || !operationPermissionModel || !candidateOperationDryRunEvidence || !taskResultAuditTrail || !matchedPlaybookLearningGap || !criticReviewerResultCapture || !ownerApprovedResultCaptureDryRun || !ownerApprovedResultCaptureReadback || !runtimeReadbackApprovalPackage || !runtimeReadbackImplementationReview || !reportLiveDeliveryApprovalPackage || !runtimeReadbackFixtureApproval || !runtimeReadbackPromotionGate || !ownerApprovedFixturePromotionGate || !canonicalRuntimeReadbackOwnerAcceptance || !failureReceiptNoSendReplay || !reviewerQueueNoWriteReadback || !resultCaptureNoWriteReadback || !resultCapturePromotionApprovalGate || !ownerApprovedResultCapturePromotionDryRun || !resultCaptureWriteGateReview || !resultCaptureWriterImplementationReview || !resultCaptureWriterDryRunFixture || !resultCaptureWriterDryRunReadback || !resultCaptureOwnerPromotionReview || !resultCaptureOwnerApprovedExecutionRehearsal || !resultCaptureOwnerAcceptanceMaintenanceGate || !resultCaptureOwnerAcceptanceReadbackPreflightHold || !resultCaptureOwnerApprovedPreflightReleasePackage || !resultCaptureOwnerApprovedReleaseReadinessReadback || !resultCaptureOwnerReleaseApprovalGate || !resultCapturePostReleaseVerifierRollbackGate || !resultCaptureFinalReleaseCandidateReadback || !resultCaptureReleaseAuthorizationHold || !resultCaptureReleaseAuthorizationReadbackGate || !resultCaptureReleaseVerifierPreflightGate || !resultCaptureReleaseVerifierOwnerReviewPacket || !resultCaptureReleaseDecisionHold || !resultCaptureReleaseDecisionReadback || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) { return (
@@ -3353,6 +3360,46 @@ export function AutomationInventoryTab() { + resultCaptureReleaseDecisionHold.rollups.playbook_trust_write_count + resultCaptureReleaseDecisionHold.rollups.production_write_count ) + const resultCaptureReleaseDecisionReadbackOverall = resultCaptureReleaseDecisionReadback.program_status.overall_completion_percent + const resultCaptureReleaseDecisionReadbacks = resultCaptureReleaseDecisionReadback.rollups.release_decision_readback_count + const resultCaptureReleaseOwnerDecisionReadbacks = resultCaptureReleaseDecisionReadback.rollups.owner_decision_readback_count + const resultCaptureReleaseVerifierDecisionReadbacks = resultCaptureReleaseDecisionReadback.rollups.verifier_decision_readback_count + const resultCaptureReleaseRollbackDecisionReadbacks = resultCaptureReleaseDecisionReadback.rollups.rollback_decision_readback_count + const resultCaptureReleaseMaintenanceDecisionReadbacks = resultCaptureReleaseDecisionReadback.rollups.maintenance_window_decision_readback_count + const resultCaptureReleaseLiveApplyDecisionReadbacks = resultCaptureReleaseDecisionReadback.rollups.live_apply_decision_readback_count + const resultCaptureReleaseDecisionReadbackBlockedTransitions = resultCaptureReleaseDecisionReadback.rollups.blocked_readback_transition_count + const resultCaptureReleaseDecisionReadbackActions = resultCaptureReleaseDecisionReadback.rollups.operator_action_count + const resultCaptureReleaseDecisionReadbackApprovalRequired = ( + resultCaptureReleaseDecisionReadback.rollups.approval_required_release_decision_count + + resultCaptureReleaseDecisionReadback.rollups.approval_required_owner_decision_count + + resultCaptureReleaseDecisionReadback.rollups.approval_required_verifier_decision_count + + resultCaptureReleaseDecisionReadback.rollups.approval_required_rollback_decision_count + + resultCaptureReleaseDecisionReadback.rollups.approval_required_maintenance_window_decision_count + + resultCaptureReleaseDecisionReadback.rollups.approval_required_live_apply_decision_count + ) + const resultCaptureReleaseDecisionReadbackBlocked = ( + resultCaptureReleaseDecisionReadback.rollups.blocked_release_decision_count + + resultCaptureReleaseDecisionReadback.rollups.blocked_owner_decision_count + + resultCaptureReleaseDecisionReadback.rollups.blocked_verifier_decision_count + + resultCaptureReleaseDecisionReadback.rollups.blocked_rollback_decision_count + + resultCaptureReleaseDecisionReadback.rollups.blocked_maintenance_window_decision_count + + resultCaptureReleaseDecisionReadback.rollups.blocked_live_apply_decision_count + + resultCaptureReleaseDecisionReadback.rollups.critical_blocker_count + ) + const resultCaptureReleaseDecisionReadbackLiveWrites = ( + resultCaptureReleaseDecisionReadback.rollups.writer_apply_count + + resultCaptureReleaseDecisionReadback.rollups.execution_apply_count + + resultCaptureReleaseDecisionReadback.rollups.receipt_write_count + + resultCaptureReleaseDecisionReadback.rollups.reviewer_queue_write_count + + resultCaptureReleaseDecisionReadback.rollups.gateway_queue_write_count + + resultCaptureReleaseDecisionReadback.rollups.telegram_send_count + + resultCaptureReleaseDecisionReadback.rollups.bot_api_call_count + + resultCaptureReleaseDecisionReadback.rollups.report_receipt_write_count + + resultCaptureReleaseDecisionReadback.rollups.result_capture_write_count + + resultCaptureReleaseDecisionReadback.rollups.learning_write_count + + resultCaptureReleaseDecisionReadback.rollups.playbook_trust_write_count + + resultCaptureReleaseDecisionReadback.rollups.production_write_count + ) const reportTruthOverall = reportTruthActionabilityReview.program_status.overall_completion_percent const reportTruthFindings = reportTruthActionabilityReview.rollups.zero_signal_finding_count const reportTruthCritical = reportTruthActionabilityReview.rollups.critical_finding_count @@ -8087,6 +8134,160 @@ export function AutomationInventoryTab() {
+
+
+
+ + + {t('resultCaptureReleaseDecisionReadback.title')} + +
+ +
+ +
+ } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> +
+ +
+
+ {t('resultCaptureReleaseDecisionReadback.priorTitle')} +

+ {resultCaptureReleaseDecisionReadback.prior_release_decision_hold.readiness_note} +

+
+ + + +
+
+ +
+ {t('resultCaptureReleaseDecisionReadback.truthTitle')} +

+ {resultCaptureReleaseDecisionReadback.release_decision_readback_truth.truth_note} +

+
+ + + + + + + + + +
+
+
+ +
+ {resultCaptureReleaseDecisionReadback.release_decision_readbacks.slice(0, 5).map(readback => ( +
+
+ + {readback.display_name} + + +
+ + {readback.readback_summary} + +
+ + + + + +
+
+ ))} +
+ +
+ {[ + ...resultCaptureReleaseDecisionReadback.owner_decision_readbacks.slice(0, 2), + ...resultCaptureReleaseDecisionReadback.verifier_decision_readbacks.slice(0, 2), + ...resultCaptureReleaseDecisionReadback.rollback_decision_readbacks.slice(0, 2), + ...resultCaptureReleaseDecisionReadback.maintenance_window_decision_readbacks.slice(0, 2), + ...resultCaptureReleaseDecisionReadback.live_apply_decision_readbacks.slice(0, 2), + ].map(readback => ( +
+
+ + {readback.display_name} + + +
+ + {readback.readback_summary} + +
+ + + + +
+
+ ))} +
+ +
+ {resultCaptureReleaseDecisionReadback.blocked_readback_transitions.slice(0, 6).map(transition => ( +
+
+ + {transition.transition_id} + + +
+ + {transition.reason} + + +
+ ))} +
+ +
+ {resultCaptureReleaseDecisionReadback.operator_actions.slice(0, 5).map(action => ( +
+
+ + {action.action_id} + + +
+ + {action.operator_instruction} + +
+ + +
+
+ ))} +
+
+
diff --git a/apps/web/src/lib/api-client.ts b/apps/web/src/lib/api-client.ts index b3300778c..b0e7ecb6f 100644 --- a/apps/web/src/lib/api-client.ts +++ b/apps/web/src/lib/api-client.ts @@ -590,6 +590,11 @@ export const apiClient = { return handleResponse(res) }, + async getAiAgentResultCaptureReleaseDecisionReadback() { + const res = await fetch(`${API_BASE_URL}/agents/agent-result-capture-release-decision-readback`) + return handleResponse(res) + }, + async getAiAgentOwnerApprovedFixtureDryRun() { const res = await fetch(`${API_BASE_URL}/agents/agent-owner-approved-fixture-dry-run`) return handleResponse(res) @@ -9305,6 +9310,229 @@ export interface AiAgentResultCaptureReleaseDecisionHoldSnapshot { } } +interface AiAgentReleaseDecisionReadbackItem { + readback_id: string + display_name: string + owner_agent: string + source_hold_id: string + readback_status: string + readback_mode: string + readback_summary: string + release_decision_passed: boolean + release_authorization_granted: boolean + runtime_write_allowed: boolean + telegram_send_allowed: boolean + evidence_hash?: string +} + +export interface AiAgentResultCaptureReleaseDecisionReadbackSnapshot { + schema_version: 'ai_agent_result_capture_release_decision_readback_v1' + generated_at: string + program_status: { + overall_completion_percent: number + current_priority: 'P0' | 'P1' | 'P2' | 'P3' + current_task_id: 'P2-139' + next_task_id: 'P2-140' + read_only_mode: true + runtime_authority: 'result_capture_release_decision_readback_only_no_live_write' + status_note: string + } + source_refs: string[] + prior_release_decision_hold: { + schema_version: string + release_decision_hold_count: number + owner_decision_hold_count: number + verifier_decision_hold_count: number + rollback_decision_hold_count: number + maintenance_window_decision_hold_count: number + live_apply_decision_hold_count: number + blocked_decision_transition_count: number + operator_action_count: number + approval_required_total: number + blocked_total: number + readiness_note: string + owner_release_authorized_count: number + owner_release_approved_count: number + owner_review_approved_count: number + owner_decision_approved_count: number + verifier_decision_approved_count: number + maintenance_window_approved_count: number + rollback_owner_confirmed_count: number + post_release_verifier_ready_count: number + final_release_candidate_approved_count: number + final_release_candidate_pass_count: number + release_decision_pass_count: number + release_authorization_granted_count: number + release_authorization_pass_count: number + rollback_release_pass_count: number + live_apply_release_pass_count: number + writer_apply_count: number + execution_apply_count: number + receipt_write_count: number + reviewer_queue_write_count: number + gateway_queue_write_count: number + telegram_send_count: number + bot_api_call_count: number + report_receipt_write_count: number + result_capture_write_count: number + learning_write_count: number + playbook_trust_write_count: number + production_write_count: number + secret_read_count: number + destructive_operation_count: number + } + release_decision_readback_truth: { + p2_138_release_decision_hold_loaded: boolean + release_decision_readback_ready: boolean + owner_decision_still_required: boolean + verifier_decision_still_required: boolean + rollback_decision_still_required: boolean + maintenance_window_decision_still_required: boolean + live_apply_decision_still_required: boolean + redaction_review_still_required: boolean + release_decision_readback_only: boolean + truth_note: string + owner_release_authorized: boolean + owner_release_approved: boolean + owner_review_approved: boolean + owner_decision_approved: boolean + verifier_decision_approved: boolean + maintenance_window_approved: boolean + rollback_owner_confirmed: boolean + post_release_verifier_ready: boolean + final_release_candidate_approved: boolean + final_release_candidate_passed: boolean + release_decision_passed: boolean + release_authorization_granted: boolean + release_authorization_passed: boolean + rollback_release_passed: boolean + live_apply_release_passed: boolean + writer_apply_enabled: boolean + execution_apply_enabled: boolean + receipt_write_enabled: boolean + reviewer_queue_write_enabled: boolean + gateway_queue_write_enabled: boolean + telegram_send_enabled: boolean + bot_api_call_enabled: boolean + report_receipt_write_enabled: boolean + result_capture_write_enabled: boolean + learning_write_enabled: boolean + playbook_trust_write_enabled: boolean + production_write_enabled: boolean + secret_read_enabled: boolean + destructive_operation_enabled: boolean + owner_release_authorized_count: number + owner_release_approved_count: number + owner_review_approved_count: number + owner_decision_approved_count: number + verifier_decision_approved_count: number + maintenance_window_approved_count: number + rollback_owner_confirmed_count: number + post_release_verifier_ready_count: number + final_release_candidate_approved_count: number + final_release_candidate_pass_count: number + release_decision_pass_count: number + release_authorization_granted_count: number + release_authorization_pass_count: number + rollback_release_pass_count: number + live_apply_release_pass_count: number + writer_apply_count: number + execution_apply_count: number + receipt_write_count: number + reviewer_queue_write_count: number + gateway_queue_write_count: number + telegram_send_count: number + bot_api_call_count: number + report_receipt_write_count: number + result_capture_write_count: number + learning_write_count: number + playbook_trust_write_count: number + production_write_count: number + secret_read_count: number + destructive_operation_count: number + } + release_decision_readbacks: AiAgentReleaseDecisionReadbackItem[] + owner_decision_readbacks: AiAgentReleaseDecisionReadbackItem[] + verifier_decision_readbacks: AiAgentReleaseDecisionReadbackItem[] + rollback_decision_readbacks: AiAgentReleaseDecisionReadbackItem[] + maintenance_window_decision_readbacks: AiAgentReleaseDecisionReadbackItem[] + live_apply_decision_readbacks: AiAgentReleaseDecisionReadbackItem[] + blocked_readback_transitions: { + transition_id: string + status: string + reason: string + runtime_write_allowed: boolean + }[] + operator_actions: { + action_id: string + owner_agent: string + status: string + operator_instruction: string + runtime_write_allowed: boolean + }[] + display_redaction_contract: { + redaction_required: boolean + raw_prompt_display_allowed: boolean + private_reasoning_display_allowed: boolean + secret_value_display_allowed: boolean + raw_runtime_payload_display_allowed: boolean + internal_collaboration_content_display_allowed: boolean + frontend_display_policy: string + } + rollups: { + release_decision_readback_count: number + owner_decision_readback_count: number + verifier_decision_readback_count: number + rollback_decision_readback_count: number + maintenance_window_decision_readback_count: number + live_apply_decision_readback_count: number + blocked_readback_transition_count: number + operator_action_count: number + approval_required_release_decision_count: number + blocked_release_decision_count: number + approval_required_owner_decision_count: number + blocked_owner_decision_count: number + approval_required_verifier_decision_count: number + blocked_verifier_decision_count: number + approval_required_rollback_decision_count: number + blocked_rollback_decision_count: number + approval_required_maintenance_window_decision_count: number + blocked_maintenance_window_decision_count: number + approval_required_live_apply_decision_count: number + blocked_live_apply_decision_count: number + critical_blocker_count: number + owner_release_authorized_count: number + owner_release_approved_count: number + owner_review_approved_count: number + owner_decision_approved_count: number + verifier_decision_approved_count: number + maintenance_window_approved_count: number + rollback_owner_confirmed_count: number + post_release_verifier_ready_count: number + final_release_candidate_approved_count: number + final_release_candidate_pass_count: number + release_decision_pass_count: number + release_authorization_granted_count: number + release_authorization_pass_count: number + rollback_release_pass_count: number + live_apply_release_pass_count: number + writer_apply_count: number + execution_apply_count: number + receipt_write_count: number + reviewer_queue_write_count: number + gateway_queue_write_count: number + telegram_send_count: number + bot_api_call_count: number + report_receipt_write_count: number + result_capture_write_count: number + learning_write_count: number + playbook_trust_write_count: number + production_write_count: number + secret_read_count: number + destructive_operation_count: number + } +} + export interface AiAgentOwnerApprovedFixtureDryRunSnapshot { schema_version: 'ai_agent_owner_approved_fixture_dry_run_v1' generated_at: string diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 22d3ceee3..6a11bb54e 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,27 @@ +## 2026-06-14|P2-139 釋出決策讀回關卡本地完成 + +**背景**:P2-138 release decision hold 已正式驗證,但 hold 可見仍不得被誤讀成 owner decision approved、release decision passed、release authorization granted / passed、rollback release passed 或 live apply passed。P2-139 因此只建立 release decision readback,讓後續 operator / owner 能看見各決策仍被阻擋與仍需批准。 + +**完成內容**: +- 新增 `ai_agent_result_capture_release_decision_readback_v1` schema、committed snapshot、loader 與 API endpoint `GET /api/v1/agents/agent-result-capture-release-decision-readback`。 +- P2-139 snapshot 固定 5 個 release decision readback、5 個 owner decision readback、5 個 verifier decision readback、5 個 rollback decision readback、5 個 maintenance window decision readback、5 個 live-apply decision readback、6 個 blocked readback transition 與 5 個 operator action。 +- Governance automation inventory 頁新增 P2-139 區塊,顯示 P2-139 進度 `100%`、釋出決策讀回 `5`、負責人決策讀回 `5`、驗證器決策讀回 `5`、回滾決策讀回 `5`、維護窗口決策讀回 `5`、正式套用讀回 `5`、已阻擋讀回 `6`、operator action `5`、需批准 `12`、阻擋 `12`、正式寫入 / 發送 `0`。 +- Release decision readback truth 固定為 `result_capture_release_decision_readback_only_no_live_write`;owner release authorized、owner review approved、owner decision approved、verifier decision approved、maintenance window approved、release decision passed、release authorization granted、release authorization passed、rollback release passed、live apply release passed、writer apply、execution apply、receipt write、reviewer queue write、Gateway queue write、Telegram send、Bot API、report receipt、result capture write、learning write、PlayBook trust write、production write、secret read 與 destructive operation 仍全部維持 `0 / false`。 + +**本地驗證**: +- JSON parse:P2-139 schema / snapshot、`zh-TW.json`、`en.json` 通過。 +- Python 編譯:P2-139 loader 與 `agents.py` 通過。 +- API/service pytest:P2-139 `7 passed`。 +- i18n key mirror:`11809` keys,`zh-TW.json` / `en.json` 鏡像差異 `0`。 +- Web typecheck:本臨時 worktree 無 `node_modules`,`pnpm --filter @awoooi/web typecheck` 停在 `tsc: command not found`;未安裝依賴,避免增加主機負載,等待 Gitea CD 在乾淨環境跑完整前端驗證。 + +**安全邊界**: +- P2-139 仍是只讀 release decision readback;不接受口頭批准、不把 hold / readback 解讀成 owner release authorized、不把 owner decision readback 解讀成決策通過、不批准維護窗口、不核發或通過 release authorization、不通過 rollback release、不釋放 live apply、不套用 writer、不執行正式寫入、不寫 receipt、不寫 result capture、不寫 learning、不更新 PlayBook trust、不寫 reviewer queue、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 report receipt、不讀 canonical runtime target、不做 live query、不寫 production target、不讀 secret、不執行 destructive action、不回傳內部工作內容。 +- 本段尚未正式部署;需要 feature commit、deploy marker、production API readback 與 desktop / mobile Browser smoke 後,才可記錄正式驗證完成。 + +**下一步**: +- 推送 P2-139 feature commit,等待 Gitea CD / code-review;正式驗證通過後,才可由 `P2-140` 承接。 + ## 2026-06-14|P2-138 寫入邊界前端補強正式驗證完成 **背景**:P2-138 已正式驗證,但 governance UI 的 P2-138 真相區塊只顯示 `Gateway 寫入=0` 與聚合的 `正式寫入 / 發送 0`,對資安邊界來說仍需拆出 Telegram、Bot API 與 production write 的明確 `0` 值,避免操作者用聚合值推論。 diff --git a/docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md b/docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md index c966b0165..60ed14bfb 100644 --- a/docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md +++ b/docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md @@ -12,7 +12,7 @@ | Nemotron 實際整合應用 | 30% | 完整回放前仍被關卡擋下 | `blocked_needs_evidence`,下一關是 `refresh_source_evidence_then_5_record_smoke_only` | | 工具 / 服務 / 套件 AI 自動化 | 92% | P0 已完成;P1 服務 / runtime / 監控 / provider / service health / 備份 / DR / 套件與供應鏈只讀基線已完成;P1-007 失敗限定通知合約與前端 redaction 合約已完成;下一主線是 P2-004 依賴 / 供應鏈漂移監控 | 狀態分類、盤點 schema、權限矩陣、靜態盤點種子、只讀 API、UI 骨架、驗證、自動化待辦 schema / 快照 / API / 分組 UI、Backup / DR 目標盤點、準備度矩陣、備份通知政策、Backup / DR 證據 UI、復原演練批准包模板、異地 / escrow 準備度狀態、任務批准邊界、確定性進度彙總、Python 套件 / 供應鏈只讀基線、JS pnpm/npm 只讀基線、Docker build surface 只讀基線、CVE / license / drift 嚴重度政策、定期依賴漂移與外部資料來源檢查設計、依賴升級批准包模板、runtime_surface_inventory_v1 schema / snapshot / API / UI、gitea_workflow_runner_health_v1 schema / snapshot / API / UI、observability_contract_matrix_v1 schema / snapshot / API / UI、ai_provider_route_matrix_v1 schema / snapshot / API / UI、service_health_gap_matrix_v1 schema / snapshot / API / UI、service health evidence cards UI、service_health_failure_notification_policy_v1 schema / snapshot / API / UI 已完成 | | OpenClaw / Hermes / NemoTron 佈建布局 | 45% | P1-401 / P1-402 已完成;仍是只讀 layout 與治理頁顯示,不是 runtime deploy | `ai_agent_deployment_layout_v1` schema、`ai_agent_deployment_layout_2026-06-11.json`、`GET /api/v1/agents/agent-deployment-layout`、治理頁自動化盤點 UI、`AI_AGENT_DEPLOYMENT_LAYOUT_2026-06-11.md` | -| OpenClaw / Hermes / NemoTron 主動溝通、學習與成長證據 | 100% | P2-401A 到 P2-135 已完成只讀證據面、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 與 release authorization readback gate;P2-135 已正式驗證,固定 5 個 release authorization readback、5 個 rollback release readback、5 個 maintenance window readback hold、5 個 live-apply release readback hold、6 個 blocked release readback transition 與 5 個 operator action。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_authorization_readback_gate_v1`、`GET /api/v1/agents/agent-result-capture-release-authorization-readback-gate`、P2-135 + P2-134 本地 pytest `14 passed`、JSON parse、Python compile、Web typecheck 通過、正式部署與 production smoke 已完成、`ai_agent_result_capture_release_authorization_hold_v1`、`GET /api/v1/agents/agent-result-capture-release-authorization-hold`、正式站 deploy marker `18b867c3`、正式 API readback、正式站 `/zh-TW/governance?tab=automation-inventory&_v=18b867c3-p2-134-prod-desktop` desktop / mobile smoke、禁用內部協作片語 `0`、水平溢位 `0`、危險控制 `0`、console error `0`、`ai_agent_result_capture_final_release_candidate_readback_v1`、`GET /api/v1/agents/agent-result-capture-final-release-candidate-readback`、正式站 deploy marker `8be5ddab`、`ai_agent_result_capture_post_release_verifier_rollback_gate_v1`、`GET /api/v1/agents/agent-result-capture-post-release-verifier-rollback-gate`、正式站 deploy marker `934af770`、正式站 `/zh-TW/governance?tab=automation-inventory` desktop / mobile smoke、`ai_agent_result_capture_owner_release_approval_gate_v1`、`GET /api/v1/agents/agent-result-capture-owner-release-approval-gate`、正式站 deploy marker `03617db7`、`ai_agent_result_capture_owner_approved_release_readiness_readback_v1`、`GET /api/v1/agents/agent-result-capture-owner-approved-release-readiness-readback`、正式站 deploy marker `6fcf7241`、`ai_agent_result_capture_owner_approved_preflight_release_package_v1`、`GET /api/v1/agents/agent-result-capture-owner-approved-preflight-release-package`、`ai_agent_result_capture_owner_acceptance_readback_preflight_hold_v1`、`GET /api/v1/agents/agent-result-capture-owner-acceptance-readback-preflight-hold`、`ai_agent_result_capture_owner_acceptance_maintenance_gate_v1`、`GET /api/v1/agents/agent-result-capture-owner-acceptance-maintenance-gate`、`ai_agent_result_capture_owner_approved_execution_rehearsal_v1`、`GET /api/v1/agents/agent-result-capture-owner-approved-execution-rehearsal`、`ai_agent_result_capture_owner_promotion_review_v1`、`ai_agent_result_capture_writer_dry_run_readback_v1`、`ai_agent_result_capture_writer_dry_run_fixture_v1`、`ai_agent_result_capture_writer_implementation_review_v1`、`ai_agent_result_capture_write_gate_review_v1`、`ai_agent_interaction_learning_proof_v1`、MASTER §3.2.1b / §3.2.1d / §3.4.3 | +| OpenClaw / Hermes / NemoTron 主動溝通、學習與成長證據 | 100% | P2-401A 到 P2-139 已完成只讀證據面、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 與 release decision readback;P2-139 已本地完成,固定 5 個 release decision readback、5 個 owner decision readback、5 個 verifier decision readback、5 個 rollback decision readback、5 個 maintenance window decision readback、5 個 live-apply decision readback、6 個 blocked readback transition 與 5 個 operator action。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_readback_v1`、`GET /api/v1/agents/agent-result-capture-release-decision-readback`、P2-139 API/service pytest `7 passed`、JSON parse、Python compile、i18n key mirror `11809`、治理頁 P2-139 區塊;本臨時 worktree 無 `node_modules`,Web typecheck 需由 Gitea CD 乾淨環境驗證;`ai_agent_result_capture_release_decision_hold_v1`、`GET /api/v1/agents/agent-result-capture-release-decision-hold`、deploy marker `bfd26e76`、正式 API readback、desktop / mobile smoke、禁用內部協作片語 `0`、水平溢位 `0`、危險控制 `0`、console error `0`、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 | | 本工作清單與分析報告 | 100% | 已完成 | 本 MD 文件 | @@ -81,6 +81,12 @@ ### 2026-06-14 11:40 狀態同步 +- `P2-139` release decision readback 已本地完成:新增 `ai_agent_result_capture_release_decision_readback_v1`、`GET /api/v1/agents/agent-result-capture-release-decision-readback`、治理頁 P2-139 區塊與繁中 UI 文案。 +- 本地證據:P2-139 API/service pytest `7 passed`、JSON parse、Python compile、i18n key mirror `11809` 通過。 +- 本臨時 worktree 沒有 `node_modules`,`pnpm --filter @awoooi/web typecheck` 停在 `tsc: command not found`;未安裝依賴,避免增加主機負載,等待 Gitea CD 在乾淨環境跑完整前端驗證。 +- P2-139 固定 5 個 release decision readback、5 個 owner decision readback、5 個 verifier decision readback、5 個 rollback decision readback、5 個 maintenance window decision readback、5 個 live-apply decision readback、6 個 blocked readback transition、5 個 operator action、需批准 `12`、阻擋 `12`、正式寫入 / 發送 `0`。 +- 邊界仍維持:owner release authorized、owner review approved、owner decision approved、verifier decision approved、maintenance window approved、release decision passed、release authorization granted / passed、rollback release passed、live apply release passed、writer apply、execution apply、receipt write、reviewer queue write、Gateway queue write、Telegram send、Bot API、report receipt、result capture write、learning write、PlayBook trust write、production write、secret read、destructive operation 全部 `0 / false`。 +- P2-139 推送與正式驗證後才可交給 `P2-140`;仍不得直接開啟 result capture writer、learning writer、PlayBook trust writer、reviewer queue write、Gateway queue write、Telegram send、Bot API call 或 production write。 - `P2-138` 前端寫入邊界已補強並正式驗證:commit `49852d3d`、deploy marker `923fb117`、code-review run `4215` success、CD run `4214` success。 - Governance automation inventory 的 P2-138 truth chip 已拆出 `Gateway 寫入=0`、`Telegram 送出=0`、`Bot API 呼叫=0`、`正式寫入=0`,不再只靠聚合的正式寫入 / 發送數推論。 - 本地證據:JSON parse OK、i18n key parity `11780`、Web typecheck 通過、Web production build 通過、security mirror guard OK、source-control owner response guard OK、doc secrets sanity OK(796 files)、diff scan 未命中工作視窗片語。 @@ -92,7 +98,7 @@ AI Agent 自動化工作包目前完成度:**99.8%**。本工作清單文件 三 Agent 佈建布局目前完成度:**45%**。第一波已完成只讀 schema / snapshot / API / 測試 / 報告,第二波已接入治理頁自動化盤點 UI;正式 runtime 佈署、Telegram E2E 發送與 AgentSession 工作流仍需逐項 gate。 -三 Agent 主動溝通、學習與成長證據目前完成度:**100%**。P2-403A 到 P2-138 已把互動證據、報表治理、runtime readback、reviewer / result capture / writer 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、release authorization readback gate、release verifier preflight gate、release verifier owner review packet 與 release decision hold 固定成可驗證證據。P2-138 最新合約已正式驗證,deploy marker `bfd26e76`;P2-137 已正式驗證,deploy marker `d023f5d7`。目前 live AgentSession、Agent message、handoff、canonical runtime readback、live query、runtime score、result capture write、learning write、Telegram receipt、Gateway queue write、reviewer queue write、runtime verifier execution、live report delivery、AI analysis runtime、中低風險 auto worker、Telegram 實發、shadow worker live、delivery receipt E2E、KM / LOGBOOK / audit DB / timeline / PlayBook trust runtime 寫入仍全部為 `0`。真正下一步是 `P2-139` release decision readback。 +三 Agent 主動溝通、學習與成長證據目前完成度:**100%**。P2-403A 到 P2-139 已把互動證據、報表治理、runtime readback、reviewer / result capture / writer 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、release authorization readback gate、release verifier preflight gate、release verifier owner review packet、release decision hold 與 release decision readback 固定成可驗證證據。P2-139 已本地完成,P2-138 最新寫入邊界補強已正式驗證,deploy marker `923fb117`。目前 live AgentSession、Agent message、handoff、canonical runtime readback、live query、runtime score、result capture write、learning write、Telegram receipt、Gateway queue write、reviewer queue write、runtime verifier execution、live report delivery、AI analysis runtime、中低風險 auto worker、Telegram 實發、shadow worker live、delivery receipt E2E、KM / LOGBOOK / audit DB / timeline / PlayBook trust runtime 寫入仍全部為 `0`。真正下一步是 P2-139 正式部署驗證,通過後由 `P2-140` 承接。 AI Agent 主動營運委派與版本生命週期目前完成度:**100%**。已完成 12 類版本 domain、24 類可委派能力、5 種 cadence、8 類 MCP、4 類 RAG memory、只讀 API、`P2-402B` repo-only daily version freshness snapshot、`P2-402C` Renovate / OSV-Scanner / Trivy / Syft / Grype 工具採用批准包、`P2-402D` Telegram action-required digest policy、`P2-402E` Gitea PR 草案 lane、`P2-402F` host OS / K3s / stateful services 版本只讀盤點,以及 `P2-402G` governance UI 顯示可委派能力;`P2-403A` 到 `P2-138` 已補互動、學習證據面、live read model gate、Redis dry-run gate、learning writeback approval package、Telegram receipt approval package、owner-approved learning dry-run preview、runtime write gate review、post-write verifier package、runtime verifier evidence review、報表真相、TG 戰情室收斂、日週月報、Agent 工作量、圖表化報告、風險自動化政策、報表 runtime 啟動前閘門、no-write dry-run 證據包、fixture/readback/verifier dry-run 證據包、shadow/no-write execution gate、操作類別權限模型、13 類候選操作 dry-run 證據、任務結果稽核軌跡、matched PlayBook 學習缺口、critic / reviewer result capture、owner-approved result capture dry-run / readback、result capture 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、release authorization readback gate、release verifier preflight gate、release verifier owner review packet 與 release decision hold。下一步是 P2-139 release decision readback;外部 registry / package source / host probe / SSH / kubectl / 工具安裝 / CI 變更 / 實際 PR creation / Telegram 實發與 learning write 仍需 gate。 @@ -1083,7 +1089,7 @@ UI: | P2-136 | 完成 | 100 | OpenClaw + Hermes + NemoTron | release verifier preflight gate | `ai_agent_result_capture_release_verifier_preflight_gate_v1` / schema / snapshot / 只讀 API / governance UI;feature commit `913d7f68`、deploy marker `f2fa8454` 已正式驗證;5 個 release verifier preflight、5 個 rollback verifier preflight、5 個 maintenance window verifier hold、5 個 live-apply verifier hold、6 個 blocked verifier preflight transition、5 個 operator action;需批准 `8`、blocked status subtotal `4`、critical blocker `5`、前端顯示阻擋總數 `9`;runtime authority 固定 `result_capture_release_verifier_preflight_gate_only_no_live_write`;post-release verifier ready、release authorization granted / passed、rollback release、live apply release、writer apply、execution apply、receipt write、result capture、learning、PlayBook trust、Gateway、Telegram、production write、secret read、destructive operation 全為 `0` | production API readback、desktop / mobile smoke、禁用內部協作片語 `0`、水平溢位 `0`、危險控制 `0`、console error `0`;已由 P2-137 承接,不把 verifier preflight 視為 post-release verifier ready、不核發 release authorization、不釋放 live apply、不套用 writer | | P2-137 | 完成 | 100 | OpenClaw + Hermes + NemoTron | release verifier owner review packet | `ai_agent_result_capture_release_verifier_owner_review_packet_v1` / schema / snapshot / 只讀 API / governance UI;feature commit `f737f278`、deploy marker `d023f5d7` 已正式驗證;5 個 owner review packet、5 個 verifier review packet、5 個 rollback owner review packet、5 個 maintenance window review hold、5 個 live-apply owner review hold、6 個 blocked owner review transition、5 個 operator action;需批准 `10`、阻擋 `10`;runtime authority 固定 `result_capture_release_verifier_owner_review_packet_only_no_live_write`;owner release authorized / owner review approved / maintenance window approved / rollback owner confirmed / post-release verifier ready / release authorization granted / release authorization passed / rollback release / live apply release / writer apply / execution apply / receipt write / result capture / learning / PlayBook trust / reviewer queue / Gateway / Telegram / Bot API / production write / secret read / destructive operation 全為 `0` | 本地 pytest `7 passed`、JSON parse、Python compile、Web typecheck 通過;production API readback、desktop / mobile smoke、水平溢位 `0`、P2-137 卡片危險控制 `0`、console error `0`、HTTP 4xx/5xx `0`;已由 P2-138 承接 | | P2-138 | 完成 | 100 | OpenClaw + Hermes + NemoTron | release decision hold | `ai_agent_result_capture_release_decision_hold_v1` / schema / snapshot / 只讀 API / governance UI;feature commit `655df33d` 與 maintenance window 補強 commit `1ae67f1f` 已由 deploy marker `bfd26e76` 正式驗證;承接 P2-137,只建立 5 個 release decision hold、5 個 owner decision hold、5 個 verifier decision hold、5 個 rollback decision hold、5 個 maintenance window decision hold、5 個 live-apply decision hold、6 個 blocked decision transition、5 個 operator action;需批准 `12`、阻擋 `12`;runtime authority 固定 `result_capture_release_decision_hold_only_no_live_write`;owner release authorized / owner review approved / owner decision approved / verifier decision approved / maintenance window approved / release decision passed / release authorization granted / passed / rollback release / live apply release / writer apply / execution apply / receipt write / reviewer queue / Gateway / Telegram / Bot API / result capture / learning / PlayBook trust / production write / secret read / destructive operation 全為 `0` | 本地 P2-138 + P2-137 pytest `15 passed`、JSON parse、Python compile、i18n key mirror `11777`、Web typecheck 與 Web production build 通過;production API readback、desktop / mobile smoke、水平溢位 `0`、P2-138 卡片危險控制 `0`、console / page error `0`、HTTP 4xx/5xx `0`;不得把 P2-138 當 runtime gate,已由 P2-139 承接 | -| P2-139 | 計畫中 | 0 | OpenClaw + Hermes + NemoTron | release decision readback | 承接 P2-138,只能建立 release decision hold readback 的只讀證據;不得把 release decision hold 視為決策通過,不得讀 secret、不得寫 reviewer queue、不得寫 Gateway queue、不得送 Telegram、不得呼叫 Bot API、不得 production write | P2-138 正式部署驗證後才可開始;仍不得把 P2-139 當 runtime gate | +| P2-139 | 本地完成 | 100 | OpenClaw + Hermes + NemoTron | release decision readback | `ai_agent_result_capture_release_decision_readback_v1` / schema / snapshot / 只讀 API / governance UI;承接 P2-138,只讀回 5 個 release decision readback、5 個 owner decision readback、5 個 verifier decision readback、5 個 rollback decision readback、5 個 maintenance window decision readback、5 個 live-apply decision readback、6 個 blocked readback transition、5 個 operator action;需批准 `12`、阻擋 `12`;runtime authority 固定 `result_capture_release_decision_readback_only_no_live_write`;owner release authorized / owner review approved / owner decision approved / verifier decision approved / maintenance window approved / release decision passed / release authorization granted / passed / rollback release / live apply release / writer apply / execution apply / receipt write / reviewer queue / Gateway / Telegram / Bot API / result capture / learning / PlayBook trust / production write / secret read / destructive operation 全為 `0` | 本地 P2-139 API/service pytest `7 passed`、JSON parse、Python compile、i18n key mirror `11809` 通過;本臨時 worktree 無 `node_modules`,Web typecheck 等 Gitea CD 驗證;不得把 P2-139 當 runtime gate,正式部署驗證後才可由 P2-140 承接 | ### P3 - 候選 Agent 擴展 diff --git a/docs/evaluations/ai_agent_result_capture_release_decision_readback_2026-06-14.json b/docs/evaluations/ai_agent_result_capture_release_decision_readback_2026-06-14.json new file mode 100644 index 000000000..399a03557 --- /dev/null +++ b/docs/evaluations/ai_agent_result_capture_release_decision_readback_2026-06-14.json @@ -0,0 +1,674 @@ +{ + "schema_version": "ai_agent_result_capture_release_decision_readback_v1", + "generated_at": "2026-06-14T11:24:00+08:00", + "program_status": { + "overall_completion_percent": 100, + "current_priority": "P2", + "current_task_id": "P2-139", + "next_task_id": "P2-140", + "read_only_mode": true, + "runtime_authority": "result_capture_release_decision_readback_only_no_live_write", + "status_note": "P2-139 只讀回 P2-138 release decision hold;不得視為 owner decision approved、release decision passed、release authorization granted / passed、rollback release passed 或 live apply passed,不得寫 reviewer / Gateway queue、送 Telegram、呼叫 Bot API、寫 result capture、learning、PlayBook trust 或 production target。" + }, + "source_refs": [ + "docs/evaluations/ai_agent_result_capture_release_decision_hold_2026-06-14.json", + "docs/evaluations/ai_agent_result_capture_release_verifier_owner_review_packet_2026-06-14.json", + "docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md#60-建立-release-decision-readback" + ], + "prior_release_decision_hold": { + "schema_version": "ai_agent_result_capture_release_decision_hold_v1", + "release_decision_hold_count": 5, + "owner_decision_hold_count": 5, + "verifier_decision_hold_count": 5, + "rollback_decision_hold_count": 5, + "maintenance_window_decision_hold_count": 5, + "live_apply_decision_hold_count": 5, + "blocked_decision_transition_count": 6, + "operator_action_count": 5, + "approval_required_total": 12, + "blocked_total": 12, + "readiness_note": "P2-138 已把 release / owner / verifier / rollback / maintenance / live apply decision hold 固定成只讀;P2-139 只讀回 hold 狀態,不把 hold 視為決策通過。", + "owner_release_authorized_count": 0, + "owner_release_approved_count": 0, + "owner_review_approved_count": 0, + "owner_decision_approved_count": 0, + "verifier_decision_approved_count": 0, + "maintenance_window_approved_count": 0, + "rollback_owner_confirmed_count": 0, + "post_release_verifier_ready_count": 0, + "final_release_candidate_approved_count": 0, + "final_release_candidate_pass_count": 0, + "release_decision_pass_count": 0, + "release_authorization_granted_count": 0, + "release_authorization_pass_count": 0, + "rollback_release_pass_count": 0, + "live_apply_release_pass_count": 0, + "writer_apply_count": 0, + "execution_apply_count": 0, + "receipt_write_count": 0, + "reviewer_queue_write_count": 0, + "gateway_queue_write_count": 0, + "telegram_send_count": 0, + "bot_api_call_count": 0, + "report_receipt_write_count": 0, + "result_capture_write_count": 0, + "learning_write_count": 0, + "playbook_trust_write_count": 0, + "production_write_count": 0, + "secret_read_count": 0, + "destructive_operation_count": 0 + }, + "release_decision_readback_truth": { + "p2_138_release_decision_hold_loaded": true, + "release_decision_readback_ready": true, + "owner_decision_still_required": true, + "verifier_decision_still_required": true, + "rollback_decision_still_required": true, + "maintenance_window_decision_still_required": true, + "live_apply_decision_still_required": true, + "redaction_review_still_required": true, + "release_decision_readback_only": true, + "truth_note": "P2-139 只讀回 P2-138 release decision hold;readback 可見不代表 owner / verifier / rollback / maintenance / live apply 任一決策通過,也不代表 runtime queue 或 Telegram 可以寫入。", + "owner_release_authorized": false, + "owner_release_approved": false, + "owner_review_approved": false, + "owner_decision_approved": false, + "verifier_decision_approved": false, + "maintenance_window_approved": false, + "rollback_owner_confirmed": false, + "post_release_verifier_ready": false, + "final_release_candidate_approved": false, + "final_release_candidate_passed": false, + "release_decision_passed": false, + "release_authorization_granted": false, + "release_authorization_passed": false, + "rollback_release_passed": false, + "live_apply_release_passed": false, + "writer_apply_enabled": false, + "execution_apply_enabled": false, + "receipt_write_enabled": false, + "reviewer_queue_write_enabled": false, + "gateway_queue_write_enabled": false, + "telegram_send_enabled": false, + "bot_api_call_enabled": false, + "report_receipt_write_enabled": false, + "result_capture_write_enabled": false, + "learning_write_enabled": false, + "playbook_trust_write_enabled": false, + "production_write_enabled": false, + "secret_read_enabled": false, + "destructive_operation_enabled": false, + "owner_release_authorized_count": 0, + "owner_release_approved_count": 0, + "owner_review_approved_count": 0, + "owner_decision_approved_count": 0, + "verifier_decision_approved_count": 0, + "maintenance_window_approved_count": 0, + "rollback_owner_confirmed_count": 0, + "post_release_verifier_ready_count": 0, + "final_release_candidate_approved_count": 0, + "final_release_candidate_pass_count": 0, + "release_decision_pass_count": 0, + "release_authorization_granted_count": 0, + "release_authorization_pass_count": 0, + "rollback_release_pass_count": 0, + "live_apply_release_pass_count": 0, + "writer_apply_count": 0, + "execution_apply_count": 0, + "receipt_write_count": 0, + "reviewer_queue_write_count": 0, + "gateway_queue_write_count": 0, + "telegram_send_count": 0, + "bot_api_call_count": 0, + "report_receipt_write_count": 0, + "result_capture_write_count": 0, + "learning_write_count": 0, + "playbook_trust_write_count": 0, + "production_write_count": 0, + "secret_read_count": 0, + "destructive_operation_count": 0 + }, + "release_decision_readbacks": [ + { + "readback_id": "release_decision_readback_result_capture", + "display_name": "Result capture 釋出決策讀回", + "owner_agent": "openclaw", + "source_hold_id": "release_decision_hold_result_capture", + "readback_status": "readback_complete", + "readback_mode": "release_decision_readback", + "readback_summary": "Result capture 僅可進入 release decision hold;owner review packet 未等於決策通過,仍不得寫入 result capture。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false, + "evidence_hash": "sha256:8311111111111111111111111111111111111111111111111111111111111111" + }, + { + "readback_id": "release_decision_readback_learning", + "display_name": "Learning 釋出決策讀回", + "owner_agent": "hermes", + "source_hold_id": "release_decision_hold_learning", + "readback_status": "approval_required", + "readback_mode": "release_decision_readback", + "readback_summary": "Learning 僅可進入 release decision hold;owner review packet 未等於決策通過,仍不得寫入 learning。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false, + "evidence_hash": "sha256:8322222222222222222222222222222222222222222222222222222222222222" + }, + { + "readback_id": "release_decision_readback_playbook_trust", + "display_name": "PlayBook trust 釋出決策讀回", + "owner_agent": "nemotron", + "source_hold_id": "release_decision_hold_playbook_trust", + "readback_status": "blocked_by_policy", + "readback_mode": "release_decision_readback", + "readback_summary": "PlayBook trust 僅可進入 release decision hold;owner review packet 未等於決策通過,仍不得寫入 trust。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false, + "evidence_hash": "sha256:8333333333333333333333333333333333333333333333333333333333333333" + }, + { + "readback_id": "release_decision_readback_reviewer_queue", + "display_name": "Reviewer queue 釋出決策讀回", + "owner_agent": "openclaw", + "source_hold_id": "release_decision_hold_reviewer_queue", + "readback_status": "approval_required", + "readback_mode": "release_decision_readback", + "readback_summary": "Reviewer queue 僅可進入 release decision hold;owner review packet 未等於決策通過,仍不得寫 reviewer queue。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false, + "evidence_hash": "sha256:8344444444444444444444444444444444444444444444444444444444444444" + }, + { + "readback_id": "release_decision_readback_gateway_queue", + "display_name": "Gateway queue 釋出決策讀回", + "owner_agent": "nemotron", + "source_hold_id": "release_decision_hold_gateway_queue", + "readback_status": "readback_complete", + "readback_mode": "release_decision_readback", + "readback_summary": "Gateway queue 僅可進入 release decision hold;owner review packet 未等於決策通過,仍不得寫 Gateway queue。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false, + "evidence_hash": "sha256:8355555555555555555555555555555555555555555555555555555555555555" + } + ], + "owner_decision_readbacks": [ + { + "readback_id": "owner_decision_readback_result_capture", + "display_name": "Result capture 負責人決策讀回", + "owner_agent": "openclaw", + "source_hold_id": "owner_decision_hold_result_capture", + "readback_status": "readback_complete", + "readback_mode": "owner_decision_readback", + "readback_summary": "負責人尚未核准 Result capture release decision。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "owner_decision_readback_learning", + "display_name": "Learning 負責人決策讀回", + "owner_agent": "hermes", + "source_hold_id": "owner_decision_hold_learning", + "readback_status": "approval_required", + "readback_mode": "owner_decision_readback", + "readback_summary": "負責人尚未核准 Learning release decision。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "owner_decision_readback_playbook_trust", + "display_name": "PlayBook trust 負責人決策讀回", + "owner_agent": "nemotron", + "source_hold_id": "owner_decision_hold_playbook_trust", + "readback_status": "blocked_by_policy", + "readback_mode": "owner_decision_readback", + "readback_summary": "負責人尚未核准 PlayBook trust release decision。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "owner_decision_readback_reviewer_queue", + "display_name": "Reviewer queue 負責人決策讀回", + "owner_agent": "openclaw", + "source_hold_id": "owner_decision_hold_reviewer_queue", + "readback_status": "approval_required", + "readback_mode": "owner_decision_readback", + "readback_summary": "負責人尚未核准 Reviewer queue release decision。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "owner_decision_readback_gateway_queue", + "display_name": "Gateway queue 負責人決策讀回", + "owner_agent": "nemotron", + "source_hold_id": "owner_decision_hold_gateway_queue", + "readback_status": "readback_complete", + "readback_mode": "owner_decision_readback", + "readback_summary": "負責人尚未核准 Gateway queue release decision。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + } + ], + "verifier_decision_readbacks": [ + { + "readback_id": "verifier_decision_readback_result_capture", + "display_name": "Result capture 驗證器決策讀回", + "owner_agent": "openclaw", + "source_hold_id": "verifier_decision_hold_result_capture", + "readback_status": "readback_complete", + "readback_mode": "verifier_decision_readback", + "readback_summary": "post-release verifier 未核准前不得通過 Result capture release authorization。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "verifier_decision_readback_learning", + "display_name": "Learning 驗證器決策讀回", + "owner_agent": "hermes", + "source_hold_id": "verifier_decision_hold_learning", + "readback_status": "approval_required", + "readback_mode": "verifier_decision_readback", + "readback_summary": "post-release verifier 未核准前不得通過 Learning release authorization。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "verifier_decision_readback_playbook_trust", + "display_name": "PlayBook trust 驗證器決策讀回", + "owner_agent": "nemotron", + "source_hold_id": "verifier_decision_hold_playbook_trust", + "readback_status": "blocked_by_policy", + "readback_mode": "verifier_decision_readback", + "readback_summary": "post-release verifier 未核准前不得通過 PlayBook trust release authorization。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "verifier_decision_readback_reviewer_queue", + "display_name": "Reviewer queue 驗證器決策讀回", + "owner_agent": "openclaw", + "source_hold_id": "verifier_decision_hold_reviewer_queue", + "readback_status": "approval_required", + "readback_mode": "verifier_decision_readback", + "readback_summary": "post-release verifier 未核准前不得通過 Reviewer queue release authorization。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "verifier_decision_readback_gateway_queue", + "display_name": "Gateway queue 驗證器決策讀回", + "owner_agent": "nemotron", + "source_hold_id": "verifier_decision_hold_gateway_queue", + "readback_status": "readback_complete", + "readback_mode": "verifier_decision_readback", + "readback_summary": "post-release verifier 未核准前不得通過 Gateway queue release authorization。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + } + ], + "rollback_decision_readbacks": [ + { + "readback_id": "rollback_decision_readback_result_capture", + "display_name": "Result capture 回滾決策讀回", + "owner_agent": "openclaw", + "source_hold_id": "rollback_decision_hold_result_capture", + "readback_status": "readback_complete", + "readback_mode": "rollback_decision_readback", + "readback_summary": "rollback owner 未確認前不得通過 Result capture rollback release。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "rollback_decision_readback_learning", + "display_name": "Learning 回滾決策讀回", + "owner_agent": "hermes", + "source_hold_id": "rollback_decision_hold_learning", + "readback_status": "approval_required", + "readback_mode": "rollback_decision_readback", + "readback_summary": "rollback owner 未確認前不得通過 Learning rollback release。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "rollback_decision_readback_playbook_trust", + "display_name": "PlayBook trust 回滾決策讀回", + "owner_agent": "nemotron", + "source_hold_id": "rollback_decision_hold_playbook_trust", + "readback_status": "blocked_by_policy", + "readback_mode": "rollback_decision_readback", + "readback_summary": "rollback owner 未確認前不得通過 PlayBook trust rollback release。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "rollback_decision_readback_reviewer_queue", + "display_name": "Reviewer queue 回滾決策讀回", + "owner_agent": "openclaw", + "source_hold_id": "rollback_decision_hold_reviewer_queue", + "readback_status": "approval_required", + "readback_mode": "rollback_decision_readback", + "readback_summary": "rollback owner 未確認前不得通過 Reviewer queue rollback release。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "rollback_decision_readback_gateway_queue", + "display_name": "Gateway queue 回滾決策讀回", + "owner_agent": "nemotron", + "source_hold_id": "rollback_decision_hold_gateway_queue", + "readback_status": "readback_complete", + "readback_mode": "rollback_decision_readback", + "readback_summary": "rollback owner 未確認前不得通過 Gateway queue rollback release。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + } + ], + "maintenance_window_decision_readbacks": [ + { + "readback_id": "maintenance_window_decision_readback_result_capture", + "display_name": "Result capture 維護窗口決策讀回", + "owner_agent": "openclaw", + "source_hold_id": "maintenance_window_decision_hold_result_capture", + "readback_status": "readback_complete", + "readback_mode": "maintenance_window_decision_readback", + "readback_summary": "維護窗口未批准前不得釋放 Result capture 正式套用。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "maintenance_window_decision_readback_learning", + "display_name": "Learning 維護窗口決策讀回", + "owner_agent": "hermes", + "source_hold_id": "maintenance_window_decision_hold_learning", + "readback_status": "approval_required", + "readback_mode": "maintenance_window_decision_readback", + "readback_summary": "維護窗口未批准前不得釋放 Learning 正式套用。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "maintenance_window_decision_readback_playbook_trust", + "display_name": "PlayBook trust 維護窗口決策讀回", + "owner_agent": "nemotron", + "source_hold_id": "maintenance_window_decision_hold_playbook_trust", + "readback_status": "blocked_by_policy", + "readback_mode": "maintenance_window_decision_readback", + "readback_summary": "維護窗口未批准前不得釋放 PlayBook trust 正式套用。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "maintenance_window_decision_readback_reviewer_queue", + "display_name": "Reviewer queue 維護窗口決策讀回", + "owner_agent": "openclaw", + "source_hold_id": "maintenance_window_decision_hold_reviewer_queue", + "readback_status": "approval_required", + "readback_mode": "maintenance_window_decision_readback", + "readback_summary": "維護窗口未批准前不得釋放 Reviewer queue 正式套用。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "maintenance_window_decision_readback_gateway_queue", + "display_name": "Gateway queue 維護窗口決策讀回", + "owner_agent": "nemotron", + "source_hold_id": "maintenance_window_decision_hold_gateway_queue", + "readback_status": "readback_complete", + "readback_mode": "maintenance_window_decision_readback", + "readback_summary": "維護窗口未批准前不得釋放 Gateway queue 正式套用。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + } + ], + "live_apply_decision_readbacks": [ + { + "readback_id": "live_apply_decision_readback_result_capture", + "display_name": "Result capture 正式套用決策讀回", + "owner_agent": "openclaw", + "source_hold_id": "live_apply_decision_hold_result_capture", + "readback_status": "readback_complete", + "readback_mode": "live_apply_decision_readback", + "readback_summary": "release authorization 未核發與通過前不得正式套用 Result capture。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "live_apply_decision_readback_learning", + "display_name": "Learning 正式套用決策讀回", + "owner_agent": "hermes", + "source_hold_id": "live_apply_decision_hold_learning", + "readback_status": "approval_required", + "readback_mode": "live_apply_decision_readback", + "readback_summary": "release authorization 未核發與通過前不得正式套用 Learning。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "live_apply_decision_readback_playbook_trust", + "display_name": "PlayBook trust 正式套用決策讀回", + "owner_agent": "nemotron", + "source_hold_id": "live_apply_decision_hold_playbook_trust", + "readback_status": "blocked_by_policy", + "readback_mode": "live_apply_decision_readback", + "readback_summary": "release authorization 未核發與通過前不得正式套用 PlayBook trust。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "live_apply_decision_readback_reviewer_queue", + "display_name": "Reviewer queue 正式套用決策讀回", + "owner_agent": "openclaw", + "source_hold_id": "live_apply_decision_hold_reviewer_queue", + "readback_status": "approval_required", + "readback_mode": "live_apply_decision_readback", + "readback_summary": "release authorization 未核發與通過前不得正式套用 Reviewer queue。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + }, + { + "readback_id": "live_apply_decision_readback_gateway_queue", + "display_name": "Gateway queue 正式套用決策讀回", + "owner_agent": "nemotron", + "source_hold_id": "live_apply_decision_hold_gateway_queue", + "readback_status": "readback_complete", + "readback_mode": "live_apply_decision_readback", + "readback_summary": "release authorization 未核發與通過前不得正式套用 Gateway queue。", + "release_decision_passed": false, + "release_authorization_granted": false, + "runtime_write_allowed": false, + "telegram_send_allowed": false + } + ], + "blocked_readback_transitions": [ + { + "transition_id": "readback_readback_to_release_authorization", + "status": "blocked_by_policy", + "reason": "release decision readback 尚未通過,不得轉 release authorization granted。", + "runtime_write_allowed": false + }, + { + "transition_id": "readback_readback_to_reviewer_queue", + "status": "approval_required", + "reason": "reviewer queue write 未授權,不得把決策保留寫入 reviewer queue。", + "runtime_write_allowed": false + }, + { + "transition_id": "readback_readback_to_gateway_queue", + "status": "blocked_by_policy", + "reason": "Gateway queue write 未授權,不得把決策保留寫入 Gateway queue。", + "runtime_write_allowed": false + }, + { + "transition_id": "readback_readback_to_telegram_send", + "status": "approval_required", + "reason": "Telegram send 未授權,不得發送 release decision readback 通知。", + "runtime_write_allowed": false + }, + { + "transition_id": "readback_readback_to_writer_apply", + "status": "blocked_by_policy", + "reason": "writer apply 未授權,不得套用 result capture、learning 或 PlayBook trust。", + "runtime_write_allowed": false + }, + { + "transition_id": "readback_readback_to_production_target", + "status": "approval_required", + "reason": "production write 未授權,不得觸及任何 production target。", + "runtime_write_allowed": false + } + ], + "operator_actions": [ + { + "action_id": "review_release_decision_readback_scope", + "owner_agent": "openclaw", + "status": "ready_for_operator_review", + "operator_instruction": "審查 release decision readback 是否只引用 redacted evidence;不得核發 release authorization。", + "runtime_write_allowed": false + }, + { + "action_id": "confirm_owner_decision_inputs", + "owner_agent": "hermes", + "status": "approval_required", + "operator_instruction": "確認 owner decision 所需輸入仍缺 maintenance window、rollback owner 與 verifier decision;不得寫 production。", + "runtime_write_allowed": false + }, + { + "action_id": "verify_queue_write_closed", + "owner_agent": "nemotron", + "status": "ready_for_operator_review", + "operator_instruction": "確認 reviewer queue、Gateway queue 與 Telegram 仍關閉;不得呼叫 Bot API。", + "runtime_write_allowed": false + }, + { + "action_id": "prepare_p2_139_release_decision_readback", + "owner_agent": "openclaw", + "status": "ready_for_operator_review", + "operator_instruction": "下一關只可建立 release decision readback,不得 writer apply、queue write 或 result capture write。", + "runtime_write_allowed": false + }, + { + "action_id": "document_decision_readback_boundary", + "owner_agent": "hermes", + "status": "approval_required", + "operator_instruction": "同步治理文件的 release decision readback 邊界;不得送 Telegram。", + "runtime_write_allowed": false + } + ], + "display_redaction_contract": { + "redaction_required": true, + "raw_prompt_display_allowed": false, + "private_reasoning_display_allowed": false, + "secret_value_display_allowed": false, + "raw_runtime_payload_display_allowed": false, + "internal_collaboration_content_display_allowed": false, + "frontend_display_policy": "前端只能顯示 readback summary、狀態與 redacted evidence refs;不得顯示 prompt、private reasoning、secret、raw runtime payload 或內部協作內容。" + }, + "rollups": { + "release_decision_readback_count": 5, + "owner_decision_readback_count": 5, + "verifier_decision_readback_count": 5, + "rollback_decision_readback_count": 5, + "maintenance_window_decision_readback_count": 5, + "live_apply_decision_readback_count": 5, + "blocked_readback_transition_count": 6, + "operator_action_count": 5, + "approval_required_release_decision_count": 2, + "blocked_release_decision_count": 1, + "approval_required_owner_decision_count": 2, + "blocked_owner_decision_count": 1, + "approval_required_verifier_decision_count": 2, + "blocked_verifier_decision_count": 1, + "approval_required_rollback_decision_count": 2, + "blocked_rollback_decision_count": 1, + "approval_required_maintenance_window_decision_count": 2, + "blocked_maintenance_window_decision_count": 1, + "approval_required_live_apply_decision_count": 2, + "blocked_live_apply_decision_count": 1, + "critical_blocker_count": 6, + "owner_release_authorized_count": 0, + "owner_release_approved_count": 0, + "owner_review_approved_count": 0, + "owner_decision_approved_count": 0, + "verifier_decision_approved_count": 0, + "maintenance_window_approved_count": 0, + "rollback_owner_confirmed_count": 0, + "post_release_verifier_ready_count": 0, + "final_release_candidate_approved_count": 0, + "final_release_candidate_pass_count": 0, + "release_decision_pass_count": 0, + "release_authorization_granted_count": 0, + "release_authorization_pass_count": 0, + "rollback_release_pass_count": 0, + "live_apply_release_pass_count": 0, + "writer_apply_count": 0, + "execution_apply_count": 0, + "receipt_write_count": 0, + "reviewer_queue_write_count": 0, + "gateway_queue_write_count": 0, + "telegram_send_count": 0, + "bot_api_call_count": 0, + "report_receipt_write_count": 0, + "result_capture_write_count": 0, + "learning_write_count": 0, + "playbook_trust_write_count": 0, + "production_write_count": 0, + "secret_read_count": 0, + "destructive_operation_count": 0 + } +} diff --git a/docs/schemas/ai_agent_result_capture_release_decision_readback_v1.schema.json b/docs/schemas/ai_agent_result_capture_release_decision_readback_v1.schema.json new file mode 100644 index 000000000..8471519a2 --- /dev/null +++ b/docs/schemas/ai_agent_result_capture_release_decision_readback_v1.schema.json @@ -0,0 +1,118 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://awoooi.wooo.work/schemas/ai_agent_result_capture_release_decision_readback_v1.schema.json", + "title": "AI Agent result capture release decision readback v1", + "type": "object", + "required": [ + "schema_version", + "generated_at", + "program_status", + "source_refs", + "prior_release_decision_hold", + "release_decision_readback_truth", + "release_decision_readbacks", + "owner_decision_readbacks", + "verifier_decision_readbacks", + "rollback_decision_readbacks", + "maintenance_window_decision_readbacks", + "live_apply_decision_readbacks", + "blocked_readback_transitions", + "operator_actions", + "display_redaction_contract", + "rollups" + ], + "properties": { + "schema_version": { + "const": "ai_agent_result_capture_release_decision_readback_v1" + }, + "generated_at": { + "type": "string" + }, + "program_status": { + "type": "object" + }, + "source_refs": { + "type": "array", + "items": { + "type": "string" + } + }, + "prior_release_decision_hold": { + "type": "object" + }, + "release_decision_readback_truth": { + "type": "object" + }, + "release_decision_readbacks": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "owner_decision_readbacks": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "verifier_decision_readbacks": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "rollback_decision_readbacks": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "maintenance_window_decision_readbacks": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "live_apply_decision_readbacks": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "blocked_readback_transitions": { + "type": "array", + "minItems": 6, + "maxItems": 6, + "items": { + "type": "object" + } + }, + "operator_actions": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "display_redaction_contract": { + "type": "object" + }, + "rollups": { + "type": "object" + } + }, + "additionalProperties": false +} diff --git a/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md b/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md index ee0a14f9e..a4f29ed93 100644 --- a/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md +++ b/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md @@ -676,6 +676,7 @@ Alert / Sentry / SigNoz / Gitea / Market Watch / Operator | `docs/evaluations/ai_agent_result_capture_release_verifier_preflight_gate_2026-06-14.json` + `GET /api/v1/agents/agent-result-capture-release-verifier-preflight-gate` | P2-136 release verifier preflight gate;承接 P2-135 release authorization readback gate,建立 5 個 release verifier preflight、5 個 rollback verifier preflight、5 個 maintenance window verifier hold、5 個 live-apply verifier hold、6 個 blocked verifier preflight transition 與 5 個 operator action;runtime authority 固定 `result_capture_release_verifier_preflight_gate_only_no_live_write`;post-release verifier ready、owner release authorized、owner release approved、maintenance window approved、rollback owner confirmed、release authorization granted、release authorization passed、rollback release passed、live apply release passed、writer apply、execution apply、receipt write、canonical runtime target read、live query、reviewer queue write、Gateway queue write、Telegram send、Bot API call、report receipt write、result capture write、learning write、PlayBook trust write、production write、secret read 與 destructive action 全部 `0 / false`;deploy marker `f2fa8454` 已正式驗證,正式 API readback 與 Browser desktop / mobile smoke 已完成,下一步 P2-137 owner / verifier review packet | | `docs/evaluations/ai_agent_result_capture_release_verifier_owner_review_packet_2026-06-14.json` + `GET /api/v1/agents/agent-result-capture-release-verifier-owner-review-packet` | P2-137 release verifier owner review packet;承接 P2-136 release verifier preflight gate,建立 5 個 owner review packet、5 個 verifier review packet、5 個 rollback owner review packet、5 個 maintenance window review hold、5 個 live-apply owner review hold、6 個 blocked owner review transition 與 5 個 operator action;runtime authority 固定 `result_capture_release_verifier_owner_review_packet_only_no_live_write`;owner release authorized、owner review approved、maintenance window approved、rollback owner confirmed、post-release verifier ready、release authorization granted、release authorization passed、rollback release passed、live apply release passed、writer apply、execution apply、receipt write、canonical runtime target read、live query、reviewer queue write、Gateway queue write、Telegram send、Bot API call、report receipt write、result capture write、learning write、PlayBook trust write、production write、secret read 與 destructive action 全部 `0 / false`;deploy marker `d023f5d7` 已正式驗證,正式 API readback 與 desktop / mobile smoke 已完成,下一步 P2-138 release decision hold | | `docs/evaluations/ai_agent_result_capture_release_decision_hold_2026-06-14.json` + `GET /api/v1/agents/agent-result-capture-release-decision-hold` | P2-138 release decision hold;承接 P2-137 release verifier owner review packet,建立 5 個 release decision hold、5 個 owner decision hold、5 個 verifier decision hold、5 個 rollback decision hold、5 個 maintenance window decision hold、5 個 live-apply decision hold、6 個 blocked decision transition 與 5 個 operator action;runtime authority 固定 `result_capture_release_decision_hold_only_no_live_write`;owner release authorized、owner review approved、owner decision approved、verifier decision approved、maintenance window approved、release decision passed、release authorization granted、release authorization passed、rollback release passed、live apply release passed、writer apply、execution apply、receipt write、canonical runtime target read、live query、reviewer queue write、Gateway queue write、Telegram send、Bot API call、report receipt write、result capture write、learning write、PlayBook trust write、production write、secret read 與 destructive action 全部 `0 / false`;feature commit `655df33d` 與 maintenance window 補強 commit `1ae67f1f` 已由 deploy marker `bfd26e76` 正式驗證,正式 API readback 與 desktop / mobile smoke 已完成,下一步 P2-139 release decision readback | +| `docs/evaluations/ai_agent_result_capture_release_decision_readback_2026-06-14.json` + `GET /api/v1/agents/agent-result-capture-release-decision-readback` | P2-139 release decision readback;承接 P2-138 release decision hold,建立 5 個 release decision readback、5 個 owner decision readback、5 個 verifier decision readback、5 個 rollback decision readback、5 個 maintenance window decision readback、5 個 live-apply decision readback、6 個 blocked readback transition 與 5 個 operator action;runtime authority 固定 `result_capture_release_decision_readback_only_no_live_write`;owner release authorized、owner review approved、owner decision approved、verifier decision approved、maintenance window approved、release decision passed、release authorization granted、release authorization passed、rollback release passed、live apply release passed、writer apply、execution apply、receipt write、canonical runtime target read、live query、reviewer queue write、Gateway queue write、Telegram send、Bot API call、report receipt write、result capture write、learning write、PlayBook trust write、production write、secret read 與 destructive action 全部 `0 / false`;本地 API/service pytest `7 passed`、JSON parse、Python compile、i18n key mirror 通過,下一步正式部署驗證 | | `docs/evaluations/ai_agent_live_read_model_gate_2026-06-11.json` + `GET /api/v1/agents/agent-live-read-model-gate` | P2-403B AgentSession / Redis Streams live read model gate;定義 safe fields、Redis envelope、worker gate、rollback plan 與 no-write smoke,不連 DB、不讀寫 Redis、不啟動 worker | #### 3.2.1c 2026-06-11 AI Agent 主動營運委派與版本生命週期契約 @@ -803,7 +804,7 @@ Repo / registry / release notes / K8s / host / observability / backup evidence 57. 建立 release verifier preflight gate。✅ P2-136 已完成並正式驗證;release verifier preflight `5`、rollback verifier preflight `5`、maintenance window verifier hold `5`、live-apply verifier hold `5`、blocked verifier preflight transition `6`、operator action `5`,approval-required preflight / rollback / maintenance / live apply `2 / 2 / 2 / 2`、blocked preflight / rollback / maintenance / live apply `1 / 1 / 1 / 1`、critical blocker `5`,前端顯示阻擋總數 `9`;post-release verifier ready、owner release authorized、owner release approved、maintenance window approved、rollback owner confirmed、final release candidate approved、final release candidate passed、release authorization granted、release authorization passed、rollback release passed、live apply release passed、writer apply、execution apply、receipt write、reviewer queue write、Gateway queue write、Telegram send、Bot API call、report receipt write、result capture write、learning write、PlayBook trust write、production write、secret read、destructive operation 仍為 `0 / false`;deploy marker `f2fa8454`、正式 API readback 與 desktop / mobile smoke 已完成。已由 P2-137 承接。 58. 建立 owner / verifier review packet。✅ P2-137 已完成並正式驗證;owner review packet `5`、verifier review packet `5`、rollback owner review packet `5`、maintenance window review hold `5`、live-apply owner review hold `5`、blocked owner review transition `6`、operator action `5`,approval-required owner / verifier / rollback / maintenance / live apply `2 / 2 / 2 / 2 / 2`、blocked owner / verifier / rollback / maintenance / live apply `1 / 1 / 1 / 1 / 1`、critical blocker `5`;owner release authorized、owner review approved、maintenance window approved、rollback owner confirmed、post-release verifier ready、release authorization granted、release authorization passed、rollback release passed、live apply release passed、writer apply、execution apply、receipt write、reviewer queue write、Gateway queue write、Telegram send、Bot API call、report receipt write、result capture write、learning write、PlayBook trust write、production write、secret read、destructive operation 仍為 `0 / false`;本地 API/service pytest `7 passed`、JSON parse、Python compile、Web typecheck 通過;deploy marker `d023f5d7`、正式 API readback 與 desktop / mobile smoke 已完成。已由 P2-138 承接。 59. 建立 release decision hold。✅ P2-138 最新合約已完成並正式驗證;release decision hold `5`、owner decision hold `5`、verifier decision hold `5`、rollback decision hold `5`、maintenance window decision hold `5`、live-apply decision hold `5`、blocked decision transition `6`、operator action `5`,approval-required release / owner / verifier / rollback / maintenance / live apply `2 / 2 / 2 / 2 / 2 / 2`、blocked release / owner / verifier / rollback / maintenance / live apply `1 / 1 / 1 / 1 / 1 / 1`、critical blocker `6`;owner release authorized、owner review approved、owner decision approved、verifier decision approved、maintenance window approved、release decision passed、release authorization granted、release authorization passed、rollback release passed、live apply release passed、writer apply、execution apply、receipt write、reviewer queue write、Gateway queue write、Telegram send、Bot API call、report receipt write、result capture write、learning write、PlayBook trust write、production write、secret read、destructive operation 仍為 `0 / false`;本地 P2-138 + P2-137 regression `15 passed`、JSON parse、Python compile、i18n key mirror、Web typecheck 與 Web production build 通過;deploy marker `bfd26e76`、正式 API readback 與 desktop / mobile smoke 已完成。已由 P2-139 承接。 -60. 建立 release decision readback。⬜ P2-139 planned;承接 P2-138,只能整理 release decision hold readback 的只讀證據,不得把 hold 視為決策通過,不得寫 reviewer queue、Gateway queue、Telegram、Bot API、result capture、learning、PlayBook trust 或 production target。 +60. 建立 release decision readback。✅ P2-139 已本地完成;release decision readback `5`、owner decision readback `5`、verifier decision readback `5`、rollback decision readback `5`、maintenance window decision readback `5`、live-apply decision readback `5`、blocked readback transition `6`、operator action `5`,approval-required release / owner / verifier / rollback / maintenance / live apply `2 / 2 / 2 / 2 / 2 / 2`、blocked release / owner / verifier / rollback / maintenance / live apply `1 / 1 / 1 / 1 / 1 / 1`、critical blocker `6`;owner release authorized、owner review approved、owner decision approved、verifier decision approved、maintenance window approved、release decision passed、release authorization granted、release authorization passed、rollback release passed、live apply release passed、writer apply、execution apply、receipt write、reviewer queue write、Gateway queue write、Telegram send、Bot API call、report receipt write、result capture write、learning write、PlayBook trust write、production write、secret read、destructive operation 仍為 `0 / false`;本地 API/service pytest `7 passed`、JSON parse、Python compile、i18n key mirror 通過;正式部署驗證後才可由 P2-140 承接。 #### 3.2.1d 2026-06-11 Agent 互動、學習與成長證據面 @@ -1969,6 +1970,13 @@ Phase 6 完成後 - Desktop `1440x1000` 與 mobile `390x844` smoke 均確認 P2-138 區塊、`P2-139`、`Telegram 送出=0`、`Bot API 呼叫=0`、`正式寫入=0` 可見;水平溢位 `0`、overflowing element `0`、P2-138 卡片危險控制 `0`、console / page error `0`、HTTP 4xx/5xx `0`、禁用內部協作片語命中 `0`。 - 本波仍不讀 canonical runtime target、不做 live query、不寫 reviewer queue、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 report receipt、不寫 result capture、不寫 learning、不更新 PlayBook trust、不寫 production target、不讀 secret、不執行 destructive action、不回傳內部工作內容;P2-139 仍只能走 release decision readback 的只讀證據。 +### 2026-06-14 11:40 (台北) — §3.2 / §5 — 新增 P2-139 release decision readback — 本地完成決策讀回只讀關卡 + +- 新增 `ai_agent_result_capture_release_decision_readback_v1` schema、snapshot、service loader、FastAPI endpoint `GET /api/v1/agents/agent-result-capture-release-decision-readback`、governance automation inventory UI 與 i18n 文案。 +- P2-139 承接 P2-138 release decision hold,只讀回 5 個 release decision readback、5 個 owner decision readback、5 個 verifier decision readback、5 個 rollback decision readback、5 個 maintenance window decision readback、5 個 live-apply decision readback、6 個 blocked readback transition 與 5 個 operator action。 +- 本地驗證:P2-139 API/service pytest `7 passed`、JSON parse、Python compile、i18n key mirror `11809` 通過;本臨時 worktree 無 `node_modules`,Web typecheck 需由 Gitea CD 乾淨環境驗證。 +- 本波仍不讀 canonical runtime target、不做 live query、不寫 reviewer queue、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 report receipt、不寫 result capture、不寫 learning、不更新 PlayBook trust、不寫 production target、不讀 secret、不執行 destructive action、不回傳內部工作內容;正式驗證後才可由 P2-140 承接。 + ### 2026-06-14 08:36 (台北) — §3.2 / §5 — 正式驗證 P2-134 release authorization hold — 完成釋出授權保留只讀關卡 - Feature commit `e0a6d339` 已由 deploy marker `18b867c3 chore(cd): deploy e0a6d33 [skip ci]` 部署;正式 API health 回 `healthy`、`environment=prod`、`mock_mode=false`。