From 04c473bee5ec5d5ed6b612bf0dd899ef02a07170 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 14 Jun 2026 04:48:55 +0800 Subject: [PATCH] =?UTF-8?q?feat(governance):=20=E6=96=B0=E5=A2=9E=20owner?= =?UTF-8?q?=20release=20approval=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/api/src/api/v1/agents.py | 34 ++ ...ult_capture_owner_release_approval_gate.py | 452 +++++++++++++++++ ...ult_capture_owner_release_approval_gate.py | 108 ++++ ...capture_owner_release_approval_gate_api.py | 46 ++ apps/web/messages/en.json | 32 ++ apps/web/messages/zh-TW.json | 32 ++ .../tabs/automation-inventory-tab.tsx | 183 ++++++- apps/web/src/lib/api-client.ts | 206 ++++++++ docs/LOGBOOK.md | 24 + ...AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md | 9 +- ...wner_release_approval_gate_2026-06-14.json | 461 ++++++++++++++++++ ...owner_release_approval_gate_v1.schema.json | 100 ++++ ...-04-15-MASTER-ai-autonomous-flywheel-v2.md | 14 +- 13 files changed, 1695 insertions(+), 6 deletions(-) create mode 100644 apps/api/src/services/ai_agent_result_capture_owner_release_approval_gate.py create mode 100644 apps/api/tests/test_ai_agent_result_capture_owner_release_approval_gate.py create mode 100644 apps/api/tests/test_ai_agent_result_capture_owner_release_approval_gate_api.py create mode 100644 docs/evaluations/ai_agent_result_capture_owner_release_approval_gate_2026-06-14.json create mode 100644 docs/schemas/ai_agent_result_capture_owner_release_approval_gate_v1.schema.json diff --git a/apps/api/src/api/v1/agents.py b/apps/api/src/api/v1/agents.py index 4d5a13622..9b6d3403d 100644 --- a/apps/api/src/api/v1/agents.py +++ b/apps/api/src/api/v1/agents.py @@ -139,6 +139,9 @@ from src.services.ai_agent_result_capture_owner_approved_preflight_release_packa from src.services.ai_agent_result_capture_owner_approved_release_readiness_readback import ( load_latest_ai_agent_result_capture_owner_approved_release_readiness_readback, ) +from src.services.ai_agent_result_capture_owner_release_approval_gate import ( + load_latest_ai_agent_result_capture_owner_release_approval_gate, +) from src.services.ai_agent_result_capture_promotion_approval_gate import ( load_latest_ai_agent_result_capture_promotion_approval_gate, ) @@ -2017,6 +2020,37 @@ async def get_agent_result_capture_owner_approved_release_readiness_readback() - ) from exc +@router.get( + "/agent-result-capture-owner-release-approval-gate", + response_model=dict[str, Any], + summary="取得 AI Agent result capture owner release approval gate", + description=( + "讀取最新已提交的 P2-131 owner release approval gate;" + "此端點只回傳 owner release approval packet、maintenance window gate、" + "live apply approval gate、rollback owner approval check、blocked approval transition 與 operator handoff," + "不批准 owner release、不批准 maintenance window、不釋放 live apply、不套用 writer、不寫 receipt、" + "不寫 result capture、learning、PlayBook trust、reviewer queue、Gateway queue,不送 Telegram、" + "不呼叫 Bot API、不讀 secret。" + ), +) +async def get_agent_result_capture_owner_release_approval_gate() -> dict[str, Any]: + """Return the latest read-only owner release approval gate.""" + try: + payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_owner_release_approval_gate) + 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_owner_release_approval_gate_invalid", error=str(exc)) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="AI Agent result capture owner release approval gate 無效", + ) 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_owner_release_approval_gate.py b/apps/api/src/services/ai_agent_result_capture_owner_release_approval_gate.py new file mode 100644 index 000000000..df900c429 --- /dev/null +++ b/apps/api/src/services/ai_agent_result_capture_owner_release_approval_gate.py @@ -0,0 +1,452 @@ +""" +AI Agent result capture owner release approval gate snapshot. + +Loads the latest committed P2-131 owner release approval gate. This module +validates committed evidence only; it never approves owner release, approves +maintenance windows, releases live apply, applies writers, writes receipts, +writes result captures, writes learning records, updates PlayBook trust, +writes reviewer / Gateway queues, sends Telegram messages, reads secrets, or +performs destructive operations. +""" + +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + +from src.services.snapshot_paths import default_evaluations_dir + +_DEFAULT_EVALUATIONS_DIR = default_evaluations_dir(Path(__file__)) +_SNAPSHOT_PATTERN = "ai_agent_result_capture_owner_release_approval_gate_*.json" +_SCHEMA_VERSION = "ai_agent_result_capture_owner_release_approval_gate_v1" +_RUNTIME_AUTHORITY = "result_capture_owner_release_approval_gate_only_no_live_write" + + +def load_latest_ai_agent_result_capture_owner_release_approval_gate( + evaluations_dir: Path | None = None, +) -> dict[str, Any]: + """Load the newest committed owner release approval gate.""" + directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR + candidates = sorted(directory.glob(_SNAPSHOT_PATTERN)) + if not candidates: + raise FileNotFoundError(f"no AI Agent result capture owner release approval gate 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_packets(payload, label) + _require_maintenance_windows(payload, label) + _require_live_apply_gates(payload, label) + _require_rollback_checks(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-131", + "next_task_id": "P2-132", + "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_owner_approved_release_readiness_readback") or {} + expected = { + "schema_version": "ai_agent_result_capture_owner_approved_release_readiness_readback_v1", + "release_readiness_readback_count": 5, + "owner_release_readiness_check_count": 5, + "live_apply_readiness_gate_count": 5, + "rollback_readiness_check_count": 5, + "blocked_readiness_transition_count": 6, + "operator_action_count": 5, + "approval_required_total": 8, + "blocked_total": 9, + "owner_release_approved_count": 0, + "maintenance_window_approved_count": 0, + "rollback_owner_confirmed_count": 0, + "post_release_verifier_ready_count": 0, + "release_readiness_pass_count": 0, + "live_apply_release_pass_count": 0, + "writer_apply_count": 0, + "execution_apply_count": 0, + "receipt_write_count": 0, + "result_capture_write_count": 0, + "learning_write_count": 0, + "playbook_trust_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, + } + mismatches = _mismatches(prior, expected) + if mismatches: + raise ValueError(f"{label}: prior_owner_approved_release_readiness_readback mismatch: {mismatches}") + if not prior.get("readiness_note"): + raise ValueError(f"{label}: prior_owner_approved_release_readiness_readback.readiness_note is required") + + +def _require_truth(payload: dict[str, Any], label: str) -> None: + truth = payload.get("owner_release_approval_truth") or {} + required_true = { + "p2_130_readiness_loaded", + "owner_release_approval_gate_ready", + "owner_release_review_required", + "maintenance_window_review_required", + "live_apply_approval_hold_active", + "rollback_owner_review_required", + "post_release_verifier_required", + "redaction_review_required", + "owner_release_approval_gate_only", + } + missing = sorted(field for field in required_true if truth.get(field) is not True) + if missing: + raise ValueError(f"{label}: owner release approval gate flags must remain true: {missing}") + + required_false = { + "owner_release_approved", + "maintenance_window_approved", + "rollback_owner_confirmed", + "post_release_verifier_ready", + "release_approval_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}: owner release approval live/send/write flags must remain false: {unsafe}") + + zero_counts = { + "owner_release_approved_count", + "maintenance_window_approved_count", + "rollback_owner_confirmed_count", + "post_release_verifier_ready_count", + "release_approval_pass_count", + "live_apply_release_pass_count", + "writer_apply_count", + "execution_apply_count", + "receipt_write_count", + "reviewer_queue_write_count", + "gateway_queue_write_count", + "telegram_send_count", + "bot_api_call_count", + "report_receipt_write_count", + "result_capture_write_count", + "learning_write_count", + "playbook_trust_write_count", + "production_write_count", + "secret_read_count", + "destructive_operation_count", + } + non_zero = sorted(field for field in zero_counts if truth.get(field) != 0) + if non_zero: + raise ValueError(f"{label}: owner release approval live counters must remain zero: {non_zero}") + if not truth.get("truth_note"): + raise ValueError(f"{label}: owner_release_approval_truth.truth_note is required") + + +def _require_packets(payload: dict[str, Any], label: str) -> None: + items = payload.get("owner_release_approval_packets") or [] + _require_ids( + items, + "packet_id", + { + "approval_gate_result_capture_writer", + "approval_gate_learning_writer", + "approval_gate_playbook_trust_writer", + "approval_gate_reviewer_queue_writer", + "approval_gate_gateway_queue_writer", + }, + label, + "owner release approval packets", + ) + for item in items: + item_id = item.get("packet_id") + if item.get("approval_mode") != "owner_release_approval_gate": + raise ValueError(f"{label}: owner release approval packet {item_id} mode is invalid") + if item.get("owner_release_approved") is not False or item.get("release_approval_passed") is not False: + raise ValueError(f"{label}: owner release approval packet {item_id} must stay unapproved and unpassed") + if item.get("status") not in {"ready_for_owner_review", "approval_required", "blocked_by_policy"}: + raise ValueError(f"{label}: owner release approval packet {item_id} status is invalid") + if not item.get("approval_summary") or not _is_redacted_sha256(item.get("evidence_hash")): + raise ValueError(f"{label}: owner release approval packet {item_id} must include summary and redacted evidence_hash") + + +def _require_maintenance_windows(payload: dict[str, Any], label: str) -> None: + items = payload.get("maintenance_window_approval_gates") or [] + _require_ids( + items, + "gate_id", + { + "maintenance_window_result_capture", + "maintenance_window_learning", + "maintenance_window_playbook_trust", + "maintenance_window_reviewer_queue", + "maintenance_window_gateway_queue", + }, + label, + "maintenance window approval gates", + ) + for item in items: + item_id = item.get("gate_id") + if item.get("gate_mode") != "maintenance_window_approval_gate": + raise ValueError(f"{label}: maintenance window approval gate {item_id} mode is invalid") + if item.get("maintenance_window_review_required") is not True or item.get("maintenance_window_approved") is not False: + raise ValueError(f"{label}: maintenance window approval gate {item_id} must remain required and unapproved") + if item.get("status") not in {"ready_for_owner_review", "approval_required", "blocked_by_policy"}: + raise ValueError(f"{label}: maintenance window approval gate {item_id} status is invalid") + if not item.get("required_before_live_apply"): + raise ValueError(f"{label}: maintenance window approval gate {item_id} required_before_live_apply is required") + + +def _require_live_apply_gates(payload: dict[str, Any], label: str) -> None: + items = payload.get("live_apply_release_approval_gates") or [] + _require_ids( + items, + "gate_id", + { + "live_apply_approval_result_capture", + "live_apply_approval_learning", + "live_apply_approval_playbook_trust", + "live_apply_approval_reviewer_queue", + "live_apply_approval_gateway_queue", + }, + label, + "live apply release approval gates", + ) + for item in items: + item_id = item.get("gate_id") + if item.get("gate_mode") != "live_apply_release_approval_gate": + raise ValueError(f"{label}: live apply release approval gate {item_id} mode is invalid") + if item.get("release_approval_passed") is not False or item.get("live_apply_release_enabled") is not False: + raise ValueError(f"{label}: live apply release approval gate {item_id} must stay held and disabled") + if item.get("status") not in {"ready_for_owner_review", "approval_required", "blocked_by_policy"}: + raise ValueError(f"{label}: live apply release approval gate {item_id} status is invalid") + if not item.get("hold_reason") or not item.get("release_condition"): + raise ValueError(f"{label}: live apply release approval gate {item_id} hold_reason and release_condition are required") + + +def _require_rollback_checks(payload: dict[str, Any], label: str) -> None: + items = payload.get("rollback_owner_approval_checks") or [] + _require_ids( + items, + "check_id", + { + "rollback_owner_result_capture", + "rollback_owner_learning", + "rollback_owner_playbook_trust", + "rollback_owner_reviewer_queue", + "rollback_owner_gateway_queue", + }, + label, + "rollback owner approval checks", + ) + for item in items: + item_id = item.get("check_id") + if item.get("rollback_owner_required") is not True or item.get("rollback_owner_confirmed") is not False: + raise ValueError(f"{label}: rollback owner approval check {item_id} must remain required and unconfirmed") + if item.get("status") not in {"ready_for_owner_review", "approval_required", "blocked_by_policy"}: + raise ValueError(f"{label}: rollback owner approval check {item_id} status is invalid") + if not item.get("rollback_scope") or not item.get("hold_reason"): + raise ValueError(f"{label}: rollback owner approval check {item_id} rollback_scope and hold_reason are required") + + +def _require_blocked_transitions(payload: dict[str, Any], label: str) -> None: + items = payload.get("blocked_approval_transitions") or [] + _require_ids( + items, + "blocker_id", + { + "blocked_writer_apply_approval", + "blocked_execution_apply_approval", + "blocked_receipt_write_approval", + "blocked_result_capture_write_approval", + "blocked_gateway_queue_write_approval", + "blocked_telegram_send_approval", + }, + label, + "blocked approval transitions", + ) + for item in items: + item_id = item.get("blocker_id") + if item.get("severity") not in {"critical", "high"}: + raise ValueError(f"{label}: blocked approval transition {item_id} severity is invalid") + if item.get("status") not in {"blocked_by_policy", "approval_required"}: + raise ValueError(f"{label}: blocked approval transition {item_id} status is invalid") + if not item.get("blocked_action") or not item.get("blocked_until") or not _is_redacted_sha256(item.get("evidence_hash")): + raise ValueError(f"{label}: blocked approval transition {item_id} must include action, until, and redacted evidence_hash") + + +def _require_actions(payload: dict[str, Any], label: str) -> None: + items = payload.get("operator_actions") or [] + _require_ids( + items, + "action_id", + { + "review_owner_release_approval_packets", + "verify_maintenance_window_hold", + "verify_live_apply_approval_hold", + "verify_rollback_owner_gate", + "prepare_p2_132_post_release_verifier_gate", + }, + 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 remain no-write") + 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} instruction is required") + + +def _require_display_redaction(payload: dict[str, Any], label: str) -> None: + redaction = 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(redaction, expected) + if mismatches: + raise ValueError(f"{label}: display_redaction_contract mismatch: {mismatches}") + if not redaction.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 = { + "owner_release_approval_packet_count": len(payload.get("owner_release_approval_packets") or []), + "maintenance_window_approval_gate_count": len(payload.get("maintenance_window_approval_gates") or []), + "live_apply_release_approval_gate_count": len(payload.get("live_apply_release_approval_gates") or []), + "rollback_owner_approval_check_count": len(payload.get("rollback_owner_approval_checks") or []), + "blocked_approval_transition_count": len(payload.get("blocked_approval_transitions") or []), + "operator_action_count": len(payload.get("operator_actions") or []), + "approval_required_packet_count": _count_status(payload.get("owner_release_approval_packets"), "approval_required"), + "blocked_packet_count": _count_status(payload.get("owner_release_approval_packets"), "blocked_by_policy"), + "approval_required_maintenance_window_count": _count_status(payload.get("maintenance_window_approval_gates"), "approval_required"), + "blocked_maintenance_window_count": _count_status(payload.get("maintenance_window_approval_gates"), "blocked_by_policy"), + "approval_required_live_apply_count": _count_status(payload.get("live_apply_release_approval_gates"), "approval_required"), + "blocked_live_apply_count": _count_status(payload.get("live_apply_release_approval_gates"), "blocked_by_policy"), + "approval_required_rollback_count": _count_status(payload.get("rollback_owner_approval_checks"), "approval_required"), + "blocked_rollback_count": _count_status(payload.get("rollback_owner_approval_checks"), "blocked_by_policy"), + "critical_blocker_count": sum(1 for item in payload.get("blocked_approval_transitions") or [] if item.get("severity") == "critical"), + } + mismatches = _mismatches(rollups, expected) + if mismatches: + raise ValueError(f"{label}: rollup counts mismatch: {mismatches}") + + zero_fields = { + "owner_release_approved_count", + "maintenance_window_approved_count", + "rollback_owner_confirmed_count", + "post_release_verifier_ready_count", + "release_approval_pass_count", + "live_apply_release_pass_count", + "writer_apply_count", + "execution_apply_count", + "receipt_write_count", + "reviewer_queue_write_count", + "gateway_queue_write_count", + "telegram_send_count", + "bot_api_call_count", + "report_receipt_write_count", + "result_capture_write_count", + "learning_write_count", + "playbook_trust_write_count", + "production_write_count", + "secret_read_count", + "destructive_operation_count", + } + non_zero = sorted(field for field in zero_fields if rollups.get(field) != 0) + if non_zero: + raise ValueError(f"{label}: owner release approval rollup counters must remain zero: {non_zero}") + + +def _require_ids(items: list[dict[str, Any]], key: str, expected: set[str], label: str, group: str) -> None: + ids = {item.get(key) for item in items} + if ids != expected: + raise ValueError(f"{label}: {group} must match {sorted(expected)}") + + +def _require_no_forbidden_display_terms(payload: dict[str, Any], label: str) -> None: + forbidden = { + "work_window_transcript", + "session_id", + "browser_context", + "authorization_header", + "raw Telegram payload", + "private reasoning", + "raw prompt", + "chain-of-thought", + "批准!繼續", + "My request for Codex", + "In app browser", + } + serialized = json.dumps(payload, ensure_ascii=False) + lower = serialized.lower() + found = sorted(term for term in forbidden if term.lower() in lower) + if found: + raise ValueError(f"{label}: forbidden display terms present: {found}") + + +def _count_status(items: Any, status: str) -> int: + if not isinstance(items, list): + return 0 + return sum(1 for item in items if isinstance(item, dict) and item.get("status") == status) + + +def _is_redacted_sha256(value: Any) -> bool: + return isinstance(value, str) and value.startswith("sha256:") and len(value) == 71 + + +def _mismatches(source: dict[str, Any], expected: dict[str, Any]) -> dict[str, dict[str, Any]]: + return { + key: {"expected": expected_value, "actual": source.get(key)} + for key, expected_value in expected.items() + if source.get(key) != expected_value + } diff --git a/apps/api/tests/test_ai_agent_result_capture_owner_release_approval_gate.py b/apps/api/tests/test_ai_agent_result_capture_owner_release_approval_gate.py new file mode 100644 index 000000000..3eaa9e721 --- /dev/null +++ b/apps/api/tests/test_ai_agent_result_capture_owner_release_approval_gate.py @@ -0,0 +1,108 @@ +from __future__ import annotations + +import json +from pathlib import Path + +import pytest + +from src.services.ai_agent_result_capture_owner_release_approval_gate import ( + load_latest_ai_agent_result_capture_owner_release_approval_gate, +) + +REPO_ROOT = Path(__file__).resolve().parents[3] +FIXTURE = REPO_ROOT / "docs/evaluations/ai_agent_result_capture_owner_release_approval_gate_2026-06-14.json" + + +def test_load_latest_ai_agent_result_capture_owner_release_approval_gate_snapshot() -> None: + data = load_latest_ai_agent_result_capture_owner_release_approval_gate() + + assert data["schema_version"] == "ai_agent_result_capture_owner_release_approval_gate_v1" + assert data["program_status"]["current_task_id"] == "P2-131" + assert data["program_status"]["next_task_id"] == "P2-132" + assert data["program_status"]["runtime_authority"] == "result_capture_owner_release_approval_gate_only_no_live_write" + + rollups = data["rollups"] + assert rollups["owner_release_approval_packet_count"] == 5 + assert rollups["maintenance_window_approval_gate_count"] == 5 + assert rollups["live_apply_release_approval_gate_count"] == 5 + assert rollups["rollback_owner_approval_check_count"] == 5 + assert rollups["blocked_approval_transition_count"] == 6 + assert rollups["operator_action_count"] == 5 + assert rollups["critical_blocker_count"] == 5 + assert rollups["owner_release_approved_count"] == 0 + assert rollups["maintenance_window_approved_count"] == 0 + assert rollups["rollback_owner_confirmed_count"] == 0 + assert rollups["post_release_verifier_ready_count"] == 0 + assert rollups["release_approval_pass_count"] == 0 + assert rollups["live_apply_release_pass_count"] == 0 + assert rollups["writer_apply_count"] == 0 + assert rollups["execution_apply_count"] == 0 + assert rollups["receipt_write_count"] == 0 + assert rollups["gateway_queue_write_count"] == 0 + assert rollups["telegram_send_count"] == 0 + assert rollups["bot_api_call_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 + assert {item["owner_release_approved"] for item in data["owner_release_approval_packets"]} == {False} + assert {item["maintenance_window_approved"] for item in data["maintenance_window_approval_gates"]} == {False} + assert {item["live_apply_release_enabled"] for item in data["live_apply_release_approval_gates"]} == {False} + assert {item["rollback_owner_confirmed"] for item in data["rollback_owner_approval_checks"]} == {False} + + +def _copy_fixture(tmp_path: Path) -> dict: + source = json.loads(FIXTURE.read_text(encoding="utf-8")) + target = tmp_path / "ai_agent_result_capture_owner_release_approval_gate_2026-06-14.json" + target.write_text(json.dumps(source, ensure_ascii=False), encoding="utf-8") + return source + + +def test_result_capture_owner_release_approval_gate_rejects_owner_release_approved(tmp_path: Path) -> None: + source = _copy_fixture(tmp_path) + source["owner_release_approval_packets"][0]["owner_release_approved"] = True + target = tmp_path / "ai_agent_result_capture_owner_release_approval_gate_2026-06-14.json" + target.write_text(json.dumps(source, ensure_ascii=False), encoding="utf-8") + + with pytest.raises(ValueError, match="must stay unapproved and unpassed"): + load_latest_ai_agent_result_capture_owner_release_approval_gate(tmp_path) + + +def test_result_capture_owner_release_approval_gate_rejects_maintenance_window_approved(tmp_path: Path) -> None: + source = _copy_fixture(tmp_path) + source["maintenance_window_approval_gates"][0]["maintenance_window_approved"] = True + target = tmp_path / "ai_agent_result_capture_owner_release_approval_gate_2026-06-14.json" + target.write_text(json.dumps(source, ensure_ascii=False), encoding="utf-8") + + with pytest.raises(ValueError, match="must remain required and unapproved"): + load_latest_ai_agent_result_capture_owner_release_approval_gate(tmp_path) + + +def test_result_capture_owner_release_approval_gate_rejects_live_apply_enabled(tmp_path: Path) -> None: + source = _copy_fixture(tmp_path) + source["live_apply_release_approval_gates"][0]["live_apply_release_enabled"] = True + target = tmp_path / "ai_agent_result_capture_owner_release_approval_gate_2026-06-14.json" + target.write_text(json.dumps(source, ensure_ascii=False), encoding="utf-8") + + with pytest.raises(ValueError, match="must stay held and disabled"): + load_latest_ai_agent_result_capture_owner_release_approval_gate(tmp_path) + + +def test_result_capture_owner_release_approval_gate_rejects_rollup_drift(tmp_path: Path) -> None: + source = _copy_fixture(tmp_path) + source["rollups"]["owner_release_approval_packet_count"] = 4 + target = tmp_path / "ai_agent_result_capture_owner_release_approval_gate_2026-06-14.json" + target.write_text(json.dumps(source, ensure_ascii=False), encoding="utf-8") + + with pytest.raises(ValueError, match="rollup counts mismatch"): + load_latest_ai_agent_result_capture_owner_release_approval_gate(tmp_path) + + +def test_result_capture_owner_release_approval_gate_rejects_forbidden_display_terms(tmp_path: Path) -> None: + source = _copy_fixture(tmp_path) + source["operator_actions"][0]["operator_instruction"] = "work_window_transcript must never show" + target = tmp_path / "ai_agent_result_capture_owner_release_approval_gate_2026-06-14.json" + target.write_text(json.dumps(source, ensure_ascii=False), encoding="utf-8") + + with pytest.raises(ValueError, match="forbidden display terms"): + load_latest_ai_agent_result_capture_owner_release_approval_gate(tmp_path) diff --git a/apps/api/tests/test_ai_agent_result_capture_owner_release_approval_gate_api.py b/apps/api/tests/test_ai_agent_result_capture_owner_release_approval_gate_api.py new file mode 100644 index 000000000..2e4028406 --- /dev/null +++ b/apps/api/tests/test_ai_agent_result_capture_owner_release_approval_gate_api.py @@ -0,0 +1,46 @@ +from __future__ import annotations + +import pytest +from httpx import ASGITransport, AsyncClient + +from src.main import app + + +@pytest.mark.asyncio +async def test_get_agent_result_capture_owner_release_approval_gate_api() -> None: + transport = ASGITransport(app=app) + async with AsyncClient(transport=transport, base_url="http://testserver") as client: + response = await client.get("/api/v1/agents/agent-result-capture-owner-release-approval-gate") + + assert response.status_code == 200 + data = response.json() + assert data["schema_version"] == "ai_agent_result_capture_owner_release_approval_gate_v1" + assert data["program_status"]["current_task_id"] == "P2-131" + assert data["program_status"]["next_task_id"] == "P2-132" + + rollups = data["rollups"] + assert rollups["owner_release_approval_packet_count"] == 5 + assert rollups["maintenance_window_approval_gate_count"] == 5 + assert rollups["live_apply_release_approval_gate_count"] == 5 + assert rollups["rollback_owner_approval_check_count"] == 5 + assert rollups["blocked_approval_transition_count"] == 6 + assert rollups["operator_action_count"] == 5 + assert rollups["owner_release_approved_count"] == 0 + assert rollups["maintenance_window_approved_count"] == 0 + assert rollups["rollback_owner_confirmed_count"] == 0 + assert rollups["post_release_verifier_ready_count"] == 0 + assert rollups["release_approval_pass_count"] == 0 + assert rollups["live_apply_release_pass_count"] == 0 + assert rollups["writer_apply_count"] == 0 + assert rollups["execution_apply_count"] == 0 + assert rollups["receipt_write_count"] == 0 + assert rollups["result_capture_write_count"] == 0 + assert rollups["learning_write_count"] == 0 + assert rollups["playbook_trust_write_count"] == 0 + assert rollups["gateway_queue_write_count"] == 0 + assert rollups["telegram_send_count"] == 0 + assert rollups["bot_api_call_count"] == 0 + assert rollups["production_write_count"] == 0 + assert {item["owner_release_approved"] for item in data["owner_release_approval_packets"]} == {False} + assert {item["maintenance_window_approved"] for item in data["maintenance_window_approval_gates"]} == {False} + assert {item["live_apply_release_enabled"] for item in data["live_apply_release_approval_gates"]} == {False} diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index d567abb6e..6196ce792 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -5976,6 +5976,38 @@ "rollbackPassed": "rollback readiness passed={value}" } }, + "resultCaptureOwnerReleaseApprovalGate": { + "title": "P2-131 owner release approval gate", + "source": "產生 {generated};目前 {current};下一步 {next}", + "priorTitle": "前一關 release readiness", + "truthTitle": "owner release approval 真相", + "metrics": { + "overall": "完成度", + "packets": "Approval packets", + "maintenanceWindows": "Maintenance gates", + "liveApplyGates": "Live-apply approval gates", + "rollbackChecks": "Rollback owner checks", + "blockers": "已阻擋 approval", + "actions": "操作選項", + "approvalRequired": "需批准", + "blocked": "阻擋", + "liveWrites": "正式寫入 / 發送" + }, + "flags": { + "p2Loaded": "已載入 P2-130={value}", + "ownerReleaseReviewRequired": "owner release review required={value}", + "liveApplyApprovalHoldActive": "live apply approval hold active={value}" + }, + "labels": { + "ownerReleaseApproved": "owner release approved={value}", + "maintenanceApproved": "maintenance approved={value}", + "releaseApprovalPassed": "release approval passed={value}", + "gatewayWrites": "Gateway 寫入={value}", + "liveApplyReleaseEnabled": "live apply release enabled={value}", + "rollbackRequired": "需要 rollback owner={value}", + "rollbackConfirmed": "rollback owner confirmed={value}" + } + }, "resultCaptureOwnerAcceptanceReadbackPreflightHold": { "title": "P2-128 owner acceptance readback / live-apply preflight hold", "source": "產生 {generated};目前 {current};下一步 {next}", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index d567abb6e..6196ce792 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -5976,6 +5976,38 @@ "rollbackPassed": "rollback readiness passed={value}" } }, + "resultCaptureOwnerReleaseApprovalGate": { + "title": "P2-131 owner release approval gate", + "source": "產生 {generated};目前 {current};下一步 {next}", + "priorTitle": "前一關 release readiness", + "truthTitle": "owner release approval 真相", + "metrics": { + "overall": "完成度", + "packets": "Approval packets", + "maintenanceWindows": "Maintenance gates", + "liveApplyGates": "Live-apply approval gates", + "rollbackChecks": "Rollback owner checks", + "blockers": "已阻擋 approval", + "actions": "操作選項", + "approvalRequired": "需批准", + "blocked": "阻擋", + "liveWrites": "正式寫入 / 發送" + }, + "flags": { + "p2Loaded": "已載入 P2-130={value}", + "ownerReleaseReviewRequired": "owner release review required={value}", + "liveApplyApprovalHoldActive": "live apply approval hold active={value}" + }, + "labels": { + "ownerReleaseApproved": "owner release approved={value}", + "maintenanceApproved": "maintenance approved={value}", + "releaseApprovalPassed": "release approval passed={value}", + "gatewayWrites": "Gateway 寫入={value}", + "liveApplyReleaseEnabled": "live apply release enabled={value}", + "rollbackRequired": "需要 rollback owner={value}", + "rollbackConfirmed": "rollback owner confirmed={value}" + } + }, "resultCaptureOwnerAcceptanceReadbackPreflightHold": { "title": "P2-128 owner acceptance readback / live-apply preflight hold", "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 d1797f9d0..c410e1360 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 @@ -78,6 +78,7 @@ import { type AiAgentResultCaptureOwnerAcceptanceReadbackPreflightHoldSnapshot, type AiAgentResultCaptureOwnerApprovedPreflightReleasePackageSnapshot, type AiAgentResultCaptureOwnerApprovedReleaseReadinessReadbackSnapshot, + type AiAgentResultCaptureOwnerReleaseApprovalGateSnapshot, type AiAgentResultCaptureWriterImplementationReviewSnapshot, type AiAgentOwnerApprovedFixturePromotionGateSnapshot, type AiAgentRuntimeWorkerShadowGateSnapshot, @@ -479,6 +480,7 @@ export function AutomationInventoryTab() { const [resultCaptureOwnerAcceptanceReadbackPreflightHold, setResultCaptureOwnerAcceptanceReadbackPreflightHold] = useState(null) const [resultCaptureOwnerApprovedPreflightReleasePackage, setResultCaptureOwnerApprovedPreflightReleasePackage] = useState(null) const [resultCaptureOwnerApprovedReleaseReadinessReadback, setResultCaptureOwnerApprovedReleaseReadinessReadback] = useState(null) + const [resultCaptureOwnerReleaseApprovalGate, setResultCaptureOwnerReleaseApprovalGate] = useState(null) const [reportTruthActionabilityReview, setReportTruthActionabilityReview] = useState(null) const [ownerDryRunPackage, setOwnerDryRunPackage] = useState(null) const [hostStatefulInventory, setHostStatefulInventory] = useState(null) @@ -546,6 +548,7 @@ export function AutomationInventoryTab() { apiClient.getAiAgentResultCaptureOwnerAcceptanceReadbackPreflightHold(), apiClient.getAiAgentResultCaptureOwnerApprovedPreflightReleasePackage(), apiClient.getAiAgentResultCaptureOwnerApprovedReleaseReadinessReadback(), + apiClient.getAiAgentResultCaptureOwnerReleaseApprovalGate(), apiClient.getAiAgentReportTruthActionabilityReview(), apiClient.getAiAgentOwnerApprovedFixtureDryRun(), apiClient.getAiAgentHostStatefulVersionInventory(), @@ -612,6 +615,7 @@ export function AutomationInventoryTab() { resultCaptureOwnerAcceptanceReadbackPreflightHoldResult, resultCaptureOwnerApprovedPreflightReleasePackageResult, resultCaptureOwnerApprovedReleaseReadinessReadbackResult, + resultCaptureOwnerReleaseApprovalGateResult, reportTruthActionabilityReviewResult, ownerDryRunPackageResult, hostStatefulInventoryResult, @@ -675,6 +679,7 @@ export function AutomationInventoryTab() { setResultCaptureOwnerAcceptanceReadbackPreflightHold(resultCaptureOwnerAcceptanceReadbackPreflightHoldResult.status === 'fulfilled' ? resultCaptureOwnerAcceptanceReadbackPreflightHoldResult.value : null) setResultCaptureOwnerApprovedPreflightReleasePackage(resultCaptureOwnerApprovedPreflightReleasePackageResult.status === 'fulfilled' ? resultCaptureOwnerApprovedPreflightReleasePackageResult.value : null) setResultCaptureOwnerApprovedReleaseReadinessReadback(resultCaptureOwnerApprovedReleaseReadinessReadbackResult.status === 'fulfilled' ? resultCaptureOwnerApprovedReleaseReadinessReadbackResult.value : null) + setResultCaptureOwnerReleaseApprovalGate(resultCaptureOwnerReleaseApprovalGateResult.status === 'fulfilled' ? resultCaptureOwnerReleaseApprovalGateResult.value : null) setReportTruthActionabilityReview(reportTruthActionabilityReviewResult.status === 'fulfilled' ? reportTruthActionabilityReviewResult.value : null) setOwnerDryRunPackage(ownerDryRunPackageResult.status === 'fulfilled' ? ownerDryRunPackageResult.value : null) setHostStatefulInventory(hostStatefulInventoryResult.status === 'fulfilled' ? hostStatefulInventoryResult.value : null) @@ -736,6 +741,7 @@ export function AutomationInventoryTab() { resultCaptureOwnerAcceptanceReadbackPreflightHoldResult, resultCaptureOwnerApprovedPreflightReleasePackageResult, resultCaptureOwnerApprovedReleaseReadinessReadbackResult, + resultCaptureOwnerReleaseApprovalGateResult, reportTruthActionabilityReviewResult, ownerDryRunPackageResult, hostStatefulInventoryResult, @@ -1978,7 +1984,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 || !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 || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) { return (
@@ -3022,6 +3028,40 @@ export function AutomationInventoryTab() { + resultCaptureOwnerApprovedReleaseReadinessReadback.rollups.playbook_trust_write_count + resultCaptureOwnerApprovedReleaseReadinessReadback.rollups.production_write_count ) + const resultCaptureOwnerReleaseApprovalOverall = resultCaptureOwnerReleaseApprovalGate.program_status.overall_completion_percent + const resultCaptureOwnerReleaseApprovalPackets = resultCaptureOwnerReleaseApprovalGate.rollups.owner_release_approval_packet_count + const resultCaptureOwnerReleaseApprovalMaintenanceWindows = resultCaptureOwnerReleaseApprovalGate.rollups.maintenance_window_approval_gate_count + const resultCaptureOwnerReleaseApprovalLiveApplyGates = resultCaptureOwnerReleaseApprovalGate.rollups.live_apply_release_approval_gate_count + const resultCaptureOwnerReleaseApprovalRollbacks = resultCaptureOwnerReleaseApprovalGate.rollups.rollback_owner_approval_check_count + const resultCaptureOwnerReleaseApprovalBlockedTransitions = resultCaptureOwnerReleaseApprovalGate.rollups.blocked_approval_transition_count + const resultCaptureOwnerReleaseApprovalActions = resultCaptureOwnerReleaseApprovalGate.rollups.operator_action_count + const resultCaptureOwnerReleaseApprovalRequired = ( + resultCaptureOwnerReleaseApprovalGate.rollups.approval_required_packet_count + + resultCaptureOwnerReleaseApprovalGate.rollups.approval_required_maintenance_window_count + + resultCaptureOwnerReleaseApprovalGate.rollups.approval_required_live_apply_count + + resultCaptureOwnerReleaseApprovalGate.rollups.approval_required_rollback_count + ) + const resultCaptureOwnerReleaseApprovalBlocked = ( + resultCaptureOwnerReleaseApprovalGate.rollups.blocked_packet_count + + resultCaptureOwnerReleaseApprovalGate.rollups.blocked_maintenance_window_count + + resultCaptureOwnerReleaseApprovalGate.rollups.blocked_live_apply_count + + resultCaptureOwnerReleaseApprovalGate.rollups.blocked_rollback_count + + resultCaptureOwnerReleaseApprovalGate.rollups.critical_blocker_count + ) + const resultCaptureOwnerReleaseApprovalLiveWrites = ( + resultCaptureOwnerReleaseApprovalGate.rollups.writer_apply_count + + resultCaptureOwnerReleaseApprovalGate.rollups.execution_apply_count + + resultCaptureOwnerReleaseApprovalGate.rollups.receipt_write_count + + resultCaptureOwnerReleaseApprovalGate.rollups.reviewer_queue_write_count + + resultCaptureOwnerReleaseApprovalGate.rollups.gateway_queue_write_count + + resultCaptureOwnerReleaseApprovalGate.rollups.telegram_send_count + + resultCaptureOwnerReleaseApprovalGate.rollups.bot_api_call_count + + resultCaptureOwnerReleaseApprovalGate.rollups.report_receipt_write_count + + resultCaptureOwnerReleaseApprovalGate.rollups.result_capture_write_count + + resultCaptureOwnerReleaseApprovalGate.rollups.learning_write_count + + resultCaptureOwnerReleaseApprovalGate.rollups.playbook_trust_write_count + + resultCaptureOwnerReleaseApprovalGate.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 @@ -7571,6 +7611,147 @@ export function AutomationInventoryTab() {
+
+
+
+ + + {t('resultCaptureOwnerReleaseApprovalGate.title')} + +
+ +
+ +
+ } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> +
+ +
+
+ {t('resultCaptureOwnerReleaseApprovalGate.priorTitle')} + + {resultCaptureOwnerReleaseApprovalGate.prior_owner_approved_release_readiness_readback.readiness_note} + +
+ + + +
+
+ +
+ {t('resultCaptureOwnerReleaseApprovalGate.truthTitle')} + + {resultCaptureOwnerReleaseApprovalGate.owner_release_approval_truth.truth_note} + +
+ + + + + + +
+
+
+ +
+ {resultCaptureOwnerReleaseApprovalGate.owner_release_approval_packets.slice(0, 5).map(packet => ( +
+
+ + {packet.display_name} + + +
+ + {packet.source_readiness} → {packet.approval_summary} + +
+ + + +
+
+ ))} +
+ +
+ {resultCaptureOwnerReleaseApprovalGate.maintenance_window_approval_gates.slice(0, 5).map(gate => ( +
+
+ + {gate.display_name} + + +
+ + {gate.required_before_live_apply} + +
+ + + +
+
+ ))} +
+ +
+ {resultCaptureOwnerReleaseApprovalGate.live_apply_release_approval_gates.slice(0, 5).map(gate => ( +
+
+ + {gate.display_name} + + +
+ + {gate.hold_reason} {gate.release_condition} + + +
+ ))} +
+ +
+ {resultCaptureOwnerReleaseApprovalGate.rollback_owner_approval_checks.slice(0, 5).map(rollback => ( +
+
+ + {rollback.display_name} + + +
+ + {rollback.rollback_scope} {rollback.hold_reason} + +
+ + + +
+
+ ))} +
+
+
diff --git a/apps/web/src/lib/api-client.ts b/apps/web/src/lib/api-client.ts index 9166e65e8..6f1e2b3f4 100644 --- a/apps/web/src/lib/api-client.ts +++ b/apps/web/src/lib/api-client.ts @@ -550,6 +550,11 @@ export const apiClient = { return handleResponse(res) }, + async getAiAgentResultCaptureOwnerReleaseApprovalGate() { + const res = await fetch(`${API_BASE_URL}/agents/agent-result-capture-owner-release-approval-gate`) + return handleResponse(res) + }, + async getAiAgentOwnerApprovedFixtureDryRun() { const res = await fetch(`${API_BASE_URL}/agents/agent-owner-approved-fixture-dry-run`) return handleResponse(res) @@ -7540,6 +7545,207 @@ export interface AiAgentResultCaptureOwnerApprovedReleaseReadinessReadbackSnapsh } } +export interface AiAgentResultCaptureOwnerReleaseApprovalGateSnapshot { + schema_version: 'ai_agent_result_capture_owner_release_approval_gate_v1' + generated_at: string + program_status: { + overall_completion_percent: number + current_priority: 'P0' | 'P1' | 'P2' | 'P3' + current_task_id: 'P2-131' + next_task_id: 'P2-132' + read_only_mode: true + runtime_authority: 'result_capture_owner_release_approval_gate_only_no_live_write' + status_note: string + } + source_refs: string[] + prior_owner_approved_release_readiness_readback: { + schema_version: string + release_readiness_readback_count: number + owner_release_readiness_check_count: number + live_apply_readiness_gate_count: number + rollback_readiness_check_count: number + blocked_readiness_transition_count: number + operator_action_count: number + approval_required_total: number + blocked_total: number + owner_release_approved_count: number + maintenance_window_approved_count: number + rollback_owner_confirmed_count: number + post_release_verifier_ready_count: number + release_readiness_pass_count: number + live_apply_release_pass_count: number + writer_apply_count: number + execution_apply_count: number + receipt_write_count: number + result_capture_write_count: number + learning_write_count: number + playbook_trust_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 + readiness_note: string + } + owner_release_approval_truth: { + p2_130_readiness_loaded: boolean + owner_release_approval_gate_ready: boolean + owner_release_review_required: boolean + maintenance_window_review_required: boolean + live_apply_approval_hold_active: boolean + rollback_owner_review_required: boolean + post_release_verifier_required: boolean + redaction_review_required: boolean + owner_release_approval_gate_only: boolean + owner_release_approved: boolean + maintenance_window_approved: boolean + rollback_owner_confirmed: boolean + post_release_verifier_ready: boolean + release_approval_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_approved_count: number + maintenance_window_approved_count: number + rollback_owner_confirmed_count: number + post_release_verifier_ready_count: number + release_approval_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 + truth_note: string + } + owner_release_approval_packets: Array<{ + packet_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + source_readiness: string + status: 'ready_for_owner_review' | 'approval_required' | 'blocked_by_policy' + approval_mode: 'owner_release_approval_gate' + owner_release_approved: false + release_approval_passed: false + approval_summary: string + evidence_hash: string + }> + maintenance_window_approval_gates: Array<{ + gate_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + status: 'ready_for_owner_review' | 'approval_required' | 'blocked_by_policy' + gate_mode: 'maintenance_window_approval_gate' + maintenance_window_review_required: true + maintenance_window_approved: false + required_before_live_apply: string + }> + live_apply_release_approval_gates: Array<{ + gate_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + status: 'ready_for_owner_review' | 'approval_required' | 'blocked_by_policy' + gate_mode: 'live_apply_release_approval_gate' + release_approval_passed: false + live_apply_release_enabled: false + hold_reason: string + release_condition: string + }> + rollback_owner_approval_checks: Array<{ + check_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + status: 'ready_for_owner_review' | 'approval_required' | 'blocked_by_policy' + rollback_owner_required: true + rollback_owner_confirmed: false + rollback_scope: string + hold_reason: string + }> + blocked_approval_transitions: Array<{ + blocker_id: string + display_name: string + severity: 'high' | 'critical' + status: 'approval_required' | 'blocked_by_policy' + blocked_action: string + blocked_until: string + evidence_hash: string + }> + operator_actions: Array<{ + action_id: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + status: 'ready_for_operator_review' | 'approval_required' + operator_instruction: string + 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: string + } + rollups: { + owner_release_approval_packet_count: number + maintenance_window_approval_gate_count: number + live_apply_release_approval_gate_count: number + rollback_owner_approval_check_count: number + blocked_approval_transition_count: number + operator_action_count: number + approval_required_packet_count: number + blocked_packet_count: number + approval_required_maintenance_window_count: number + blocked_maintenance_window_count: number + approval_required_live_apply_count: number + blocked_live_apply_count: number + approval_required_rollback_count: number + blocked_rollback_count: number + critical_blocker_count: number + owner_release_approved_count: number + maintenance_window_approved_count: number + rollback_owner_confirmed_count: number + post_release_verifier_ready_count: number + release_approval_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 24dcbd017..a0e742813 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,27 @@ +## 2026-06-14|P2-131 Owner release approval gate 本地完成 + +**背景**:P2-130 已把 owner-approved release readiness readback 正式驗證完成;但 readiness readback 仍不得被誤讀成 owner release approved、maintenance window approved 或 live apply passed。P2-131 因此只建立 owner release approval gate,把 readiness 轉成可審核批准門檻與 hold 證據,不接受口頭批准、不批准 owner release、不開維護窗口、不釋放 live apply、不套用 writer、不寫 receipt、不寫 result capture / learning / PlayBook trust / reviewer queue / Gateway queue,也不送 Telegram 或呼叫 Bot API。 + +**完成內容**: +- 新增 `ai_agent_result_capture_owner_release_approval_gate_v1` schema、committed snapshot、loader 與 API endpoint `GET /api/v1/agents/agent-result-capture-owner-release-approval-gate`。 +- P2-131 snapshot 固定 5 個 owner release approval packet、5 個 maintenance window approval gate、5 個 live-apply release approval gate、5 個 rollback owner approval check、6 個 blocked approval transition 與 5 個 operator action。 +- Governance automation inventory 頁新增 P2-131 區塊,顯示 P2-131 進度 `100%`、approval packet `5`、maintenance gate `5`、live-apply approval gate `5`、rollback owner check `5`、blocked approval `6`、operator action `5`、需批准 `8`、阻擋 `9`、正式寫入 / 發送 `0`。 +- Owner release approval truth 固定為 `result_capture_owner_release_approval_gate_only_no_live_write`;owner release approved、maintenance window approved、rollback owner confirmed、post-release verifier ready、release approval 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-131 schema / snapshot、`zh-TW.json`、`en.json` 通過。 +- Python 編譯:P2-131 loader 與 `agents.py` 通過。 +- API/service pytest:P2-131 + P2-130 regression `14 passed`。 +- Web typecheck:`pnpm --filter @awoooi/web typecheck` 通過。 +- Web production build:`NEXT_PUBLIC_API_URL=https://awoooi.wooo.work pnpm --filter @awoooi/web build` 通過;僅既有 Sentry setup / deprecation warning,governance First Load JS `433 kB`。 +- 本段仍是本地完成;正式 API readback、正式站 desktop / mobile Browser smoke 與 deploy marker 需在推送 Gitea main 並完成 CD 後補齊。 + +**安全邊界**: +- P2-131 仍是 owner release approval gate;不接受口頭批准、不把 approval gate 解讀成 owner release approved、不批准維護窗口、不確認 rollback owner、不啟用 post-release verifier live read、不釋放 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。 + +**下一步**: +- `P2-132`:post-release verifier / rollback gate;只有 P2-131 正式驗證後才可把 owner release approval packet、maintenance window approval gate、live-apply release approval gate、rollback owner approval check 與 blocked approval transition 轉成 post-release verifier gate,仍不得直接開啟 result capture writer、learning writer、PlayBook trust writer、reviewer queue write、Gateway queue write、Telegram send、Bot API call 或 production write。 + ## 2026-06-14|P2-130 Owner-approved release readiness readback 完成與正式驗證 **背景**:P2-129 已把 owner-approved release package、release preflight check、live-apply release gate、rollback release check 與 blocked release transition 正式驗證完成;但 release package 仍不得被誤讀成 owner release approved、maintenance window approved 或 live apply passed。P2-130 因此只建立 owner-approved release readiness readback,把 package 讀回成 readiness 狀態與 hold 證據,不批准 owner release、不開維護窗口、不釋放 live apply、不套用 writer、不寫 receipt、不寫 result capture / learning / PlayBook trust / reviewer queue / Gateway queue,也不送 Telegram 或呼叫 Bot API。 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 18d1cf196..c50352352 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-130 已完成只讀證據面、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;P2-130 已正式驗證,固定 5 個 release readiness readback、5 個 owner release readiness check、5 個 live-apply readiness gate、5 個 rollback readiness check、6 個 blocked readiness transition 與 5 個 operator action,deploy marker `6fcf7241`。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_owner_approved_release_readiness_readback_v1`、`GET /api/v1/agents/agent-result-capture-owner-approved-release-readiness-readback`、正式站 deploy marker `6fcf7241`、正式站 `/zh-TW/governance?tab=automation-inventory` desktop / mobile smoke、`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-131 已完成只讀證據面、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;P2-131 本地完成,固定 5 個 owner release approval packet、5 個 maintenance window approval gate、5 個 live-apply release approval gate、5 個 rollback owner approval check、6 個 blocked approval 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_owner_release_approval_gate_v1`、`GET /api/v1/agents/agent-result-capture-owner-release-approval-gate`、`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`、正式站 `/zh-TW/governance?tab=automation-inventory` desktop / mobile smoke、`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 | | 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 文件 | @@ -20,9 +20,9 @@ AI Agent 自動化工作包目前完成度:**99.3%**。本工作清單文件 三 Agent 佈建布局目前完成度:**45%**。第一波已完成只讀 schema / snapshot / API / 測試 / 報告,第二波已接入治理頁自動化盤點 UI;正式 runtime 佈署、Telegram E2E 發送與 AgentSession 工作流仍需逐項 gate。 -三 Agent 主動溝通、學習與成長證據目前完成度:**100%**。P2-403A 到 P2-130 已把互動證據、報表治理、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 全部固定成可驗證證據。P2-130 已正式驗證,deploy marker `6fcf7241`,固定 5 個 release readiness readback、5 個 owner release readiness check、5 個 live-apply readiness gate、5 個 rollback readiness check、6 個 blocked readiness transition 與 5 個 operator action;desktop / mobile smoke 已確認禁用內部協作片語、水平溢位、危險控制、console error、API bad response 與 request failure 全部為 `0`。目前 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-131`。 +三 Agent 主動溝通、學習與成長證據目前完成度:**100%**。P2-403A 到 P2-131 已把互動證據、報表治理、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 全部固定成可驗證證據。P2-131 已本地驗證,固定 5 個 owner release approval packet、5 個 maintenance window approval gate、5 個 live-apply release approval gate、5 個 rollback owner approval check、6 個 blocked approval transition 與 5 個 operator action;正式站待驗證。目前 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-132`。 -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-130` 已補互動、學習證據面、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。下一步是 `P2-131`;外部 registry / package source / host probe / SSH / kubectl / 工具安裝 / CI 變更 / 實際 PR creation / Telegram 實發與 learning write 仍需 gate。 +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-131` 已補互動、學習證據面、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。下一步是 `P2-132`;外部 registry / package source / host probe / SSH / kubectl / 工具安裝 / CI 變更 / 實際 PR creation / Telegram 實發與 learning write 仍需 gate。 完成度計算模型: @@ -1002,7 +1002,8 @@ UI: | P2-127 | 完成 | 100 | OpenClaw + Hermes + NemoTron | owner acceptance / maintenance window gate | `ai_agent_result_capture_owner_acceptance_maintenance_gate_v1` / schema / snapshot / 只讀 API / governance UI;正式站 deploy marker `7b034b58` 已驗證;5 個 owner acceptance packet、5 個 maintenance window、5 個 rollback owner check、5 個 post-apply verifier gate、6 個 blocked live write、5 個 operator action;runtime authority 固定 `result_capture_owner_acceptance_maintenance_gate_only_no_live_write`;owner accepted / maintenance window approved / rollback owner confirmed / post-apply verifier ready / writer apply / execution apply / receipt write / result capture / learning / PlayBook trust / reviewer queue / Gateway / Telegram / Bot API / report receipt / production write 全為 `0`;desktop / mobile smoke 禁用內部協作片語 `0`、水平溢位 `0`、P2-127 區塊危險入口 `0` | 已由 P2-128 承接;不接受口頭批准、不開維護窗口、不套用 writer、不寫 receipt、不寫 result capture、不寫 learning、不更新 PlayBook trust、不送 Telegram、不寫 production | | P2-128 | 完成 | 100 | OpenClaw + Hermes + NemoTron | owner acceptance readback / live-apply preflight hold | `ai_agent_result_capture_owner_acceptance_readback_preflight_hold_v1` / schema / snapshot / 只讀 API / governance UI;正式站 deploy marker `0a3f1533` 已驗證;5 個 owner acceptance readback、5 個 preflight hold check、5 個 live-apply hold gate、5 個 rollback preflight check、6 個 blocked apply transition、5 個 operator action;runtime authority 固定 `result_capture_owner_acceptance_readback_preflight_hold_only_no_live_write`;owner acceptance received / maintenance window approved / rollback owner confirmed / post-apply verifier ready / live apply preflight passed / writer apply / execution apply / receipt write / result capture / learning / PlayBook trust / reviewer queue / Gateway / Telegram / Bot API / report receipt / production write 全為 `0`;desktop / mobile smoke 禁用內部協作片語 `0`、水平溢位 `0`、P2-128 區塊危險入口 `0` | 已由 P2-129 承接;不釋放 live apply、不套用 writer、不寫 receipt、不寫 result capture、不寫 learning、不更新 PlayBook trust、不送 Telegram、不寫 production | | P2-129 | 完成 | 100 | OpenClaw + Hermes + NemoTron | owner-approved preflight release package | `ai_agent_result_capture_owner_approved_preflight_release_package_v1` / schema / snapshot / 只讀 API / governance UI;正式站 deploy marker `7e5b4793` 已驗證;5 個 owner-approved release package、5 個 release preflight check、5 個 live-apply release gate、5 個 rollback release check、6 個 blocked release transition、5 個 operator action;runtime authority 固定 `result_capture_owner_approved_preflight_release_package_only_no_live_write`;owner release approved / maintenance window approved / rollback owner confirmed / post-release verifier ready / live apply release passed / writer apply / execution apply / receipt write / result capture / learning / PlayBook trust / reviewer queue / Gateway / Telegram / Bot API / report receipt / production write 全為 `0`;desktop / mobile smoke 禁用內部協作片語 `0`、水平溢位 `0`、P2-129 區塊危險入口 `0` | 已由 P2-130 承接;不把 release package 視為正式批准、不釋放 live apply、不套用 writer、不寫 receipt、不寫 result capture、不寫 learning、不更新 PlayBook trust、不送 Telegram、不寫 production | -| P2-130 | 完成 | 100 | OpenClaw + Hermes + NemoTron | owner-approved release readiness readback | `ai_agent_result_capture_owner_approved_release_readiness_readback_v1` / schema / snapshot / 只讀 API / governance UI;正式站 deploy marker `6fcf7241` 已驗證;5 個 release readiness readback、5 個 owner release readiness check、5 個 live-apply readiness gate、5 個 rollback readiness check、6 個 blocked readiness transition、5 個 operator action;runtime authority 固定 `result_capture_owner_approved_release_readiness_readback_only_no_live_write`;owner release approved / maintenance window approved / rollback owner confirmed / post-release verifier ready / release readiness passed / live apply release passed / writer apply / execution apply / receipt write / result capture / learning / PlayBook trust / reviewer queue / Gateway / Telegram / Bot API / report receipt / production write 全為 `0`;desktop / mobile smoke 禁用內部協作片語 `0`、水平溢位 `0`、P2-130 區塊危險入口 `0`、console error `0`、API bad response `0`、request failure `0` | 下一步 P2-131;不把 readiness 視為正式批准、不釋放 live apply、不套用 writer、不寫 receipt、不寫 result capture、不寫 learning、不更新 PlayBook trust、不送 Telegram、不寫 production | +| P2-130 | 完成 | 100 | OpenClaw + Hermes + NemoTron | owner-approved release readiness readback | `ai_agent_result_capture_owner_approved_release_readiness_readback_v1` / schema / snapshot / 只讀 API / governance UI;正式站 deploy marker `6fcf7241` 已驗證;5 個 release readiness readback、5 個 owner release readiness check、5 個 live-apply readiness gate、5 個 rollback readiness check、6 個 blocked readiness transition、5 個 operator action;runtime authority 固定 `result_capture_owner_approved_release_readiness_readback_only_no_live_write`;owner release approved / maintenance window approved / rollback owner confirmed / post-release verifier ready / release readiness passed / live apply release passed / writer apply / execution apply / receipt write / result capture / learning / PlayBook trust / reviewer queue / Gateway / Telegram / Bot API / report receipt / production write 全為 `0`;desktop / mobile smoke 禁用內部協作片語 `0`、水平溢位 `0`、P2-130 區塊危險入口 `0`、console error `0`、API bad response `0`、request failure `0` | 已由 P2-131 承接;不把 readiness 視為正式批准、不釋放 live apply、不套用 writer、不寫 receipt、不寫 result capture、不寫 learning、不更新 PlayBook trust、不送 Telegram、不寫 production | +| P2-131 | 本地完成,正式站待驗證 | 100 | OpenClaw + Hermes + NemoTron | owner release approval gate | `ai_agent_result_capture_owner_release_approval_gate_v1` / schema / snapshot / 只讀 API / governance UI;5 個 owner release approval packet、5 個 maintenance window approval gate、5 個 live-apply release approval gate、5 個 rollback owner approval check、6 個 blocked approval transition、5 個 operator action;runtime authority 固定 `result_capture_owner_release_approval_gate_only_no_live_write`;owner release approved / maintenance window approved / rollback owner confirmed / post-release verifier ready / release approval passed / live apply release passed / writer apply / execution apply / receipt write / result capture / learning / PlayBook trust / reviewer queue / Gateway / Telegram / Bot API / report receipt / production write 全為 `0` | 下一步 P2-132;不把 approval gate 視為正式批准、不釋放 live apply、不套用 writer、不寫 receipt、不寫 result capture、不寫 learning、不更新 PlayBook trust、不送 Telegram、不寫 production | ### P3 - 候選 Agent 擴展 diff --git a/docs/evaluations/ai_agent_result_capture_owner_release_approval_gate_2026-06-14.json b/docs/evaluations/ai_agent_result_capture_owner_release_approval_gate_2026-06-14.json new file mode 100644 index 000000000..db885114a --- /dev/null +++ b/docs/evaluations/ai_agent_result_capture_owner_release_approval_gate_2026-06-14.json @@ -0,0 +1,461 @@ +{ + "schema_version": "ai_agent_result_capture_owner_release_approval_gate_v1", + "generated_at": "2026-06-14T07:08:00+08:00", + "program_status": { + "overall_completion_percent": 100, + "current_priority": "P2", + "current_task_id": "P2-131", + "next_task_id": "P2-132", + "read_only_mode": true, + "runtime_authority": "result_capture_owner_release_approval_gate_only_no_live_write", + "status_note": "P2-131 只把 P2-130 owner-approved release readiness readback 轉成 owner release approval gate;不得視為 owner release approved,不得批准 maintenance window,不得釋放 live apply、套用 writer、寫 receipt、寫 result capture、寫 learning、寫 queue、送 Telegram 或寫入 production。" + }, + "source_refs": [ + "docs/evaluations/ai_agent_result_capture_owner_approved_release_readiness_readback_2026-06-14.json", + "docs/evaluations/ai_agent_result_capture_owner_approved_preflight_release_package_2026-06-14.json", + "docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md#51-建立-owner-approved-release-readiness-readback" + ], + "prior_owner_approved_release_readiness_readback": { + "schema_version": "ai_agent_result_capture_owner_approved_release_readiness_readback_v1", + "release_readiness_readback_count": 5, + "owner_release_readiness_check_count": 5, + "live_apply_readiness_gate_count": 5, + "rollback_readiness_check_count": 5, + "blocked_readiness_transition_count": 6, + "operator_action_count": 5, + "approval_required_total": 8, + "blocked_total": 9, + "owner_release_approved_count": 0, + "maintenance_window_approved_count": 0, + "rollback_owner_confirmed_count": 0, + "post_release_verifier_ready_count": 0, + "release_readiness_pass_count": 0, + "live_apply_release_pass_count": 0, + "writer_apply_count": 0, + "execution_apply_count": 0, + "receipt_write_count": 0, + "result_capture_write_count": 0, + "learning_write_count": 0, + "playbook_trust_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, + "readiness_note": "P2-130 已把 release readiness readback、owner release readiness check、live-apply readiness gate、rollback readiness check 與 blocked readiness transition 固定為只讀 readiness;P2-131 只建立 approval gate,不視為正式批准。" + }, + "owner_release_approval_truth": { + "p2_130_readiness_loaded": true, + "owner_release_approval_gate_ready": true, + "owner_release_review_required": true, + "maintenance_window_review_required": true, + "live_apply_approval_hold_active": true, + "rollback_owner_review_required": true, + "post_release_verifier_required": true, + "redaction_review_required": true, + "owner_release_approval_gate_only": true, + "owner_release_approved": false, + "maintenance_window_approved": false, + "rollback_owner_confirmed": false, + "post_release_verifier_ready": false, + "release_approval_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_approved_count": 0, + "maintenance_window_approved_count": 0, + "rollback_owner_confirmed_count": 0, + "post_release_verifier_ready_count": 0, + "release_approval_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, + "truth_note": "P2-131 只建立 owner release approval gate;approval gate 可見不代表 owner release approved、maintenance window approved、post-release verifier ready 或 live apply 可執行。" + }, + "owner_release_approval_packets": [ + { + "packet_id": "approval_gate_result_capture_writer", + "display_name": "Result capture owner release approval gate", + "owner_agent": "openclaw", + "source_readiness": "readback_release_readiness_result_capture_writer", + "status": "ready_for_owner_review", + "approval_mode": "owner_release_approval_gate", + "owner_release_approved": false, + "release_approval_passed": false, + "approval_summary": "將 result capture writer readiness 轉成 owner review packet;未取得 owner approval 前不得套用 writer 或寫 receipt。", + "evidence_hash": "sha256:b111111111111111111111111111111111111111111111111111111111111111" + }, + { + "packet_id": "approval_gate_learning_writer", + "display_name": "Learning owner release approval gate", + "owner_agent": "hermes", + "source_readiness": "readback_release_readiness_learning_writer", + "status": "approval_required", + "approval_mode": "owner_release_approval_gate", + "owner_release_approved": false, + "release_approval_passed": false, + "approval_summary": "將 KM / learning readiness 轉成 owner review packet;不寫 KM、不寫 learning metadata。", + "evidence_hash": "sha256:b222222222222222222222222222222222222222222222222222222222222222" + }, + { + "packet_id": "approval_gate_playbook_trust_writer", + "display_name": "PlayBook trust owner release approval gate", + "owner_agent": "nemotron", + "source_readiness": "readback_release_readiness_playbook_trust_writer", + "status": "blocked_by_policy", + "approval_mode": "owner_release_approval_gate", + "owner_release_approved": false, + "release_approval_passed": false, + "approval_summary": "PlayBook trust 仍需 OpenClaw 仲裁與負向強化 reviewer;未完成前不得 release。", + "evidence_hash": "sha256:b333333333333333333333333333333333333333333333333333333333333333" + }, + { + "packet_id": "approval_gate_reviewer_queue_writer", + "display_name": "Reviewer queue owner release approval gate", + "owner_agent": "openclaw", + "source_readiness": "readback_release_readiness_reviewer_queue_writer", + "status": "approval_required", + "approval_mode": "owner_release_approval_gate", + "owner_release_approved": false, + "release_approval_passed": false, + "approval_summary": "將 reviewer queue readiness 轉成 owner review packet;不寫 reviewer queue。", + "evidence_hash": "sha256:b444444444444444444444444444444444444444444444444444444444444444" + }, + { + "packet_id": "approval_gate_gateway_queue_writer", + "display_name": "Gateway queue owner release approval gate", + "owner_agent": "nemotron", + "source_readiness": "readback_release_readiness_gateway_queue_writer", + "status": "ready_for_owner_review", + "approval_mode": "owner_release_approval_gate", + "owner_release_approved": false, + "release_approval_passed": false, + "approval_summary": "將 Gateway queue readiness 轉成 owner review packet;不寫 Gateway queue、不送 Telegram。", + "evidence_hash": "sha256:b555555555555555555555555555555555555555555555555555555555555555" + } + ], + "maintenance_window_approval_gates": [ + { + "gate_id": "maintenance_window_result_capture", + "display_name": "Result capture maintenance window gate", + "owner_agent": "openclaw", + "status": "ready_for_owner_review", + "gate_mode": "maintenance_window_approval_gate", + "maintenance_window_review_required": true, + "maintenance_window_approved": false, + "required_before_live_apply": "owner release approved、maintenance window approved、rollback owner confirmed、post-release verifier ready。" + }, + { + "gate_id": "maintenance_window_learning", + "display_name": "Learning maintenance window gate", + "owner_agent": "hermes", + "status": "approval_required", + "gate_mode": "maintenance_window_approval_gate", + "maintenance_window_review_required": true, + "maintenance_window_approved": false, + "required_before_live_apply": "KM stale guard、owner release approved、maintenance window approved、post-release verifier ready。" + }, + { + "gate_id": "maintenance_window_playbook_trust", + "display_name": "PlayBook trust maintenance window gate", + "owner_agent": "nemotron", + "status": "blocked_by_policy", + "gate_mode": "maintenance_window_approval_gate", + "maintenance_window_review_required": true, + "maintenance_window_approved": false, + "required_before_live_apply": "OpenClaw 仲裁與 trust reviewer 通過後才可進維護窗口審查。" + }, + { + "gate_id": "maintenance_window_reviewer_queue", + "display_name": "Reviewer queue maintenance window gate", + "owner_agent": "openclaw", + "status": "approval_required", + "gate_mode": "maintenance_window_approval_gate", + "maintenance_window_review_required": true, + "maintenance_window_approved": false, + "required_before_live_apply": "reviewer SLA owner、dedupe key owner、maintenance window approved。" + }, + { + "gate_id": "maintenance_window_gateway_queue", + "display_name": "Gateway queue maintenance window gate", + "owner_agent": "nemotron", + "status": "ready_for_owner_review", + "gate_mode": "maintenance_window_approval_gate", + "maintenance_window_review_required": true, + "maintenance_window_approved": false, + "required_before_live_apply": "SRE route lock、Telegram receipt owner、maintenance window approved。" + } + ], + "live_apply_release_approval_gates": [ + { + "gate_id": "live_apply_approval_result_capture", + "display_name": "Result capture live apply approval gate", + "owner_agent": "openclaw", + "status": "ready_for_owner_review", + "gate_mode": "live_apply_release_approval_gate", + "release_approval_passed": false, + "live_apply_release_enabled": false, + "hold_reason": "owner release approved、maintenance window approved 與 post-release verifier ready 尚未成立。", + "release_condition": "P2-132 只能先建立 post-release verifier / rollback gate,不得直接 writer apply。" + }, + { + "gate_id": "live_apply_approval_learning", + "display_name": "Learning live apply approval gate", + "owner_agent": "hermes", + "status": "approval_required", + "gate_mode": "live_apply_release_approval_gate", + "release_approval_passed": false, + "live_apply_release_enabled": false, + "hold_reason": "learning write scope、KM owner 與 rollback owner 尚未 approved。", + "release_condition": "需要 owner release approval gate、maintenance window gate 與 post-release verifier 同時通過。" + }, + { + "gate_id": "live_apply_approval_playbook_trust", + "display_name": "PlayBook trust live apply approval gate", + "owner_agent": "nemotron", + "status": "blocked_by_policy", + "gate_mode": "live_apply_release_approval_gate", + "release_approval_passed": false, + "live_apply_release_enabled": false, + "hold_reason": "OpenClaw 仲裁、trust reviewer 與負向強化審查尚未完成。", + "release_condition": "不得因 approval gate 可見而自動更新 PlayBook trust。" + }, + { + "gate_id": "live_apply_approval_reviewer_queue", + "display_name": "Reviewer queue live apply approval gate", + "owner_agent": "openclaw", + "status": "approval_required", + "gate_mode": "live_apply_release_approval_gate", + "release_approval_passed": false, + "live_apply_release_enabled": false, + "hold_reason": "reviewer queue owner 與 rollback owner 尚未 approved。", + "release_condition": "不得寫 reviewer queue,僅保留 owner review packet。" + }, + { + "gate_id": "live_apply_approval_gateway_queue", + "display_name": "Gateway queue live apply approval gate", + "owner_agent": "nemotron", + "status": "ready_for_owner_review", + "gate_mode": "live_apply_release_approval_gate", + "release_approval_passed": false, + "live_apply_release_enabled": false, + "hold_reason": "Telegram receipt owner 與 SRE route lock 尚未 approved。", + "release_condition": "不得寫 Gateway queue、不得送 Telegram、不得呼叫 Bot API。" + } + ], + "rollback_owner_approval_checks": [ + { + "check_id": "rollback_owner_result_capture", + "display_name": "Result capture rollback owner approval check", + "owner_agent": "openclaw", + "status": "ready_for_owner_review", + "rollback_owner_required": true, + "rollback_owner_confirmed": false, + "rollback_scope": "撤回 result capture release approval gate、receipt preview 與 verifier handoff。", + "hold_reason": "rollback owner 尚未 confirmed。" + }, + { + "check_id": "rollback_owner_learning", + "display_name": "Learning rollback owner approval check", + "owner_agent": "hermes", + "status": "approval_required", + "rollback_owner_required": true, + "rollback_owner_confirmed": false, + "rollback_scope": "撤回 learning release approval gate、KM write scope 與 stale guard handoff。", + "hold_reason": "learning rollback owner 尚未 confirmed。" + }, + { + "check_id": "rollback_owner_playbook_trust", + "display_name": "PlayBook trust rollback owner approval check", + "owner_agent": "nemotron", + "status": "blocked_by_policy", + "rollback_owner_required": true, + "rollback_owner_confirmed": false, + "rollback_scope": "撤回 PlayBook trust approval gate、trust delta 與 reviewer handoff。", + "hold_reason": "trust rollback owner 與 OpenClaw 仲裁尚未 confirmed。" + }, + { + "check_id": "rollback_owner_reviewer_queue", + "display_name": "Reviewer queue rollback owner approval check", + "owner_agent": "openclaw", + "status": "approval_required", + "rollback_owner_required": true, + "rollback_owner_confirmed": false, + "rollback_scope": "撤回 reviewer queue approval gate、dedupe key 與 SLA handoff。", + "hold_reason": "reviewer queue rollback owner 尚未 confirmed。" + }, + { + "check_id": "rollback_owner_gateway_queue", + "display_name": "Gateway queue rollback owner approval check", + "owner_agent": "nemotron", + "status": "ready_for_owner_review", + "rollback_owner_required": true, + "rollback_owner_confirmed": false, + "rollback_scope": "撤回 Gateway queue approval gate、route lock 與 Telegram receipt draft。", + "hold_reason": "Gateway rollback owner 尚未 confirmed,不得送 Telegram。" + } + ], + "blocked_approval_transitions": [ + { + "blocker_id": "blocked_writer_apply_approval", + "display_name": "Writer apply approval blocked", + "severity": "critical", + "status": "blocked_by_policy", + "blocked_action": "writer_apply_after_owner_release_approval_gate", + "blocked_until": "owner release approved + maintenance window approved + post-release verifier ready", + "evidence_hash": "sha256:c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1" + }, + { + "blocker_id": "blocked_execution_apply_approval", + "display_name": "Execution apply approval blocked", + "severity": "critical", + "status": "blocked_by_policy", + "blocked_action": "execution_apply_after_owner_release_approval_gate", + "blocked_until": "maintenance window approved + rollback owner confirmed", + "evidence_hash": "sha256:c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2" + }, + { + "blocker_id": "blocked_receipt_write_approval", + "display_name": "Receipt write approval blocked", + "severity": "critical", + "status": "approval_required", + "blocked_action": "receipt_write_after_owner_release_approval_gate", + "blocked_until": "post-release verifier ready + rollback owner confirmed", + "evidence_hash": "sha256:c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3" + }, + { + "blocker_id": "blocked_result_capture_write_approval", + "display_name": "Result capture write approval blocked", + "severity": "critical", + "status": "blocked_by_policy", + "blocked_action": "result_capture_write_after_owner_release_approval_gate", + "blocked_until": "owner release approved + result capture verifier ready", + "evidence_hash": "sha256:c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4" + }, + { + "blocker_id": "blocked_gateway_queue_write_approval", + "display_name": "Gateway queue write approval blocked", + "severity": "critical", + "status": "approval_required", + "blocked_action": "gateway_queue_write_after_owner_release_approval_gate", + "blocked_until": "SRE route lock + Telegram receipt owner approved", + "evidence_hash": "sha256:c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5" + }, + { + "blocker_id": "blocked_telegram_send_approval", + "display_name": "Telegram send approval blocked", + "severity": "high", + "status": "approval_required", + "blocked_action": "telegram_send_after_owner_release_approval_gate", + "blocked_until": "Gateway queue release approved + Telegram receipt E2E approved", + "evidence_hash": "sha256:c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6" + } + ], + "operator_actions": [ + { + "action_id": "review_owner_release_approval_packets", + "owner_agent": "openclaw", + "status": "ready_for_operator_review", + "operator_instruction": "審核 5 個 owner release approval packet 是否仍符合 P2-130 readiness 邊界;不要把 approval gate 視為正式批准。", + "runtime_write_allowed": false + }, + { + "action_id": "verify_maintenance_window_hold", + "owner_agent": "hermes", + "status": "ready_for_operator_review", + "operator_instruction": "確認 maintenance window gate 仍全部未 approved,且所有 live apply approval gate 仍為 false。", + "runtime_write_allowed": false + }, + { + "action_id": "verify_live_apply_approval_hold", + "owner_agent": "nemotron", + "status": "ready_for_operator_review", + "operator_instruction": "確認 live apply approval 已讀回但仍 hold;不可套用 writer 或執行正式寫入。", + "runtime_write_allowed": false + }, + { + "action_id": "verify_rollback_owner_gate", + "owner_agent": "openclaw", + "status": "approval_required", + "operator_instruction": "確認 rollback owner scope、owner 與 hold reason 已整理,但 rollback_owner_confirmed 仍為 false。", + "runtime_write_allowed": false + }, + { + "action_id": "prepare_p2_132_post_release_verifier_gate", + "owner_agent": "hermes", + "status": "ready_for_operator_review", + "operator_instruction": "下一關只可建立 P2-132 post-release verifier gate,不可放行 writer 或正式寫入。", + "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": "前端只能顯示 owner release approval gate 摘要、狀態、數量、紅acted hash 與 0 / false 邊界;不得顯示內部協作環境對話、原始提示詞、私有推理、secret、授權標頭或原始 runtime payload。" + }, + "rollups": { + "owner_release_approval_packet_count": 5, + "maintenance_window_approval_gate_count": 5, + "live_apply_release_approval_gate_count": 5, + "rollback_owner_approval_check_count": 5, + "blocked_approval_transition_count": 6, + "operator_action_count": 5, + "approval_required_packet_count": 2, + "blocked_packet_count": 1, + "approval_required_maintenance_window_count": 2, + "blocked_maintenance_window_count": 1, + "approval_required_live_apply_count": 2, + "blocked_live_apply_count": 1, + "approval_required_rollback_count": 2, + "blocked_rollback_count": 1, + "critical_blocker_count": 5, + "owner_release_approved_count": 0, + "maintenance_window_approved_count": 0, + "rollback_owner_confirmed_count": 0, + "post_release_verifier_ready_count": 0, + "release_approval_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_owner_release_approval_gate_v1.schema.json b/docs/schemas/ai_agent_result_capture_owner_release_approval_gate_v1.schema.json new file mode 100644 index 000000000..8be9af153 --- /dev/null +++ b/docs/schemas/ai_agent_result_capture_owner_release_approval_gate_v1.schema.json @@ -0,0 +1,100 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://awoooi.wooo.work/schemas/ai_agent_result_capture_owner_release_approval_gate_v1.schema.json", + "title": "AI Agent result capture owner release approval gate v1", + "type": "object", + "required": [ + "schema_version", + "generated_at", + "program_status", + "source_refs", + "prior_owner_approved_release_readiness_readback", + "owner_release_approval_truth", + "owner_release_approval_packets", + "maintenance_window_approval_gates", + "live_apply_release_approval_gates", + "rollback_owner_approval_checks", + "blocked_approval_transitions", + "operator_actions", + "display_redaction_contract", + "rollups" + ], + "properties": { + "schema_version": { + "const": "ai_agent_result_capture_owner_release_approval_gate_v1" + }, + "generated_at": { + "type": "string" + }, + "program_status": { + "type": "object" + }, + "source_refs": { + "type": "array", + "items": { + "type": "string" + } + }, + "prior_owner_approved_release_readiness_readback": { + "type": "object" + }, + "owner_release_approval_truth": { + "type": "object" + }, + "owner_release_approval_packets": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "maintenance_window_approval_gates": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "live_apply_release_approval_gates": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "rollback_owner_approval_checks": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "blocked_approval_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 7f45467fd..8c401cd0c 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 @@ -668,6 +668,7 @@ Alert / Sentry / SigNoz / Gitea / Market Watch / Operator | `docs/evaluations/ai_agent_result_capture_owner_acceptance_readback_preflight_hold_2026-06-14.json` + `GET /api/v1/agents/agent-result-capture-owner-acceptance-readback-preflight-hold` | P2-128 owner acceptance readback / live-apply preflight hold;承接 P2-127 owner acceptance / maintenance window gate,建立 5 個 owner acceptance readback、5 個 preflight hold check、5 個 live-apply hold gate、5 個 rollback preflight check、6 個 blocked apply transition 與 5 個 operator action;runtime authority 固定 `result_capture_owner_acceptance_readback_preflight_hold_only_no_live_write`;owner acceptance received、maintenance window approved、rollback owner confirmed、post-apply verifier ready、live apply preflight 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 `0a3f1533` 已正式驗證,已由 P2-129 承接 | | `docs/evaluations/ai_agent_result_capture_owner_approved_preflight_release_package_2026-06-14.json` + `GET /api/v1/agents/agent-result-capture-owner-approved-preflight-release-package` | P2-129 owner-approved preflight release package;承接 P2-128 owner acceptance readback / live-apply preflight hold,建立 5 個 owner-approved release package、5 個 release preflight check、5 個 live-apply release gate、5 個 rollback release check、6 個 blocked release transition 與 5 個 operator action;runtime authority 固定 `result_capture_owner_approved_preflight_release_package_only_no_live_write`;owner release approved、maintenance window approved、rollback owner confirmed、post-release verifier ready、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 `7e5b4793` 已正式驗證,已由 P2-130 承接 | | `docs/evaluations/ai_agent_result_capture_owner_approved_release_readiness_readback_2026-06-14.json` + `GET /api/v1/agents/agent-result-capture-owner-approved-release-readiness-readback` | P2-130 owner-approved release readiness readback;承接 P2-129 owner-approved preflight release package,建立 5 個 release readiness readback、5 個 owner release readiness check、5 個 live-apply readiness gate、5 個 rollback readiness check、6 個 blocked readiness transition 與 5 個 operator action;runtime authority 固定 `result_capture_owner_approved_release_readiness_readback_only_no_live_write`;owner release approved、maintenance window approved、rollback owner confirmed、post-release verifier ready、release readiness 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 `6fcf7241` 已正式驗證,下一步 P2-131 | +| `docs/evaluations/ai_agent_result_capture_owner_release_approval_gate_2026-06-14.json` + `GET /api/v1/agents/agent-result-capture-owner-release-approval-gate` | P2-131 owner release approval gate;承接 P2-130 owner-approved release readiness readback,建立 5 個 owner release approval packet、5 個 maintenance window approval gate、5 個 live-apply release approval gate、5 個 rollback owner approval check、6 個 blocked approval transition 與 5 個 operator action;runtime authority 固定 `result_capture_owner_release_approval_gate_only_no_live_write`;owner release approved、maintenance window approved、rollback owner confirmed、post-release verifier ready、release approval 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`,下一步 P2-132 | | `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 主動營運委派與版本生命週期契約 @@ -786,7 +787,8 @@ Repo / registry / release notes / K8s / host / observability / backup evidence 48. 建立 owner acceptance / maintenance window gate。✅ P2-127 已完成並正式驗證;owner acceptance packet `5`、maintenance window `5`、rollback owner check `5`、post-apply verifier gate `5`、blocked live write `6`、operator action `5`,approval-required packet / window / rollback / verifier `2 / 2 / 2 / 2`、blocked packet / window / rollback / verifier `1 / 1 / 1 / 1`、critical blocker `5`;owner accepted、maintenance window approved、rollback owner confirmed、post-apply verifier ready、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 仍為 `0 / false`;deploy marker `7b034b58`、正式 API readback 與 desktop / mobile smoke 已完成。已由 P2-128 承接。 49. 建立 owner acceptance readback / live-apply preflight hold。✅ P2-128 已完成並正式驗證;owner acceptance readback `5`、preflight hold check `5`、live-apply hold gate `5`、rollback preflight check `5`、blocked apply transition `6`、operator action `5`,approval-required readback / preflight / hold / rollback `2 / 2 / 2 / 2`、blocked readback / preflight / hold / rollback `1 / 1 / 1 / 1`、critical blocker `5`;owner acceptance received、maintenance window approved、rollback owner confirmed、post-apply verifier ready、live apply preflight 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 仍為 `0 / false`;deploy marker `0a3f1533`、正式 API readback 與 desktop / mobile smoke 已完成。已由 P2-129 承接。 50. 建立 owner-approved preflight release package。✅ P2-129 已完成並正式驗證;owner-approved release package `5`、release preflight check `5`、live-apply release gate `5`、rollback release check `5`、blocked release transition `6`、operator action `5`,approval-required package / preflight / release gate / rollback `2 / 2 / 2 / 2`、blocked package / preflight / release gate / rollback `1 / 1 / 1 / 1`、critical blocker `5`;owner release approved、maintenance window approved、rollback owner confirmed、post-release verifier ready、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 仍為 `0 / false`;deploy marker `7e5b4793`、正式 API readback 與 desktop / mobile smoke 已完成。已由 P2-130 承接。 -51. 建立 owner-approved release readiness readback。✅ P2-130 已完成並正式驗證;release readiness readback `5`、owner release readiness check `5`、live-apply readiness gate `5`、rollback readiness check `5`、blocked readiness transition `6`、operator action `5`,approval-required readback / owner check / readiness gate / rollback `2 / 2 / 2 / 2`、blocked readback / owner check / readiness gate / rollback `1 / 1 / 1 / 1`、critical blocker `5`;owner release approved、maintenance window approved、rollback owner confirmed、post-release verifier ready、release readiness 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 仍為 `0 / false`;deploy marker `6fcf7241`、正式 API readback 與 desktop / mobile smoke 已完成。下一步 P2-131。 +51. 建立 owner-approved release readiness readback。✅ P2-130 已完成並正式驗證;release readiness readback `5`、owner release readiness check `5`、live-apply readiness gate `5`、rollback readiness check `5`、blocked readiness transition `6`、operator action `5`,approval-required readback / owner check / readiness gate / rollback `2 / 2 / 2 / 2`、blocked readback / owner check / readiness gate / rollback `1 / 1 / 1 / 1`、critical blocker `5`;owner release approved、maintenance window approved、rollback owner confirmed、post-release verifier ready、release readiness 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 仍為 `0 / false`;deploy marker `6fcf7241`、正式 API readback 與 desktop / mobile smoke 已完成。已由 P2-131 承接。 +52. 建立 owner release approval gate。✅ P2-131 已本地完成,正式站待驗證;owner release approval packet `5`、maintenance window approval gate `5`、live-apply release approval gate `5`、rollback owner approval check `5`、blocked approval transition `6`、operator action `5`,approval-required packet / maintenance / live apply / rollback `2 / 2 / 2 / 2`、blocked packet / maintenance / live apply / rollback `1 / 1 / 1 / 1`、critical blocker `5`;owner release approved、maintenance window approved、rollback owner confirmed、post-release verifier ready、release approval 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 仍為 `0 / false`。下一步 P2-132。 #### 3.2.1d 2026-06-11 Agent 互動、學習與成長證據面 @@ -2107,6 +2109,16 @@ Phase 6 完成後 - 政策裁決:P2-126 只允許 owner-approved execution rehearsal、no-write apply check、post-write verifier rehearsal、rollback drill、blocked live apply 與 operator handoff 可視化;不得把 rehearsal 解讀成 owner approval record 已收、no-write apply 已執行、writer apply、execution apply、receipt write、result capture write、learning write、PlayBook trust write、reviewer queue write、Gateway queue write、Telegram 實發、Bot API 呼叫、report receipt write 或 live writer 已啟用。 - 本波仍不讀 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-127 承接。 +### 2026-06-14 07:08 (台北) — §3.2 / §5 — 本地完成 P2-131 owner release approval gate — 把 readiness 轉成可審核批准門檻 + +- 新增 `ai_agent_result_capture_owner_release_approval_gate_v1` schema / committed snapshot / loader / API / 測試,承接 P2-130 owner-approved release readiness readback,定義 5 個 owner release approval packet、5 個 maintenance window approval gate、5 個 live-apply release approval gate、5 個 rollback owner approval check、6 個 blocked approval transition 與 5 個 operator action。 +- Governance automation inventory 新增 P2-131 區塊,將 owner release approval packet、maintenance window gate、live-apply approval gate、rollback owner check、blocked approval transition 與 operator action 全部以只讀方式呈現。 +- 本地 API/service regression:P2-131 + P2-130 `14 passed`;JSON parse、Python 3.11 py_compile、`pnpm --filter @awoooi/web typecheck` 與 production build 通過。 +- 本地 snapshot 固定 `schema_version=ai_agent_result_capture_owner_release_approval_gate_v1`、current `P2-131`、next `P2-132`、completion `100`;owner release approval packet `5`、maintenance window approval gate `5`、live-apply release approval gate `5`、rollback owner approval check `5`、blocked approval transition `6`、operator action `5`、approval-required packet / maintenance / live apply / rollback `2 / 2 / 2 / 2`、blocked packet / maintenance / live apply / rollback `1 / 1 / 1 / 1`、critical blocker `5`。 +- 本地 0 / false 邊界:owner release approved、maintenance window approved、rollback owner confirmed、post-release verifier ready、release approval 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-131 只允許 owner release approval gate 可視化;不得把 approval gate 解讀成 owner release approved、maintenance window approved、rollback owner confirmed、post-release verifier ready、live apply release passed、writer apply、execution apply、receipt write、result capture write、learning write、PlayBook trust write、reviewer queue write、Gateway queue write、Telegram 實發、Bot API 呼叫、report receipt write 或 live writer 已啟用。 +- 本波仍不讀 canonical runtime target、不做 live query、不寫 reviewer queue、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 report receipt、不寫 result capture、不寫 learning、不更新 PlayBook trust、不寫 production target、不讀 secret、不執行 destructive action、不回傳內部協作內容;推送 Gitea main 後補正式 API / Browser readback,下一步 P2-132。 + ### 2026-06-14 06:18 (台北) — §3.2 / §5 — 正式驗證 P2-130 owner-approved release readiness readback — 把 release package 讀回成 readiness hold - 新增 `ai_agent_result_capture_owner_approved_release_readiness_readback_v1` schema / committed snapshot / loader / API / 測試,承接 P2-129 owner-approved preflight release package,定義 5 個 release readiness readback、5 個 owner release readiness check、5 個 live-apply readiness gate、5 個 rollback readiness check、6 個 blocked readiness transition 與 5 個 operator action。