diff --git a/apps/api/src/api/v1/agents.py b/apps/api/src/api/v1/agents.py index d49cb4dd3..fd398a9b1 100644 --- a/apps/api/src/api/v1/agents.py +++ b/apps/api/src/api/v1/agents.py @@ -130,6 +130,9 @@ from src.services.ai_agent_result_capture_owner_approved_execution_rehearsal imp from src.services.ai_agent_result_capture_owner_acceptance_maintenance_gate import ( load_latest_ai_agent_result_capture_owner_acceptance_maintenance_gate, ) +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_promotion_approval_gate import ( load_latest_ai_agent_result_capture_promotion_approval_gate, ) @@ -1917,6 +1920,36 @@ async def get_agent_result_capture_owner_acceptance_maintenance_gate() -> dict[s ) from exc +@router.get( + "/agent-result-capture-owner-acceptance-readback-preflight-hold", + response_model=dict[str, Any], + summary="取得 AI Agent result capture owner acceptance readback preflight hold", + description=( + "讀取最新已提交的 P2-128 owner acceptance readback / preflight hold;" + "此端點只回傳 owner acceptance readback、live-apply preflight hold、" + "live apply hold gate、rollback preflight、blocked apply 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_acceptance_readback_preflight_hold() -> dict[str, Any]: + """Return the latest read-only owner acceptance readback / preflight hold package.""" + try: + payload = await asyncio.to_thread(load_latest_ai_agent_result_capture_owner_acceptance_readback_preflight_hold) + 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_acceptance_readback_preflight_hold_invalid", error=str(exc)) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="AI Agent result capture owner acceptance readback preflight hold 無效", + ) 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_acceptance_readback_preflight_hold.py b/apps/api/src/services/ai_agent_result_capture_owner_acceptance_readback_preflight_hold.py new file mode 100644 index 000000000..fa838ba27 --- /dev/null +++ b/apps/api/src/services/ai_agent_result_capture_owner_acceptance_readback_preflight_hold.py @@ -0,0 +1,414 @@ +""" +AI Agent result capture owner acceptance readback preflight hold snapshot. + +Loads the latest committed P2-128 owner acceptance readback / preflight hold +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_acceptance_readback_preflight_hold_*.json" +_SCHEMA_VERSION = "ai_agent_result_capture_owner_acceptance_readback_preflight_hold_v1" +_RUNTIME_AUTHORITY = "result_capture_owner_acceptance_readback_preflight_hold_only_no_live_write" + + +def load_latest_ai_agent_result_capture_owner_acceptance_readback_preflight_hold( + evaluations_dir: Path | None = None, +) -> dict[str, Any]: + """Load the newest committed owner acceptance readback / preflight hold 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 acceptance readback preflight hold 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_acceptance_readbacks(payload, label) + _require_preflight_holds(payload, label) + _require_live_apply_hold_gates(payload, label) + _require_rollback_preflights(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-128", + "next_task_id": "P2-129", + "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_maintenance_gate") or {} + expected = { + "schema_version": "ai_agent_result_capture_owner_acceptance_maintenance_gate_v1", + "owner_acceptance_packet_count": 5, + "maintenance_window_count": 5, + "rollback_owner_check_count": 5, + "post_apply_verifier_gate_count": 5, + "blocked_live_write_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, + "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_maintenance_gate mismatch: {mismatches}") + if not prior.get("readiness_note"): + raise ValueError(f"{label}: prior_owner_acceptance_maintenance_gate.readiness_note is required") + + +def _require_truth(payload: dict[str, Any], label: str) -> None: + truth = payload.get("readback_truth") or {} + required_true = { + "p2_127_owner_acceptance_gate_loaded", + "owner_acceptance_readback_ready", + "preflight_hold_required", + "live_apply_hold_active", + "rollback_preflight_required", + "post_apply_verifier_required", + "redaction_review_required", + "readback_only", + } + missing = sorted(field for field in required_true if truth.get(field) is not True) + if missing: + raise ValueError(f"{label}: readback ready flags must remain true: {missing}") + + required_false = { + "owner_acceptance_received", + "maintenance_window_approved", + "rollback_owner_confirmed", + "post_apply_verifier_ready", + "live_apply_preflight_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_acceptance_received_count", + "maintenance_window_approved_count", + "rollback_owner_confirmed_count", + "post_apply_verifier_ready_count", + "live_apply_preflight_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}: readback live counters must remain zero: {non_zero}") + if not truth.get("truth_note"): + raise ValueError(f"{label}: readback_truth.truth_note is required") + + +def _require_acceptance_readbacks(payload: dict[str, Any], label: str) -> None: + items = payload.get("owner_acceptance_readbacks") or [] + required = { + "readback_result_capture_writer", + "readback_learning_writer", + "readback_playbook_trust_writer", + "readback_reviewer_queue_writer", + "readback_gateway_queue_writer", + } + ids = {item.get("readback_id") for item in items} + if ids != required: + raise ValueError(f"{label}: owner acceptance readbacks must match {sorted(required)}") + for item in items: + item_id = item.get("readback_id") + if item.get("readback_mode") != "owner_acceptance_status_readback": + raise ValueError(f"{label}: readback {item_id} must remain owner acceptance status readback") + if item.get("owner_acceptance_received") is not False: + raise ValueError(f"{label}: readback {item_id} must not mark owner acceptance received") + if item.get("status") not in {"ready_for_preflight_review", "approval_required", "blocked_by_policy"}: + raise ValueError(f"{label}: readback {item_id} status is invalid") + if not item.get("readback_summary") or not _is_redacted_sha256(item.get("source_hash")): + raise ValueError(f"{label}: readback {item_id} must include summary and redacted source_hash") + + +def _require_preflight_holds(payload: dict[str, Any], label: str) -> None: + items = payload.get("preflight_hold_checks") or [] + required = { + "preflight_result_capture_writer", + "preflight_learning_writer", + "preflight_playbook_trust_writer", + "preflight_reviewer_queue_writer", + "preflight_gateway_queue_writer", + } + ids = {item.get("check_id") for item in items} + if ids != required: + raise ValueError(f"{label}: preflight hold checks must match {sorted(required)}") + for item in items: + item_id = item.get("check_id") + if item.get("preflight_mode") != "live_apply_preflight_hold": + raise ValueError(f"{label}: preflight {item_id} must remain live apply preflight hold") + if item.get("hold_required") is not True or item.get("preflight_passed") is not False: + raise ValueError(f"{label}: preflight {item_id} must stay held and unpassed") + if item.get("status") not in {"ready_for_preflight_review", "approval_required", "blocked_by_policy"}: + raise ValueError(f"{label}: preflight {item_id} status is invalid") + if not item.get("required_before_release"): + raise ValueError(f"{label}: preflight {item_id} required_before_release is required") + + +def _require_live_apply_hold_gates(payload: dict[str, Any], label: str) -> None: + items = payload.get("live_apply_hold_gates") or [] + required = { + "hold_gate_result_capture", + "hold_gate_learning", + "hold_gate_playbook_trust", + "hold_gate_reviewer_queue", + "hold_gate_gateway_queue", + } + ids = {item.get("gate_id") for item in items} + if ids != required: + raise ValueError(f"{label}: live apply hold gates must match {sorted(required)}") + for item in items: + item_id = item.get("gate_id") + if item.get("gate_mode") != "live_apply_hold_gate": + raise ValueError(f"{label}: hold gate {item_id} must remain live apply hold gate") + if item.get("live_apply_enabled") is not False: + raise ValueError(f"{label}: hold gate {item_id} must not enable live apply") + if item.get("status") not in {"ready_for_preflight_review", "approval_required", "blocked_by_policy"}: + raise ValueError(f"{label}: hold gate {item_id} status is invalid") + if not item.get("hold_reason") or not item.get("release_condition"): + raise ValueError(f"{label}: hold gate {item_id} hold_reason and release_condition are required") + + +def _require_rollback_preflights(payload: dict[str, Any], label: str) -> None: + items = payload.get("rollback_preflight_checks") or [] + required = { + "rollback_preflight_result_capture", + "rollback_preflight_learning", + "rollback_preflight_playbook_trust", + "rollback_preflight_reviewer_queue", + "rollback_preflight_gateway_queue", + } + ids = {item.get("check_id") for item in items} + if ids != required: + raise ValueError(f"{label}: rollback preflight 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_preflight_passed") is not False: + raise ValueError(f"{label}: rollback preflight {item_id} must stay required and unpassed") + if item.get("status") not in {"ready_for_preflight_review", "approval_required", "blocked_by_policy"}: + raise ValueError(f"{label}: rollback preflight {item_id} status is invalid") + if not item.get("rollback_scope") or not item.get("hold_reason"): + raise ValueError(f"{label}: rollback preflight {item_id} scope and hold_reason are required") + + +def _require_blocked_transitions(payload: dict[str, Any], label: str) -> None: + items = payload.get("blocked_apply_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 apply 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_acceptance_readbacks", + "hold_preflight_release", + "verify_rollback_preflight", + "verify_gateway_telegram_hold", + "prepare_p2_129_release_package", + } + 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 {} + readbacks = payload.get("owner_acceptance_readbacks") or [] + preflights = payload.get("preflight_hold_checks") or [] + hold_gates = payload.get("live_apply_hold_gates") or [] + rollbacks = payload.get("rollback_preflight_checks") or [] + blockers = payload.get("blocked_apply_transitions") or [] + actions = payload.get("operator_actions") or [] + expected = { + "owner_acceptance_readback_count": len(readbacks), + "preflight_hold_check_count": len(preflights), + "live_apply_hold_gate_count": len(hold_gates), + "rollback_preflight_check_count": len(rollbacks), + "blocked_apply_transition_count": len(blockers), + "operator_action_count": len(actions), + "approval_required_readback_count": sum(1 for item in readbacks if item.get("status") == "approval_required"), + "blocked_readback_count": sum(1 for item in readbacks 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_hold_gate_count": sum(1 for item in hold_gates if item.get("status") == "approval_required"), + "blocked_hold_gate_count": sum(1 for item in hold_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_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, + "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_acceptance_readback_preflight_hold.py b/apps/api/tests/test_ai_agent_result_capture_owner_acceptance_readback_preflight_hold.py new file mode 100644 index 000000000..2812f80ec --- /dev/null +++ b/apps/api/tests/test_ai_agent_result_capture_owner_acceptance_readback_preflight_hold.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_acceptance_readback_preflight_hold import ( + load_latest_ai_agent_result_capture_owner_acceptance_readback_preflight_hold, +) + +REPO_ROOT = Path(__file__).resolve().parents[3] +FIXTURE = REPO_ROOT / "docs/evaluations/ai_agent_result_capture_owner_acceptance_readback_preflight_hold_2026-06-14.json" + + +def test_load_latest_ai_agent_result_capture_owner_acceptance_readback_preflight_hold_snapshot() -> None: + data = load_latest_ai_agent_result_capture_owner_acceptance_readback_preflight_hold() + + assert data["schema_version"] == "ai_agent_result_capture_owner_acceptance_readback_preflight_hold_v1" + assert data["program_status"]["current_task_id"] == "P2-128" + assert data["program_status"]["next_task_id"] == "P2-129" + assert data["program_status"]["runtime_authority"] == "result_capture_owner_acceptance_readback_preflight_hold_only_no_live_write" + + rollups = data["rollups"] + assert rollups["owner_acceptance_readback_count"] == 5 + assert rollups["preflight_hold_check_count"] == 5 + assert rollups["live_apply_hold_gate_count"] == 5 + assert rollups["rollback_preflight_check_count"] == 5 + assert rollups["blocked_apply_transition_count"] == 6 + assert rollups["operator_action_count"] == 5 + assert rollups["critical_blocker_count"] == 5 + assert rollups["owner_acceptance_received_count"] == 0 + assert rollups["maintenance_window_approved_count"] == 0 + assert rollups["rollback_owner_confirmed_count"] == 0 + assert rollups["post_apply_verifier_ready_count"] == 0 + assert rollups["live_apply_preflight_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_acceptance_received"] for item in data["owner_acceptance_readbacks"]} == {False} + assert {item["preflight_passed"] for item in data["preflight_hold_checks"]} == {False} + assert {item["live_apply_enabled"] for item in data["live_apply_hold_gates"]} == {False} + assert {item["rollback_preflight_passed"] for item in data["rollback_preflight_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_acceptance_readback_preflight_hold_2026-06-14.json" + target.write_text(json.dumps(source, ensure_ascii=False), encoding="utf-8") + return source + + +def test_result_capture_owner_acceptance_readback_preflight_hold_rejects_owner_acceptance_received(tmp_path: Path) -> None: + source = _copy_fixture(tmp_path) + source["owner_acceptance_readbacks"][0]["owner_acceptance_received"] = True + target = tmp_path / "ai_agent_result_capture_owner_acceptance_readback_preflight_hold_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 acceptance received"): + load_latest_ai_agent_result_capture_owner_acceptance_readback_preflight_hold(tmp_path) + + +def test_result_capture_owner_acceptance_readback_preflight_hold_rejects_preflight_passed(tmp_path: Path) -> None: + source = _copy_fixture(tmp_path) + source["preflight_hold_checks"][0]["preflight_passed"] = True + target = tmp_path / "ai_agent_result_capture_owner_acceptance_readback_preflight_hold_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_acceptance_readback_preflight_hold(tmp_path) + + +def test_result_capture_owner_acceptance_readback_preflight_hold_rejects_live_apply_enabled(tmp_path: Path) -> None: + source = _copy_fixture(tmp_path) + source["live_apply_hold_gates"][0]["live_apply_enabled"] = True + target = tmp_path / "ai_agent_result_capture_owner_acceptance_readback_preflight_hold_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"): + load_latest_ai_agent_result_capture_owner_acceptance_readback_preflight_hold(tmp_path) + + +def test_result_capture_owner_acceptance_readback_preflight_hold_rejects_rollup_drift(tmp_path: Path) -> None: + source = _copy_fixture(tmp_path) + source["rollups"]["owner_acceptance_readback_count"] = 4 + target = tmp_path / "ai_agent_result_capture_owner_acceptance_readback_preflight_hold_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_acceptance_readback_preflight_hold(tmp_path) + + +def test_result_capture_owner_acceptance_readback_preflight_hold_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_acceptance_readback_preflight_hold_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_acceptance_readback_preflight_hold(tmp_path) diff --git a/apps/api/tests/test_ai_agent_result_capture_owner_acceptance_readback_preflight_hold_api.py b/apps/api/tests/test_ai_agent_result_capture_owner_acceptance_readback_preflight_hold_api.py new file mode 100644 index 000000000..6c659a332 --- /dev/null +++ b/apps/api/tests/test_ai_agent_result_capture_owner_acceptance_readback_preflight_hold_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_acceptance_readback_preflight_hold_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-acceptance-readback-preflight-hold") + + assert response.status_code == 200 + data = response.json() + assert data["schema_version"] == "ai_agent_result_capture_owner_acceptance_readback_preflight_hold_v1" + assert data["program_status"]["current_task_id"] == "P2-128" + assert data["program_status"]["next_task_id"] == "P2-129" + + rollups = data["rollups"] + assert rollups["owner_acceptance_readback_count"] == 5 + assert rollups["preflight_hold_check_count"] == 5 + assert rollups["live_apply_hold_gate_count"] == 5 + assert rollups["rollback_preflight_check_count"] == 5 + assert rollups["blocked_apply_transition_count"] == 6 + assert rollups["operator_action_count"] == 5 + assert rollups["owner_acceptance_received_count"] == 0 + assert rollups["maintenance_window_approved_count"] == 0 + assert rollups["rollback_owner_confirmed_count"] == 0 + assert rollups["post_apply_verifier_ready_count"] == 0 + assert rollups["live_apply_preflight_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_acceptance_received"] for item in data["owner_acceptance_readbacks"]} == {False} + assert {item["preflight_passed"] for item in data["preflight_hold_checks"]} == {False} + assert {item["live_apply_enabled"] for item in data["live_apply_hold_gates"]} == {False} diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 4901d83b7..38bf7ab0e 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -5911,6 +5911,39 @@ "rollbackConfirmed": "rollback 已確認={value}" } }, + "resultCaptureOwnerAcceptanceReadbackPreflightHold": { + "title": "P2-128 owner acceptance readback / live-apply preflight hold", + "source": "產生 {generated};目前 {current};下一步 {next}", + "priorTitle": "前一關 owner acceptance gate", + "truthTitle": "preflight hold 真相", + "metrics": { + "overall": "完成度", + "readbacks": "Acceptance readbacks", + "preflights": "Preflight holds", + "holdGates": "Live-apply holds", + "rollbackPreflights": "Rollback preflights", + "blockers": "已阻擋 release", + "actions": "操作選項", + "approvalRequired": "需批准", + "blocked": "阻擋", + "liveWrites": "正式寫入 / 發送" + }, + "flags": { + "p2Loaded": "已載入 P2-127={value}", + "preflightHoldRequired": "preflight hold required={value}", + "liveApplyHoldActive": "live apply hold active={value}" + }, + "labels": { + "ownerAcceptanceReceived": "owner acceptance received={value}", + "maintenanceApproved": "maintenance approved={value}", + "gatewayWrites": "Gateway 寫入={value}", + "readbackReceived": "acceptance received={value}", + "preflightPassed": "preflight passed={value}", + "liveApplyEnabled": "live apply enabled={value}", + "rollbackRequired": "需要 rollback owner={value}", + "rollbackPassed": "rollback preflight passed={value}" + } + }, "resultCaptureWriteGateReview": { "title": "P2-121 result capture write gate review", "source": "產生 {generated};目前 {current};下一步 {next}", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 4901d83b7..38bf7ab0e 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -5911,6 +5911,39 @@ "rollbackConfirmed": "rollback 已確認={value}" } }, + "resultCaptureOwnerAcceptanceReadbackPreflightHold": { + "title": "P2-128 owner acceptance readback / live-apply preflight hold", + "source": "產生 {generated};目前 {current};下一步 {next}", + "priorTitle": "前一關 owner acceptance gate", + "truthTitle": "preflight hold 真相", + "metrics": { + "overall": "完成度", + "readbacks": "Acceptance readbacks", + "preflights": "Preflight holds", + "holdGates": "Live-apply holds", + "rollbackPreflights": "Rollback preflights", + "blockers": "已阻擋 release", + "actions": "操作選項", + "approvalRequired": "需批准", + "blocked": "阻擋", + "liveWrites": "正式寫入 / 發送" + }, + "flags": { + "p2Loaded": "已載入 P2-127={value}", + "preflightHoldRequired": "preflight hold required={value}", + "liveApplyHoldActive": "live apply hold active={value}" + }, + "labels": { + "ownerAcceptanceReceived": "owner acceptance received={value}", + "maintenanceApproved": "maintenance approved={value}", + "gatewayWrites": "Gateway 寫入={value}", + "readbackReceived": "acceptance received={value}", + "preflightPassed": "preflight passed={value}", + "liveApplyEnabled": "live apply enabled={value}", + "rollbackRequired": "需要 rollback owner={value}", + "rollbackPassed": "rollback preflight passed={value}" + } + }, "resultCaptureWriteGateReview": { "title": "P2-121 result capture write gate review", "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 3b6024978..559708f70 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 @@ -75,6 +75,7 @@ import { type AiAgentResultCaptureOwnerPromotionReviewSnapshot, type AiAgentResultCaptureOwnerApprovedExecutionRehearsalSnapshot, type AiAgentResultCaptureOwnerAcceptanceMaintenanceGateSnapshot, + type AiAgentResultCaptureOwnerAcceptanceReadbackPreflightHoldSnapshot, type AiAgentResultCaptureWriterImplementationReviewSnapshot, type AiAgentOwnerApprovedFixturePromotionGateSnapshot, type AiAgentRuntimeWorkerShadowGateSnapshot, @@ -473,6 +474,7 @@ export function AutomationInventoryTab() { const [resultCaptureOwnerPromotionReview, setResultCaptureOwnerPromotionReview] = useState(null) const [resultCaptureOwnerApprovedExecutionRehearsal, setResultCaptureOwnerApprovedExecutionRehearsal] = useState(null) const [resultCaptureOwnerAcceptanceMaintenanceGate, setResultCaptureOwnerAcceptanceMaintenanceGate] = useState(null) + const [resultCaptureOwnerAcceptanceReadbackPreflightHold, setResultCaptureOwnerAcceptanceReadbackPreflightHold] = useState(null) const [reportTruthActionabilityReview, setReportTruthActionabilityReview] = useState(null) const [ownerDryRunPackage, setOwnerDryRunPackage] = useState(null) const [hostStatefulInventory, setHostStatefulInventory] = useState(null) @@ -537,6 +539,7 @@ export function AutomationInventoryTab() { apiClient.getAiAgentResultCaptureOwnerPromotionReview(), apiClient.getAiAgentResultCaptureOwnerApprovedExecutionRehearsal(), apiClient.getAiAgentResultCaptureOwnerAcceptanceMaintenanceGate(), + apiClient.getAiAgentResultCaptureOwnerAcceptanceReadbackPreflightHold(), apiClient.getAiAgentReportTruthActionabilityReview(), apiClient.getAiAgentOwnerApprovedFixtureDryRun(), apiClient.getAiAgentHostStatefulVersionInventory(), @@ -600,6 +603,7 @@ export function AutomationInventoryTab() { resultCaptureOwnerPromotionReviewResult, resultCaptureOwnerApprovedExecutionRehearsalResult, resultCaptureOwnerAcceptanceMaintenanceGateResult, + resultCaptureOwnerAcceptanceReadbackPreflightHoldResult, reportTruthActionabilityReviewResult, ownerDryRunPackageResult, hostStatefulInventoryResult, @@ -660,6 +664,7 @@ export function AutomationInventoryTab() { setResultCaptureOwnerPromotionReview(resultCaptureOwnerPromotionReviewResult.status === 'fulfilled' ? resultCaptureOwnerPromotionReviewResult.value : null) setResultCaptureOwnerApprovedExecutionRehearsal(resultCaptureOwnerApprovedExecutionRehearsalResult.status === 'fulfilled' ? resultCaptureOwnerApprovedExecutionRehearsalResult.value : null) setResultCaptureOwnerAcceptanceMaintenanceGate(resultCaptureOwnerAcceptanceMaintenanceGateResult.status === 'fulfilled' ? resultCaptureOwnerAcceptanceMaintenanceGateResult.value : null) + setResultCaptureOwnerAcceptanceReadbackPreflightHold(resultCaptureOwnerAcceptanceReadbackPreflightHoldResult.status === 'fulfilled' ? resultCaptureOwnerAcceptanceReadbackPreflightHoldResult.value : null) setReportTruthActionabilityReview(reportTruthActionabilityReviewResult.status === 'fulfilled' ? reportTruthActionabilityReviewResult.value : null) setOwnerDryRunPackage(ownerDryRunPackageResult.status === 'fulfilled' ? ownerDryRunPackageResult.value : null) setHostStatefulInventory(hostStatefulInventoryResult.status === 'fulfilled' ? hostStatefulInventoryResult.value : null) @@ -718,6 +723,7 @@ export function AutomationInventoryTab() { resultCaptureOwnerPromotionReviewResult, resultCaptureOwnerApprovedExecutionRehearsalResult, resultCaptureOwnerAcceptanceMaintenanceGateResult, + resultCaptureOwnerAcceptanceReadbackPreflightHoldResult, reportTruthActionabilityReviewResult, ownerDryRunPackageResult, hostStatefulInventoryResult, @@ -1960,7 +1966,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 || !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 || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) { return (
@@ -2902,6 +2908,40 @@ export function AutomationInventoryTab() { + resultCaptureOwnerAcceptanceMaintenanceGate.rollups.playbook_trust_write_count + resultCaptureOwnerAcceptanceMaintenanceGate.rollups.production_write_count ) + const resultCaptureAcceptanceReadbackOverall = resultCaptureOwnerAcceptanceReadbackPreflightHold.program_status.overall_completion_percent + const resultCaptureAcceptanceReadbacks = resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.owner_acceptance_readback_count + const resultCaptureAcceptancePreflights = resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.preflight_hold_check_count + const resultCaptureAcceptanceHoldGates = resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.live_apply_hold_gate_count + const resultCaptureAcceptanceRollbackPreflights = resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.rollback_preflight_check_count + const resultCaptureAcceptanceBlockedTransitions = resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.blocked_apply_transition_count + const resultCaptureAcceptanceReadbackActions = resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.operator_action_count + const resultCaptureAcceptanceReadbackApprovalRequired = ( + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.approval_required_readback_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.approval_required_preflight_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.approval_required_hold_gate_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.approval_required_rollback_count + ) + const resultCaptureAcceptanceReadbackBlocked = ( + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.blocked_readback_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.blocked_preflight_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.blocked_hold_gate_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.blocked_rollback_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.critical_blocker_count + ) + const resultCaptureAcceptanceReadbackLiveWrites = ( + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.writer_apply_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.execution_apply_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.receipt_write_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.reviewer_queue_write_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.gateway_queue_write_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.telegram_send_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.bot_api_call_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.report_receipt_write_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.result_capture_write_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.learning_write_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.rollups.playbook_trust_write_count + + resultCaptureOwnerAcceptanceReadbackPreflightHold.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 @@ -7451,6 +7491,147 @@ export function AutomationInventoryTab() {
+
+
+
+ + + {t('resultCaptureOwnerAcceptanceReadbackPreflightHold.title')} + +
+ +
+ +
+ } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> +
+ +
+
+ {t('resultCaptureOwnerAcceptanceReadbackPreflightHold.priorTitle')} + + {resultCaptureOwnerAcceptanceReadbackPreflightHold.prior_owner_acceptance_maintenance_gate.readiness_note} + +
+ + + +
+
+ +
+ {t('resultCaptureOwnerAcceptanceReadbackPreflightHold.truthTitle')} + + {resultCaptureOwnerAcceptanceReadbackPreflightHold.readback_truth.truth_note} + +
+ + + + + + +
+
+
+ +
+ {resultCaptureOwnerAcceptanceReadbackPreflightHold.owner_acceptance_readbacks.slice(0, 5).map(readback => ( +
+
+ + {readback.display_name} + + +
+ + {readback.source_packet} → {readback.readback_summary} + +
+ + + +
+
+ ))} +
+ +
+ {resultCaptureOwnerAcceptanceReadbackPreflightHold.preflight_hold_checks.slice(0, 5).map(preflight => ( +
+
+ + {preflight.display_name} + + +
+ + {preflight.required_before_release} + +
+ + + +
+
+ ))} +
+ +
+ {resultCaptureOwnerAcceptanceReadbackPreflightHold.live_apply_hold_gates.slice(0, 5).map(gate => ( +
+
+ + {gate.display_name} + + +
+ + {gate.hold_reason} {gate.release_condition} + + +
+ ))} +
+ +
+ {resultCaptureOwnerAcceptanceReadbackPreflightHold.rollback_preflight_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 b1aff8d4b..8380ee02f 100644 --- a/apps/web/src/lib/api-client.ts +++ b/apps/web/src/lib/api-client.ts @@ -535,6 +535,11 @@ export const apiClient = { return handleResponse(res) }, + async getAiAgentResultCaptureOwnerAcceptanceReadbackPreflightHold() { + const res = await fetch(`${API_BASE_URL}/agents/agent-result-capture-owner-acceptance-readback-preflight-hold`) + return handleResponse(res) + }, + async getAiAgentOwnerApprovedFixtureDryRun() { const res = await fetch(`${API_BASE_URL}/agents/agent-owner-approved-fixture-dry-run`) return handleResponse(res) @@ -6938,6 +6943,199 @@ export interface AiAgentResultCaptureOwnerAcceptanceMaintenanceGateSnapshot { } } +export interface AiAgentResultCaptureOwnerAcceptanceReadbackPreflightHoldSnapshot { + schema_version: 'ai_agent_result_capture_owner_acceptance_readback_preflight_hold_v1' + generated_at: string + program_status: { + overall_completion_percent: number + current_priority: 'P0' | 'P1' | 'P2' | 'P3' + current_task_id: 'P2-128' + next_task_id: 'P2-129' + read_only_mode: true + runtime_authority: 'result_capture_owner_acceptance_readback_preflight_hold_only_no_live_write' + status_note: string + } + source_refs: string[] + prior_owner_acceptance_maintenance_gate: { + schema_version: string + owner_acceptance_packet_count: number + maintenance_window_count: number + rollback_owner_check_count: number + post_apply_verifier_gate_count: number + blocked_live_write_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 + 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 + } + readback_truth: { + p2_127_owner_acceptance_gate_loaded: boolean + owner_acceptance_readback_ready: boolean + preflight_hold_required: boolean + live_apply_hold_active: boolean + rollback_preflight_required: boolean + post_apply_verifier_required: boolean + redaction_review_required: boolean + readback_only: boolean + owner_acceptance_received: boolean + maintenance_window_approved: boolean + rollback_owner_confirmed: boolean + post_apply_verifier_ready: boolean + live_apply_preflight_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_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 + 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_acceptance_readbacks: Array<{ + readback_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + source_packet: string + status: 'ready_for_preflight_review' | 'approval_required' | 'blocked_by_policy' + readback_mode: 'owner_acceptance_status_readback' + owner_acceptance_received: false + readback_summary: string + source_hash: string + }> + preflight_hold_checks: Array<{ + check_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + status: 'ready_for_preflight_review' | 'approval_required' | 'blocked_by_policy' + preflight_mode: 'live_apply_preflight_hold' + hold_required: true + preflight_passed: false + required_before_release: string + }> + live_apply_hold_gates: Array<{ + gate_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + status: 'ready_for_preflight_review' | 'approval_required' | 'blocked_by_policy' + gate_mode: 'live_apply_hold_gate' + live_apply_enabled: false + hold_reason: string + release_condition: string + }> + rollback_preflight_checks: Array<{ + check_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + status: 'ready_for_preflight_review' | 'approval_required' | 'blocked_by_policy' + rollback_owner_required: true + rollback_preflight_passed: false + rollback_scope: string + hold_reason: string + }> + blocked_apply_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 + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + 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_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_readback_count: number + blocked_readback_count: number + approval_required_preflight_count: number + blocked_preflight_count: number + approval_required_hold_gate_count: number + blocked_hold_gate_count: number + approval_required_rollback_count: number + blocked_rollback_count: number + critical_blocker_count: 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 + 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 4a55aeea1..10d25cf5b 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,27 @@ +## 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。 + +**完成內容**: +- 新增 `ai_agent_result_capture_owner_acceptance_readback_preflight_hold_v1` schema、committed snapshot、loader 與 API endpoint `GET /api/v1/agents/agent-result-capture-owner-acceptance-readback-preflight-hold`。 +- P2-128 snapshot 固定 5 個 owner acceptance readback、5 個 preflight hold check、5 個 live-apply hold gate、5 個 rollback preflight check、6 個 blocked apply transition 與 5 個 operator action。 +- Governance automation inventory 頁新增 P2-128 區塊,顯示 P2-128 進度 `100%`、acceptance readback `5`、preflight hold `5`、live-apply hold `5`、rollback preflight `5`、blocked release `6`、operator action `5`、需批准 `8`、阻擋 `9`、正式寫入 / 發送 `0`。 +- Readback truth 固定為 `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、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-128 schema / snapshot、`zh-TW.json`、`en.json` 通過。 +- Python 編譯:P2-128 loader 與 `agents.py` 通過。 +- API/service pytest:P2-128 + P2-127 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 `431 kB`。 +- 本段仍是本地完成;正式 API readback、正式站 desktop / mobile Browser smoke 與 deploy marker 需在推送 Gitea main 並完成 CD 後補齊。 + +**安全邊界**: +- P2-128 仍是 owner acceptance readback / live-apply preflight hold;不接受口頭批准、不把 readback 解讀成 owner acceptance received、不批准維護窗口、不確認 rollback owner、不啟用 post-apply 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-129`:owner-approved preflight release package;只有 P2-128 正式驗證後才可把 acceptance readback、preflight hold、live-apply hold gate、rollback preflight 與 blocked apply transition 轉成 release package,仍不得直接開啟 result capture writer、learning writer、PlayBook trust writer、reviewer queue write、Gateway queue write、Telegram send、Bot API call 或 production write。 + ## 2026-06-14|km-vectorize 03:00 官方排程失敗與 evidence retention 補強 **背景**:03:10 heartbeat 依重啟 SOP 只讀檢查 120 上 ArgoCD、`km-vectorize` 官方 CronJob、backup status、credential escrow 與 full cold-start scorecard。本輪沒有手動建立 Job、沒有刪 Job / Pod、沒有 `kubectl patch` live、沒有重啟任何服務。 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 cad8e6de9..13b45e805 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-127 已完成只讀證據面、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;P2-127 已由 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 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_maintenance_gate_v1`、`GET /api/v1/agents/agent-result-capture-owner-acceptance-maintenance-gate`、正式站 `/zh-TW/governance?tab=automation-inventory` desktop / mobile smoke、`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-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 固定 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`、`ai_agent_result_capture_owner_acceptance_maintenance_gate_v1`、`GET /api/v1/agents/agent-result-capture-owner-acceptance-maintenance-gate`、正式站 `/zh-TW/governance?tab=automation-inventory` desktop / mobile smoke、`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.1%**。本工作清單文件本身完成度:**100%**。 +AI Agent 自動化工作包目前完成度:**99.2%**。本工作清單文件本身完成度:**100%**。 三 Agent 佈建布局目前完成度:**45%**。第一波已完成只讀 schema / snapshot / API / 測試 / 報告,第二波已接入治理頁自動化盤點 UI;正式 runtime 佈署、Telegram E2E 發送與 AgentSession 工作流仍需逐項 gate。 -三 Agent 主動溝通、學習與成長證據目前完成度:**100%**。P2-403A 到 P2-127 已把互動證據、報表治理、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 全部固定成可驗證證據。P2-127 已本地與正式站驗證,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;正式站 desktop / mobile smoke 皆為禁用內部協作片語 `0`、水平溢位 `0`、P2-127 區塊危險入口 `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-128`。 +三 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 已本地驗證,固定 5 個 owner acceptance readback、5 個 preflight hold check、5 個 live-apply hold gate、5 個 rollback preflight check、6 個 blocked apply 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-129`。 -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-127` 已補互動、學習證據面、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。下一步是 `P2-128`;外部 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-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。 完成度計算模型: @@ -999,7 +999,8 @@ UI: | P2-124 | 完成 | 100 | OpenClaw + Hermes + NemoTron | result capture writer dry-run readback | `ai_agent_result_capture_writer_dry_run_readback_v1` / schema / snapshot / 只讀 API / governance UI;正式站 deploy marker `110911c4` 已驗證;5 個 dry-run readback、5 個 receipt verifier、5 個 promotion gate、6 個 blocked promotion write、5 個 operator action;runtime authority 固定 `result_capture_writer_dry_run_readback_only_no_live_write`;writer apply / dry-run execution / receipt write / promotion apply / result capture / learning / PlayBook trust / reviewer queue / Gateway / Telegram / Bot API / report receipt / production write 全為 `0` | 已由 P2-125 承接;不套用 writer、不執行 dry-run、不寫 receipt、不寫 result capture、不寫 learning、不更新 PlayBook trust、不送 Telegram、不寫 production | | 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-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;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` | 下一步 P2-129;不釋放 live apply、不套用 writer、不寫 receipt、不寫 result capture、不寫 learning、不更新 PlayBook trust、不送 Telegram、不寫 production | ### P3 - 候選 Agent 擴展 diff --git a/docs/evaluations/ai_agent_result_capture_owner_acceptance_readback_preflight_hold_2026-06-14.json b/docs/evaluations/ai_agent_result_capture_owner_acceptance_readback_preflight_hold_2026-06-14.json new file mode 100644 index 000000000..ea97f1d4d --- /dev/null +++ b/docs/evaluations/ai_agent_result_capture_owner_acceptance_readback_preflight_hold_2026-06-14.json @@ -0,0 +1,445 @@ +{ + "schema_version": "ai_agent_result_capture_owner_acceptance_readback_preflight_hold_v1", + "generated_at": "2026-06-14T04:18:00+08:00", + "program_status": { + "overall_completion_percent": 100, + "current_priority": "P2", + "current_task_id": "P2-128", + "next_task_id": "P2-129", + "read_only_mode": true, + "runtime_authority": "result_capture_owner_acceptance_readback_preflight_hold_only_no_live_write", + "status_note": "P2-128 只把 P2-127 owner acceptance / maintenance window gate 讀回成 preflight hold;不得釋放 live apply、寫 receipt、寫 result capture、寫 learning、寫 queue、送 Telegram 或寫入 production。" + }, + "source_refs": [ + "docs/evaluations/ai_agent_result_capture_owner_acceptance_maintenance_gate_2026-06-14.json", + "docs/evaluations/ai_agent_result_capture_owner_approved_execution_rehearsal_2026-06-14.json", + "docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md#48-建立-owner-acceptance--maintenance-window-gate" + ], + "prior_owner_acceptance_maintenance_gate": { + "schema_version": "ai_agent_result_capture_owner_acceptance_maintenance_gate_v1", + "owner_acceptance_packet_count": 5, + "maintenance_window_count": 5, + "rollback_owner_check_count": 5, + "post_apply_verifier_gate_count": 5, + "blocked_live_write_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, + "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-127 已把 owner acceptance、maintenance window、rollback owner 與 post-apply verifier gate 固定為可審核封包;P2-128 只讀回這些封包並建立 live-apply preflight hold。" + }, + "readback_truth": { + "p2_127_owner_acceptance_gate_loaded": true, + "owner_acceptance_readback_ready": true, + "preflight_hold_required": true, + "live_apply_hold_active": true, + "rollback_preflight_required": true, + "post_apply_verifier_required": true, + "redaction_review_required": true, + "readback_only": true, + "owner_acceptance_received": false, + "maintenance_window_approved": false, + "rollback_owner_confirmed": false, + "post_apply_verifier_ready": false, + "live_apply_preflight_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_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, + "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-128 只做 acceptance readback 與 preflight hold;readback 可見不代表 owner 已接受、維護窗口已批准或 live apply 可執行。" + }, + "owner_acceptance_readbacks": [ + { + "readback_id": "readback_result_capture_writer", + "display_name": "Result capture owner acceptance readback", + "owner_agent": "openclaw", + "source_packet": "acceptance_result_capture_writer", + "status": "ready_for_preflight_review", + "readback_mode": "owner_acceptance_status_readback", + "owner_acceptance_received": false, + "readback_summary": "只讀回 owner role、affected scope、rollback owner 與 verifier plan;不產生 acceptance record。", + "source_hash": "sha256:c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1" + }, + { + "readback_id": "readback_learning_writer", + "display_name": "Learning owner acceptance readback", + "owner_agent": "hermes", + "source_packet": "acceptance_learning_writer", + "status": "approval_required", + "readback_mode": "owner_acceptance_status_readback", + "owner_acceptance_received": false, + "readback_summary": "只讀回 KM owner、stale guard owner 與 learning write scope;不寫 KM 或 learning metadata。", + "source_hash": "sha256:c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2" + }, + { + "readback_id": "readback_playbook_trust_writer", + "display_name": "PlayBook trust owner acceptance readback", + "owner_agent": "nemotron", + "source_packet": "acceptance_playbook_trust_writer", + "status": "blocked_by_policy", + "readback_mode": "owner_acceptance_status_readback", + "owner_acceptance_received": false, + "readback_summary": "只讀回 trust delta reviewer 與 rollback scope;未完成負向強化審查前不得放行。", + "source_hash": "sha256:c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3" + }, + { + "readback_id": "readback_reviewer_queue_writer", + "display_name": "Reviewer queue owner acceptance readback", + "owner_agent": "openclaw", + "source_packet": "acceptance_reviewer_queue_writer", + "status": "approval_required", + "readback_mode": "owner_acceptance_status_readback", + "owner_acceptance_received": false, + "readback_summary": "只讀回 reviewer queue owner、SLA owner 與 dedupe key owner;不寫 reviewer queue。", + "source_hash": "sha256:c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4" + }, + { + "readback_id": "readback_gateway_queue_writer", + "display_name": "Gateway queue owner acceptance readback", + "owner_agent": "nemotron", + "source_packet": "acceptance_gateway_queue_writer", + "status": "ready_for_preflight_review", + "readback_mode": "owner_acceptance_status_readback", + "owner_acceptance_received": false, + "readback_summary": "只讀回 SRE route owner、Telegram receipt owner、route lock 與 redaction owner;不寫 Gateway queue。", + "source_hash": "sha256:c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5" + } + ], + "preflight_hold_checks": [ + { + "check_id": "preflight_result_capture_writer", + "display_name": "Result capture live-apply preflight hold", + "owner_agent": "openclaw", + "status": "ready_for_preflight_review", + "preflight_mode": "live_apply_preflight_hold", + "hold_required": true, + "preflight_passed": false, + "required_before_release": "owner acceptance record、maintenance window、rollback owner、post-apply verifier readiness。" + }, + { + "check_id": "preflight_learning_writer", + "display_name": "Learning live-apply preflight hold", + "owner_agent": "hermes", + "status": "approval_required", + "preflight_mode": "live_apply_preflight_hold", + "hold_required": true, + "preflight_passed": false, + "required_before_release": "KM owner acceptance、stale guard、rollback owner、post-write verifier readiness。" + }, + { + "check_id": "preflight_playbook_trust_writer", + "display_name": "PlayBook trust live-apply preflight hold", + "owner_agent": "nemotron", + "status": "blocked_by_policy", + "preflight_mode": "live_apply_preflight_hold", + "hold_required": true, + "preflight_passed": false, + "required_before_release": "負向強化審查、trust delta reviewer、rollback owner 與 owner acceptance。" + }, + { + "check_id": "preflight_reviewer_queue_writer", + "display_name": "Reviewer queue live-apply preflight hold", + "owner_agent": "openclaw", + "status": "approval_required", + "preflight_mode": "live_apply_preflight_hold", + "hold_required": true, + "preflight_passed": false, + "required_before_release": "reviewer SLA owner、dedupe key owner、queue rollback owner 與 verifier readiness。" + }, + { + "check_id": "preflight_gateway_queue_writer", + "display_name": "Gateway queue live-apply preflight hold", + "owner_agent": "nemotron", + "status": "ready_for_preflight_review", + "preflight_mode": "live_apply_preflight_hold", + "hold_required": true, + "preflight_passed": false, + "required_before_release": "SRE route lock、Telegram receipt owner、redaction owner 與 Gateway rollback owner。" + } + ], + "live_apply_hold_gates": [ + { + "gate_id": "hold_gate_result_capture", + "display_name": "Result capture live apply hold gate", + "owner_agent": "openclaw", + "status": "ready_for_preflight_review", + "gate_mode": "live_apply_hold_gate", + "live_apply_enabled": false, + "hold_reason": "owner acceptance 仍未 received,且 post-apply verifier 未 ready。", + "release_condition": "P2-129 之後另行建立 owner-approved preflight release package。" + }, + { + "gate_id": "hold_gate_learning", + "display_name": "Learning live apply hold gate", + "owner_agent": "hermes", + "status": "approval_required", + "gate_mode": "live_apply_hold_gate", + "live_apply_enabled": false, + "hold_reason": "learning write 仍缺 KM owner acceptance 與 stale guard rollback。", + "release_condition": "需 owner-approved learning write release package。" + }, + { + "gate_id": "hold_gate_playbook_trust", + "display_name": "PlayBook trust live apply hold gate", + "owner_agent": "nemotron", + "status": "blocked_by_policy", + "gate_mode": "live_apply_hold_gate", + "live_apply_enabled": false, + "hold_reason": "trust delta 與負向強化審查仍未完成。", + "release_condition": "需 OpenClaw 仲裁與 owner-approved trust release package。" + }, + { + "gate_id": "hold_gate_reviewer_queue", + "display_name": "Reviewer queue live apply hold gate", + "owner_agent": "openclaw", + "status": "approval_required", + "gate_mode": "live_apply_hold_gate", + "live_apply_enabled": false, + "hold_reason": "reviewer queue 寫入仍缺 SLA owner 與 rollback owner。", + "release_condition": "需 reviewer queue owner-approved release package。" + }, + { + "gate_id": "hold_gate_gateway_queue", + "display_name": "Gateway queue live apply hold gate", + "owner_agent": "nemotron", + "status": "ready_for_preflight_review", + "gate_mode": "live_apply_hold_gate", + "live_apply_enabled": false, + "hold_reason": "Gateway queue 與 Telegram send 仍缺 SRE route lock 與 receipt owner。", + "release_condition": "需 Gateway queue / Telegram receipt release package。" + } + ], + "rollback_preflight_checks": [ + { + "check_id": "rollback_preflight_result_capture", + "display_name": "Result capture rollback preflight", + "owner_agent": "openclaw", + "status": "ready_for_preflight_review", + "rollback_owner_required": true, + "rollback_preflight_passed": false, + "rollback_scope": "撤回 result capture write preview、receipt hash 與 audit trail append。", + "hold_reason": "rollback owner 尚未 confirmed,不得 release live apply。" + }, + { + "check_id": "rollback_preflight_learning", + "display_name": "Learning rollback preflight", + "owner_agent": "hermes", + "status": "approval_required", + "rollback_owner_required": true, + "rollback_preflight_passed": false, + "rollback_scope": "撤回 learning draft、KM write preview 與 stale guard marker。", + "hold_reason": "KM rollback owner 尚未 confirmed。" + }, + { + "check_id": "rollback_preflight_playbook_trust", + "display_name": "PlayBook trust rollback preflight", + "owner_agent": "nemotron", + "status": "blocked_by_policy", + "rollback_owner_required": true, + "rollback_preflight_passed": false, + "rollback_scope": "撤回 trust delta preview 與 negative reinforcement draft。", + "hold_reason": "trust rollback owner 與負向強化 reviewer 尚未 ready。" + }, + { + "check_id": "rollback_preflight_reviewer_queue", + "display_name": "Reviewer queue rollback preflight", + "owner_agent": "openclaw", + "status": "approval_required", + "rollback_owner_required": true, + "rollback_preflight_passed": false, + "rollback_scope": "撤回 reviewer queue preview、dedupe key 與 SLA route handoff。", + "hold_reason": "reviewer queue rollback owner 尚未 confirmed。" + }, + { + "check_id": "rollback_preflight_gateway_queue", + "display_name": "Gateway queue rollback preflight", + "owner_agent": "nemotron", + "status": "ready_for_preflight_review", + "rollback_owner_required": true, + "rollback_preflight_passed": false, + "rollback_scope": "撤回 Gateway queue preview、route lock 與 Telegram receipt draft。", + "hold_reason": "Gateway rollback owner 尚未 confirmed,不得送 Telegram。" + } + ], + "blocked_apply_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 acceptance received + preflight hold released", + "evidence_hash": "sha256:d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1" + }, + { + "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 + rollback preflight passed", + "evidence_hash": "sha256:d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2" + }, + { + "blocker_id": "blocked_receipt_write_release", + "display_name": "Receipt write release blocked", + "severity": "high", + "status": "approval_required", + "blocked_action": "receipt_write_release", + "blocked_until": "post-apply verifier ready + owner release package", + "evidence_hash": "sha256:d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3" + }, + { + "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": "dual approval + preflight hold released", + "evidence_hash": "sha256:d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4" + }, + { + "blocker_id": "blocked_gateway_queue_write_release", + "display_name": "Gateway queue write release blocked", + "severity": "critical", + "status": "blocked_by_policy", + "blocked_action": "gateway_queue_write_release", + "blocked_until": "SRE route lock + Telegram receipt owner accepted", + "evidence_hash": "sha256:d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5" + }, + { + "blocker_id": "blocked_telegram_send_release", + "display_name": "Telegram send release blocked", + "severity": "critical", + "status": "blocked_by_policy", + "blocked_action": "telegram_send_release", + "blocked_until": "Gateway queue E2E receipt + SRE route lock + redaction owner accepted", + "evidence_hash": "sha256:d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6" + } + ], + "operator_actions": [ + { + "action_id": "review_acceptance_readbacks", + "display_name": "審查 acceptance readback", + "owner_agent": "openclaw", + "operator_instruction": "確認 readback 只呈現 owner / scope / hash / status,沒有把 readback 解讀成已批准。", + "runtime_write_allowed": false + }, + { + "action_id": "hold_preflight_release", + "display_name": "維持 preflight release hold", + "owner_agent": "hermes", + "operator_instruction": "確認所有 live-apply preflight hold 仍為 active,且未產生 writer apply release。", + "runtime_write_allowed": false + }, + { + "action_id": "verify_rollback_preflight", + "display_name": "檢查 rollback preflight", + "owner_agent": "openclaw", + "operator_instruction": "確認 rollback owner 仍未 confirmed,且 release package 尚未建立。", + "runtime_write_allowed": false + }, + { + "action_id": "verify_gateway_telegram_hold", + "display_name": "檢查 Gateway / Telegram hold", + "owner_agent": "nemotron", + "operator_instruction": "確認 Gateway queue write、Telegram send 與 Bot API call 全部維持 0。", + "runtime_write_allowed": false + }, + { + "action_id": "prepare_p2_129_release_package", + "display_name": "準備 P2-129 release package", + "owner_agent": "hermes", + "operator_instruction": "只準備下一關 owner-approved release package,不得套用任何 live write。", + "runtime_write_allowed": false + } + ], + "display_redaction_contract": { + "redaction_required": true, + "raw_prompt_display_allowed": false, + "private_reasoning_display_allowed": false, + "secret_value_display_allowed": false, + "raw_runtime_payload_display_allowed": false, + "internal_collaboration_content_display_allowed": false, + "frontend_display_policy": "只顯示 readback id、owner、status、redacted hash、preflight hold、rollback preflight 與 operator instruction;不顯示提示詞、私有推理、secret、原始載荷、chat id 或內部協作內容。" + }, + "rollups": { + "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_readback_count": 2, + "blocked_readback_count": 1, + "approval_required_preflight_count": 2, + "blocked_preflight_count": 1, + "approval_required_hold_gate_count": 2, + "blocked_hold_gate_count": 1, + "approval_required_rollback_count": 2, + "blocked_rollback_count": 1, + "critical_blocker_count": 5, + "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, + "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_acceptance_readback_preflight_hold_v1.schema.json b/docs/schemas/ai_agent_result_capture_owner_acceptance_readback_preflight_hold_v1.schema.json new file mode 100644 index 000000000..e2ed85809 --- /dev/null +++ b/docs/schemas/ai_agent_result_capture_owner_acceptance_readback_preflight_hold_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_acceptance_readback_preflight_hold_v1.schema.json", + "title": "AI Agent result capture owner acceptance readback preflight hold v1", + "type": "object", + "required": [ + "schema_version", + "generated_at", + "program_status", + "source_refs", + "prior_owner_acceptance_maintenance_gate", + "readback_truth", + "owner_acceptance_readbacks", + "preflight_hold_checks", + "live_apply_hold_gates", + "rollback_preflight_checks", + "blocked_apply_transitions", + "operator_actions", + "display_redaction_contract", + "rollups" + ], + "properties": { + "schema_version": { + "const": "ai_agent_result_capture_owner_acceptance_readback_preflight_hold_v1" + }, + "generated_at": { + "type": "string" + }, + "program_status": { + "type": "object" + }, + "source_refs": { + "type": "array", + "items": { + "type": "string" + } + }, + "prior_owner_acceptance_maintenance_gate": { + "type": "object" + }, + "readback_truth": { + "type": "object" + }, + "owner_acceptance_readbacks": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "preflight_hold_checks": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "live_apply_hold_gates": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "rollback_preflight_checks": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "items": { + "type": "object" + } + }, + "blocked_apply_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 edebe7a4c..cb66421ca 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 @@ -664,7 +664,8 @@ Alert / Sentry / SigNoz / Gitea / Market Watch / Operator | `docs/evaluations/ai_agent_result_capture_writer_dry_run_readback_2026-06-14.json` + `GET /api/v1/agents/agent-result-capture-writer-dry-run-readback` | P2-124 result capture writer dry-run readback;承接 P2-123 writer dry-run fixture,建立 5 個 dry-run readback、5 個 receipt verifier、5 個 promotion gate、6 個 blocked promotion write 與 5 個 operator action;runtime authority 固定 `result_capture_writer_dry_run_readback_only_no_live_write`;owner approval、dual approval、dry-run hash、receipt verifier pass、writer apply、dry-run execution、receipt write、promotion apply、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-125 承接 | | `docs/evaluations/ai_agent_result_capture_owner_promotion_review_2026-06-14.json` + `GET /api/v1/agents/agent-result-capture-owner-promotion-review` | P2-125 result capture owner promotion review / execution gate;承接 P2-124 writer dry-run readback,建立 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 owner confirmed、post-write 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-126 承接 | | `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_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`,下一步 P2-129 | | `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 主動營運委派與版本生命週期契約 @@ -780,7 +781,8 @@ Repo / registry / release notes / K8s / host / observability / backup evidence 45. 建立 result capture writer dry-run readback。✅ P2-124 已完成並正式驗證;dry-run readback `5`、receipt verifier `5`、promotion gate `5`、blocked promotion write `6`、operator action `5`,approval-required readback / verifier / gate `2 / 2 / 2`、blocked readback / verifier / gate `1 / 1 / 1`、critical blocker `4`;owner approval、dual approval、dry-run hash、receipt verifier pass、writer apply、dry-run execution、receipt write、promotion apply、result capture write、learning write、PlayBook trust write、reviewer queue write、Gateway queue write、Telegram send、Bot API call、report receipt write、canonical runtime target read、live query、production write 仍為 `0 / false`。已由 P2-125 承接。 46. 建立 result capture owner promotion review / execution gate。✅ P2-125 已完成並正式驗證;owner promotion packet `5`、execution gate check `5`、rollback owner review `5`、blocked execution write `6`、operator action `5`,approval-required packet / gate / rollback `2 / 2 / 2`、blocked packet / gate / rollback `1 / 1 / 1`、critical blocker `5`、approval-blocked total `6 / 8`;owner promotion approved、execution gate pass、rollback owner confirmed、post-write verifier ready、writer apply、execution apply、receipt write、result capture write、learning write、PlayBook trust write、reviewer queue write、Gateway queue write、Telegram send、Bot API call、report receipt write、canonical runtime target read、live query、production write 仍為 `0 / false`。已由 P2-126 承接。 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。 +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`。下一步 P2-129。 #### 3.2.1d 2026-06-11 Agent 互動、學習與成長證據面 @@ -2101,6 +2103,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 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。 +- Governance automation inventory 新增 P2-128 區塊,將 acceptance readback、preflight hold、live-apply hold gate、rollback preflight、blocked apply transition 與 operator action 全部以只讀方式呈現。 +- 本地 API/service regression:P2-128 + P2-127 `14 passed`;JSON parse、Python 3.11 py_compile、`pnpm --filter @awoooi/web typecheck`、production build 與 `git diff --check` 通過。 +- 本地 snapshot 固定 `schema_version=ai_agent_result_capture_owner_acceptance_readback_preflight_hold_v1`、current `P2-128`、next `P2-129`、completion `100`;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`。 +- 本地 0 / false 邊界: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、secret read 與 destructive operation 均為 `0 / false`。 +- 政策裁決:P2-128 只允許 owner acceptance readback、preflight hold、live-apply hold gate、rollback preflight 與 blocked apply transition 可視化;不得把 readback 解讀成 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 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-129。 + ### 2026-06-14 03:20 (台北) — §3.2 / §5 — 正式驗證 P2-127 owner acceptance / maintenance window gate — 把 no-write rehearsal 推進成 owner acceptance 可審核封包 - 新增 `ai_agent_result_capture_owner_acceptance_maintenance_gate_v1` schema / committed snapshot / loader / API / 測試,承接 P2-126 owner-approved execution rehearsal / no-write apply gate,定義 5 個 owner acceptance packet、5 個 maintenance window、5 個 rollback owner check、5 個 post-apply verifier gate、6 個 blocked live write 與 5 個 operator action。