diff --git a/apps/api/src/api/v1/agents.py b/apps/api/src/api/v1/agents.py index fd398a9b1..69b32728b 100644 --- a/apps/api/src/api/v1/agents.py +++ b/apps/api/src/api/v1/agents.py @@ -133,6 +133,9 @@ from src.services.ai_agent_result_capture_owner_acceptance_maintenance_gate impo from src.services.ai_agent_result_capture_owner_acceptance_readback_preflight_hold import ( load_latest_ai_agent_result_capture_owner_acceptance_readback_preflight_hold, ) +from src.services.ai_agent_result_capture_owner_approved_preflight_release_package import ( + load_latest_ai_agent_result_capture_owner_approved_preflight_release_package, +) from src.services.ai_agent_result_capture_promotion_approval_gate import ( load_latest_ai_agent_result_capture_promotion_approval_gate, ) @@ -1950,6 +1953,36 @@ async def get_agent_result_capture_owner_acceptance_readback_preflight_hold() -> ) from exc +@router.get( + "/agent-result-capture-owner-approved-preflight-release-package", + response_model=dict[str, Any], + summary="取得 AI Agent result capture owner-approved preflight release package", + description=( + "讀取最新已提交的 P2-129 owner-approved preflight release package;" + "此端點只回傳 owner-approved release package、release preflight check、" + "live apply release gate、rollback release check、blocked release transition 與 operator handoff," + "不釋放 live apply、不套用 writer、不寫 receipt、不寫 result capture、learning、PlayBook trust、" + "reviewer queue、Gateway queue,不送 Telegram、不呼叫 Bot API、不讀 secret。" + ), +) +async def get_agent_result_capture_owner_approved_preflight_release_package() -> dict[str, Any]: + """Return the latest read-only owner-approved preflight release package.""" + try: + payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_owner_approved_preflight_release_package) + 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_approved_preflight_release_package_invalid", error=str(exc)) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="AI Agent result capture owner-approved preflight release package 無效", + ) 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_approved_preflight_release_package.py b/apps/api/src/services/ai_agent_result_capture_owner_approved_preflight_release_package.py new file mode 100644 index 000000000..ea8fd671c --- /dev/null +++ b/apps/api/src/services/ai_agent_result_capture_owner_approved_preflight_release_package.py @@ -0,0 +1,415 @@ +""" +AI Agent result capture owner-approved preflight release package snapshot. + +Loads the latest committed P2-129 owner-approved preflight release package. +This module validates committed evidence only; it never 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_approved_preflight_release_package_*.json" +_SCHEMA_VERSION = "ai_agent_result_capture_owner_approved_preflight_release_package_v1" +_RUNTIME_AUTHORITY = "result_capture_owner_approved_preflight_release_package_only_no_live_write" + + +def load_latest_ai_agent_result_capture_owner_approved_preflight_release_package( + evaluations_dir: Path | None = None, +) -> dict[str, Any]: + """Load the newest committed owner-approved preflight release package.""" + 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-approved preflight release package 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_release_packages(payload, label) + _require_release_preflights(payload, label) + _require_live_apply_release_gates(payload, label) + _require_rollback_releases(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-129", + "next_task_id": "P2-130", + "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_acceptance_readback_preflight_hold") or {} + expected = { + "schema_version": "ai_agent_result_capture_owner_acceptance_readback_preflight_hold_v1", + "owner_acceptance_readback_count": 5, + "preflight_hold_check_count": 5, + "live_apply_hold_gate_count": 5, + "rollback_preflight_check_count": 5, + "blocked_apply_transition_count": 6, + "operator_action_count": 5, + "approval_required_total": 8, + "blocked_total": 9, + "owner_acceptance_received_count": 0, + "maintenance_window_approved_count": 0, + "rollback_owner_confirmed_count": 0, + "post_apply_verifier_ready_count": 0, + "live_apply_preflight_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_acceptance_readback_preflight_hold mismatch: {mismatches}") + if not prior.get("readiness_note"): + raise ValueError(f"{label}: prior_owner_acceptance_readback_preflight_hold.readiness_note is required") + + +def _require_truth(payload: dict[str, Any], label: str) -> None: + truth = payload.get("release_truth") or {} + required_true = { + "p2_128_preflight_hold_loaded", + "owner_approved_release_package_ready", + "owner_release_review_required", + "live_apply_release_hold_active", + "rollback_release_required", + "post_release_verifier_required", + "redaction_review_required", + "release_package_only", + } + missing = sorted(field for field in required_true if truth.get(field) is not True) + if missing: + raise ValueError(f"{label}: release package ready flags must remain true: {missing}") + + required_false = { + "owner_release_approved", + "maintenance_window_approved", + "rollback_owner_confirmed", + "post_release_verifier_ready", + "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}: live release/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", + "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}: release package live counters must remain zero: {non_zero}") + if not truth.get("truth_note"): + raise ValueError(f"{label}: release_truth.truth_note is required") + + +def _require_release_packages(payload: dict[str, Any], label: str) -> None: + items = payload.get("owner_approved_release_packages") or [] + required = { + "release_package_result_capture_writer", + "release_package_learning_writer", + "release_package_playbook_trust_writer", + "release_package_reviewer_queue_writer", + "release_package_gateway_queue_writer", + } + ids = {item.get("package_id") for item in items} + if ids != required: + raise ValueError(f"{label}: owner-approved release packages must match {sorted(required)}") + for item in items: + item_id = item.get("package_id") + if item.get("package_mode") != "owner_approved_preflight_release_package": + raise ValueError(f"{label}: release package {item_id} must remain owner-approved preflight package") + if item.get("owner_release_approved") is not False: + raise ValueError(f"{label}: release package {item_id} must not mark owner release approved") + if item.get("status") not in {"ready_for_release_review", "approval_required", "blocked_by_policy"}: + raise ValueError(f"{label}: release package {item_id} status is invalid") + if not item.get("release_summary") or not _is_redacted_sha256(item.get("evidence_hash")): + raise ValueError(f"{label}: release package {item_id} must include summary and redacted evidence_hash") + + +def _require_release_preflights(payload: dict[str, Any], label: str) -> None: + items = payload.get("release_preflight_checks") or [] + required = { + "release_preflight_result_capture_writer", + "release_preflight_learning_writer", + "release_preflight_playbook_trust_writer", + "release_preflight_reviewer_queue_writer", + "release_preflight_gateway_queue_writer", + } + ids = {item.get("check_id") for item in items} + if ids != required: + raise ValueError(f"{label}: release preflight checks must match {sorted(required)}") + for item in items: + item_id = item.get("check_id") + if item.get("preflight_mode") != "release_preflight_check": + raise ValueError(f"{label}: release preflight {item_id} must remain release preflight check") + if item.get("release_hold_required") is not True or item.get("release_preflight_passed") is not False: + raise ValueError(f"{label}: release preflight {item_id} must stay held and unpassed") + if item.get("status") not in {"ready_for_release_review", "approval_required", "blocked_by_policy"}: + raise ValueError(f"{label}: release preflight {item_id} status is invalid") + if not item.get("required_before_live_apply"): + raise ValueError(f"{label}: release preflight {item_id} required_before_live_apply is required") + + +def _require_live_apply_release_gates(payload: dict[str, Any], label: str) -> None: + items = payload.get("live_apply_release_gates") or [] + required = { + "release_gate_result_capture", + "release_gate_learning", + "release_gate_playbook_trust", + "release_gate_reviewer_queue", + "release_gate_gateway_queue", + } + ids = {item.get("gate_id") for item in items} + if ids != required: + raise ValueError(f"{label}: live apply release gates must match {sorted(required)}") + for item in items: + item_id = item.get("gate_id") + if item.get("gate_mode") != "live_apply_release_gate": + raise ValueError(f"{label}: release gate {item_id} must remain live apply release gate") + if item.get("live_apply_release_enabled") is not False: + raise ValueError(f"{label}: release gate {item_id} must not enable live apply release") + if item.get("status") not in {"ready_for_release_review", "approval_required", "blocked_by_policy"}: + raise ValueError(f"{label}: release gate {item_id} status is invalid") + if not item.get("release_reason") or not item.get("release_condition"): + raise ValueError(f"{label}: release gate {item_id} release_reason and release_condition are required") + + +def _require_rollback_releases(payload: dict[str, Any], label: str) -> None: + items = payload.get("rollback_release_checks") or [] + required = { + "rollback_release_result_capture", + "rollback_release_learning", + "rollback_release_playbook_trust", + "rollback_release_reviewer_queue", + "rollback_release_gateway_queue", + } + ids = {item.get("check_id") for item in items} + if ids != required: + raise ValueError(f"{label}: rollback release checks must match {sorted(required)}") + for item in items: + item_id = item.get("check_id") + if item.get("rollback_owner_required") is not True or item.get("rollback_release_passed") is not False: + raise ValueError(f"{label}: rollback release {item_id} must stay required and unpassed") + if item.get("status") not in {"ready_for_release_review", "approval_required", "blocked_by_policy"}: + raise ValueError(f"{label}: rollback release {item_id} status is invalid") + if not item.get("rollback_scope") or not item.get("hold_reason"): + raise ValueError(f"{label}: rollback release {item_id} scope and hold_reason are required") + + +def _require_blocked_transitions(payload: dict[str, Any], label: str) -> None: + items = payload.get("blocked_release_transitions") or [] + required = { + "blocked_writer_apply_release", + "blocked_execution_apply_release", + "blocked_receipt_write_release", + "blocked_result_capture_write_release", + "blocked_gateway_queue_write_release", + "blocked_telegram_send_release", + } + ids = {item.get("blocker_id") for item in items} + if ids != required: + raise ValueError(f"{label}: blocked release transitions must match {sorted(required)}") + for item in items: + item_id = item.get("blocker_id") + if item.get("status") not in {"approval_required", "blocked_by_policy"}: + raise ValueError(f"{label}: blocker {item_id} status is invalid") + if item.get("severity") not in {"high", "critical"}: + raise ValueError(f"{label}: blocker {item_id} severity is invalid") + if not item.get("blocked_action") or not item.get("blocked_until"): + raise ValueError(f"{label}: blocker {item_id} must include blocked_action and blocked_until") + if not _is_redacted_sha256(item.get("evidence_hash")): + raise ValueError(f"{label}: blocker {item_id} must expose redacted evidence_hash") + + +def _require_actions(payload: dict[str, Any], label: str) -> None: + actions = payload.get("operator_actions") or [] + required = { + "review_owner_approved_release_packages", + "verify_release_preflight_hold", + "verify_rollback_release", + "verify_gateway_telegram_release_hold", + "prepare_p2_130_release_readiness_readback", + } + ids = {action.get("action_id") for action in actions} + if ids != required: + raise ValueError(f"{label}: operator actions must match {sorted(required)}") + for action in actions: + action_id = action.get("action_id") + if action.get("runtime_write_allowed") is not False: + raise ValueError(f"{label}: action {action_id} must not allow runtime write") + if not action.get("operator_instruction"): + raise ValueError(f"{label}: action {action_id} operator_instruction is required") + + +def _require_display_redaction(payload: dict[str, Any], label: str) -> None: + contract = payload.get("display_redaction_contract") or {} + expected = { + "redaction_required": True, + "raw_prompt_display_allowed": False, + "private_reasoning_display_allowed": False, + "secret_value_display_allowed": False, + "raw_runtime_payload_display_allowed": False, + "internal_collaboration_content_display_allowed": False, + } + mismatches = _mismatches(contract, expected) + if mismatches: + raise ValueError(f"{label}: display_redaction_contract mismatch: {mismatches}") + if not contract.get("frontend_display_policy"): + raise ValueError(f"{label}: display_redaction_contract.frontend_display_policy is required") + + +def _require_rollup_consistency(payload: dict[str, Any], label: str) -> None: + rollups = payload.get("rollups") or {} + packages = payload.get("owner_approved_release_packages") or [] + preflights = payload.get("release_preflight_checks") or [] + gates = payload.get("live_apply_release_gates") or [] + rollbacks = payload.get("rollback_release_checks") or [] + blockers = payload.get("blocked_release_transitions") or [] + actions = payload.get("operator_actions") or [] + expected = { + "owner_approved_release_package_count": len(packages), + "release_preflight_check_count": len(preflights), + "live_apply_release_gate_count": len(gates), + "rollback_release_check_count": len(rollbacks), + "blocked_release_transition_count": len(blockers), + "operator_action_count": len(actions), + "approval_required_package_count": sum(1 for item in packages if item.get("status") == "approval_required"), + "blocked_package_count": sum(1 for item in packages if item.get("status") == "blocked_by_policy"), + "approval_required_preflight_count": sum(1 for item in preflights if item.get("status") == "approval_required"), + "blocked_preflight_count": sum(1 for item in preflights if item.get("status") == "blocked_by_policy"), + "approval_required_release_gate_count": sum(1 for item in gates if item.get("status") == "approval_required"), + "blocked_release_gate_count": sum(1 for item in gates if item.get("status") == "blocked_by_policy"), + "approval_required_rollback_count": sum(1 for item in rollbacks if item.get("status") == "approval_required"), + "blocked_rollback_count": sum(1 for item in rollbacks if item.get("status") == "blocked_by_policy"), + "critical_blocker_count": sum(1 for item in blockers if item.get("severity") == "critical"), + "owner_release_approved_count": 0, + "maintenance_window_approved_count": 0, + "rollback_owner_confirmed_count": 0, + "post_release_verifier_ready_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, + } + mismatches = _mismatches(rollups, expected) + if mismatches: + raise ValueError(f"{label}: rollup counts mismatch: {mismatches}") + + +def _require_no_forbidden_display_terms(payload: dict[str, Any], label: str) -> None: + serialized = json.dumps(payload, ensure_ascii=False) + forbidden = { + "work_window_transcript", + "session_id", + "browser_context", + "authorization_header", + "raw Telegram payload", + "private reasoning", + "raw prompt", + "chain-of-thought", + } + hits = sorted(term for term in forbidden if term in serialized) + if hits: + raise ValueError(f"{label}: forbidden display terms present: {hits}") + + +def _is_redacted_sha256(value: Any) -> bool: + if not isinstance(value, str) or not value.startswith("sha256:"): + return False + digest = value.removeprefix("sha256:") + return len(digest) == 64 and all(char in "0123456789abcdef" for char in digest) + + +def _mismatches(payload: dict[str, Any], expected: dict[str, Any]) -> dict[str, dict[str, Any]]: + return { + key: {"expected": value, "actual": payload.get(key)} + for key, value in expected.items() + if payload.get(key) != value + } diff --git a/apps/api/tests/test_ai_agent_result_capture_owner_approved_preflight_release_package.py b/apps/api/tests/test_ai_agent_result_capture_owner_approved_preflight_release_package.py new file mode 100644 index 000000000..f4ef36d84 --- /dev/null +++ b/apps/api/tests/test_ai_agent_result_capture_owner_approved_preflight_release_package.py @@ -0,0 +1,107 @@ +from __future__ import annotations + +import json +from pathlib import Path + +import pytest + +from src.services.ai_agent_result_capture_owner_approved_preflight_release_package import ( + load_latest_ai_agent_result_capture_owner_approved_preflight_release_package, +) + +REPO_ROOT = Path(__file__).resolve().parents[3] +FIXTURE = REPO_ROOT / "docs/evaluations/ai_agent_result_capture_owner_approved_preflight_release_package_2026-06-14.json" + + +def test_load_latest_ai_agent_result_capture_owner_approved_preflight_release_package_snapshot() -> None: + data = load_latest_ai_agent_result_capture_owner_approved_preflight_release_package() + + assert data["schema_version"] == "ai_agent_result_capture_owner_approved_preflight_release_package_v1" + assert data["program_status"]["current_task_id"] == "P2-129" + assert data["program_status"]["next_task_id"] == "P2-130" + assert data["program_status"]["runtime_authority"] == "result_capture_owner_approved_preflight_release_package_only_no_live_write" + + rollups = data["rollups"] + assert rollups["owner_approved_release_package_count"] == 5 + assert rollups["release_preflight_check_count"] == 5 + assert rollups["live_apply_release_gate_count"] == 5 + assert rollups["rollback_release_check_count"] == 5 + assert rollups["blocked_release_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["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_approved_release_packages"]} == {False} + assert {item["release_preflight_passed"] for item in data["release_preflight_checks"]} == {False} + assert {item["live_apply_release_enabled"] for item in data["live_apply_release_gates"]} == {False} + assert {item["rollback_release_passed"] for item in data["rollback_release_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_approved_preflight_release_package_2026-06-14.json" + target.write_text(json.dumps(source, ensure_ascii=False), encoding="utf-8") + return source + + +def test_result_capture_owner_approved_preflight_release_package_rejects_owner_release_approved(tmp_path: Path) -> None: + source = _copy_fixture(tmp_path) + source["owner_approved_release_packages"][0]["owner_release_approved"] = True + target = tmp_path / "ai_agent_result_capture_owner_approved_preflight_release_package_2026-06-14.json" + target.write_text(json.dumps(source, ensure_ascii=False), encoding="utf-8") + + with pytest.raises(ValueError, match="must not mark owner release approved"): + load_latest_ai_agent_result_capture_owner_approved_preflight_release_package(tmp_path) + + +def test_result_capture_owner_approved_preflight_release_package_rejects_release_preflight_passed(tmp_path: Path) -> None: + source = _copy_fixture(tmp_path) + source["release_preflight_checks"][0]["release_preflight_passed"] = True + target = tmp_path / "ai_agent_result_capture_owner_approved_preflight_release_package_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 unpassed"): + load_latest_ai_agent_result_capture_owner_approved_preflight_release_package(tmp_path) + + +def test_result_capture_owner_approved_preflight_release_package_rejects_live_apply_release_enabled(tmp_path: Path) -> None: + source = _copy_fixture(tmp_path) + source["live_apply_release_gates"][0]["live_apply_release_enabled"] = True + target = tmp_path / "ai_agent_result_capture_owner_approved_preflight_release_package_2026-06-14.json" + target.write_text(json.dumps(source, ensure_ascii=False), encoding="utf-8") + + with pytest.raises(ValueError, match="must not enable live apply release"): + load_latest_ai_agent_result_capture_owner_approved_preflight_release_package(tmp_path) + + +def test_result_capture_owner_approved_preflight_release_package_rejects_rollup_drift(tmp_path: Path) -> None: + source = _copy_fixture(tmp_path) + source["rollups"]["owner_approved_release_package_count"] = 4 + target = tmp_path / "ai_agent_result_capture_owner_approved_preflight_release_package_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_approved_preflight_release_package(tmp_path) + + +def test_result_capture_owner_approved_preflight_release_package_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_approved_preflight_release_package_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_approved_preflight_release_package(tmp_path) diff --git a/apps/api/tests/test_ai_agent_result_capture_owner_approved_preflight_release_package_api.py b/apps/api/tests/test_ai_agent_result_capture_owner_approved_preflight_release_package_api.py new file mode 100644 index 000000000..0eb2e3c8e --- /dev/null +++ b/apps/api/tests/test_ai_agent_result_capture_owner_approved_preflight_release_package_api.py @@ -0,0 +1,45 @@ +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_approved_preflight_release_package_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-approved-preflight-release-package") + + assert response.status_code == 200 + data = response.json() + assert data["schema_version"] == "ai_agent_result_capture_owner_approved_preflight_release_package_v1" + assert data["program_status"]["current_task_id"] == "P2-129" + assert data["program_status"]["next_task_id"] == "P2-130" + + rollups = data["rollups"] + assert rollups["owner_approved_release_package_count"] == 5 + assert rollups["release_preflight_check_count"] == 5 + assert rollups["live_apply_release_gate_count"] == 5 + assert rollups["rollback_release_check_count"] == 5 + assert rollups["blocked_release_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["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_approved_release_packages"]} == {False} + assert {item["release_preflight_passed"] for item in data["release_preflight_checks"]} == {False} + assert {item["live_apply_release_enabled"] for item in data["live_apply_release_gates"]} == {False} diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 38bf7ab0e..0b80e618d 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -5911,6 +5911,39 @@ "rollbackConfirmed": "rollback 已確認={value}" } }, + "resultCaptureOwnerApprovedPreflightReleasePackage": { + "title": "P2-129 owner-approved preflight release package", + "source": "產生 {generated};目前 {current};下一步 {next}", + "priorTitle": "前一關 preflight hold", + "truthTitle": "release package 真相", + "metrics": { + "overall": "完成度", + "packages": "Release packages", + "releasePreflights": "Release preflights", + "releaseGates": "Live-apply release gates", + "rollbackChecks": "Rollback release checks", + "blockers": "已阻擋 release", + "actions": "操作選項", + "approvalRequired": "需批准", + "blocked": "阻擋", + "liveWrites": "正式寫入 / 發送" + }, + "flags": { + "p2Loaded": "已載入 P2-128={value}", + "ownerReleaseReviewRequired": "owner release review required={value}", + "liveApplyReleaseHoldActive": "live apply release hold active={value}" + }, + "labels": { + "ownerReleaseApproved": "owner release approved={value}", + "maintenanceApproved": "maintenance approved={value}", + "gatewayWrites": "Gateway 寫入={value}", + "releaseApproved": "release approved={value}", + "releasePreflightPassed": "release preflight passed={value}", + "liveApplyReleaseEnabled": "live apply release enabled={value}", + "rollbackRequired": "需要 rollback owner={value}", + "rollbackPassed": "rollback release passed={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 38bf7ab0e..0b80e618d 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -5911,6 +5911,39 @@ "rollbackConfirmed": "rollback 已確認={value}" } }, + "resultCaptureOwnerApprovedPreflightReleasePackage": { + "title": "P2-129 owner-approved preflight release package", + "source": "產生 {generated};目前 {current};下一步 {next}", + "priorTitle": "前一關 preflight hold", + "truthTitle": "release package 真相", + "metrics": { + "overall": "完成度", + "packages": "Release packages", + "releasePreflights": "Release preflights", + "releaseGates": "Live-apply release gates", + "rollbackChecks": "Rollback release checks", + "blockers": "已阻擋 release", + "actions": "操作選項", + "approvalRequired": "需批准", + "blocked": "阻擋", + "liveWrites": "正式寫入 / 發送" + }, + "flags": { + "p2Loaded": "已載入 P2-128={value}", + "ownerReleaseReviewRequired": "owner release review required={value}", + "liveApplyReleaseHoldActive": "live apply release hold active={value}" + }, + "labels": { + "ownerReleaseApproved": "owner release approved={value}", + "maintenanceApproved": "maintenance approved={value}", + "gatewayWrites": "Gateway 寫入={value}", + "releaseApproved": "release approved={value}", + "releasePreflightPassed": "release preflight passed={value}", + "liveApplyReleaseEnabled": "live apply release enabled={value}", + "rollbackRequired": "需要 rollback owner={value}", + "rollbackPassed": "rollback release passed={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 559708f70..f71e97182 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 @@ -76,6 +76,7 @@ import { type AiAgentResultCaptureOwnerApprovedExecutionRehearsalSnapshot, type AiAgentResultCaptureOwnerAcceptanceMaintenanceGateSnapshot, type AiAgentResultCaptureOwnerAcceptanceReadbackPreflightHoldSnapshot, + type AiAgentResultCaptureOwnerApprovedPreflightReleasePackageSnapshot, type AiAgentResultCaptureWriterImplementationReviewSnapshot, type AiAgentOwnerApprovedFixturePromotionGateSnapshot, type AiAgentRuntimeWorkerShadowGateSnapshot, @@ -475,6 +476,7 @@ export function AutomationInventoryTab() { const [resultCaptureOwnerApprovedExecutionRehearsal, setResultCaptureOwnerApprovedExecutionRehearsal] = useState(null) const [resultCaptureOwnerAcceptanceMaintenanceGate, setResultCaptureOwnerAcceptanceMaintenanceGate] = useState(null) const [resultCaptureOwnerAcceptanceReadbackPreflightHold, setResultCaptureOwnerAcceptanceReadbackPreflightHold] = useState(null) + const [resultCaptureOwnerApprovedPreflightReleasePackage, setResultCaptureOwnerApprovedPreflightReleasePackage] = useState(null) const [reportTruthActionabilityReview, setReportTruthActionabilityReview] = useState(null) const [ownerDryRunPackage, setOwnerDryRunPackage] = useState(null) const [hostStatefulInventory, setHostStatefulInventory] = useState(null) @@ -540,6 +542,7 @@ export function AutomationInventoryTab() { apiClient.getAiAgentResultCaptureOwnerApprovedExecutionRehearsal(), apiClient.getAiAgentResultCaptureOwnerAcceptanceMaintenanceGate(), apiClient.getAiAgentResultCaptureOwnerAcceptanceReadbackPreflightHold(), + apiClient.getAiAgentResultCaptureOwnerApprovedPreflightReleasePackage(), apiClient.getAiAgentReportTruthActionabilityReview(), apiClient.getAiAgentOwnerApprovedFixtureDryRun(), apiClient.getAiAgentHostStatefulVersionInventory(), @@ -604,6 +607,7 @@ export function AutomationInventoryTab() { resultCaptureOwnerApprovedExecutionRehearsalResult, resultCaptureOwnerAcceptanceMaintenanceGateResult, resultCaptureOwnerAcceptanceReadbackPreflightHoldResult, + resultCaptureOwnerApprovedPreflightReleasePackageResult, reportTruthActionabilityReviewResult, ownerDryRunPackageResult, hostStatefulInventoryResult, @@ -665,6 +669,7 @@ export function AutomationInventoryTab() { setResultCaptureOwnerApprovedExecutionRehearsal(resultCaptureOwnerApprovedExecutionRehearsalResult.status === 'fulfilled' ? resultCaptureOwnerApprovedExecutionRehearsalResult.value : null) setResultCaptureOwnerAcceptanceMaintenanceGate(resultCaptureOwnerAcceptanceMaintenanceGateResult.status === 'fulfilled' ? resultCaptureOwnerAcceptanceMaintenanceGateResult.value : null) setResultCaptureOwnerAcceptanceReadbackPreflightHold(resultCaptureOwnerAcceptanceReadbackPreflightHoldResult.status === 'fulfilled' ? resultCaptureOwnerAcceptanceReadbackPreflightHoldResult.value : null) + setResultCaptureOwnerApprovedPreflightReleasePackage(resultCaptureOwnerApprovedPreflightReleasePackageResult.status === 'fulfilled' ? resultCaptureOwnerApprovedPreflightReleasePackageResult.value : null) setReportTruthActionabilityReview(reportTruthActionabilityReviewResult.status === 'fulfilled' ? reportTruthActionabilityReviewResult.value : null) setOwnerDryRunPackage(ownerDryRunPackageResult.status === 'fulfilled' ? ownerDryRunPackageResult.value : null) setHostStatefulInventory(hostStatefulInventoryResult.status === 'fulfilled' ? hostStatefulInventoryResult.value : null) @@ -724,6 +729,7 @@ export function AutomationInventoryTab() { resultCaptureOwnerApprovedExecutionRehearsalResult, resultCaptureOwnerAcceptanceMaintenanceGateResult, resultCaptureOwnerAcceptanceReadbackPreflightHoldResult, + resultCaptureOwnerApprovedPreflightReleasePackageResult, reportTruthActionabilityReviewResult, ownerDryRunPackageResult, hostStatefulInventoryResult, @@ -1966,7 +1972,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 || !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 || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) { return (
@@ -2942,6 +2948,40 @@ export function AutomationInventoryTab() { + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.playbook_trust_write_count + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.production_write_count ) + const resultCapturePreflightReleaseOverall = resultCaptureOwnerApprovedPreflightReleasePackage.program_status.overall_completion_percent + const resultCapturePreflightReleasePackages = resultCaptureOwnerApprovedPreflightReleasePackage.rollups.owner_approved_release_package_count + const resultCapturePreflightReleaseChecks = resultCaptureOwnerApprovedPreflightReleasePackage.rollups.release_preflight_check_count + const resultCapturePreflightReleaseGates = resultCaptureOwnerApprovedPreflightReleasePackage.rollups.live_apply_release_gate_count + const resultCapturePreflightReleaseRollbacks = resultCaptureOwnerApprovedPreflightReleasePackage.rollups.rollback_release_check_count + const resultCapturePreflightReleaseBlockedTransitions = resultCaptureOwnerApprovedPreflightReleasePackage.rollups.blocked_release_transition_count + const resultCapturePreflightReleaseActions = resultCaptureOwnerApprovedPreflightReleasePackage.rollups.operator_action_count + const resultCapturePreflightReleaseApprovalRequired = ( + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.approval_required_package_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.approval_required_preflight_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.approval_required_release_gate_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.approval_required_rollback_count + ) + const resultCapturePreflightReleaseBlocked = ( + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.blocked_package_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.blocked_preflight_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.blocked_release_gate_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.blocked_rollback_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.critical_blocker_count + ) + const resultCapturePreflightReleaseLiveWrites = ( + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.writer_apply_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.execution_apply_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.receipt_write_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.reviewer_queue_write_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.gateway_queue_write_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.telegram_send_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.bot_api_call_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.report_receipt_write_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.result_capture_write_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.learning_write_count + + resultCaptureOwnerApprovedPreflightReleasePackage.rollups.playbook_trust_write_count + + resultCaptureOwnerApprovedPreflightReleasePackage.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 @@ -7491,6 +7531,147 @@ export function AutomationInventoryTab() {
+
+
+
+ + + {t('resultCaptureOwnerApprovedPreflightReleasePackage.title')} + +
+ +
+ +
+ } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> +
+ +
+
+ {t('resultCaptureOwnerApprovedPreflightReleasePackage.priorTitle')} + + {resultCaptureOwnerApprovedPreflightReleasePackage.prior_owner_acceptance_readback_preflight_hold.readiness_note} + +
+ + + +
+
+ +
+ {t('resultCaptureOwnerApprovedPreflightReleasePackage.truthTitle')} + + {resultCaptureOwnerApprovedPreflightReleasePackage.release_truth.truth_note} + +
+ + + + + + +
+
+
+ +
+ {resultCaptureOwnerApprovedPreflightReleasePackage.owner_approved_release_packages.slice(0, 5).map(pkg => ( +
+
+ + {pkg.display_name} + + +
+ + {pkg.source_readback} → {pkg.release_summary} + +
+ + + +
+
+ ))} +
+ +
+ {resultCaptureOwnerApprovedPreflightReleasePackage.release_preflight_checks.slice(0, 5).map(preflight => ( +
+
+ + {preflight.display_name} + + +
+ + {preflight.required_before_live_apply} + +
+ + + +
+
+ ))} +
+ +
+ {resultCaptureOwnerApprovedPreflightReleasePackage.live_apply_release_gates.slice(0, 5).map(gate => ( +
+
+ + {gate.display_name} + + +
+ + {gate.release_reason} {gate.release_condition} + + +
+ ))} +
+ +
+ {resultCaptureOwnerApprovedPreflightReleasePackage.rollback_release_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 8380ee02f..20e93c3f0 100644 --- a/apps/web/src/lib/api-client.ts +++ b/apps/web/src/lib/api-client.ts @@ -540,6 +540,11 @@ export const apiClient = { return handleResponse(res) }, + async getAiAgentResultCaptureOwnerApprovedPreflightReleasePackage() { + const res = await fetch(`${API_BASE_URL}/agents/agent-result-capture-owner-approved-preflight-release-package`) + return handleResponse(res) + }, + async getAiAgentOwnerApprovedFixtureDryRun() { const res = await fetch(`${API_BASE_URL}/agents/agent-owner-approved-fixture-dry-run`) return handleResponse(res) @@ -7136,6 +7141,200 @@ export interface AiAgentResultCaptureOwnerAcceptanceReadbackPreflightHoldSnapsho } } +export interface AiAgentResultCaptureOwnerApprovedPreflightReleasePackageSnapshot { + schema_version: 'ai_agent_result_capture_owner_approved_preflight_release_package_v1' + generated_at: string + program_status: { + overall_completion_percent: number + current_priority: 'P0' | 'P1' | 'P2' | 'P3' + current_task_id: 'P2-129' + next_task_id: 'P2-130' + read_only_mode: true + runtime_authority: 'result_capture_owner_approved_preflight_release_package_only_no_live_write' + status_note: string + } + source_refs: string[] + prior_owner_acceptance_readback_preflight_hold: { + schema_version: string + owner_acceptance_readback_count: number + preflight_hold_check_count: number + live_apply_hold_gate_count: number + rollback_preflight_check_count: number + blocked_apply_transition_count: number + operator_action_count: number + approval_required_total: number + blocked_total: number + owner_acceptance_received_count: number + maintenance_window_approved_count: number + rollback_owner_confirmed_count: number + post_apply_verifier_ready_count: number + live_apply_preflight_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 + } + release_truth: { + p2_128_preflight_hold_loaded: boolean + owner_approved_release_package_ready: boolean + owner_release_review_required: boolean + live_apply_release_hold_active: boolean + rollback_release_required: boolean + post_release_verifier_required: boolean + redaction_review_required: boolean + release_package_only: boolean + owner_release_approved: boolean + maintenance_window_approved: boolean + rollback_owner_confirmed: boolean + post_release_verifier_ready: 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 + 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_approved_release_packages: Array<{ + package_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + source_readback: string + status: 'ready_for_release_review' | 'approval_required' | 'blocked_by_policy' + package_mode: 'owner_approved_preflight_release_package' + owner_release_approved: false + release_summary: string + evidence_hash: string + }> + release_preflight_checks: Array<{ + check_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + status: 'ready_for_release_review' | 'approval_required' | 'blocked_by_policy' + preflight_mode: 'release_preflight_check' + release_hold_required: true + release_preflight_passed: false + required_before_live_apply: string + }> + live_apply_release_gates: Array<{ + gate_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + status: 'ready_for_release_review' | 'approval_required' | 'blocked_by_policy' + gate_mode: 'live_apply_release_gate' + live_apply_release_enabled: false + release_reason: string + release_condition: string + }> + rollback_release_checks: Array<{ + check_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + status: 'ready_for_release_review' | 'approval_required' | 'blocked_by_policy' + rollback_owner_required: true + rollback_release_passed: false + rollback_scope: string + hold_reason: string + }> + blocked_release_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_approved_release_package_count: number + release_preflight_check_count: number + live_apply_release_gate_count: number + rollback_release_check_count: number + blocked_release_transition_count: number + operator_action_count: number + approval_required_package_count: number + blocked_package_count: number + approval_required_preflight_count: number + blocked_preflight_count: number + approval_required_release_gate_count: number + blocked_release_gate_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 + 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 519a16652..b564d7216 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,28 @@ +## 2026-06-14|P2-129 Owner-approved preflight release package 本地完成 + +**背景**:P2-128 已把 owner acceptance readback、preflight hold、live-apply hold gate、rollback preflight 與 blocked apply transition 固定成正式驗證完成的只讀 hold;但真正往 live apply release 前進前,仍需要把這些 hold 整理成 owner-approved preflight release package,讓下一關可以讀回 release readiness,而不是直接放行 writer。P2-129 因此只建立 release package,不接受 owner 口頭批准、不釋放 live apply、不套用 writer、不寫 receipt、不寫 result capture / learning / PlayBook trust / reviewer queue / Gateway queue,也不送 Telegram 或呼叫 Bot API。 + +**完成內容**: +- 新增 `ai_agent_result_capture_owner_approved_preflight_release_package_v1` schema、committed snapshot、loader 與 API endpoint `GET /api/v1/agents/agent-result-capture-owner-approved-preflight-release-package`。 +- P2-129 snapshot 固定 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。 +- Governance automation inventory 頁新增 P2-129 區塊,顯示 P2-129 進度 `100%`、release package `5`、release preflight `5`、live-apply release gate `5`、rollback release check `5`、blocked release `6`、operator action `5`、需批准 `8`、阻擋 `9`、正式寫入 / 發送 `0`。 +- Release truth 固定為 `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、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-129 schema / snapshot、`zh-TW.json`、`en.json` 通過。 +- Python 編譯:P2-129 loader 與 `agents.py` 通過。 +- API/service pytest:P2-129 + P2-128 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 / webpack cache warning,governance First Load JS `432 kB`。 +- `git diff --check`、`doc-secrets-sanity-check.py docs .gitea`、`source-control-owner-response-guard.py --root .`、`security-mirror-progress-guard.py --root .` 通過。 +- 本段仍是本地完成;正式 API readback、正式站 desktop / mobile Browser smoke 與 deploy marker 需在推送 Gitea main 並完成 CD 後補齊。 + +**安全邊界**: +- P2-129 仍是 owner-approved preflight release package;不接受口頭批准、不把 release package 解讀成 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-130`:owner-approved release readiness readback;只有 P2-129 正式驗證後才可把 release package、release preflight check、live-apply release gate、rollback release check 與 blocked release transition 轉成 release readiness readback,仍不得直接開啟 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-128 Owner acceptance readback / live-apply preflight hold 完成與正式驗證 **背景**:P2-127 已把 owner acceptance、maintenance window、rollback owner 與 post-apply verifier gate 固定成可審核封包;但正式 live apply release 前,仍需要把這些封包讀回成 preflight hold、live-apply hold gate、rollback preflight 與 blocked apply transition。P2-128 因此只建立 acceptance readback / preflight hold,不接受 owner 口頭批准、不釋放 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 cedfd922f..10c9c9edd 100644 --- a/docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md +++ b/docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md @@ -12,17 +12,17 @@ | 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-128 已完成只讀證據面、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;P2-128 已由 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 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_acceptance_readback_preflight_hold_v1`、`GET /api/v1/agents/agent-result-capture-owner-acceptance-readback-preflight-hold`、正式站 `/zh-TW/governance?tab=automation-inventory` desktop / mobile smoke、`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-129 已完成只讀證據面、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;P2-129 本地完成,固定 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 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_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`、正式站 `/zh-TW/governance?tab=automation-inventory` desktop / mobile smoke、`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 文件 | -AI Agent 自動化工作包目前完成度:**99.2%**。本工作清單文件本身完成度:**100%**。 +AI Agent 自動化工作包目前完成度:**99.3%**。本工作清單文件本身完成度:**100%**。 三 Agent 佈建布局目前完成度:**45%**。第一波已完成只讀 schema / snapshot / API / 測試 / 報告,第二波已接入治理頁自動化盤點 UI;正式 runtime 佈署、Telegram E2E 發送與 AgentSession 工作流仍需逐項 gate。 -三 Agent 主動溝通、學習與成長證據目前完成度:**100%**。P2-403A 到 P2-128 已把互動證據、報表治理、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 全部固定成可驗證證據。P2-128 已本地與正式站驗證,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;正式站 desktop / mobile smoke 皆為禁用內部協作片語 `0`、水平溢位 `0`、P2-128 區塊危險入口 `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-129`。 +三 Agent 主動溝通、學習與成長證據目前完成度:**100%**。P2-403A 到 P2-129 已把互動證據、報表治理、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 全部固定成可驗證證據。P2-129 已本地驗證,固定 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;正式站待驗證。目前 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-130`。 -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-128` 已補互動、學習證據面、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。下一步是 `P2-129`;外部 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-129` 已補互動、學習證據面、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。下一步是 `P2-130`;外部 registry / package source / host probe / SSH / kubectl / 工具安裝 / CI 變更 / 實際 PR creation / Telegram 實發與 learning write 仍需 gate。 完成度計算模型: @@ -1000,7 +1000,8 @@ UI: | P2-125 | 完成 | 100 | OpenClaw + Hermes + NemoTron | result capture owner promotion review / execution gate | `ai_agent_result_capture_owner_promotion_review_v1` / schema / snapshot / 只讀 API / governance UI;正式站 deploy marker `a86f9cef` 已驗證;5 個 owner promotion packet、5 個 execution gate check、5 個 rollback owner review、6 個 blocked execution write、5 個 operator action;execution truth 固定 `result_capture_owner_promotion_review_only_no_live_write`;owner promotion approved / execution gate pass / rollback confirmed / writer apply / execution apply / receipt write / result capture / learning / PlayBook trust / reviewer queue / Gateway / Telegram / Bot API / report receipt / production write 全為 `0` | 已由 P2-126 承接;不套用 writer、不執行正式寫入、不寫 receipt、不寫 result capture、不寫 learning、不更新 PlayBook trust、不送 Telegram、不寫 production | | P2-126 | 完成 | 100 | OpenClaw + Hermes + NemoTron | owner-approved execution rehearsal / no-write apply gate | `ai_agent_result_capture_owner_approved_execution_rehearsal_v1` / schema / snapshot / 只讀 API / governance UI;正式站 deploy marker `02ff5763` 已驗證;5 個 execution rehearsal、5 個 no-write apply check、5 個 post-write verifier rehearsal、5 個 rollback drill、6 個 blocked live apply、5 個 operator action;execution rehearsal truth 固定 `result_capture_owner_approved_execution_rehearsal_only_no_live_write`;owner approval record received / no-write apply executed / post-write verifier passed / rollback confirmed / writer apply / execution apply / receipt write / result capture / learning / PlayBook trust / reviewer queue / Gateway / Telegram / Bot API / report receipt / production write 全為 `0` | 已由 P2-127 承接;不套用 writer、不執行 no-write apply、不寫 receipt、不寫 result capture、不寫 learning、不更新 PlayBook trust、不送 Telegram、不寫 production | | 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-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;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` | 下一步 P2-130;不把 release package 視為正式批准、不釋放 live apply、不套用 writer、不寫 receipt、不寫 result capture、不寫 learning、不更新 PlayBook trust、不送 Telegram、不寫 production | ### P3 - 候選 Agent 擴展 diff --git a/docs/evaluations/ai_agent_result_capture_owner_approved_preflight_release_package_2026-06-14.json b/docs/evaluations/ai_agent_result_capture_owner_approved_preflight_release_package_2026-06-14.json new file mode 100644 index 000000000..ba9527aa4 --- /dev/null +++ b/docs/evaluations/ai_agent_result_capture_owner_approved_preflight_release_package_2026-06-14.json @@ -0,0 +1,446 @@ +{ + "schema_version": "ai_agent_result_capture_owner_approved_preflight_release_package_v1", + "generated_at": "2026-06-14T05:12:00+08:00", + "program_status": { + "overall_completion_percent": 100, + "current_priority": "P2", + "current_task_id": "P2-129", + "next_task_id": "P2-130", + "read_only_mode": true, + "runtime_authority": "result_capture_owner_approved_preflight_release_package_only_no_live_write", + "status_note": "P2-129 只把 P2-128 acceptance readback / preflight hold 轉成 owner-approved preflight release package;不得釋放 live apply、套用 writer、寫 receipt、寫 result capture、寫 learning、寫 queue、送 Telegram 或寫入 production。" + }, + "source_refs": [ + "docs/evaluations/ai_agent_result_capture_owner_acceptance_readback_preflight_hold_2026-06-14.json", + "docs/evaluations/ai_agent_result_capture_owner_acceptance_maintenance_gate_2026-06-14.json", + "docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md#49-建立-owner-acceptance-readback--live-apply-preflight-hold" + ], + "prior_owner_acceptance_readback_preflight_hold": { + "schema_version": "ai_agent_result_capture_owner_acceptance_readback_preflight_hold_v1", + "owner_acceptance_readback_count": 5, + "preflight_hold_check_count": 5, + "live_apply_hold_gate_count": 5, + "rollback_preflight_check_count": 5, + "blocked_apply_transition_count": 6, + "operator_action_count": 5, + "approval_required_total": 8, + "blocked_total": 9, + "owner_acceptance_received_count": 0, + "maintenance_window_approved_count": 0, + "rollback_owner_confirmed_count": 0, + "post_apply_verifier_ready_count": 0, + "live_apply_preflight_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-128 已把 owner acceptance readback、preflight hold、live-apply hold gate、rollback preflight 與 blocked apply transition 固定為只讀 hold;P2-129 只建立 release package,不放行 live apply。" + }, + "release_truth": { + "p2_128_preflight_hold_loaded": true, + "owner_approved_release_package_ready": true, + "owner_release_review_required": true, + "live_apply_release_hold_active": true, + "rollback_release_required": true, + "post_release_verifier_required": true, + "redaction_review_required": true, + "release_package_only": true, + "owner_release_approved": false, + "maintenance_window_approved": false, + "rollback_owner_confirmed": false, + "post_release_verifier_ready": 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, + "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-129 只建立 owner-approved preflight release package;package 可見不代表 owner release approved、maintenance window approved 或 live apply 可執行。" + }, + "owner_approved_release_packages": [ + { + "package_id": "release_package_result_capture_writer", + "display_name": "Result capture owner-approved preflight release package", + "owner_agent": "openclaw", + "source_readback": "readback_result_capture_writer", + "status": "ready_for_release_review", + "package_mode": "owner_approved_preflight_release_package", + "owner_release_approved": false, + "release_summary": "整理 result capture writer 的 owner role、rollback owner、post-release verifier 與 no-write receipt evidence;不產生 live release record。", + "evidence_hash": "sha256:e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1" + }, + { + "package_id": "release_package_learning_writer", + "display_name": "Learning owner-approved preflight release package", + "owner_agent": "hermes", + "source_readback": "readback_learning_writer", + "status": "approval_required", + "package_mode": "owner_approved_preflight_release_package", + "owner_release_approved": false, + "release_summary": "整理 KM owner、learning write scope、stale guard 與 rollback owner;不寫 KM 或 learning metadata。", + "evidence_hash": "sha256:e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2" + }, + { + "package_id": "release_package_playbook_trust_writer", + "display_name": "PlayBook trust owner-approved preflight release package", + "owner_agent": "nemotron", + "source_readback": "readback_playbook_trust_writer", + "status": "blocked_by_policy", + "package_mode": "owner_approved_preflight_release_package", + "owner_release_approved": false, + "release_summary": "整理 trust delta、負向強化 reviewer 與 rollback owner;未完成 OpenClaw 仲裁前不得 release。", + "evidence_hash": "sha256:e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3" + }, + { + "package_id": "release_package_reviewer_queue_writer", + "display_name": "Reviewer queue owner-approved preflight release package", + "owner_agent": "openclaw", + "source_readback": "readback_reviewer_queue_writer", + "status": "approval_required", + "package_mode": "owner_approved_preflight_release_package", + "owner_release_approved": false, + "release_summary": "整理 reviewer queue owner、SLA owner、dedupe key owner 與 rollback owner;不寫 reviewer queue。", + "evidence_hash": "sha256:e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e4" + }, + { + "package_id": "release_package_gateway_queue_writer", + "display_name": "Gateway queue owner-approved preflight release package", + "owner_agent": "nemotron", + "source_readback": "readback_gateway_queue_writer", + "status": "ready_for_release_review", + "package_mode": "owner_approved_preflight_release_package", + "owner_release_approved": false, + "release_summary": "整理 SRE route lock、Telegram receipt owner、redaction owner 與 Gateway rollback owner;不寫 Gateway queue、不送 Telegram。", + "evidence_hash": "sha256:e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5" + } + ], + "release_preflight_checks": [ + { + "check_id": "release_preflight_result_capture_writer", + "display_name": "Result capture release preflight check", + "owner_agent": "openclaw", + "status": "ready_for_release_review", + "preflight_mode": "release_preflight_check", + "release_hold_required": true, + "release_preflight_passed": false, + "required_before_live_apply": "owner release approval、maintenance window、rollback owner、post-release verifier readiness。" + }, + { + "check_id": "release_preflight_learning_writer", + "display_name": "Learning release preflight check", + "owner_agent": "hermes", + "status": "approval_required", + "preflight_mode": "release_preflight_check", + "release_hold_required": true, + "release_preflight_passed": false, + "required_before_live_apply": "KM owner release approval、stale guard pass、rollback owner、post-release verifier readiness。" + }, + { + "check_id": "release_preflight_playbook_trust_writer", + "display_name": "PlayBook trust release preflight check", + "owner_agent": "nemotron", + "status": "blocked_by_policy", + "preflight_mode": "release_preflight_check", + "release_hold_required": true, + "release_preflight_passed": false, + "required_before_live_apply": "OpenClaw 仲裁、負向強化審查、trust delta reviewer 與 owner release approval。" + }, + { + "check_id": "release_preflight_reviewer_queue_writer", + "display_name": "Reviewer queue release preflight check", + "owner_agent": "openclaw", + "status": "approval_required", + "preflight_mode": "release_preflight_check", + "release_hold_required": true, + "release_preflight_passed": false, + "required_before_live_apply": "reviewer SLA owner、dedupe key owner、queue rollback owner 與 post-release verifier readiness。" + }, + { + "check_id": "release_preflight_gateway_queue_writer", + "display_name": "Gateway queue release preflight check", + "owner_agent": "nemotron", + "status": "ready_for_release_review", + "preflight_mode": "release_preflight_check", + "release_hold_required": true, + "release_preflight_passed": false, + "required_before_live_apply": "SRE route lock、Telegram receipt owner、redaction owner 與 Gateway rollback owner。" + } + ], + "live_apply_release_gates": [ + { + "gate_id": "release_gate_result_capture", + "display_name": "Result capture live apply release gate", + "owner_agent": "openclaw", + "status": "ready_for_release_review", + "gate_mode": "live_apply_release_gate", + "live_apply_release_enabled": false, + "release_reason": "release package 已整理,但 owner release approval 與 post-release verifier 仍未 ready。", + "release_condition": "P2-130 之後另行建立 release readiness readback。" + }, + { + "gate_id": "release_gate_learning", + "display_name": "Learning live apply release gate", + "owner_agent": "hermes", + "status": "approval_required", + "gate_mode": "live_apply_release_gate", + "live_apply_release_enabled": false, + "release_reason": "learning write 仍缺 KM owner release approval 與 stale guard rollback。", + "release_condition": "需 owner-approved learning release readiness readback。" + }, + { + "gate_id": "release_gate_playbook_trust", + "display_name": "PlayBook trust live apply release gate", + "owner_agent": "nemotron", + "status": "blocked_by_policy", + "gate_mode": "live_apply_release_gate", + "live_apply_release_enabled": false, + "release_reason": "trust delta 與負向強化審查仍未完成。", + "release_condition": "需 OpenClaw 仲裁與 owner-approved trust release readiness readback。" + }, + { + "gate_id": "release_gate_reviewer_queue", + "display_name": "Reviewer queue live apply release gate", + "owner_agent": "openclaw", + "status": "approval_required", + "gate_mode": "live_apply_release_gate", + "live_apply_release_enabled": false, + "release_reason": "reviewer queue 寫入仍缺 SLA owner 與 rollback owner release approval。", + "release_condition": "需 reviewer queue owner-approved release readiness readback。" + }, + { + "gate_id": "release_gate_gateway_queue", + "display_name": "Gateway queue live apply release gate", + "owner_agent": "nemotron", + "status": "ready_for_release_review", + "gate_mode": "live_apply_release_gate", + "live_apply_release_enabled": false, + "release_reason": "Gateway queue 與 Telegram send 仍缺 SRE route lock 與 receipt owner release approval。", + "release_condition": "需 Gateway queue / Telegram receipt release readiness readback。" + } + ], + "rollback_release_checks": [ + { + "check_id": "rollback_release_result_capture", + "display_name": "Result capture rollback release check", + "owner_agent": "openclaw", + "status": "ready_for_release_review", + "rollback_owner_required": true, + "rollback_release_passed": false, + "rollback_scope": "撤回 result capture write release package、receipt hash 與 audit trail append。", + "hold_reason": "rollback owner 尚未 confirmed,不得 release live apply。" + }, + { + "check_id": "rollback_release_learning", + "display_name": "Learning rollback release check", + "owner_agent": "hermes", + "status": "approval_required", + "rollback_owner_required": true, + "rollback_release_passed": false, + "rollback_scope": "撤回 learning release package、KM write preview 與 stale guard marker。", + "hold_reason": "KM rollback owner 尚未 confirmed。" + }, + { + "check_id": "rollback_release_playbook_trust", + "display_name": "PlayBook trust rollback release check", + "owner_agent": "nemotron", + "status": "blocked_by_policy", + "rollback_owner_required": true, + "rollback_release_passed": false, + "rollback_scope": "撤回 trust delta release package 與 negative reinforcement draft。", + "hold_reason": "trust rollback owner 與負向強化 reviewer 尚未 ready。" + }, + { + "check_id": "rollback_release_reviewer_queue", + "display_name": "Reviewer queue rollback release check", + "owner_agent": "openclaw", + "status": "approval_required", + "rollback_owner_required": true, + "rollback_release_passed": false, + "rollback_scope": "撤回 reviewer queue release package、dedupe key 與 SLA route handoff。", + "hold_reason": "reviewer queue rollback owner 尚未 confirmed。" + }, + { + "check_id": "rollback_release_gateway_queue", + "display_name": "Gateway queue rollback release check", + "owner_agent": "nemotron", + "status": "ready_for_release_review", + "rollback_owner_required": true, + "rollback_release_passed": false, + "rollback_scope": "撤回 Gateway queue release package、route lock 與 Telegram receipt draft。", + "hold_reason": "Gateway rollback owner 尚未 confirmed,不得送 Telegram。" + } + ], + "blocked_release_transitions": [ + { + "blocker_id": "blocked_writer_apply_release", + "display_name": "Writer apply release blocked", + "severity": "critical", + "status": "blocked_by_policy", + "blocked_action": "writer_apply_release", + "blocked_until": "owner release approved + release preflight passed", + "evidence_hash": "sha256:f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1" + }, + { + "blocker_id": "blocked_execution_apply_release", + "display_name": "Execution apply release blocked", + "severity": "critical", + "status": "blocked_by_policy", + "blocked_action": "execution_apply_release", + "blocked_until": "maintenance window approved + post-release verifier ready", + "evidence_hash": "sha256:f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2" + }, + { + "blocker_id": "blocked_receipt_write_release", + "display_name": "Receipt write release blocked", + "severity": "critical", + "status": "approval_required", + "blocked_action": "receipt_write_release", + "blocked_until": "post-release verifier ready + rollback owner confirmed", + "evidence_hash": "sha256:f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3" + }, + { + "blocker_id": "blocked_result_capture_write_release", + "display_name": "Result capture write release blocked", + "severity": "critical", + "status": "blocked_by_policy", + "blocked_action": "result_capture_write_release", + "blocked_until": "owner release approved + result capture verifier ready", + "evidence_hash": "sha256:f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4" + }, + { + "blocker_id": "blocked_gateway_queue_write_release", + "display_name": "Gateway queue write release blocked", + "severity": "critical", + "status": "approval_required", + "blocked_action": "gateway_queue_write_release", + "blocked_until": "SRE route lock + Telegram receipt owner approved", + "evidence_hash": "sha256:f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5" + }, + { + "blocker_id": "blocked_telegram_send_release", + "display_name": "Telegram send release blocked", + "severity": "high", + "status": "approval_required", + "blocked_action": "telegram_send_release", + "blocked_until": "Gateway queue release approved + Telegram receipt E2E approved", + "evidence_hash": "sha256:f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6" + } + ], + "operator_actions": [ + { + "action_id": "review_owner_approved_release_packages", + "owner_agent": "openclaw", + "status": "ready_for_operator_review", + "operator_instruction": "審核 5 個 owner-approved release package 是否仍符合 P2-128 hold 邊界;不要把 package 視為正式批准。", + "runtime_write_allowed": false + }, + { + "action_id": "verify_release_preflight_hold", + "owner_agent": "hermes", + "status": "ready_for_operator_review", + "operator_instruction": "確認 release preflight 仍全部未 pass,且所有 live apply release gate 仍為 false。", + "runtime_write_allowed": false + }, + { + "action_id": "verify_rollback_release", + "owner_agent": "nemotron", + "status": "ready_for_operator_review", + "operator_instruction": "確認 rollback release scope、owner 與 hold reason 已整理,但 rollback_release_passed 仍為 false。", + "runtime_write_allowed": false + }, + { + "action_id": "verify_gateway_telegram_release_hold", + "owner_agent": "openclaw", + "status": "approval_required", + "operator_instruction": "確認 Gateway queue 與 Telegram send release 仍被擋住;不呼叫 Gateway、不呼叫 Bot API。", + "runtime_write_allowed": false + }, + { + "action_id": "prepare_p2_130_release_readiness_readback", + "owner_agent": "hermes", + "status": "ready_for_operator_review", + "operator_instruction": "下一關只可建立 P2-130 release readiness readback,不可放行 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": "前端只能顯示 release package 摘要、狀態、數量、紅acted hash 與 0 / false 邊界;不得顯示工作視窗對話、原始提示詞、私有推理、secret、authorization header 或原始 runtime payload。" + }, + "rollups": { + "owner_approved_release_package_count": 5, + "release_preflight_check_count": 5, + "live_apply_release_gate_count": 5, + "rollback_release_check_count": 5, + "blocked_release_transition_count": 6, + "operator_action_count": 5, + "approval_required_package_count": 2, + "blocked_package_count": 1, + "approval_required_preflight_count": 2, + "blocked_preflight_count": 1, + "approval_required_release_gate_count": 2, + "blocked_release_gate_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, + "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_approved_preflight_release_package_v1.schema.json b/docs/schemas/ai_agent_result_capture_owner_approved_preflight_release_package_v1.schema.json new file mode 100644 index 000000000..598ed2f4e --- /dev/null +++ b/docs/schemas/ai_agent_result_capture_owner_approved_preflight_release_package_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_approved_preflight_release_package_v1.schema.json", + "title": "AI Agent result capture owner approved preflight release package v1", + "type": "object", + "required": [ + "schema_version", + "generated_at", + "program_status", + "source_refs", + "prior_owner_acceptance_readback_preflight_hold", + "release_truth", + "owner_approved_release_packages", + "release_preflight_checks", + "live_apply_release_gates", + "rollback_release_checks", + "blocked_release_transitions", + "operator_actions", + "display_redaction_contract", + "rollups" + ], + "properties": { + "schema_version": { + "const": "ai_agent_result_capture_owner_approved_preflight_release_package_v1" + }, + "generated_at": { + "type": "string" + }, + "program_status": { + "type": "object" + }, + "source_refs": { + "type": "array", + "items": { + "type": "string" + } + }, + "prior_owner_acceptance_readback_preflight_hold": { + "type": "object" + }, + "release_truth": { + "type": "object" + }, + "owner_approved_release_packages": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "release_preflight_checks": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "live_apply_release_gates": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "rollback_release_checks": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "blocked_release_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 7ed34948b..b6e43f682 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 @@ -666,6 +666,7 @@ Alert / Sentry / SigNoz / Gitea / Market Watch / Operator | `docs/evaluations/ai_agent_result_capture_owner_approved_execution_rehearsal_2026-06-14.json` + `GET /api/v1/agents/agent-result-capture-owner-approved-execution-rehearsal` | P2-126 owner-approved execution rehearsal / no-write apply gate;承接 P2-125 owner promotion review,建立 5 個 execution rehearsal、5 個 no-write apply check、5 個 post-write verifier rehearsal、5 個 rollback drill、6 個 blocked live apply 與 5 個 operator action;execution rehearsal truth 固定 `result_capture_owner_approved_execution_rehearsal_only_no_live_write`;owner approval record received、no-write apply executed、post-write verifier passed、rollback drill confirmed、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-127 承接 | | `docs/evaluations/ai_agent_result_capture_owner_acceptance_maintenance_gate_2026-06-14.json` + `GET /api/v1/agents/agent-result-capture-owner-acceptance-maintenance-gate` | P2-127 owner acceptance / maintenance window gate;承接 P2-126 owner-approved execution rehearsal,建立 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、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-128 承接 | | `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`,下一步 P2-130 | | `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 主動營運委派與版本生命週期契約 @@ -783,6 +784,7 @@ Repo / registry / release notes / K8s / host / observability / backup evidence 47. 建立 owner-approved execution rehearsal / no-write apply gate。✅ P2-126 已完成並正式驗證;execution rehearsal `5`、no-write apply check `5`、post-write verifier rehearsal `5`、rollback drill `5`、blocked live apply `6`、operator action `5`,approval-required rehearsal / check / verifier / rollback `2 / 2 / 2 / 2`、blocked rehearsal / check / verifier / rollback `1 / 1 / 1 / 1`、critical blocker `5`;owner approval record received、no-write apply executed、post-write verifier passed、rollback drill confirmed、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-127 承接。 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`。下一步 P2-130。 #### 3.2.1d 2026-06-11 Agent 互動、學習與成長證據面 @@ -2103,6 +2105,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 05:12 (台北) — §3.2 / §5 — 本地完成 P2-129 owner-approved preflight release package — 把 preflight hold 整理成 release package + +- 新增 `ai_agent_result_capture_owner_approved_preflight_release_package_v1` schema / committed snapshot / loader / API / 測試,承接 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。 +- Governance automation inventory 新增 P2-129 區塊,將 release package、release preflight、live-apply release gate、rollback release、blocked release transition 與 operator action 全部以只讀方式呈現。 +- 本地 API/service regression:P2-129 + P2-128 `14 passed`;JSON parse、Python 3.11 py_compile、`pnpm --filter @awoooi/web typecheck`、production build、`git diff --check`、`doc-secrets-sanity-check.py docs .gitea`、`source-control-owner-response-guard.py --root .` 與 `security-mirror-progress-guard.py --root .` 通過。 +- 本地 snapshot 固定 `schema_version=ai_agent_result_capture_owner_approved_preflight_release_package_v1`、current `P2-129`、next `P2-130`、completion `100`;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`。 +- 本地 0 / false 邊界: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、secret read 與 destructive operation 均為 `0 / false`。 +- 政策裁決:P2-129 只允許 owner-approved preflight release package 可視化;不得把 package 解讀成 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-130。 + ### 2026-06-14 04:18 (台北) — §3.2 / §5 — 正式驗證 P2-128 owner acceptance readback / live-apply preflight hold — 把 acceptance gate 讀回成 preflight hold - 新增 `ai_agent_result_capture_owner_acceptance_readback_preflight_hold_v1` schema / committed snapshot / loader / API / 測試,承接 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。