diff --git a/apps/api/src/api/v1/agents.py b/apps/api/src/api/v1/agents.py index 754c518cf..a5fccf531 100644 --- a/apps/api/src/api/v1/agents.py +++ b/apps/api/src/api/v1/agents.py @@ -43,6 +43,12 @@ from src.services.agent_service import ( TaskState, get_agent_service, ) +from src.services.ai_agent_12_agent_war_room import ( + load_latest_ai_agent_12_agent_war_room, +) +from src.services.ai_agent_action_audit_ledger import ( + load_latest_ai_agent_action_audit_ledger, +) from src.services.ai_agent_automation_backlog_snapshot import ( load_latest_ai_agent_automation_backlog_snapshot, ) @@ -70,6 +76,9 @@ from src.services.ai_agent_failure_receipt_no_send_replay import ( from src.services.ai_agent_gitea_pr_draft_lane import ( load_latest_ai_agent_gitea_pr_draft_lane, ) +from src.services.ai_agent_high_risk_owner_review_queue import ( + load_latest_ai_agent_high_risk_owner_review_queue, +) from src.services.ai_agent_host_stateful_version_inventory import ( load_latest_ai_agent_host_stateful_version_inventory, ) @@ -82,33 +91,15 @@ from src.services.ai_agent_learning_writeback_approval_package import ( from src.services.ai_agent_live_read_model_gate import ( load_latest_ai_agent_live_read_model_gate, ) -from src.services.ai_agent_12_agent_war_room import ( - load_latest_ai_agent_12_agent_war_room, -) -from src.services.ai_agent_professional_task_expansion import ( - load_latest_ai_agent_professional_task_expansion, -) -from src.services.ai_agent_receipt_readback_owner_review import ( - load_latest_ai_agent_receipt_readback_owner_review, -) -from src.services.ai_agent_report_no_write_analysis_runtime import ( - load_latest_ai_agent_report_no_write_analysis_runtime, -) -from src.services.ai_agent_high_risk_owner_review_queue import ( - load_latest_ai_agent_high_risk_owner_review_queue, -) -from src.services.ai_agent_report_source_health import ( - build_ai_agent_report_source_health, -) from src.services.ai_agent_low_medium_risk_whitelist import ( load_latest_ai_agent_low_medium_risk_whitelist, ) -from src.services.host_runaway_aiops_loop_readiness import ( - load_latest_host_runaway_aiops_loop_readiness, -) from src.services.ai_agent_matched_playbook_learning_gap import ( load_latest_ai_agent_matched_playbook_learning_gap, ) +from src.services.ai_agent_operation_permission_model import ( + load_latest_ai_agent_operation_permission_model, +) from src.services.ai_agent_owner_approved_fixture_dry_run import ( load_latest_ai_agent_owner_approved_fixture_dry_run, ) @@ -127,116 +118,29 @@ from src.services.ai_agent_owner_approved_result_capture_promotion_dry_run impor from src.services.ai_agent_owner_approved_result_capture_readback import ( load_latest_ai_agent_owner_approved_result_capture_readback, ) -from src.services.ai_agent_operation_permission_model import ( - load_latest_ai_agent_operation_permission_model, -) from src.services.ai_agent_post_write_verifier_package import ( load_latest_ai_agent_post_write_verifier_package, ) from src.services.ai_agent_proactive_operations_contract import ( load_latest_ai_agent_proactive_operations_contract, ) +from src.services.ai_agent_professional_task_expansion import ( + load_latest_ai_agent_professional_task_expansion, +) +from src.services.ai_agent_receipt_readback_owner_review import ( + load_latest_ai_agent_receipt_readback_owner_review, +) from src.services.ai_agent_redis_dry_run_gate import ( load_latest_ai_agent_redis_dry_run_gate, ) -from src.services.ai_agent_reviewer_queue_no_write_readback import ( - load_latest_ai_agent_reviewer_queue_no_write_readback, -) -from src.services.ai_agent_result_capture_no_write_readback import ( - load_latest_ai_agent_result_capture_no_write_readback, -) -from src.services.ai_agent_result_capture_release_decision_hold import ( - load_latest_ai_agent_result_capture_release_decision_hold, -) -from src.services.ai_agent_result_capture_release_decision_readback import ( - load_latest_ai_agent_result_capture_release_decision_readback, -) -from src.services.ai_agent_result_capture_release_decision_next_handoff import ( - load_latest_ai_agent_result_capture_release_decision_next_handoff, -) -from src.services.ai_agent_result_capture_release_decision_input_prep import ( - load_latest_ai_agent_result_capture_release_decision_input_prep, -) -from src.services.ai_agent_result_capture_release_decision_owner_response_preflight import ( - load_latest_ai_agent_result_capture_release_decision_owner_response_preflight, -) -from src.services.ai_agent_result_capture_release_decision_owner_response_readback import ( - load_latest_ai_agent_result_capture_release_decision_owner_response_readback, -) -from src.services.ai_agent_result_capture_release_decision_owner_response_acceptance_gate import ( - load_latest_ai_agent_result_capture_release_decision_owner_response_acceptance_gate, -) -from src.services.ai_agent_result_capture_owner_promotion_review import ( - load_latest_ai_agent_result_capture_owner_promotion_review, -) -from src.services.ai_agent_result_capture_owner_approved_execution_rehearsal import ( - load_latest_ai_agent_result_capture_owner_approved_execution_rehearsal, -) -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_owner_approved_preflight_release_package import ( - load_latest_ai_agent_result_capture_owner_approved_preflight_release_package, -) -from src.services.ai_agent_result_capture_owner_approved_release_readiness_readback import ( - load_latest_ai_agent_result_capture_owner_approved_release_readiness_readback, -) -from src.services.ai_agent_result_capture_owner_release_approval_gate import ( - load_latest_ai_agent_result_capture_owner_release_approval_gate, -) -from src.services.ai_agent_result_capture_final_release_candidate_readback import ( - load_latest_ai_agent_result_capture_final_release_candidate_readback, -) -from src.services.ai_agent_result_capture_release_authorization_hold import ( - load_latest_ai_agent_result_capture_release_authorization_hold, -) -from src.services.ai_agent_result_capture_release_authorization_readback_gate import ( - load_latest_ai_agent_result_capture_release_authorization_readback_gate, -) -from src.services.ai_agent_result_capture_release_verifier_preflight_gate import ( - load_latest_ai_agent_result_capture_release_verifier_preflight_gate, -) -from src.services.ai_agent_result_capture_release_verifier_owner_review_packet import ( - load_latest_ai_agent_result_capture_release_verifier_owner_review_packet, -) -from src.services.ai_agent_result_capture_post_release_verifier_rollback_gate import ( - load_latest_ai_agent_result_capture_post_release_verifier_rollback_gate, -) -from src.services.ai_agent_result_capture_promotion_approval_gate import ( - load_latest_ai_agent_result_capture_promotion_approval_gate, -) -from src.services.ai_agent_result_capture_write_gate_review import ( - load_latest_ai_agent_result_capture_write_gate_review, -) -from src.services.ai_agent_result_capture_writer_implementation_review import ( - load_latest_ai_agent_result_capture_writer_implementation_review, -) -from src.services.ai_agent_result_capture_writer_dry_run_fixture import ( - load_latest_ai_agent_result_capture_writer_dry_run_fixture, -) -from src.services.ai_agent_result_capture_writer_dry_run_readback import ( - load_latest_ai_agent_result_capture_writer_dry_run_readback, -) -from src.services.ai_agent_runtime_readback_approval_package import ( - load_latest_ai_agent_runtime_readback_approval_package, -) -from src.services.ai_agent_runtime_readback_implementation_review import ( - load_latest_ai_agent_runtime_readback_implementation_review, -) -from src.services.ai_agent_runtime_readback_fixture_approval import ( - load_latest_ai_agent_runtime_readback_fixture_approval, -) -from src.services.ai_agent_runtime_readback_promotion_gate import ( - load_latest_ai_agent_runtime_readback_promotion_gate, +from src.services.ai_agent_report_automation_review import ( + load_latest_ai_agent_report_automation_review, ) from src.services.ai_agent_report_live_delivery_approval_package import ( load_latest_ai_agent_report_live_delivery_approval_package, ) -from src.services.ai_agent_report_automation_review import ( - load_latest_ai_agent_report_automation_review, +from src.services.ai_agent_report_no_write_analysis_runtime import ( + load_latest_ai_agent_report_no_write_analysis_runtime, ) from src.services.ai_agent_report_runtime_dry_run import ( load_latest_ai_agent_report_runtime_dry_run, @@ -247,20 +151,119 @@ from src.services.ai_agent_report_runtime_fixture_readback import ( from src.services.ai_agent_report_runtime_readiness import ( load_latest_ai_agent_report_runtime_readiness, ) +from src.services.ai_agent_report_source_health import ( + build_ai_agent_report_source_health, +) from src.services.ai_agent_report_status_board import ( load_latest_ai_agent_report_status_board, ) from src.services.ai_agent_report_truth_actionability_review import ( load_latest_ai_agent_report_truth_actionability_review, ) +from src.services.ai_agent_result_capture_final_release_candidate_readback import ( + load_latest_ai_agent_result_capture_final_release_candidate_readback, +) +from src.services.ai_agent_result_capture_no_write_readback import ( + load_latest_ai_agent_result_capture_no_write_readback, +) +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_owner_approved_execution_rehearsal import ( + load_latest_ai_agent_result_capture_owner_approved_execution_rehearsal, +) +from src.services.ai_agent_result_capture_owner_approved_preflight_release_package import ( + load_latest_ai_agent_result_capture_owner_approved_preflight_release_package, +) +from src.services.ai_agent_result_capture_owner_approved_release_readiness_readback import ( + load_latest_ai_agent_result_capture_owner_approved_release_readiness_readback, +) +from src.services.ai_agent_result_capture_owner_promotion_review import ( + load_latest_ai_agent_result_capture_owner_promotion_review, +) +from src.services.ai_agent_result_capture_owner_release_approval_gate import ( + load_latest_ai_agent_result_capture_owner_release_approval_gate, +) +from src.services.ai_agent_result_capture_post_release_verifier_rollback_gate import ( + load_latest_ai_agent_result_capture_post_release_verifier_rollback_gate, +) +from src.services.ai_agent_result_capture_promotion_approval_gate import ( + load_latest_ai_agent_result_capture_promotion_approval_gate, +) +from src.services.ai_agent_result_capture_release_authorization_hold import ( + load_latest_ai_agent_result_capture_release_authorization_hold, +) +from src.services.ai_agent_result_capture_release_authorization_readback_gate import ( + load_latest_ai_agent_result_capture_release_authorization_readback_gate, +) +from src.services.ai_agent_result_capture_release_decision_hold import ( + load_latest_ai_agent_result_capture_release_decision_hold, +) +from src.services.ai_agent_result_capture_release_decision_input_prep import ( + load_latest_ai_agent_result_capture_release_decision_input_prep, +) +from src.services.ai_agent_result_capture_release_decision_next_handoff import ( + load_latest_ai_agent_result_capture_release_decision_next_handoff, +) +from src.services.ai_agent_result_capture_release_decision_owner_response_acceptance_gate import ( + load_latest_ai_agent_result_capture_release_decision_owner_response_acceptance_gate, +) +from src.services.ai_agent_result_capture_release_decision_owner_response_preflight import ( + load_latest_ai_agent_result_capture_release_decision_owner_response_preflight, +) +from src.services.ai_agent_result_capture_release_decision_owner_response_readback import ( + load_latest_ai_agent_result_capture_release_decision_owner_response_readback, +) +from src.services.ai_agent_result_capture_release_decision_readback import ( + load_latest_ai_agent_result_capture_release_decision_readback, +) +from src.services.ai_agent_result_capture_release_verifier_owner_review_packet import ( + load_latest_ai_agent_result_capture_release_verifier_owner_review_packet, +) +from src.services.ai_agent_result_capture_release_verifier_preflight_gate import ( + load_latest_ai_agent_result_capture_release_verifier_preflight_gate, +) +from src.services.ai_agent_result_capture_write_gate_review import ( + load_latest_ai_agent_result_capture_write_gate_review, +) +from src.services.ai_agent_result_capture_writer_dry_run_fixture import ( + load_latest_ai_agent_result_capture_writer_dry_run_fixture, +) +from src.services.ai_agent_result_capture_writer_dry_run_readback import ( + load_latest_ai_agent_result_capture_writer_dry_run_readback, +) +from src.services.ai_agent_result_capture_writer_implementation_review import ( + load_latest_ai_agent_result_capture_writer_implementation_review, +) +from src.services.ai_agent_reviewer_queue_no_write_readback import ( + load_latest_ai_agent_reviewer_queue_no_write_readback, +) +from src.services.ai_agent_runtime_readback_approval_package import ( + load_latest_ai_agent_runtime_readback_approval_package, +) +from src.services.ai_agent_runtime_readback_fixture_approval import ( + load_latest_ai_agent_runtime_readback_fixture_approval, +) +from src.services.ai_agent_runtime_readback_implementation_review import ( + load_latest_ai_agent_runtime_readback_implementation_review, +) +from src.services.ai_agent_runtime_readback_promotion_gate import ( + load_latest_ai_agent_runtime_readback_promotion_gate, +) +from src.services.ai_agent_runtime_verifier_evidence_review import ( + load_latest_ai_agent_runtime_verifier_evidence_review, +) from src.services.ai_agent_runtime_worker_shadow_gate import ( load_latest_ai_agent_runtime_worker_shadow_gate, ) from src.services.ai_agent_runtime_write_gate_review import ( load_latest_ai_agent_runtime_write_gate_review, ) -from src.services.ai_agent_runtime_verifier_evidence_review import ( - load_latest_ai_agent_runtime_verifier_evidence_review, +from src.services.ai_agent_task_result_audit_trail import ( + load_latest_ai_agent_task_result_audit_trail, ) from src.services.ai_agent_telegram_action_required_digest_policy import ( load_latest_ai_agent_telegram_action_required_digest_policy, @@ -268,9 +271,6 @@ from src.services.ai_agent_telegram_action_required_digest_policy import ( from src.services.ai_agent_telegram_receipt_approval_package import ( load_latest_ai_agent_telegram_receipt_approval_package, ) -from src.services.ai_agent_task_result_audit_trail import ( - load_latest_ai_agent_task_result_audit_trail, -) from src.services.ai_agent_tool_adoption_approval_package import ( load_latest_ai_agent_tool_adoption_approval_package, ) @@ -310,6 +310,9 @@ from src.services.docker_build_surface_inventory import ( from src.services.gitea_workflow_runner_health import ( load_latest_gitea_workflow_runner_health, ) +from src.services.host_runaway_aiops_loop_readiness import ( + load_latest_host_runaway_aiops_loop_readiness, +) from src.services.javascript_package_inventory import ( load_latest_javascript_package_inventory, ) @@ -325,10 +328,10 @@ from src.services.package_supply_chain_inventory import ( from src.services.product_code_review_gate import ( load_latest_product_code_review_gate, ) +from src.services.public_redaction import redact_public_lan_topology from src.services.runtime_surface_inventory import ( load_latest_runtime_surface_inventory, ) -from src.services.public_redaction import redact_public_lan_topology from src.services.service_health_failure_notification_policy import ( load_latest_service_health_failure_notification_policy, ) @@ -939,6 +942,36 @@ async def get_agent_high_risk_owner_review_queue() -> dict[str, Any]: ) from exc +@router.get( + "/agent-action-audit-ledger", + response_model=dict[str, Any], + summary="取得 P2-410 AI Agent 行動審計帳本", + description=( + "讀取最新已提交的 P2-410 AI Agent 行動審計帳本快照;此端點只呈現 " + "immutable audit event template、source readback、verifier receipt gate、redaction contract " + "與 no-write activation boundary。它不寫 audit DB、不寫 timeline、不寫 KM、不更新 PlayBook trust、" + "不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 production、不讀 secret、" + "不呼叫付費 API、不改主機、不執行 kubectl 或不可逆操作。" + ), +) +async def get_agent_action_audit_ledger() -> dict[str, Any]: + """回傳最新 P2-410 action audit ledger 只讀快照。""" + try: + payload = await asyncio.to_thread(load_latest_ai_agent_action_audit_ledger) + 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_action_audit_ledger_invalid", error=str(exc)) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="P2-410 AI Agent 行動審計帳本快照無效", + ) from exc + + @router.get( "/agent-host-runaway-aiops-loop-readiness", response_model=dict[str, Any], diff --git a/apps/api/src/services/ai_agent_action_audit_ledger.py b/apps/api/src/services/ai_agent_action_audit_ledger.py new file mode 100644 index 000000000..7388106fd --- /dev/null +++ b/apps/api/src/services/ai_agent_action_audit_ledger.py @@ -0,0 +1,323 @@ +""" +P2-410 AI Agent action audit ledger snapshot. + +Loads the latest committed action audit ledger. This module validates read-only +event templates and verifier receipt gates. It never writes audit DB rows, +timeline events, KM, PlayBook trust, Gateway queues, Telegram messages, secrets, +hosts, Kubernetes resources, or production state. +""" + +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_action_audit_ledger_*.json" +_SCHEMA_VERSION = "ai_agent_action_audit_ledger_v1" +_RUNTIME_AUTHORITY = "agent_action_audit_ledger_no_live_write_committed_snapshot" +_EXPECTED_CURRENT_TASK = "P2-410" +_EXPECTED_NEXT_TASK = "P2-411" +_EXPECTED_SOURCE_SCHEMAS = { + "ai_agent_low_medium_risk_whitelist_v1", + "ai_agent_high_risk_owner_review_queue_v1", + "ai_agent_task_result_audit_trail_v1", + "awoooi_sre_digest_no_send_preview_v1", + "awoooi_work_items_report_source_gap_owner_review_v1", + "telegram_notification_egress_no_new_bypass_guard_v1", + "governance_automation_inventory_readback_v1", +} +_TRUE_TRUTH_FLAGS = { + "p2_408_whitelist_loaded", + "p2_409_owner_queue_loaded", + "p2_103_result_audit_loaded", + "p2_110c_sre_digest_loaded", + "p2_110e_work_items_loaded", + "telegram_no_new_bypass_loaded", + "audit_event_templates_ready", + "verifier_receipt_gates_ready", + "immutable_event_required", + "redacted_evidence_refs_required", + "read_only_mode", +} +_FALSE_TRUTH_FLAGS = { + "audit_db_write_enabled", + "timeline_write_enabled", + "km_write_enabled", + "playbook_trust_write_enabled", + "gateway_queue_write_enabled", + "telegram_send_enabled", + "bot_api_call_enabled", + "receipt_production_write_enabled", + "production_write_enabled", + "secret_read_enabled", + "paid_api_call_enabled", + "host_write_enabled", + "kubectl_action_enabled", + "destructive_operation_enabled", +} +_ZERO_TRUTH_COUNTS = { + "audit_db_write_count_24h", + "timeline_write_count_24h", + "km_write_count_24h", + "playbook_trust_write_count_24h", + "gateway_queue_write_count_24h", + "telegram_send_count_24h", + "bot_api_call_count_24h", + "receipt_production_write_count_24h", + "production_write_count_24h", + "secret_read_count_24h", + "paid_api_call_count_24h", + "host_write_count_24h", + "kubectl_action_count_24h", + "destructive_operation_count_24h", +} +_FALSE_EVENT_FLAGS = { + "audit_db_write_allowed", + "timeline_write_allowed", + "km_write_allowed", + "playbook_trust_write_allowed", + "gateway_queue_write_allowed", + "telegram_send_allowed", + "production_write_allowed", +} +_FALSE_BOUNDARY_FLAGS = _FALSE_TRUTH_FLAGS +_ZERO_ROLLUP_FIELDS = { + "audit_db_write_count", + "timeline_write_count", + "km_write_count", + "playbook_trust_write_count", + "gateway_queue_write_count", + "telegram_send_count", + "bot_api_call_count", + "receipt_production_write_count", + "production_write_count", + "secret_read_count", + "paid_api_call_count", + "host_write_count", + "kubectl_action_count", + "destructive_operation_count", + "owner_response_received_count", + "owner_response_accepted_count", +} +_FORBIDDEN_PUBLIC_TERMS = { + "批准" + "!", + "In app " + "browser", + "My request for " + "Codex", + "codex_" + "delegation", + "source_" + "thread_id", + "chain_of_thought", + "private reasoning text", + "authorization_header", + "telegram token value", + "raw_payload", + "raw prompt", + "internal collaboration transcript", +} + + +def load_latest_ai_agent_action_audit_ledger( + evaluations_dir: Path | None = None, +) -> dict[str, Any]: + """Load the newest committed P2-410 action audit ledger snapshot.""" + directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR + candidates = sorted(directory.glob(_SNAPSHOT_PATTERN)) + if not candidates: + raise FileNotFoundError(f"no AI Agent action audit ledger 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_sources(payload, label) + _require_audit_truth(payload, label) + _require_audit_event_templates(payload, label) + _require_verifier_receipt_gates(payload, label) + _require_activation_boundaries(payload, label) + _require_redaction_contract(payload, label) + _require_rollups(payload, label) + _require_no_forbidden_public_terms(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 = { + "overall_completion_percent": 100, + "current_priority": "P0", + "current_task_id": _EXPECTED_CURRENT_TASK, + "next_task_id": _EXPECTED_NEXT_TASK, + "read_only_mode": True, + "runtime_authority": _RUNTIME_AUTHORITY, + } + 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_sources(payload: dict[str, Any], label: str) -> None: + if not payload.get("source_refs"): + raise ValueError(f"{label}: source_refs must not be empty") + sources = payload.get("source_readbacks") or [] + schemas = {item.get("source_schema_version") for item in sources} + missing = sorted(_EXPECTED_SOURCE_SCHEMAS - schemas) + if missing: + raise ValueError(f"{label}: missing source schemas: {missing}") + for item in sources: + readback_id = item.get("readback_id") or "" + for field in ("source_ref", "endpoint", "owner_agent", "status", "key_readback", "next_action"): + if not item.get(field): + raise ValueError(f"{label}: source readback {readback_id} missing {field}") + + +def _require_audit_truth(payload: dict[str, Any], label: str) -> None: + truth = payload.get("audit_truth") or {} + missing_true = sorted(flag for flag in _TRUE_TRUTH_FLAGS if truth.get(flag) is not True) + if missing_true: + raise ValueError(f"{label}: audit truth flags must remain true: {missing_true}") + unsafe_false = sorted(flag for flag in _FALSE_TRUTH_FLAGS if truth.get(flag) is not False) + if unsafe_false: + raise ValueError(f"{label}: audit truth flags must remain false: {unsafe_false}") + non_zero = sorted(field for field in _ZERO_TRUTH_COUNTS if truth.get(field) != 0) + if non_zero: + raise ValueError(f"{label}: audit truth counts must remain zero: {non_zero}") + if not truth.get("truth_note"): + raise ValueError(f"{label}: audit_truth.truth_note is required") + + +def _require_audit_event_templates(payload: dict[str, Any], label: str) -> None: + events = payload.get("audit_event_templates") or [] + if not events: + raise ValueError(f"{label}: audit_event_templates must not be empty") + source_ids = {item.get("readback_id") for item in payload.get("source_readbacks") or []} + risk_tiers = {event.get("risk_tier") for event in events} + if not {"low", "medium", "high", "critical"}.issubset(risk_tiers): + raise ValueError(f"{label}: audit event templates must cover low, medium, high, and critical") + for event in events: + event_id = event.get("audit_event_id") or "" + if event.get("immutable_event_required") is not True: + raise ValueError(f"{label}: event {event_id}.immutable_event_required must remain true") + unsafe = sorted(flag for flag in _FALSE_EVENT_FLAGS if event.get(flag) is not False) + if unsafe: + raise ValueError(f"{label}: event {event_id} write/send flags must remain false: {unsafe}") + if event.get("side_effect_count") != 0: + raise ValueError(f"{label}: event {event_id}.side_effect_count must remain zero") + for field in ("source_readback_ids", "required_audit_fields", "required_evidence_refs", "blocked_writes", "next_gate"): + if not event.get(field): + raise ValueError(f"{label}: event {event_id} missing {field}") + missing_sources = sorted(set(event.get("source_readback_ids") or []) - source_ids) + if missing_sources: + raise ValueError(f"{label}: event {event_id} references missing source readbacks: {missing_sources}") + + +def _require_verifier_receipt_gates(payload: dict[str, Any], label: str) -> None: + gates = payload.get("verifier_receipt_gates") or [] + if len(gates) < 1: + raise ValueError(f"{label}: verifier_receipt_gates must not be empty") + for gate in gates: + gate_id = gate.get("gate_id") or "" + if not gate.get("required_checks"): + raise ValueError(f"{label}: verifier gate {gate_id} missing required_checks") + if not gate.get("failure_if_missing"): + raise ValueError(f"{label}: verifier gate {gate_id} missing failure_if_missing") + for field in ("live_verifier_allowed", "receipt_write_allowed", "runtime_action_allowed"): + if gate.get(field) is not False: + raise ValueError(f"{label}: verifier gate {gate_id}.{field} must remain false") + + +def _require_activation_boundaries(payload: dict[str, Any], label: str) -> None: + boundaries = payload.get("activation_boundaries") or {} + required_true = { + "committed_snapshot_read_allowed", + "audit_event_template_preview_allowed", + "verifier_receipt_gate_preview_allowed", + "governance_ui_projection_allowed", + } + missing = sorted(field for field in required_true if boundaries.get(field) is not True) + if missing: + raise ValueError(f"{label}: activation boundaries must remain true: {missing}") + unsafe = sorted(field for field in _FALSE_BOUNDARY_FLAGS if boundaries.get(field) is not False) + if unsafe: + raise ValueError(f"{label}: activation boundaries must remain false: {unsafe}") + + +def _require_redaction_contract(payload: dict[str, Any], label: str) -> None: + contract = payload.get("display_redaction_contract") or {} + required_false = { + "unsafe_payload_display_allowed", + "private_reasoning_display_allowed", + "secret_value_display_allowed", + "raw_prompt_display_allowed", + "work_window_transcript_display_allowed", + } + if contract.get("redaction_required") is not True: + raise ValueError(f"{label}: redaction_required must remain true") + unsafe = sorted(field for field in required_false if contract.get(field) is not False) + if unsafe: + raise ValueError(f"{label}: display redaction flags must remain false: {unsafe}") + if not contract.get("allowed_display_fields") or not contract.get("blocked_display_fields"): + raise ValueError(f"{label}: display redaction contract must list allowed and blocked fields") + + +def _require_rollups(payload: dict[str, Any], label: str) -> None: + rollups = payload.get("rollups") or {} + events = payload.get("audit_event_templates") or [] + gates = payload.get("verifier_receipt_gates") or [] + sources = payload.get("source_readbacks") or [] + expected_counts = { + "source_readback_count": len(sources), + "audit_event_template_count": len(events), + "verifier_receipt_gate_count": len(gates), + "low_medium_event_count": sum(1 for event in events if event.get("risk_tier") in {"low", "medium"}), + "high_risk_event_count": sum(1 for event in events if event.get("risk_tier") == "high"), + "critical_event_count": sum(1 for event in events if event.get("risk_tier") == "critical"), + "report_gap_event_count": sum( + 1 for event in events if any("p2_110" in source for source in event.get("source_readback_ids") or []) + ), + "telegram_event_count": sum( + 1 + for event in events + if any("telegram" in source for source in event.get("source_readback_ids") or []) + ), + "required_audit_field_count": sum(len(event.get("required_audit_fields") or []) for event in events), + "blocked_runtime_action_count": len( + { + blocked + for event in events + for blocked in event.get("blocked_writes") or [] + } + ), + } + mismatches = _mismatches(rollups, expected_counts) + if mismatches: + raise ValueError(f"{label}: rollup counts mismatch: {mismatches}") + non_zero = sorted(field for field in _ZERO_ROLLUP_FIELDS if rollups.get(field) != 0) + if non_zero: + raise ValueError(f"{label}: live write/send rollups must remain zero: {non_zero}") + + +def _require_no_forbidden_public_terms(payload: dict[str, Any], label: str) -> None: + haystack = json.dumps(payload, ensure_ascii=False) + hits = sorted(term for term in _FORBIDDEN_PUBLIC_TERMS if term in haystack) + if hits: + raise ValueError(f"{label}: forbidden public terms detected: {hits}") + + +def _mismatches(source: dict[str, Any], expected: dict[str, Any]) -> dict[str, Any]: + return { + field: {"expected": value, "actual": source.get(field)} + for field, value in expected.items() + if source.get(field) != value + } diff --git a/apps/api/tests/test_ai_agent_action_audit_ledger.py b/apps/api/tests/test_ai_agent_action_audit_ledger.py new file mode 100644 index 000000000..216c57500 --- /dev/null +++ b/apps/api/tests/test_ai_agent_action_audit_ledger.py @@ -0,0 +1,133 @@ +from __future__ import annotations + +import copy +import json +from pathlib import Path + +import pytest + +from src.services.ai_agent_action_audit_ledger import ( + load_latest_ai_agent_action_audit_ledger, +) + +_REPO_ROOT = Path(__file__).resolve().parents[3] +_COMMITTED_SNAPSHOT = ( + _REPO_ROOT + / "docs" + / "evaluations" + / "ai_agent_action_audit_ledger_2026-06-19.json" +) + + +def test_load_latest_ai_agent_action_audit_ledger_reads_newest_file(tmp_path): + older = _snapshot(generated_at="2026-06-18T23:00:00+08:00") + newer = _snapshot(generated_at="2026-06-19T04:10:00+08:00") + (tmp_path / "ai_agent_action_audit_ledger_2026-06-18.json").write_text( + json.dumps(older), + encoding="utf-8", + ) + (tmp_path / "ai_agent_action_audit_ledger_2026-06-19.json").write_text( + json.dumps(newer), + encoding="utf-8", + ) + + loaded = load_latest_ai_agent_action_audit_ledger(tmp_path) + + assert loaded["generated_at"] == "2026-06-19T04:10:00+08:00" + assert loaded["program_status"]["current_task_id"] == "P2-410" + assert loaded["program_status"]["next_task_id"] == "P2-411" + assert loaded["rollups"]["audit_event_template_count"] == 8 + assert loaded["rollups"]["verifier_receipt_gate_count"] == 5 + assert loaded["rollups"]["telegram_send_count"] == 0 + + +def test_ai_agent_action_audit_ledger_requires_read_only_mode(tmp_path): + snapshot = _snapshot() + snapshot["program_status"]["read_only_mode"] = False + _write_snapshot(tmp_path, snapshot) + + with pytest.raises(ValueError, match="program_status"): + load_latest_ai_agent_action_audit_ledger(tmp_path) + + +def test_ai_agent_action_audit_ledger_blocks_audit_db_write(tmp_path): + snapshot = _snapshot() + snapshot["audit_truth"]["audit_db_write_enabled"] = True + _write_snapshot(tmp_path, snapshot) + + with pytest.raises(ValueError, match="audit_db_write_enabled"): + load_latest_ai_agent_action_audit_ledger(tmp_path) + + +def test_ai_agent_action_audit_ledger_blocks_event_gateway_write(tmp_path): + snapshot = _snapshot() + snapshot["audit_event_templates"][0]["gateway_queue_write_allowed"] = True + _write_snapshot(tmp_path, snapshot) + + with pytest.raises(ValueError, match="gateway_queue_write_allowed"): + load_latest_ai_agent_action_audit_ledger(tmp_path) + + +def test_ai_agent_action_audit_ledger_requires_all_risk_tiers(tmp_path): + snapshot = _snapshot() + for event in snapshot["audit_event_templates"]: + event["risk_tier"] = "medium" + _write_snapshot(tmp_path, snapshot) + + with pytest.raises(ValueError, match="low, medium, high, and critical"): + load_latest_ai_agent_action_audit_ledger(tmp_path) + + +def test_ai_agent_action_audit_ledger_rejects_missing_source_ref(tmp_path): + snapshot = _snapshot() + snapshot["audit_event_templates"][0]["source_readback_ids"] = ["missing_source"] + _write_snapshot(tmp_path, snapshot) + + with pytest.raises(ValueError, match="missing source readbacks"): + load_latest_ai_agent_action_audit_ledger(tmp_path) + + +def test_ai_agent_action_audit_ledger_blocks_verifier_live_mode(tmp_path): + snapshot = _snapshot() + snapshot["verifier_receipt_gates"][0]["live_verifier_allowed"] = True + _write_snapshot(tmp_path, snapshot) + + with pytest.raises(ValueError, match="live_verifier_allowed"): + load_latest_ai_agent_action_audit_ledger(tmp_path) + + +def test_ai_agent_action_audit_ledger_requires_rollup_consistency(tmp_path): + snapshot = _snapshot() + snapshot["rollups"]["audit_event_template_count"] = 99 + _write_snapshot(tmp_path, snapshot) + + with pytest.raises(ValueError, match="rollup counts"): + load_latest_ai_agent_action_audit_ledger(tmp_path) + + +def test_ai_agent_action_audit_ledger_rejects_private_terms(tmp_path): + snapshot = _snapshot() + snapshot["audit_event_templates"][0]["display_name"] = "請把 " + "In app " + "browser" + " 內容放進前端" + _write_snapshot(tmp_path, snapshot) + + with pytest.raises(ValueError, match="forbidden public terms"): + load_latest_ai_agent_action_audit_ledger(tmp_path) + + +def test_ai_agent_action_audit_ledger_fails_when_missing(tmp_path): + with pytest.raises(FileNotFoundError): + load_latest_ai_agent_action_audit_ledger(tmp_path) + + +def _snapshot(*, generated_at: str = "2026-06-19T04:10:00+08:00") -> dict: + payload = json.loads(_COMMITTED_SNAPSHOT.read_text(encoding="utf-8")) + cloned = copy.deepcopy(payload) + cloned["generated_at"] = generated_at + return cloned + + +def _write_snapshot(tmp_path, payload: dict) -> None: + (tmp_path / "ai_agent_action_audit_ledger_2026-06-19.json").write_text( + json.dumps(payload), + encoding="utf-8", + ) diff --git a/apps/api/tests/test_ai_agent_action_audit_ledger_api.py b/apps/api/tests/test_ai_agent_action_audit_ledger_api.py new file mode 100644 index 000000000..c2b9a5d70 --- /dev/null +++ b/apps/api/tests/test_ai_agent_action_audit_ledger_api.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from fastapi import FastAPI +from fastapi.testclient import TestClient + +from src.api.v1.agents import router + + +def test_ai_agent_action_audit_ledger_endpoint_returns_committed_snapshot(): + app = FastAPI() + app.include_router(router, prefix="/api/v1") + client = TestClient(app) + + response = client.get("/api/v1/agents/agent-action-audit-ledger") + + assert response.status_code == 200 + data = response.json() + assert data["schema_version"] == "ai_agent_action_audit_ledger_v1" + assert data["program_status"]["current_task_id"] == "P2-410" + assert data["program_status"]["next_task_id"] == "P2-411" + assert data["program_status"]["read_only_mode"] is True + assert ( + data["program_status"]["runtime_authority"] + == "agent_action_audit_ledger_no_live_write_committed_snapshot" + ) + assert data["rollups"]["source_readback_count"] == len(data["source_readbacks"]) == 7 + assert data["rollups"]["audit_event_template_count"] == len(data["audit_event_templates"]) == 8 + assert data["rollups"]["verifier_receipt_gate_count"] == len(data["verifier_receipt_gates"]) == 5 + assert data["rollups"]["low_medium_event_count"] == 4 + assert data["rollups"]["high_risk_event_count"] == 3 + assert data["rollups"]["critical_event_count"] == 1 + assert data["rollups"]["report_gap_event_count"] == 2 + assert data["rollups"]["telegram_event_count"] == 2 + assert data["rollups"]["blocked_runtime_action_count"] == 23 + assert data["rollups"]["audit_db_write_count"] == 0 + assert data["rollups"]["timeline_write_count"] == 0 + assert data["rollups"]["km_write_count"] == 0 + assert data["rollups"]["playbook_trust_write_count"] == 0 + assert data["rollups"]["gateway_queue_write_count"] == 0 + assert data["rollups"]["telegram_send_count"] == 0 + assert data["rollups"]["bot_api_call_count"] == 0 + assert data["rollups"]["production_write_count"] == 0 + assert data["activation_boundaries"]["committed_snapshot_read_allowed"] is True + assert data["activation_boundaries"]["audit_db_write_enabled"] is False + assert data["activation_boundaries"]["telegram_send_enabled"] is False + assert data["display_redaction_contract"]["redaction_required"] is True + assert data["display_redaction_contract"]["secret_value_display_allowed"] is False diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 7fc52ba97..157d3a29a 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,35 @@ +## 2026-06-19|P2-410 AI Agent action audit ledger 本地 API 完成 + +**背景**:P2-408 已把中 / 低風險候選、dry-run verifier、rollback proof 與高風險分流固定成只讀合約;P2-409 已把 high / critical、Telegram / Gateway / Bot API、host / kubectl、secret / paid provider 與報表缺口工作項固定進 Owner Review Queue。但若沒有一份 action audit ledger,AI Agent 後續每次分類、拒收、轉人工、no-send 預覽與 runtime 阻擋都會停留在畫面或文件敘述,無法成為可驗證、可回放、可被 verifier receipt gate 接手的事件模板。 + +**完成內容**: +- 新增 `docs/schemas/ai_agent_action_audit_ledger_v1.schema.json`。 +- 新增 `docs/evaluations/ai_agent_action_audit_ledger_2026-06-19.json`。 +- 新增 `apps/api/src/services/ai_agent_action_audit_ledger.py` 與 `GET /api/v1/agents/agent-action-audit-ledger`。 +- 新增 `apps/api/tests/test_ai_agent_action_audit_ledger.py` 與 `apps/api/tests/test_ai_agent_action_audit_ledger_api.py`。 +- P2-410 固定 current `P2-410`、next `P2-411`、runtime authority `agent_action_audit_ledger_no_live_write_committed_snapshot`。 +- P2-410 固定來源讀回 `7`、audit event template `8`、low / medium event `4`、high-risk event `3`、critical event `1`、report gap event `2`、Telegram event `2`、verifier receipt gate `5`、required audit field `48`、blocked runtime action `23`。 +- Audit event template 已涵蓋 low-risk candidate classified、medium-risk dry-run hold、high-risk owner queue pause、critical runtime action rejected、report source gap work item reviewed、SRE digest no-send preview、Telegram no-new-bypass guard 與 result route writeback blocked。 +- Verifier receipt gate 已固定 event source ref、redacted evidence ref、no-send / no-queue boundary、owner acceptance missing hold 與 postcheck plan required。 + +**驗證**: +- `python3 -m json.tool docs/schemas/ai_agent_action_audit_ledger_v1.schema.json` 通過。 +- `python3 -m json.tool docs/evaluations/ai_agent_action_audit_ledger_2026-06-19.json` 通過。 +- `PYTHONPATH=apps/api python3 -m py_compile apps/api/src/services/ai_agent_action_audit_ledger.py apps/api/src/api/v1/agents.py apps/api/tests/test_ai_agent_action_audit_ledger.py apps/api/tests/test_ai_agent_action_audit_ledger_api.py` 通過。 +- `DATABASE_URL=postgresql://test:test@localhost:5432/test PYTHONPATH=apps/api PYTHONFAULTHANDLER=1 python3.11 -m pytest apps/api/tests/test_ai_agent_action_audit_ledger.py apps/api/tests/test_ai_agent_action_audit_ledger_api.py -q`:`11 passed`。 +- P2-409 + P2-410 regression:`DATABASE_URL=postgresql://test:test@localhost:5432/test PYTHONPATH=apps/api PYTHONFAULTHANDLER=1 python3.11 -m pytest apps/api/tests/test_ai_agent_high_risk_owner_review_queue.py apps/api/tests/test_ai_agent_high_risk_owner_review_queue_api.py apps/api/tests/test_ai_agent_action_audit_ledger.py apps/api/tests/test_ai_agent_action_audit_ledger_api.py -q`:`24 passed`。 + +**完成度同步**: +- P2-410 Agent action audit ledger:本地 API / schema / snapshot / tests `100%`,正式部署 / production API readback / governance UI projection `0% -> 待推版驗證`。 +- AgentOps 治理與可觀測基礎:`87% -> 88%`。 +- 中低風險自動化:`60% -> 62%`;P2-410 已補行動帳本與 verifier receipt gate,但 auto worker 仍未開。 +- 高風險審核:`78% -> 80%`;P2-410 可記錄 pause / rejection / owner queue,但 owner response accepted 仍為 `0`。 +- Telegram Bot / TG 群組契約:`48% -> 50%`;no-send 與 no-new-bypass audit template 已建立,實發仍 `0%`。 +- 日報 / 週報 / 月報產品化總控:`92% -> 94%`;report source gap 與 SRE digest no-send preview 已能轉成 audit event template,仍未實發 Telegram。 +- IwoooS headline 仍維持 `64%`,active runtime gate 仍 `0`。 + +**邊界**:本段沒有 owner response accepted、沒有 audit DB write、沒有 timeline write、沒有 KM write、沒有 PlayBook trust update、沒有 Gateway queue write、沒有 Telegram send、沒有 Bot API call、沒有 receipt production write、沒有 production write、沒有 secret read、沒有 paid API call、沒有 host write、沒有 kubectl action、沒有 destructive operation、沒有 runtime gate、沒有 action button。P2-410 是可驗證的 action audit readback 合約,不是 runtime 修復已啟動。 + ## 2026-06-19|Telegram 通知出口 owner response 驗收帳本與 no-new-bypass guard **背景**:Telegram 通知出口清冊已固定 repo 內 `18` 個 direct Bot API `sendMessage` call site,並完成 11 份 owner request 草稿與三個 no-runtime 遷移波次。但若只有清冊與遷移草稿,仍無法阻止新 direct Bot API 旁路繼續出現,也無法讓 reviewer 判斷 owner response 是否合格、是否夾帶 secret / raw payload、是否把 CD success / route 200 / UI 可見誤當 delivery receipt。 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 1eb2be764..018fb043f 100644 --- a/docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md +++ b/docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md @@ -13,13 +13,13 @@ | 項目 | 目前完成度 | 本次判讀 | 下一個有效動作 | |---|---:|---|---| | 本工作清單細化 | 100% | 已把所有工作流拆成 P0 / P1 / P2 / P3 | 同步 LOGBOOK 與 MASTER §8 | -| AgentOps 治理與可觀測基礎 | 87% | 已有 schema / snapshot / API / UI / gate;P2-407 已正式把日報 / 週報 / 月報、P2-406B receipt owner review、P2-004 drift monitor 與 P2-403J 報表真相串成 no-write 分析草稿;P2-408 已正式部署中 / 低風險白名單、dry-run verifier、rollback proof、audit reason 與 production readback;P2-409 已本地完成高風險 Owner Review Queue、approval packet、rejection guard 與 reviewer checklist;runtime 真正執行仍低 | P2-409 正式部署驗證;P2-410 Agent action audit ledger;補 Runs mobile smoke;Observability / Tenants / Knowledge Base 接同一資產沉澱總帳 | +| AgentOps 治理與可觀測基礎 | 88% | 已有 schema / snapshot / API / UI / gate;P2-407 已正式把日報 / 週報 / 月報、P2-406B receipt owner review、P2-004 drift monitor 與 P2-403J 報表真相串成 no-write 分析草稿;P2-408 已正式部署中 / 低風險白名單、dry-run verifier、rollback proof、audit reason 與 production readback;P2-409 已本地完成高風險 Owner Review Queue;P2-410 已本地完成 action audit ledger、event template、verifier receipt gate 與 no-write API | P2-409 / P2-410 正式部署驗證;P2-411 Agent Event Bus 與 handoff protocol;補 Runs mobile smoke;Observability / Tenants / Knowledge Base 接同一資產沉澱總帳 | | OpenClaw / Hermes / NemoTron 佈建布局 | 45% | 目前是只讀 layout 與治理頁可視化,不是主機上 live agent worker | 建立 runtime agent registry 與 AgentSession ledger | | Agent 主動溝通 / 接手 / 學習 | 設計證據 100%,runtime 35% | 互動證據、War Room 與 readback gate 已齊;Event Bus、RAG writeback、PlayBook trust 寫入仍未開 | 先做 no-write event stream,再做 Owner-approved writeback | | 日報 / 週報 / 月報 | 可視化 100%,no-write 分析 100%,實發 0% | 報表批准包、P2-406B owner review、P2-407 no-write analyst 與治理頁已可見;Telegram 實發、receipt production write、AI analysis live runtime 仍為 0 | P2-408 白名單與 P2-406F no-send scheduler | -| Telegram Bot / TG 群組 | 契約 48%,實發 0% | no-send preview、dry-run、owner review gate、P2-406B receipt readback owner review、Telegram egress inventory / owner request draft 與 P2-409 高風險 queue 已串起;live send / Bot API / Gateway queue 未批准 | P2-409 正式驗證;P2-406D no-send envelope ledger、P2-406E failure-only digest route;收到合格 owner approval 後才評估 P2-406C one-message canary | -| 中低風險自動化 | 60% | P2-408 已正式部署 6 筆候選白名單、5 個 dry-run verifier、5 個 rollback proof、6 個 audit reason 與 3 類高風險分流;P2-409 已把 high / critical 與 medium live execution 風險接到 Owner Review Queue;實際 auto worker 仍未開 | P2-410 Agent action audit ledger;之後才評估 dry-run auto worker | -| 高風險審核 | 78% | P2-409 已本地完成 7 個 high / critical queue item、7 份 approval packet、8 條 rejection guard、7 份 reviewer checklist;所有高風險 action 都 pause,owner accepted 仍為 0 | P2-409 正式部署驗證;P2-410 audit ledger;P2-411 owner response acceptance readback | +| Telegram Bot / TG 群組 | 契約 50%,實發 0% | no-send preview、dry-run、owner review gate、P2-406B receipt readback owner review、Telegram egress inventory / owner request draft、P2-409 高風險 queue 與 P2-410 no-send / no-new-bypass audit template 已串起;live send / Bot API / Gateway queue 未批准 | P2-410 正式驗證;P2-406D no-send envelope ledger、P2-406E failure-only digest route;收到合格 owner approval 後才評估 P2-406C one-message canary | +| 中低風險自動化 | 62% | P2-408 已正式部署 6 筆候選白名單、5 個 dry-run verifier、5 個 rollback proof、6 個 audit reason 與 3 類高風險分流;P2-409 已把 high / critical 與 medium live execution 風險接到 Owner Review Queue;P2-410 已補 low / medium audit event、dry-run hold 與 verifier receipt gate;實際 auto worker 仍未開 | P2-410 正式驗證;P2-411 Event Bus;之後才評估 dry-run auto worker | +| 高風險審核 | 80% | P2-409 已本地完成 7 個 high / critical queue item、7 份 approval packet、8 條 rejection guard、7 份 reviewer checklist;P2-410 已補 high-risk pause、critical rejection 與 owner queue audit event;所有高風險 action 都 pause,owner accepted 仍為 0 | P2-409 / P2-410 正式部署驗證;P2-411 owner response acceptance readback | | 市場主流 Agent 追蹤 | 55% | 已有市場治理頁與 weekly watch;需擴充成固定外部來源評分與回放 | P2-412 週期性 market watch + scorecard | | 版本生命週期自動化 | 45% | repo-only snapshot 與採用批准包已完成;安裝、升級、PR creation、host update 仍未開 | P2-413 版本情報與 no-write upgrade proposal | @@ -68,8 +68,8 @@ | 7 | P2-407 | P0 | AI 報表自動分析 no-write runtime | Hermes + NemoTron | 正式驗證完成 | `ai_agent_report_no_write_analysis_runtime_v1` schema / snapshot / API / tests / governance UI 已正式部署;deploy marker `42c08ece`;production API 回 current `P2-407`、next `P2-408`、completion `100`;desktop / mobile smoke 可見 OpenClaw / Hermes / NemoTron、AwoooI SRE 戰情室與 `live total 0`;live AI runtime / Telegram / Gateway / Bot API / receipt production write / production write / secret read / paid API / host write / kubectl 仍為 0 | | 8 | P2-408 | P0 | 中 / 低風險自動處理白名單 | OpenClaw + SRE | 正式驗證完成 | `ai_agent_low_medium_risk_whitelist_v1` schema / snapshot / API / tests / governance UI 已正式部署;feature commit `b36f4b97`、deploy marker `cd1c4407`、Gitea code-review `#3209`、CD `#3208` success;production API 回 current `P2-408`、next `P2-409`、completion `100`;6 筆候選、3 low、3 medium、5 個 dry-run verifier、5 個 rollback proof、6 個 audit reason、3 類 high-risk redirect、3 個 owner gate、27 個 blocked runtime action;desktop / mobile smoke 可見 OpenClaw / Hermes / NemoTron、AwoooI SRE 戰情室與 `live total 0`;auto worker / Telegram / Gateway / Bot API / production write / secret read / paid API / host write / kubectl 仍為 0 | | 9 | P2-409 | P0 | 高風險 Owner Review Queue | OpenClaw | 本地完成,待正式部署驗證 | `ai_agent_high_risk_owner_review_queue_v1` schema / snapshot / API / tests / governance UI 已本地完成;7 個 high / critical queue item、7 份 approval packet、8 條 rejection guard、7 份 reviewer checklist、42 個 blocked runtime action;owner response accepted、live execution、Gateway queue、Telegram send、Bot API、receipt production write、production write、secret read、paid API、host write、kubectl、destructive operation 全部 `0` | -| 10 | P2-410 | P0 | Agent action audit ledger | Hermes + Security | 待辦 | 每次判斷、交接、建議、拒收、執行結果都有 immutable event | -| 11 | P2-411 | P1 | Agent Event Bus 與 handoff protocol | OpenClaw + Hermes + NemoTron | 待辦 | agent_message schema、handoff state、retry、dedup、trace_id | +| 10 | P2-410 | P0 | Agent action audit ledger | Hermes + Security | 本地 API 完成,待正式部署驗證 | `ai_agent_action_audit_ledger_v1` schema / snapshot / API / tests 已本地完成;7 個 source readback、8 個 audit event template、4 個 low / medium event、3 個 high-risk event、1 個 critical event、2 個 report gap event、2 個 Telegram event、5 個 verifier receipt gate、48 個 required audit field、23 個 blocked runtime action;audit DB / timeline / KM / PlayBook trust / Gateway / Telegram / Bot API / production write 全部 `0` | +| 11 | P2-411 | P1 | Agent Event Bus 與 handoff protocol | OpenClaw + Hermes + NemoTron | 待辦 | agent_message schema、handoff state、retry、dedup、trace_id,並承接 P2-410 audit event source ref | | 12 | P2-412 | P1 | 市場主流 AI Agent 定期評估 | Market + OpenClaw | 待辦 | 每週 primary-source watch、候選入池、scorecard、替換 gate | | 13 | P2-413 | P1 | AI Agent / 套件 / 工具 / 服務 / 主機版本生命週期 | DevOps + NemoTron | 待辦 | 版本 inventory、release diff、升級建議、PR 草稿 lane、rollback plan | | 14 | P2-414 | P1 | MCP tool registry / capability attestation | Security + DevOps | 待辦 | 工具能力、風險、scope、owner、consent、blocked actions 可讀 | @@ -148,7 +148,7 @@ |---|---:|---|---| | Agent 市場治理 | 72% | 進行中 | `agent_market_governance_snapshot_v1`、API、UI 分頁、每週觀察流程 | | Nemotron 實際整合應用 | 30% | 完整回放前仍被關卡擋下 | `blocked_needs_evidence`,下一關是 `refresh_source_evidence_then_5_record_smoke_only` | -| 工具 / 服務 / 套件 AI 自動化 | 99% | P2-004 依賴 / 供應鏈漂移監控讀回已完成,且已納入 P2-406B receipt readback owner review、P2-407 no-write analysis 與 P2-408 中 / 低風險白名單;Approvals / Runs / Alerts / Telegram 告警卡已能看到 KM / PlayBook / 腳本 / 排程 / Verifier 的沉澱狀態;下一主線是 P2-409 Owner Review Queue 與 Observability / Tenants / Knowledge Base 同款總帳 | 新增 `dependency_supply_chain_drift_monitor_v1`、`ai_agent_receipt_readback_owner_review_v1`、`ai_agent_report_no_write_analysis_runtime_v1`、`ai_agent_low_medium_risk_whitelist_v1` schema / snapshot / API / tests / governance UI 卡片;P2-408 已正式驗證 feature commit `b36f4b97` / deploy marker `cd1c4407`;9 個 drift candidate、5 個 P2-407 source readback、6 筆 draft recommendation、6 筆 P2-408 whitelist candidate、5 個 verifier、5 個 rollback proof;仍不得外部 CVE / license / registry / Agent market lookup、不得升級、不得寫 lockfile、不得 Docker build、不得 Telegram 實發 | +| 工具 / 服務 / 套件 AI 自動化 | 99% | P2-004 依賴 / 供應鏈漂移監控讀回已完成,且已納入 P2-406B receipt readback owner review、P2-407 no-write analysis、P2-408 中 / 低風險白名單、P2-409 高風險 Owner Review Queue 與 P2-410 action audit ledger;Approvals / Runs / Alerts / Telegram 告警卡已能看到 KM / PlayBook / 腳本 / 排程 / Verifier 的沉澱狀態;下一主線是 P2-411 Event Bus 與 Observability / Tenants / Knowledge Base 同款總帳 | 新增 `dependency_supply_chain_drift_monitor_v1`、`ai_agent_receipt_readback_owner_review_v1`、`ai_agent_report_no_write_analysis_runtime_v1`、`ai_agent_low_medium_risk_whitelist_v1`、`ai_agent_high_risk_owner_review_queue_v1`、`ai_agent_action_audit_ledger_v1` schema / snapshot / API / tests;P2-408 已正式驗證 feature commit `b36f4b97` / deploy marker `cd1c4407`;P2-409 / P2-410 目前本地完成、待正式驗證;仍不得外部 CVE / license / registry / Agent market lookup、不得升級、不得寫 lockfile、不得 Docker build、不得 Telegram 實發 | | 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-144 已完成只讀證據面、runtime / report / result-capture gates、no-write readback、promotion review、writer implementation review、writer dry-run fixture、writer dry-run readback、owner promotion execution gate、owner-approved execution rehearsal、owner acceptance / maintenance window gate、owner acceptance readback / preflight hold、owner-approved preflight release package、owner-approved release readiness readback、owner release approval gate、post-release verifier / rollback gate、final release candidate readback、release authorization hold / readback gate、release verifier preflight / owner review packet、release decision hold / readback、release decision next handoff、release decision input prep、12-Agent War Room、owner response 預檢與 owner response 回讀;P2-141 基線與 S4.9 owner release packet 補強皆已正式驗證,P2-142 12-Agent War Room 已完成 production readback 與 desktop / mobile smoke,P2-143 owner response 預檢已完成 production readback 與 in-app browser smoke,P2-144 owner response 回讀已完成 production API readback 與 desktop / mobile smoke。runtime worker、DB migration、production Redis consumer group、canonical runtime readback、live query、runtime score、result capture write、Telegram 實發、delivery receipt E2E、live report delivery、reviewer queue write、Gateway queue write、AI analysis runtime、中低風險 auto worker、KM / LOGBOOK / audit DB / timeline / PlayBook trust 寫入、SDK / 付費服務仍未開 gate | `ai_agent_result_capture_release_decision_owner_response_readback_v1`、`GET /api/v1/agents/agent-result-capture-release-decision-owner-response-readback`、`docs/evaluations/ai_agent_result_capture_release_decision_owner_response_readback_2026-06-14.json`、feature commit `8795f100`、deploy marker `ac938037`、Gitea code-review `2965` / CD `2964` success、5 個回覆讀回 lane、18 個 owner 必填欄位、6 個 readback validation check、6 個 rejection guard、5 個 operator action、等待外部回覆 `5`、未收件 lane `5`、正式寫入 / 發送 `0`;P2-142 feature commit `5de4b3f3`、deploy marker `1a2c9e36`、Gitea CD run `4232` success、production API readback、desktop / mobile in-app browser smoke;P2-143 feature commit `755b0a8d`、deploy marker `667d6329`、Gitea code-review `2961` / CD `2960` success、production API readback、desktop / mobile in-app browser smoke;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 | @@ -157,6 +157,8 @@ | P2-406B Receipt readback owner review | 100%(正式驗證完成) | 已把日報 / 週報 / 月報、P2-405F owner gate、Telegram receipt approval package、P2-004 drift monitor 與 P2-403J 報表真相整合成只讀 owner review,並完成 production API / desktop / mobile browser smoke | `ai_agent_receipt_readback_owner_review_v1` schema、`docs/evaluations/ai_agent_receipt_readback_owner_review_2026-06-18.json`、`GET /api/v1/agents/agent-receipt-readback-owner-review`、governance `automation-inventory` P2-406B 卡片;feature commit `649552a1`、deploy marker `2d278568`;6 個 source readback、3 個報告節奏、6 個 owner gate、8 個 receipt check、9 個 drift candidate、5 個 report truth blocker、17 個 runtime false boundary;本地 API/service regression `9 passed`;production API assert OK;desktop `1280x720` / mobile `390x844` 可見 P2-406B、AwoooI SRE 戰情室、OpenClaw / Hermes / NemoTron、`SRE_GROUP_CHAT_ID`;console error `0`、水平溢位 `0`、工作視窗片語命中 `0`;Telegram send / Gateway queue / Bot API / receipt production write / production write / secret read / paid API / host write / kubectl action 全部 `0 / false` | | P2-407 AI 報表 no-write 分析 runtime | 100%(正式驗證完成) | 已把日報 / 週報 / 月報、P2-406B receipt owner review、P2-004 drift monitor 與 P2-403J 報表真相收斂成只讀 AI 分析建議草稿,並完成 production API / desktop / mobile browser smoke;下一步是 P2-408 中 / 低風險自動處理白名單 | `ai_agent_report_no_write_analysis_runtime_v1` schema、`docs/evaluations/ai_agent_report_no_write_analysis_runtime_2026-06-18.json`、`GET /api/v1/agents/agent-report-no-write-analysis-runtime`、governance `automation-inventory` P2-407 卡片;feature commit `8548892f`、CD 修正 / 部署錨點 `adcf22cd` / `fc6c01ee` / `84ca8423` / `27143fb0`、deploy marker `42c08ece`、Gitea CD `#3177` success;5 個 source readback、3 份 report input、3 個 Agent analysis pass、6 筆 draft recommendation、4 個 draft artifact、3 個 owner review gate、9 個 blocked runtime action、2 筆需批准建議;production API assert PASS;desktop `1280x720` / mobile `390x844` 可見 P2-407、OpenClaw / Hermes / NemoTron、AwoooI SRE 戰情室、`live total 0`;console error `0`、水平溢位 `0`、工作視窗片語命中 `0`;Telegram send / Gateway queue / Bot API / receipt production write / production write / secret read / paid API / host write / kubectl action 全部 `0 / false` | | P2-408 中 / 低風險自動處理白名單 | 100%(正式驗證完成) | 已把 P2-407 no-write 分析建議轉成中 / 低風險候選白名單、dry-run verifier、rollback proof、audit reason 與高風險分流,並完成 production API / desktop / mobile browser smoke;下一步是 P2-409 Owner Review Queue | `ai_agent_low_medium_risk_whitelist_v1` schema、`docs/evaluations/ai_agent_low_medium_risk_whitelist_2026-06-18.json`、`GET /api/v1/agents/agent-low-medium-risk-whitelist`、governance `automation-inventory` P2-408 卡片;feature commit `b36f4b97`、deploy marker `cd1c4407`、Gitea code-review `#3209` / CD `#3208` success;6 筆 whitelist candidate、3 low、3 medium、5 個 dry-run verifier、5 個 rollback proof、6 個 audit reason、3 類 high-risk redirect、3 個 owner gate、27 個 blocked runtime action;本地 API/service regression `12 passed`;production API assert PASS;desktop `1280x720` / mobile `390x844` 可見 P2-408、OpenClaw / Hermes / NemoTron、AwoooI SRE 戰情室、`live total 0`;console error `0`、水平溢位 `0`、工作視窗片語命中 `0`;web typecheck 因本 worktree 缺 `apps/web/node_modules` / `tsc` 未執行;auto worker / low risk execution / medium risk execution / Telegram send / Gateway queue / Bot API / receipt production write / production write / secret read / paid API / host write / kubectl / destructive operation 全部 `0 / false` | +| P2-409 高風險 Owner Review Queue | 100%(本地完成,待正式驗證) | 已把 high / critical、Telegram / Gateway / Bot API、host / kubectl、secret / paid provider、report source gap work item write 與 OpenClaw 角色調整全部固定為 paused owner review;下一步是正式部署驗證與 P2-410 audit ledger | `ai_agent_high_risk_owner_review_queue_v1` schema、`docs/evaluations/ai_agent_high_risk_owner_review_queue_2026-06-19.json`、`GET /api/v1/agents/agent-high-risk-owner-review-queue`;7 個 source readback、7 個 queue item、5 個 high、2 個 critical、7 份 approval packet、8 條 rejection guard、7 份 reviewer checklist、42 個 blocked runtime action;本地 API/service regression `13 passed`;owner response accepted / live execution / Gateway / Telegram / Bot API / production write / secret read / paid API / host write / kubectl / destructive operation 全部 `0 / false` | +| P2-410 AI Agent action audit ledger | 100%(本地 API 完成,待正式驗證) | 已把 AI Agent 分類、拒收、no-send preview、high-risk pause、critical rejection 與 result route blocked 固定成 immutable audit event template 與 verifier receipt gate;下一步是 production API readback、governance projection 與 P2-411 Event Bus | `ai_agent_action_audit_ledger_v1` schema、`docs/evaluations/ai_agent_action_audit_ledger_2026-06-19.json`、`GET /api/v1/agents/agent-action-audit-ledger`;7 個 source readback、8 個 audit event template、4 個 low / medium event、3 個 high-risk event、1 個 critical event、2 個 report gap event、2 個 Telegram event、5 個 verifier receipt gate、48 個 required audit field、23 個 blocked runtime action;本地 API/service regression `11 passed`,P2-409 + P2-410 regression `24 passed`;audit DB / timeline / KM / PlayBook trust / Gateway / Telegram / Bot API / production write 全部 `0 / false` | | Owner response 預檢與拒收邊界 | 100% | P2-143 已完成正式部署與 production readback;承接 P2-141 input prep 與 P2-142 War Room,只建立 owner / verifier / rollback / maintenance / live-apply 五類外部回覆的 intake 預檢、必填欄位與拒收規則;正式 owner response 尚未收到、未接受、未寫入 | `ai_agent_result_capture_release_decision_owner_response_preflight_v1`、`GET /api/v1/agents/agent-result-capture-release-decision-owner-response-preflight`、feature commit `755b0a8d`、deploy marker `667d6329`、Gitea code-review `2961` / CD `2960` success、5 個 response intake lane、18 個 required owner field、6 個 validation check、6 個 rejection guard、5 個 operator action;owner response received / accepted / redacted payload / reviewer queue / Gateway / Telegram / Bot API / production write / secret read / destructive operation 全為 `0` | | Owner response 回讀狀態 | 100% | P2-144 已完成正式部署與 production readback;承接 P2-143 preflight,只讀回五類外部回覆仍未收到、未接受、未拒絕、未保存 | `ai_agent_result_capture_release_decision_owner_response_readback_v1`、`GET /api/v1/agents/agent-result-capture-release-decision-owner-response-readback`、feature commit `8795f100`、deploy marker `ac938037`、Gitea code-review `2965` / CD `2964` success、5 個 response readback lane、18 個 required owner field、6 個 readback validation check、6 個 readback rejection guard、5 個 operator action、waiting external response `5`、no external response received `5`;owner response received / accepted / redacted payload / reviewer queue / Gateway / Telegram / Bot API / production write / secret read / destructive operation 全為 `0` | | 本工作清單與分析報告 | 100% | 已完成 | 本 MD 文件 | diff --git a/docs/evaluations/ai_agent_action_audit_ledger_2026-06-19.json b/docs/evaluations/ai_agent_action_audit_ledger_2026-06-19.json new file mode 100644 index 000000000..456aa5ce1 --- /dev/null +++ b/docs/evaluations/ai_agent_action_audit_ledger_2026-06-19.json @@ -0,0 +1,436 @@ +{ + "schema_version": "ai_agent_action_audit_ledger_v1", + "generated_at": "2026-06-19T04:10:00+08:00", + "program_status": { + "overall_completion_percent": 100, + "current_priority": "P0", + "current_task_id": "P2-410", + "next_task_id": "P2-411", + "read_only_mode": true, + "runtime_authority": "agent_action_audit_ledger_no_live_write_committed_snapshot", + "status_note": "P2-410 把 P2-408 中低風險候選、P2-409 高風險 Owner Review Queue、P2-110C-E 報表資料源缺口、Telegram egress no-new-bypass guard 與既有 P2-103 task result audit trail 收斂成 AI 行動審計帳本;只建立 immutable event template、verifier receipt gate 與 no-write readback,不寫任何 runtime target。" + }, + "source_refs": [ + "docs/evaluations/ai_agent_low_medium_risk_whitelist_2026-06-18.json", + "docs/evaluations/ai_agent_high_risk_owner_review_queue_2026-06-19.json", + "docs/evaluations/ai_agent_task_result_audit_trail_2026-06-13.json", + "apps/api/src/services/ai_agent_report_source_health.py", + "apps/api/src/services/report_generation_service.py", + "docs/security/telegram-notification-egress-no-new-bypass-guard.snapshot.json", + "docs/workplans/2026-06-04-iwooos-security-governance-p0.md" + ], + "source_readbacks": [ + { + "readback_id": "p2_408_low_medium_whitelist", + "source_schema_version": "ai_agent_low_medium_risk_whitelist_v1", + "source_ref": "docs/evaluations/ai_agent_low_medium_risk_whitelist_2026-06-18.json", + "endpoint": "GET /api/v1/agents/agent-low-medium-risk-whitelist", + "owner_agent": "openclaw", + "status": "loaded", + "key_readback": "中低風險候選 6、dry-run verifier 5、rollback proof 5、blocked runtime action 27;auto worker 仍為 0。", + "next_action": "每個候選進 dry-run worker 前都必須有 immutable audit event template 與 verifier receipt gate。" + }, + { + "readback_id": "p2_409_high_risk_queue", + "source_schema_version": "ai_agent_high_risk_owner_review_queue_v1", + "source_ref": "docs/evaluations/ai_agent_high_risk_owner_review_queue_2026-06-19.json", + "endpoint": "GET /api/v1/agents/agent-high-risk-owner-review-queue", + "owner_agent": "openclaw", + "status": "loaded", + "key_readback": "高風險 queue item 7、critical 2、high 5、approval packet 7、blocked runtime action 42;owner accepted 0。", + "next_action": "每個高風險 pause / reject /補件結果必須先形成審計事件模板,不得口頭跳過。" + }, + { + "readback_id": "p2_103_task_result_audit_trail", + "source_schema_version": "ai_agent_task_result_audit_trail_v1", + "source_ref": "docs/evaluations/ai_agent_task_result_audit_trail_2026-06-13.json", + "endpoint": "GET /api/v1/agents/agent-task-result-audit-trail", + "owner_agent": "hermes", + "status": "loaded", + "key_readback": "結果路由 8、寫回契約 6、稽核點 7;KM / LOGBOOK / audit DB / timeline / Gateway / Telegram writes 全部為 0。", + "next_action": "P2-410 將 P2-103 的結果路由升級為跨候選行動帳本,而不是單一結果分類。" + }, + { + "readback_id": "p2_110c_sre_digest_no_send", + "source_schema_version": "awoooi_sre_digest_no_send_preview_v1", + "source_ref": "apps/api/src/services/report_generation_service.py", + "endpoint": "GET /api/v1/stats/sre-digest/preview", + "owner_agent": "hermes", + "status": "loaded", + "key_readback": "SRE digest no-send preview 已回讀 source 2/5、confidence 40、source gaps 3、live Telegram send 0、runtime gate 0。", + "next_action": "preview hash、source gap ids 與 no-send 邊界必須進審計事件模板,才能進 receipt gate。" + }, + { + "readback_id": "p2_110e_work_items_owner_review", + "source_schema_version": "awoooi_work_items_report_source_gap_owner_review_v1", + "source_ref": "docs/workplans/2026-06-04-iwooos-security-governance-p0.md", + "endpoint": "GET /zh-TW/awooop/work-items?project_id=awoooi", + "owner_agent": "hermes", + "status": "loaded", + "key_readback": "Work Items 已顯示 report-source-gap owner review、PlayBook 必填欄位、Verifier 檢查、live Telegram send=0、runtime gate=0。", + "next_action": "Work Item DB write、KM write、PlayBook trust write、verifier receipt write 必須先有 P2-410 audit event 與 P2-411 owner acceptance。" + }, + { + "readback_id": "telegram_egress_no_new_bypass", + "source_schema_version": "telegram_notification_egress_no_new_bypass_guard_v1", + "source_ref": "docs/security/telegram-notification-egress-no-new-bypass-guard.snapshot.json", + "endpoint": "repo-only guard", + "owner_agent": "sre", + "status": "loaded", + "key_readback": "direct Bot API baseline 18、current 18、new bypass 0、runtime gate 0;既有 direct send 仍未收斂。", + "next_action": "新增 Telegram route / send / receipt candidate 時必須附 no-new-bypass audit event 與 redaction evidence ref。" + }, + { + "readback_id": "p2_410_governance_frontend_boundary", + "source_schema_version": "governance_automation_inventory_readback_v1", + "source_ref": "apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx", + "endpoint": "GET /zh-TW/governance?tab=automation-inventory", + "owner_agent": "security", + "status": "pending_frontend_projection", + "key_readback": "本 snapshot 可供治理頁顯示 immutable event、verifier receipt gate、blocked write 與 live total 0;不可顯示 raw payload、secret、內部協作逐字內容。", + "next_action": "P2-410 production projection 後需 desktop / mobile smoke;目前先固定 API 與 committed snapshot。" + } + ], + "audit_truth": { + "p2_408_whitelist_loaded": true, + "p2_409_owner_queue_loaded": true, + "p2_103_result_audit_loaded": true, + "p2_110c_sre_digest_loaded": true, + "p2_110e_work_items_loaded": true, + "telegram_no_new_bypass_loaded": true, + "audit_event_templates_ready": true, + "verifier_receipt_gates_ready": true, + "immutable_event_required": true, + "redacted_evidence_refs_required": true, + "read_only_mode": true, + "audit_db_write_enabled": false, + "timeline_write_enabled": false, + "km_write_enabled": false, + "playbook_trust_write_enabled": false, + "gateway_queue_write_enabled": false, + "telegram_send_enabled": false, + "bot_api_call_enabled": false, + "receipt_production_write_enabled": false, + "production_write_enabled": false, + "secret_read_enabled": false, + "paid_api_call_enabled": false, + "host_write_enabled": false, + "kubectl_action_enabled": false, + "destructive_operation_enabled": false, + "audit_db_write_count_24h": 0, + "timeline_write_count_24h": 0, + "km_write_count_24h": 0, + "playbook_trust_write_count_24h": 0, + "gateway_queue_write_count_24h": 0, + "telegram_send_count_24h": 0, + "bot_api_call_count_24h": 0, + "receipt_production_write_count_24h": 0, + "production_write_count_24h": 0, + "secret_read_count_24h": 0, + "paid_api_call_count_24h": 0, + "host_write_count_24h": 0, + "kubectl_action_count_24h": 0, + "destructive_operation_count_24h": 0, + "truth_note": "P2-410 只把候選判斷、暫停、no-send preview、Work Items owner review 與 Telegram bypass guard 轉成 committed audit event template;目前沒有任何 runtime writer、receipt writer、KM writer 或 Telegram sender 被授權。" + }, + "audit_event_templates": [ + { + "audit_event_id": "audit_low_risk_candidate_classified", + "display_name": "中低風險候選分類審計事件", + "owner_agent": "openclaw", + "event_stage": "candidate_classification", + "risk_tier": "low", + "source_readback_ids": ["p2_408_low_medium_whitelist"], + "required_audit_fields": ["candidate_id", "risk_tier", "reason", "dry_run_verifier_id", "rollback_proof_id", "source_snapshot_ref"], + "required_evidence_refs": ["ai_agent_low_medium_risk_whitelist_2026-06-18.json", "dry_run_verifier_ref"], + "blocked_writes": ["auto_worker_run", "production_write", "Gateway queue write", "Telegram send"], + "immutable_event_required": true, + "audit_db_write_allowed": false, + "timeline_write_allowed": false, + "km_write_allowed": false, + "playbook_trust_write_allowed": false, + "gateway_queue_write_allowed": false, + "telegram_send_allowed": false, + "production_write_allowed": false, + "side_effect_count": 0, + "next_gate": "P2-411 owner response acceptance readback" + }, + { + "audit_event_id": "audit_medium_risk_dry_run_hold", + "display_name": "中風險 dry-run hold 審計事件", + "owner_agent": "nemotron", + "event_stage": "dry_run_hold", + "risk_tier": "medium", + "source_readback_ids": ["p2_408_low_medium_whitelist"], + "required_audit_fields": ["candidate_id", "dry_run_scope", "rollback_owner", "postcheck_plan", "blocked_runtime_actions", "operator_reason"], + "required_evidence_refs": ["dry_run_verifier_ref", "rollback_proof_ref", "audit_reason_ref"], + "blocked_writes": ["auto_worker_run", "Gateway queue write", "receipt production write", "KM write"], + "immutable_event_required": true, + "audit_db_write_allowed": false, + "timeline_write_allowed": false, + "km_write_allowed": false, + "playbook_trust_write_allowed": false, + "gateway_queue_write_allowed": false, + "telegram_send_allowed": false, + "production_write_allowed": false, + "side_effect_count": 0, + "next_gate": "P2-411 owner response acceptance readback" + }, + { + "audit_event_id": "audit_high_risk_owner_queue_pause", + "display_name": "高風險 Owner Queue 暫停審計事件", + "owner_agent": "openclaw", + "event_stage": "owner_queue_pause", + "risk_tier": "high", + "source_readback_ids": ["p2_409_high_risk_queue"], + "required_audit_fields": ["queue_item_id", "approval_packet_id", "rejection_guard_ids", "reviewer_checklist_ids", "owner_response_state", "blocked_runtime_actions"], + "required_evidence_refs": ["ai_agent_high_risk_owner_review_queue_2026-06-19.json", "approval_packet_ref"], + "blocked_writes": ["live execution", "production write", "Gateway queue write", "Telegram send", "host write"], + "immutable_event_required": true, + "audit_db_write_allowed": false, + "timeline_write_allowed": false, + "km_write_allowed": false, + "playbook_trust_write_allowed": false, + "gateway_queue_write_allowed": false, + "telegram_send_allowed": false, + "production_write_allowed": false, + "side_effect_count": 0, + "next_gate": "P2-411 owner response acceptance readback" + }, + { + "audit_event_id": "audit_critical_runtime_action_rejected", + "display_name": "Critical runtime action 拒收審計事件", + "owner_agent": "security", + "event_stage": "runtime_action_rejection", + "risk_tier": "critical", + "source_readback_ids": ["p2_409_high_risk_queue", "telegram_egress_no_new_bypass"], + "required_audit_fields": ["queue_item_id", "rejection_guard_id", "blocked_action", "redaction_state", "owner_response_state", "operator_next_step"], + "required_evidence_refs": ["rejection_guard_ref", "no_new_bypass_guard_ref"], + "blocked_writes": ["kubectl action", "host write", "secret read", "Bot API call", "destructive operation"], + "immutable_event_required": true, + "audit_db_write_allowed": false, + "timeline_write_allowed": false, + "km_write_allowed": false, + "playbook_trust_write_allowed": false, + "gateway_queue_write_allowed": false, + "telegram_send_allowed": false, + "production_write_allowed": false, + "side_effect_count": 0, + "next_gate": "P2-411 owner response acceptance readback" + }, + { + "audit_event_id": "audit_report_source_gap_work_item_reviewed", + "display_name": "報表資料源缺口 Work Item 審計事件", + "owner_agent": "hermes", + "event_stage": "work_item_owner_review", + "risk_tier": "high", + "source_readback_ids": ["p2_110e_work_items_owner_review"], + "required_audit_fields": ["work_item_id", "source_gap_id", "playbook_draft_id", "verifier_plan_id", "script_state", "schedule_state", "owner_review_state"], + "required_evidence_refs": ["agent-report-source-health", "awooop-work-items-readback"], + "blocked_writes": ["Work Items DB write", "KM write", "PlayBook trust write", "verifier receipt write", "schedule change"], + "immutable_event_required": true, + "audit_db_write_allowed": false, + "timeline_write_allowed": false, + "km_write_allowed": false, + "playbook_trust_write_allowed": false, + "gateway_queue_write_allowed": false, + "telegram_send_allowed": false, + "production_write_allowed": false, + "side_effect_count": 0, + "next_gate": "P2-411 owner response acceptance readback" + }, + { + "audit_event_id": "audit_sre_digest_no_send_preview", + "display_name": "SRE digest no-send preview 審計事件", + "owner_agent": "hermes", + "event_stage": "no_send_preview", + "risk_tier": "medium", + "source_readback_ids": ["p2_110c_sre_digest_no_send"], + "required_audit_fields": ["preview_hash", "dedup_key", "source_gap_ids", "no_send_boundary", "gateway_write_count", "telegram_send_count"], + "required_evidence_refs": ["GET /api/v1/stats/sre-digest/preview", "formatted_preview_hash"], + "blocked_writes": ["Gateway queue write", "Telegram send", "Bot API call", "receipt production write"], + "immutable_event_required": true, + "audit_db_write_allowed": false, + "timeline_write_allowed": false, + "km_write_allowed": false, + "playbook_trust_write_allowed": false, + "gateway_queue_write_allowed": false, + "telegram_send_allowed": false, + "production_write_allowed": false, + "side_effect_count": 0, + "next_gate": "P2-411 owner response acceptance readback" + }, + { + "audit_event_id": "audit_telegram_no_new_bypass_guard", + "display_name": "Telegram no-new-bypass guard 審計事件", + "owner_agent": "sre", + "event_stage": "notification_egress_guard", + "risk_tier": "high", + "source_readback_ids": ["telegram_egress_no_new_bypass"], + "required_audit_fields": ["baseline_signature_count", "current_direct_call_count", "new_bypass_count", "guarded_method_count", "runtime_gate_count"], + "required_evidence_refs": ["telegram-notification-egress-no-new-bypass-guard.snapshot.json", "guard_command_output"], + "blocked_writes": ["workflow modification", "direct Bot API migration", "Telegram send", "repository secret change"], + "immutable_event_required": true, + "audit_db_write_allowed": false, + "timeline_write_allowed": false, + "km_write_allowed": false, + "playbook_trust_write_allowed": false, + "gateway_queue_write_allowed": false, + "telegram_send_allowed": false, + "production_write_allowed": false, + "side_effect_count": 0, + "next_gate": "P2-411 owner response acceptance readback" + }, + { + "audit_event_id": "audit_result_route_writeback_blocked", + "display_name": "結果路由寫回阻擋審計事件", + "owner_agent": "nemotron", + "event_stage": "writeback_blocked", + "risk_tier": "medium", + "source_readback_ids": ["p2_103_task_result_audit_trail"], + "required_audit_fields": ["result_route_id", "target_system", "allowed_mode", "write_enabled", "runtime_writer_enabled", "blocker_summary"], + "required_evidence_refs": ["ai_agent_task_result_audit_trail_2026-06-13.json", "writeback_contract_ref"], + "blocked_writes": ["audit DB write", "timeline write", "KM write", "LOGBOOK runtime append", "PlayBook trust write"], + "immutable_event_required": true, + "audit_db_write_allowed": false, + "timeline_write_allowed": false, + "km_write_allowed": false, + "playbook_trust_write_allowed": false, + "gateway_queue_write_allowed": false, + "telegram_send_allowed": false, + "production_write_allowed": false, + "side_effect_count": 0, + "next_gate": "P2-411 owner response acceptance readback" + } + ], + "verifier_receipt_gates": [ + { + "gate_id": "gate_event_source_ref_complete", + "display_name": "事件 source ref 完整性", + "owner_agent": "hermes", + "required_checks": ["source_readback_id exists", "source_ref exists", "endpoint exists", "snapshot or route readback exists"], + "failure_if_missing": "沒有 source ref 的 AI action 不能進 dry-run worker 或 owner acceptance。", + "live_verifier_allowed": false, + "receipt_write_allowed": false, + "runtime_action_allowed": false + }, + { + "gate_id": "gate_redacted_evidence_ref_only", + "display_name": "只接受脫敏 evidence ref", + "owner_agent": "security", + "required_checks": ["no secret value", "no raw payload", "no private reasoning", "no work window transcript"], + "failure_if_missing": "疑似敏感 payload 必須隔離,不能寫 audit / timeline / KM。", + "live_verifier_allowed": false, + "receipt_write_allowed": false, + "runtime_action_allowed": false + }, + { + "gate_id": "gate_no_send_no_queue_boundary", + "display_name": "No-send / no-queue 邊界", + "owner_agent": "sre", + "required_checks": ["gateway_queue_write_count=0", "telegram_send_count=0", "bot_api_call_count=0", "receipt_write_count=0"], + "failure_if_missing": "任何 send / queue / receipt write 非 0 都不得宣稱 no-send audit ledger。", + "live_verifier_allowed": false, + "receipt_write_allowed": false, + "runtime_action_allowed": false + }, + { + "gate_id": "gate_owner_acceptance_missing_hold", + "display_name": "Owner acceptance 缺口 hold", + "owner_agent": "openclaw", + "required_checks": ["owner_response_received_count=0", "owner_response_accepted_count=0", "next_gate listed", "rollback owner required if write-capable"], + "failure_if_missing": "沒有合格 owner acceptance 前,只能停在 committed snapshot 和 reviewer queue。", + "live_verifier_allowed": false, + "receipt_write_allowed": false, + "runtime_action_allowed": false + }, + { + "gate_id": "gate_postcheck_plan_required", + "display_name": "Post-check / rollback 計畫", + "owner_agent": "nemotron", + "required_checks": ["postcheck_plan present", "rollback owner present", "blocked runtime actions listed", "verifier receipt target defined"], + "failure_if_missing": "缺 post-check / rollback 的候選不能進 P2-411,更不能進 dry-run worker。", + "live_verifier_allowed": false, + "receipt_write_allowed": false, + "runtime_action_allowed": false + } + ], + "activation_boundaries": { + "committed_snapshot_read_allowed": true, + "audit_event_template_preview_allowed": true, + "verifier_receipt_gate_preview_allowed": true, + "governance_ui_projection_allowed": true, + "audit_db_write_enabled": false, + "timeline_write_enabled": false, + "km_write_enabled": false, + "playbook_trust_write_enabled": false, + "gateway_queue_write_enabled": false, + "telegram_send_enabled": false, + "bot_api_call_enabled": false, + "receipt_production_write_enabled": false, + "production_write_enabled": false, + "secret_read_enabled": false, + "paid_api_call_enabled": false, + "host_write_enabled": false, + "kubectl_action_enabled": false, + "destructive_operation_enabled": false + }, + "display_redaction_contract": { + "redaction_required": true, + "unsafe_payload_display_allowed": false, + "private_reasoning_display_allowed": false, + "secret_value_display_allowed": false, + "raw_prompt_display_allowed": false, + "work_window_transcript_display_allowed": false, + "allowed_display_fields": ["audit_event_id", "display_name", "owner_agent", "event_stage", "risk_tier", "required_audit_fields", "blocked_writes", "next_gate"], + "blocked_display_fields": ["secret value", "authorization header", "unredacted Telegram payload", "private reasoning", "unredacted prompt", "internal collaboration content"] + }, + "rollups": { + "source_readback_count": 7, + "audit_event_template_count": 8, + "low_medium_event_count": 4, + "high_risk_event_count": 3, + "critical_event_count": 1, + "report_gap_event_count": 2, + "telegram_event_count": 2, + "verifier_receipt_gate_count": 5, + "required_audit_field_count": 48, + "blocked_runtime_action_count": 23, + "audit_db_write_count": 0, + "timeline_write_count": 0, + "km_write_count": 0, + "playbook_trust_write_count": 0, + "gateway_queue_write_count": 0, + "telegram_send_count": 0, + "bot_api_call_count": 0, + "receipt_production_write_count": 0, + "production_write_count": 0, + "secret_read_count": 0, + "paid_api_call_count": 0, + "host_write_count": 0, + "kubectl_action_count": 0, + "destructive_operation_count": 0, + "owner_response_received_count": 0, + "owner_response_accepted_count": 0 + }, + "next_actions": [ + { + "task_id": "P2-411", + "priority": "P0", + "summary": "建立 Agent action audit ledger owner response acceptance readback,只有合格 owner envelope 才能把某一類 event 往 dry-run worker 推。", + "gate": "owner_response_received=0 / accepted=0 until real redacted owner response exists" + }, + { + "task_id": "P2-412", + "priority": "P0", + "summary": "把 P2-410 的 audit event template 投影到治理頁、Runs、Work Items 與 SRE digest preview,不新增執行按鈕。", + "gate": "frontend projection only; no Gateway queue write or Telegram send" + }, + { + "task_id": "P2-413", + "priority": "P0", + "summary": "在 P2-411 owner acceptance 之後建立 fixture-only dry-run worker receipt rehearsal。", + "gate": "fixture-only; no live verifier, no production write" + } + ] +} diff --git a/docs/schemas/ai_agent_action_audit_ledger_v1.schema.json b/docs/schemas/ai_agent_action_audit_ledger_v1.schema.json new file mode 100644 index 000000000..2f8b1ad9f --- /dev/null +++ b/docs/schemas/ai_agent_action_audit_ledger_v1.schema.json @@ -0,0 +1,164 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "urn:awoooi:ai-agent-action-audit-ledger-v1", + "title": "AWOOOI AI Agent action audit ledger v1", + "description": "P2-410 將 P2-408 / P2-409 / P2-110C-E / Telegram egress no-new-bypass 的只讀結果收斂成 AI 行動審計帳本。此 schema 只允許 committed snapshot、audit event template、verifier receipt gate 與 governance readback;不授權 audit DB 寫入、timeline 寫入、KM 寫入、PlayBook trust 寫入、Gateway queue、Telegram 實發、Bot API、production write、secret read、host write、kubectl 或不可逆操作。", + "type": "object", + "required": [ + "schema_version", + "generated_at", + "program_status", + "source_refs", + "source_readbacks", + "audit_truth", + "audit_event_templates", + "verifier_receipt_gates", + "activation_boundaries", + "display_redaction_contract", + "rollups", + "next_actions" + ], + "properties": { + "schema_version": { "type": "string", "const": "ai_agent_action_audit_ledger_v1" }, + "generated_at": { "type": "string", "minLength": 1 }, + "program_status": { + "type": "object", + "required": [ + "overall_completion_percent", + "current_priority", + "current_task_id", + "next_task_id", + "read_only_mode", + "runtime_authority", + "status_note" + ], + "properties": { + "overall_completion_percent": { "type": "integer", "const": 100 }, + "current_priority": { "type": "string", "const": "P0" }, + "current_task_id": { "type": "string", "const": "P2-410" }, + "next_task_id": { "type": "string", "const": "P2-411" }, + "read_only_mode": { "type": "boolean", "const": true }, + "runtime_authority": { "type": "string", "const": "agent_action_audit_ledger_no_live_write_committed_snapshot" }, + "status_note": { "type": "string", "minLength": 1 } + }, + "additionalProperties": false + }, + "source_refs": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } }, + "source_readbacks": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/source_readback" } }, + "audit_truth": { "type": "object", "additionalProperties": { "type": ["boolean", "integer", "string"] } }, + "audit_event_templates": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/audit_event_template" } }, + "verifier_receipt_gates": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/verifier_receipt_gate" } }, + "activation_boundaries": { "type": "object", "additionalProperties": { "type": "boolean" } }, + "display_redaction_contract": { "type": "object", "additionalProperties": { "type": ["boolean", "array", "string"] } }, + "rollups": { "type": "object", "additionalProperties": { "type": ["integer", "array"] } }, + "next_actions": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/next_action" } } + }, + "$defs": { + "source_readback": { + "type": "object", + "required": [ + "readback_id", + "source_schema_version", + "source_ref", + "endpoint", + "owner_agent", + "status", + "key_readback", + "next_action" + ], + "properties": { + "readback_id": { "type": "string", "minLength": 1 }, + "source_schema_version": { "type": "string", "minLength": 1 }, + "source_ref": { "type": "string", "minLength": 1 }, + "endpoint": { "type": "string", "minLength": 1 }, + "owner_agent": { "type": "string", "enum": ["openclaw", "hermes", "nemotron", "sre", "security", "devops"] }, + "status": { "type": "string", "minLength": 1 }, + "key_readback": { "type": "string", "minLength": 1 }, + "next_action": { "type": "string", "minLength": 1 } + }, + "additionalProperties": false + }, + "audit_event_template": { + "type": "object", + "required": [ + "audit_event_id", + "display_name", + "owner_agent", + "event_stage", + "risk_tier", + "source_readback_ids", + "required_audit_fields", + "required_evidence_refs", + "blocked_writes", + "immutable_event_required", + "audit_db_write_allowed", + "timeline_write_allowed", + "km_write_allowed", + "playbook_trust_write_allowed", + "gateway_queue_write_allowed", + "telegram_send_allowed", + "production_write_allowed", + "side_effect_count", + "next_gate" + ], + "properties": { + "audit_event_id": { "type": "string", "minLength": 1 }, + "display_name": { "type": "string", "minLength": 1 }, + "owner_agent": { "type": "string", "enum": ["openclaw", "hermes", "nemotron", "sre", "security", "devops"] }, + "event_stage": { "type": "string", "minLength": 1 }, + "risk_tier": { "type": "string", "enum": ["low", "medium", "high", "critical"] }, + "source_readback_ids": { "type": "array", "minItems": 1, "items": { "type": "string" } }, + "required_audit_fields": { "type": "array", "minItems": 1, "items": { "type": "string" } }, + "required_evidence_refs": { "type": "array", "minItems": 1, "items": { "type": "string" } }, + "blocked_writes": { "type": "array", "minItems": 1, "items": { "type": "string" } }, + "immutable_event_required": { "type": "boolean", "const": true }, + "audit_db_write_allowed": { "type": "boolean", "const": false }, + "timeline_write_allowed": { "type": "boolean", "const": false }, + "km_write_allowed": { "type": "boolean", "const": false }, + "playbook_trust_write_allowed": { "type": "boolean", "const": false }, + "gateway_queue_write_allowed": { "type": "boolean", "const": false }, + "telegram_send_allowed": { "type": "boolean", "const": false }, + "production_write_allowed": { "type": "boolean", "const": false }, + "side_effect_count": { "type": "integer", "const": 0 }, + "next_gate": { "type": "string", "minLength": 1 } + }, + "additionalProperties": false + }, + "verifier_receipt_gate": { + "type": "object", + "required": [ + "gate_id", + "display_name", + "owner_agent", + "required_checks", + "failure_if_missing", + "live_verifier_allowed", + "receipt_write_allowed", + "runtime_action_allowed" + ], + "properties": { + "gate_id": { "type": "string", "minLength": 1 }, + "display_name": { "type": "string", "minLength": 1 }, + "owner_agent": { "type": "string", "enum": ["openclaw", "hermes", "nemotron", "sre", "security", "devops"] }, + "required_checks": { "type": "array", "minItems": 1, "items": { "type": "string" } }, + "failure_if_missing": { "type": "string", "minLength": 1 }, + "live_verifier_allowed": { "type": "boolean", "const": false }, + "receipt_write_allowed": { "type": "boolean", "const": false }, + "runtime_action_allowed": { "type": "boolean", "const": false } + }, + "additionalProperties": false + }, + "next_action": { + "type": "object", + "required": ["task_id", "priority", "summary", "gate"], + "properties": { + "task_id": { "type": "string", "minLength": 1 }, + "priority": { "type": "string", "enum": ["P0", "P1", "P2", "P3"] }, + "summary": { "type": "string", "minLength": 1 }, + "gate": { "type": "string", "minLength": 1 } + }, + "additionalProperties": false + } + }, + "additionalProperties": false +} diff --git a/docs/workplans/2026-06-04-iwooos-security-governance-p0.md b/docs/workplans/2026-06-04-iwooos-security-governance-p0.md index 57cec47ae..1537ff08b 100644 --- a/docs/workplans/2026-06-04-iwooos-security-governance-p0.md +++ b/docs/workplans/2026-06-04-iwooos-security-governance-p0.md @@ -7,9 +7,9 @@ | 項目 | 目前值 | |------|--------| | 工作視窗 | IwoooS / AWOOOI 資安治理 P0 | -| 本次乾淨 worktree | `/tmp/awoooi-cd-runner-secret-verify-20260618` | -| 本次分支 | detached at `gitea/main`;推送時使用 `HEAD:main`,不 force push | -| 最新觀察到的 `gitea/main` | `d1374257 docs(iwooos): 記錄 Wazuh 回讀正式驗證 [skip ci]`;最新 production deploy marker 仍是 `7cb3fd32 chore(cd): deploy ac9ee65 [skip ci]`;本輪 backup / restore / escrow readback code `1b9d44cf`、deploy marker `f5be4cb8`、code-review `3084`、CD `3083` 已正式驗證,後續 Wazuh deploy `7cb3fd32` 後 production marker 仍命中 | +| 本次乾淨 worktree | `/private/tmp/awoooi-iwooos-notification-egress-20260619` | +| 本次分支 | `codex/iwooos-notification-egress-20260619`;推送時使用一般 push,不 force push | +| 最新觀察到的 `gitea/main` | `f390cddb feat(agents): 新增高風險 owner review queue`;P2-410 action audit ledger 目前為本地 schema / snapshot / API / tests 完成,正式 deploy marker 與 production readback 待推送後驗證 | | 最新 P0 Telegram 告警 / 批准執行真相鏈基準 | code `32e4beca`、deploy marker `717b5870`、code-review `2658`、CD `2657`;no-action approval 不再觸發 executor,可執行修復 approval 會寫入 `auto_repair_executions`、KM 與 verifier | | 最新 P0 Telegram no-action 人工處置包基準 | code `cd928852`、deploy marker `9181cc0e`、code-review `2666`;正式部署 tree 已包含 no-action 人工處置包、`處置包 / 重診 / 歷史 / 靜默 / 真相鏈 / Runs` 鍵盤、production pod render / keyboard smoke | | 最新 P0 MCP evidence / PlayBook 修復候選基準 | code `cc614023`、D1 blocker clarity `47d677ac`、D2 manual draft package `febe9ecf`、D3 draft work item `e8d5eafb`、D4 work item detail panel `e8a5bac5`、D5 coverage gap contract 本地完成;目前 production deploy marker 仍為 `985a2cfe` 的 D4 Work Items detail panel,D5 尚待推送 / 部署驗證。正式部署 tree 經 production pod smoke 與 Work Items browser smoke 確認可由 MCP evidence + approved PlayBook trust 產生 medium approval candidate、綁定預配置 approval id、不外露 preallocated metadata,且通用兜底 / 診斷型 PlayBook 不會被誤當修復命令;若缺安全修復候選,Telegram 人工處置包會顯示阻擋原因、下一步、PlayBook 草案欄位與 AwoooP 修復候選草案工作項,工作項頁會顯示 PlayBook 草案處置板、必填欄位、阻擋原因、下一步與 Runs / 審批連結;D5 讓 blocked result 進一步輸出服務 coverage gap、blocking stage、必收 MCP evidence refs 與 PlayBook template fields | @@ -62,7 +62,7 @@ | Knowledge Base KM 自動化掌控台 / 資產沉澱可視化 | 本地 `100%`;正式站 desktop / mobile `100%` | 是,僅限 KM governance readback、Owner Review queue、資產沉澱總帳與 Work Items 接續入口 | `/zh-TW/knowledge-base` 已把 `KM 自動化掌控台` 前移到首屏,直接顯示 stale ratio `98.8%`、stale KM `1,900`、Owner Review `10`、`ready 10 / blocked 0`、已寫回 `1`、治理流程圖與 `KM / PlayBook / 腳本 / 排程 / Verifier` 五類沉澱狀態;不寫 KM、不提升 PlayBook trust、不批次完成 owner review、不開 runtime gate | | Observability AI 自動化資產與訊號總帳 | 本地 `100%`;正式站 desktop / mobile `100%` | 是,僅限主機 / 專案 / 網站 / 服務 / 監控訊號 / KM / PlayBook / Verifier / SRE 路由 readback | `/zh-TW/observability` 已把 `AI 自動化資產與訊號總帳` 前移到首屏,6 張卡顯示全域資產、監控訊號、服務健康、KM / PlayBook / Verifier、SRE 戰情室、Runtime Gate;總帳區操作入口 `0`,不 live probe、不 reload、不改規則、不發 Telegram、不套用修復 | | Tenants 全域產品 / 網站 / 來源資產地圖 | 本地 `100%`;正式站 desktop / mobile `100%` | 是,僅限產品 / 專案、網站 / 服務入口、來源範圍、租戶資料與 gate readback | `/zh-TW/awooop/tenants` 已把 `全域資產地圖` 前移到首屏,直接顯示 `57` 個可視資產、`16 個產品 / 專案`、`31 個網站 / 服務入口`、`10 個來源範圍`、分類堆疊、route chips、主要來源就緒、已接受回覆、執行閘門與操作入口;不改租戶政策、不改路由、不部署、不掃描、不建立 repo、不開 runtime gate | -| 日報 / 週報 / 月報與 AI Agent 報表資料鏈路 | Weekly report 資料缺口止血本地 `100%`、正式部署 `100%`;Reports 總控正式站 `100%`;P2-109 source health read model 正式站 `100%`;P2-110 weekly no-send preview 正式站 `100%`;P2-110B daily / monthly no-send preview 正式站 `100%`;P2-110C SRE digest no-send preview 正式站 `100%`;P2-110D source gap PlayBook / Verifier readback 正式站 `100%`;P2-110E AwoooP Work Items owner review 正式站 `100%`;報表產品化總控 `92%` | 是,僅限資料源 truthfulness、全 0 判讀、Reports 首屏總控、no-send preview、資產沉澱、PlayBook / Verifier 缺口處置板、AwoooP Work Items owner review 與下一步工作項 | `ac325852` / deploy marker `a4b30964` 已修正週報 Git 活動讀取失敗時假性輸出 `0`;`6d4fa7bf` / `5e849225` / `63a75f77` 已把 `/zh-TW/reports` 改成 `報表 / 告警 AI 接管總控`;`27d9f394` / deploy marker `d8862123` 新增 `agent-report-source-health`;`a46e31ba` / `48e06c6a` / deploy marker `3057342a` 已讓 weekly preview 回傳 source `2/5`、confidence `40`、三個 `report-source-gap:*` 與 KM / PlayBook / Verifier 沉澱;`77fe2a85` / deploy marker `29fe6ec8` 已讓 daily / monthly preview 也回傳同一 source health、formatted preview 與 KM / PlayBook / 腳本 / 排程 / Verifier 沉澱;`7e03b923` / deploy marker `c7c0d874` 已新增 SRE 戰情室 digest preview,回傳 live send allowed `0`、runtime gate `0` 與同一批沉澱;`6ab640e4` / deploy marker `049dc0a8` 已讓 `agent-report-source-health` 與 `/zh-TW/reports` 顯示三張 source gap PlayBook / Verifier 處置卡;`ca04b49d` / deploy marker `c33dd9a6` 已讓 `/zh-TW/awooop/work-items` 顯示 source `2/5`、資料缺口 `3`、PlayBook 草案 `3`、Verifier 計畫 `3`、owner review `3`、腳本 readback、排程 no-send 與 runtime gate `0`;仍需接 Telegram SRE digest preview 與 verifier receipt gate,不發 live Telegram、不改排程、不開 runtime gate | +| 日報 / 週報 / 月報與 AI Agent 報表資料鏈路 | Weekly report 資料缺口止血本地 `100%`、正式部署 `100%`;Reports 總控正式站 `100%`;P2-109 source health read model 正式站 `100%`;P2-110 weekly no-send preview 正式站 `100%`;P2-110B daily / monthly no-send preview 正式站 `100%`;P2-110C SRE digest no-send preview 正式站 `100%`;P2-110D source gap PlayBook / Verifier readback 正式站 `100%`;P2-110E AwoooP Work Items owner review 正式站 `100%`;P2-410 action audit ledger 本地 API `100%`;報表產品化總控 `94%` | 是,僅限資料源 truthfulness、全 0 判讀、Reports 首屏總控、no-send preview、資產沉澱、PlayBook / Verifier 缺口處置板、AwoooP Work Items owner review、audit event template 與下一步工作項 | `ac325852` / deploy marker `a4b30964` 已修正週報 Git 活動讀取失敗時假性輸出 `0`;`6d4fa7bf` / `5e849225` / `63a75f77` 已把 `/zh-TW/reports` 改成 `報表 / 告警 AI 接管總控`;`27d9f394` / deploy marker `d8862123` 新增 `agent-report-source-health`;`a46e31ba` / `48e06c6a` / deploy marker `3057342a` 已讓 weekly preview 回傳 source `2/5`、confidence `40`、三個 `report-source-gap:*` 與 KM / PlayBook / Verifier 沉澱;`77fe2a85` / deploy marker `29fe6ec8` 已讓 daily / monthly preview 也回傳同一 source health、formatted preview 與 KM / PlayBook / 腳本 / 排程 / Verifier 沉澱;`7e03b923` / deploy marker `c7c0d874` 已新增 SRE 戰情室 digest preview,回傳 live send allowed `0`、runtime gate `0` 與同一批沉澱;`6ab640e4` / deploy marker `049dc0a8` 已讓 `agent-report-source-health` 與 `/zh-TW/reports` 顯示三張 source gap PlayBook / Verifier 處置卡;`ca04b49d` / deploy marker `c33dd9a6` 已讓 `/zh-TW/awooop/work-items` 顯示 source `2/5`、資料缺口 `3`、PlayBook 草案 `3`、Verifier 計畫 `3`、owner review `3`、腳本 readback、排程 no-send 與 runtime gate `0`;P2-410 本地 action audit ledger 已把 report source gap 與 SRE digest no-send preview 固定成 audit event template 與 verifier receipt gate;仍需正式部署 P2-410、接 governance projection 與 receipt gate,不發 live Telegram、不改排程、不開 runtime gate | | Telegram 監控告警 / 批准執行真相鏈 | outbound 主鏈路 `100%`;批准後執行止血 `100%`;no-action 人工處置包 D0 `100%`;MCP / PlayBook 修復候選 D5 `88%`;Approvals / Runs / Alerts / Knowledge Base / Observability / Tenants / Telegram 告警卡資產沉澱矩陣 `100% / desktop 100% / 100% / 100% / 100% / 100% / formatter+deploy 100%`;治理長期項 `98%` | 是,僅限候選產生、阻擋原因、人工草案包、AwoooP 工作項可追蹤性、Work Items 詳細接手板、Approvals / Runs / Alerts / Knowledge Base / Observability / Tenants / Telegram 告警卡資產沉澱欄與 coverage gap metadata | 已修復 Alertmanager tenant context、既有 approval 收斂告警 recurrence、AI 分析中重複告警 recurrence、no-action approval 誤導執行、可執行修復 execution / KM / verifier 紀錄、no-action 人工處置包、MCP evidence / PlayBook trust 候選產生、通用兜底 / 診斷型 PlayBook 阻擋理由、缺候選時的 PlayBook 草案欄位 / 下一步 / AwoooP work item 入口與詳細處置板、blocked result 的服務 coverage gap / blocking stage / required MCP evidence refs,以及 Approvals / Runs / Alerts / Knowledge Base / Observability / Tenants / Telegram 告警卡的 `KM / PlayBook / 腳本 / 排程 / Verifier` 資產沉澱矩陣;完整自動修復飛輪仍需用真實告警驗證 approval -> execution -> verifier -> KM / PlayBook trust 全鏈,不調高 runtime gate | ## 2. P0 工作拆解與優先順序 @@ -86,7 +86,7 @@ | P0-7 | Telegram 批准後執行真相鏈止血 | 100% | no-action approval 不再顯示批准 / 執行中;可執行修復 approval 會寫入 `auto_repair_executions`、KM 與 verifier;下一步補 MCP evidence / PlayBook trust 產生真正修復候選 | 目標 pytest `125 passed`、py_compile、guard、production health、API / worker rollout、production pod classifier readback | | P0-8 | Telegram no-action 人工處置包與操作入口 | 100% | no-action 卡片已新增人工處置包、證據補齊清單、AwoooP 修復候選建立步驟、verifier / KM / PlayBook 回寫提醒,並改成 `處置包`、`重診`、`歷史`、`靜默`、`真相鏈`、`Runs` 鍵盤;舊訊息不 retroactive 改寫 | 目標 pytest `64 passed + 44 passed`、py_compile、guard、production health、API / worker rollout、production pod render / keyboard smoke | | P0-9 | MCP evidence -> PlayBook 修復候選產生 | D5 `88%`;Approvals ledger `100%`;Runs ledger desktop `100%`;Alerts ledger desktop / mobile `100%` | 已補 webhook fallback 先建立 incident,再收 MCP evidence、查 approved PlayBook、檢查 trust / command safety、產生 medium approval candidate 與 verifier plan;D1 追加通用兜底 PlayBook / 診斷型命令不可誤當修復、阻擋理由繁中化;D2 在缺候選時產生 `repair_candidate_draft_package_v1`、`playbook_draft_required`、下一步與必填欄位;D3 新增 `awooop_repair_candidate_draft_work_item_v1` read-only projection 與 Telegram `工作項目` deeplink;D4 讓 AwoooP Work Items 詳細呈現 PlayBook 草案處置板、必填欄位、阻擋原因、下一步、Runs / 審批連結;D5 新增 `repair_candidate_coverage_gap_v1`,讓 blocked result 帶出 coverage key、target kind、blocking stage、必收 MCP evidence refs、PlayBook template fields 與 runtime 0 / false 邊界;Approvals / Runs / Alerts 已新增 `資產沉澱` 欄或焦點矩陣,可直接看到 KM / PlayBook / 腳本 / 排程 / Verifier 的完成與卡點;下一步要補 Runs mobile smoke,並把同一總帳接到正式 Telegram 告警卡、Observability 與 Tenants,用真實告警驗證 approval -> execution -> verifier -> KM / PlayBook 回寫 | Approvals code `dafe5342` 已隨 deploy marker `42c08ece` 正式站 desktop / mobile smoke;Runs code `11c2b5d4` 已隨 deploy marker `8b6ab87c` 正式站 desktop DOM smoke;Alerts code `10cd6167` 已隨 deploy marker `d36d764a` 正式站 desktop / mobile DOM smoke;P2-407 API production readback `overall_completion_percent=100`;status-chain 後續仍必須看到 tool call、PlayBook id、risk gate、repair candidate、verifier plan | -| P0-9a | 日報 / 週報 / 月報資料鏈路 truthfulness | 92% | Weekly report 已修正 Git 活動讀取失敗時假性全 0 的問題;Reports 頁已前移資料可信度、資料源健康矩陣、日週月報 cadence、告警到 AI 接手漏斗、自動化資產沉澱與 Agent 工作量;P2-109 已建立 `agent-report-source-health` / no-send preview read model;P2-110 已讓 weekly preview API 回傳 formatted Telegram HTML、source `2/5`、三個 source gap 與 KM / PlayBook / 腳本 / 排程 / Verifier 沉澱;P2-110B 已讓 daily / monthly preview API 也回傳同一 source health、formatted Telegram HTML、source gap、KM / PlayBook / 腳本 / 排程 / Verifier 與 no-send 邊界;P2-110C 已新增 SRE digest preview,收斂日 / 週 / 月 source health、工作項與 no-send 邊界;P2-110D 已讓 source gap 具備 PlayBook 草案、Verifier 計畫、腳本 readback、排程 no-send 與 owner review 處置板;P2-110E 已把同一批 source gap 接進 AwoooP Work Items owner review;下一步接 Telegram SRE digest preview 與 verifier receipt gate | Feature commit `ac325852`、Reports commits `6d4fa7bf` / `5e849225` / `63a75f77`、P2-109 commit `27d9f394`、P2-110 commits `a46e31ba` / `48e06c6a`、P2-110B commit `77fe2a85`、P2-110C commit `7e03b923`、P2-110D commit `6ab640e4`、P2-110E commit `ca04b49d`、deploy markers `a4b30964` / `4d4c6da3` / `cd1c4407` / `d8862123` / `c922bc1a` / `3057342a` / `29fe6ec8` / `c7c0d874` / `049dc0a8` / `c33dd9a6`;production `/api/v1/agents/agent-report-source-health`、`/api/v1/stats/daily/preview`、`/api/v1/stats/weekly/preview`、`/api/v1/stats/monthly/preview`、`/api/v1/stats/sre-digest/preview`、`/zh-TW/reports` desktop / mobile、`/zh-TW/awooop/work-items` desktop / mobile readback OK;未 live send Telegram、未改排程、未開 runtime gate | +| P0-9a | 日報 / 週報 / 月報資料鏈路 truthfulness | 94% | Weekly report 已修正 Git 活動讀取失敗時假性全 0 的問題;Reports 頁已前移資料可信度、資料源健康矩陣、日週月報 cadence、告警到 AI 接手漏斗、自動化資產沉澱與 Agent 工作量;P2-109 已建立 `agent-report-source-health` / no-send preview read model;P2-110 已讓 weekly preview API 回傳 formatted Telegram HTML、source `2/5`、三個 source gap 與 KM / PlayBook / 腳本 / 排程 / Verifier 沉澱;P2-110B 已讓 daily / monthly preview API 也回傳同一 source health、formatted preview 與 no-send 邊界;P2-110C 已新增 SRE digest preview;P2-110D 已讓 source gap 具備 PlayBook 草案、Verifier 計畫、腳本 readback、排程 no-send 與 owner review 處置板;P2-110E 已把同一批 source gap 接進 AwoooP Work Items owner review;P2-410 本地 action audit ledger 已把 report gap 與 SRE digest no-send preview 轉成 audit event template 與 verifier receipt gate;下一步是 P2-410 正式部署、governance projection 與 P2-411 Event Bus | Feature commit `ac325852`、Reports commits `6d4fa7bf` / `5e849225` / `63a75f77`、P2-109 commit `27d9f394`、P2-110 commits `a46e31ba` / `48e06c6a`、P2-110B commit `77fe2a85`、P2-110C commit `7e03b923`、P2-110D commit `6ab640e4`、P2-110E commit `ca04b49d`、deploy markers `a4b30964` / `4d4c6da3` / `cd1c4407` / `d8862123` / `c922bc1a` / `3057342a` / `29fe6ec8` / `c7c0d874` / `049dc0a8` / `c33dd9a6`;P2-410 local schema / snapshot / API / tests;production `/api/v1/agents/agent-report-source-health`、`/api/v1/stats/daily/preview`、`/api/v1/stats/weekly/preview`、`/api/v1/stats/monthly/preview`、`/api/v1/stats/sre-digest/preview`、`/zh-TW/reports` desktop / mobile、`/zh-TW/awooop/work-items` desktop / mobile readback OK;未 live send Telegram、未改排程、未開 runtime gate | | P0-10 | 高價值配置 Gate path coverage、工作樹 preflight、owner packet / coverage snapshot 補強 | 100% | 已將 `k8s/nginx/**`、`scripts/ops/**/*cert*`、`scripts/ops/**/*tls*` 納入 `high-value-config-change-gate.py`,讓 Nginx public gateway 與 DNS / TLS / certbot 既有路徑命中 P0 / C0;預設模式可讀取 staged / unstaged / untracked,避免本地 preflight 漏掉未提交配置;owner packet 與 coverage snapshot 已同步最新 pattern;owner evidence 仍未提供,runtime execution 仍 false | Gate sample:`changed_files=6 matched=6 categories=3 c0=2 c1=0`;工作樹 smoke:臨時 `k8s/nginx/*` 檔命中 C0;owner packet:`packets=3 c0=2 runtime_gate=0`;coverage:`categories=14 c0=8 avg=67 runtime_gate=0`;`py_compile`、snapshot JSON parse、progress guard、owner response guard、doc secret sanity、diff check | | P0-11 | 高價值配置 Owner Packet 前台同步 | local 100%;production 100% | `/zh-TW/iwooos` 與 `/zh-TW/awooop` 已同步 latest owner packet snapshot,顯示 `packet=3 / c0=2`、Nginx public gateway、DNS / TLS / certbot 與 security tooling 影響範圍;request sent、received、accepted、runtime gate 與 action buttons 仍全部為 `0` | Feature commit `e999c16b`、deploy marker `16c6b983`、Gitea code-review `2973` / CD `2972` success;本地與正式 desktop / mobile / in-app browser smoke:IwoooS 與 AwoooP 均 HTTP `200`、必要文字與 boundary keys 可見、水平溢位 `0`、卡片內操作控制 `0`、危險連結 `0`、工作溝通片語命中 `0`;headline 不提高 | | P0-12 | IwoooS posture projection Owner Packet count sync | 100% | `iwooos-posture-projection.snapshot.json` 與 schema 已從舊 `packet=1 / c0=0` 同步為 `packet=3 / c0=2`,避免 committed projection 與前台 / owner packet snapshot 分叉;request / received / accepted / runtime gate 仍為 `0` | `security-mirror-progress-guard.py` expectation 已同步;後續驗證以 JSON parse、schema parse、progress guard、owner response guard、doc secret sanity、diff check 為準;不需要 production browser smoke |