From 414413a59268eedd391648f112e228716dd05362 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 13 Jun 2026 01:09:29 +0800 Subject: [PATCH] =?UTF-8?q?feat(governance):=20=E6=96=B0=E5=A2=9E=20matche?= =?UTF-8?q?d=20PlayBook=20=E5=AD=B8=E7=BF=92=E7=BC=BA=E5=8F=A3=E8=AD=89?= =?UTF-8?q?=E6=93=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/api/src/api/v1/agents.py | 6 +- .../ai_agent_matched_playbook_learning_gap.py | 300 ++++++------ ..._ai_agent_matched_playbook_learning_gap.py | 79 +-- ...agent_matched_playbook_learning_gap_api.py | 30 +- apps/web/messages/en.json | 92 ++-- apps/web/messages/zh-TW.json | 92 ++-- .../tabs/automation-inventory-tab.tsx | 206 ++++---- apps/web/src/lib/api-client.ts | 144 +++--- docs/LOGBOOK.md | 50 +- ...AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md | 8 +- ...T_INTERACTION_LEARNING_PROOF_2026-06-11.md | 19 +- ...ched_playbook_learning_gap_2026-06-13.json | 459 +++++++++--------- ...tched_playbook_learning_gap_v1.schema.json | 393 ++++++++------- ...-04-15-MASTER-ai-autonomous-flywheel-v2.md | 22 +- 14 files changed, 1001 insertions(+), 899 deletions(-) diff --git a/apps/api/src/api/v1/agents.py b/apps/api/src/api/v1/agents.py index ec8ff1bd3..612927d05 100644 --- a/apps/api/src/api/v1/agents.py +++ b/apps/api/src/api/v1/agents.py @@ -1136,9 +1136,9 @@ async def get_agent_task_result_audit_trail() -> dict[str, Any]: response_model=dict[str, Any], summary="取得 AI Agent matched PlayBook 學習缺口", description=( - "讀取最新已提交的 P2-104 matched_playbook_id 學習缺口契約;此端點只回傳 " - "PlayBook id 來源、approval record 序列化、learning service、await learning、測試契約、" - "live null-rate gate 與 owner gate,不查 live DB、不更新 PlayBook trust、不寫 KM、不寫 timeline、" + "讀取最新已提交的 P2-104 matched PlayBook 學習缺口;此端點只回傳 production DB 只讀回查摘要、" + "learning gap、gate、writeback candidate 與 redaction boundary," + "不寫 learning、不更新 PlayBook trust、不寫 KM、不 runtime append LOGBOOK、不寫 audit DB、不寫 timeline、" "不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 production target、不讀 secret。" ), ) diff --git a/apps/api/src/services/ai_agent_matched_playbook_learning_gap.py b/apps/api/src/services/ai_agent_matched_playbook_learning_gap.py index 1b76fd9d6..0ad7e42b1 100644 --- a/apps/api/src/services/ai_agent_matched_playbook_learning_gap.py +++ b/apps/api/src/services/ai_agent_matched_playbook_learning_gap.py @@ -1,10 +1,10 @@ """ AI Agent matched PlayBook learning gap snapshot. -Loads the latest committed P2-104 matched_playbook_id learning gap contract. -This module validates repo-committed evidence only; it never reads live DB rows, -updates PlayBook trust, writes KM, writes timelines, writes Gateway queues, -sends Telegram messages, reads secrets, or starts runtime work. +Loads the latest committed P2-104 matched PlayBook learning gap contract. This +module validates repo-committed evidence only; it never writes learning state, +updates PlayBook trust, writes KM / LOGBOOK / audit / timeline, writes Gateway +queues, sends Telegram messages, reads secrets, or starts runtime work. """ from __future__ import annotations @@ -24,7 +24,7 @@ _RUNTIME_AUTHORITY = "matched_playbook_learning_gap_contract_only_no_live_trust_ def load_latest_ai_agent_matched_playbook_learning_gap( evaluations_dir: Path | None = None, ) -> dict[str, Any]: - """Load the newest committed matched PlayBook learning gap contract.""" + """Load the newest committed AI Agent matched PlayBook learning gap contract.""" directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR candidates = sorted(directory.glob(_SNAPSHOT_PATTERN)) if not candidates: @@ -37,11 +37,11 @@ def load_latest_ai_agent_matched_playbook_learning_gap( if not isinstance(payload, dict): raise ValueError(f"{latest}: expected JSON object") _require_schema(payload, str(latest)) - _require_no_live_boundaries(payload, str(latest)) - _require_learning_checkpoints(payload, str(latest)) - _require_gap_items(payload, str(latest)) - _require_test_contracts(payload, str(latest)) - _require_owner_gates(payload, str(latest)) + _require_production_readback(payload, str(latest)) + _require_learning_gap_truth(payload, str(latest)) + _require_gap_lanes(payload, str(latest)) + _require_learning_gates(payload, str(latest)) + _require_writeback_candidates(payload, str(latest)) _require_redaction_contract(payload, str(latest)) _require_rollup_consistency(payload, str(latest)) return payload @@ -61,140 +61,160 @@ def _require_schema(payload: dict[str, Any], label: str) -> None: raise ValueError(f"{label}: next_task_id must be P2-105") -def _require_no_live_boundaries(payload: dict[str, Any], label: str) -> None: +def _require_production_readback(payload: dict[str, Any], label: str) -> None: + readback = payload.get("production_readback") or {} + if readback.get("readback_mode") != "read_only_db_readback": + raise ValueError(f"{label}: production_readback.readback_mode must remain read_only_db_readback") + if readback.get("project_id_scope") != "awoooi": + raise ValueError(f"{label}: production_readback.project_id_scope must remain awoooi") + if readback.get("rls_fail_closed_verified") is not True: + raise ValueError(f"{label}: production readback must verify RLS fail-closed") + + total = readback.get("approval_24h_total") + matched = readback.get("approval_24h_matched") + if not isinstance(total, int) or not isinstance(matched, int): + raise ValueError(f"{label}: approval_24h_total and approval_24h_matched must be integers") + if matched > total: + raise ValueError(f"{label}: approval_24h_matched cannot exceed approval_24h_total") + expected_rate = 0 if total == 0 else round((matched / total) * 100) + if readback.get("matched_rate_24h_percent") != expected_rate: + raise ValueError(f"{label}: matched_rate_24h_percent must match approval 24h readback") + if matched != total: + raise ValueError(f"{label}: P2-104 expects matched_playbook_id to be present for all 24h approvals") + if readback.get("playbook_updated_24h") != 0: + raise ValueError(f"{label}: playbook_updated_24h must remain 0 until trust write gate is approved") + + +def _require_learning_gap_truth(payload: dict[str, Any], label: str) -> None: truth = payload.get("learning_gap_truth") or {} required_true = { - "p2_103_result_audit_loaded", - "matched_playbook_source_contract_ready", - "approval_record_contract_ready", - "learning_service_contract_ready", - "execution_learning_await_contract_ready", - "e2e_test_contract_ready", - "owner_gate_contract_ready", - "all_checkpoints_have_evidence_ref", + "p2_103_task_result_audit_loaded", + "production_db_readback_completed", + "rls_fail_closed_verified", + "matched_playbook_id_present_24h", + "matched_playbook_id_gap_resolved", + "execution_learning_gap_detected", + "approved_without_execution_meta_detected", + "playbook_trust_update_gap_detected", } missing = sorted(field for field in required_true if truth.get(field) is not True) if missing: raise ValueError(f"{label}: learning gap readiness flags must remain true: {missing}") required_false = { - "runtime_execution_enabled", - "live_db_read_enabled", + "runtime_learning_write_enabled", "playbook_trust_write_enabled", + "approval_auto_execute_enabled", "km_write_enabled", + "logbook_runtime_write_enabled", + "audit_db_write_enabled", "timeline_write_enabled", "gateway_queue_write_enabled", "telegram_send_enabled", "production_write_enabled", "secret_value_read_enabled", - "host_or_cluster_command_enabled", "destructive_operation_enabled", + "work_window_transcript_display_allowed", } unsafe = sorted(field for field in required_false if truth.get(field) is not False) if unsafe: - raise ValueError(f"{label}: live read/write/send/execution flags must remain false: {unsafe}") + raise ValueError(f"{label}: live write/send/execution flags must remain false: {unsafe}") zero_counts = { - "runtime_execution_count_24h", - "live_db_read_count_24h", + "playbook_updated_24h", + "live_learning_write_count_24h", "playbook_trust_write_count_24h", - "km_write_count_24h", - "timeline_write_count_24h", "gateway_queue_write_count_24h", "telegram_send_count_24h", "production_write_count_24h", "secret_value_read_count_24h", - "host_or_cluster_command_count_24h", "destructive_operation_count_24h", } non_zero = sorted(field for field in zero_counts if truth.get(field) != 0) if non_zero: - raise ValueError(f"{label}: live read/write/send/execution counts must remain zero: {non_zero}") + raise ValueError(f"{label}: live learning/trust/send/write counts must remain zero: {non_zero}") + + if truth.get("approval_24h_total") != truth.get("approval_24h_matched"): + raise ValueError(f"{label}: matched_playbook_id gap must remain resolved for 24h approvals") + if truth.get("approved_without_execution_meta_24h", 0) <= 0: + raise ValueError(f"{label}: P2-104 must expose approved_without_execution_meta_24h as the active gap") -def _require_learning_checkpoints(payload: dict[str, Any], label: str) -> None: - checkpoints = payload.get("learning_checkpoints") or [] - checkpoint_ids = {checkpoint.get("checkpoint_id") for checkpoint in checkpoints} +def _require_gap_lanes(payload: dict[str, Any], label: str) -> None: + lanes = payload.get("gap_lanes") or [] + lane_ids = {lane.get("lane_id") for lane in lanes} required = { - "checkpoint_proposal_playbook_match", - "checkpoint_approval_record_serialization", - "checkpoint_learning_service_update", - "checkpoint_execution_await_learning", - "checkpoint_repair_candidate_playbook_id", - "checkpoint_webhook_source_correlation", - "checkpoint_live_null_rate_gate", + "lane_matched_id_present", + "lane_approved_without_execution_meta", + "lane_pending_human_gate", + "lane_execution_failed_learning_candidate", + "lane_playbook_trust_not_updated", } - if checkpoint_ids != required: - raise ValueError(f"{label}: learning checkpoints must match {sorted(required)}") + if lane_ids != required: + raise ValueError(f"{label}: gap lanes must match {sorted(required)}") - valid_status = { - "covered_by_test", - "covered_by_existing_tests", - "source_guarded", - "blocked_until_live_evidence", - } - for checkpoint in checkpoints: - checkpoint_id = checkpoint.get("checkpoint_id") - if checkpoint.get("current_status") not in valid_status: - raise ValueError(f"{label}: checkpoint {checkpoint_id} current_status is invalid") - if checkpoint.get("writes_live_state") is not False: - raise ValueError(f"{label}: checkpoint {checkpoint_id} writes_live_state must remain false") - if not isinstance(checkpoint.get("requires_owner_review"), bool): - raise ValueError(f"{label}: checkpoint {checkpoint_id} requires_owner_review must be boolean") - for field in {"source_component", "evidence_ref", "expected_signal", "gap_if_missing"}: - if not checkpoint.get(field): - raise ValueError(f"{label}: checkpoint {checkpoint_id} must list {field}") - if not _is_redacted_sha256(checkpoint.get("evidence_hash")): - raise ValueError(f"{label}: checkpoint {checkpoint_id} must expose evidence_hash") + valid_statuses = {"passed", "blocked", "owner_review_required", "ready"} + valid_risks = {"low", "medium", "high", "critical"} + for lane in lanes: + lane_id = lane.get("lane_id") + if lane.get("status") not in valid_statuses: + raise ValueError(f"{label}: lane {lane_id} status is invalid") + if lane.get("risk_tier") not in valid_risks: + raise ValueError(f"{label}: lane {lane_id} risk_tier is invalid") + if lane.get("live_write_enabled") is not False: + raise ValueError(f"{label}: lane {lane_id} live_write_enabled must remain false") + for field in {"display_name", "owner_agent", "evidence", "next_gate"}: + if not lane.get(field): + raise ValueError(f"{label}: lane {lane_id} must list {field}") + if not _is_redacted_sha256(lane.get("evidence_hash")): + raise ValueError(f"{label}: lane {lane_id} must expose evidence_hash") -def _require_gap_items(payload: dict[str, Any], label: str) -> None: - gaps = payload.get("gap_items") or [] - if not gaps: - raise ValueError(f"{label}: gap_items must not be empty") - for gap in gaps: - gap_id = gap.get("gap_id") - if gap.get("severity") not in {"critical", "high", "medium", "low"}: - raise ValueError(f"{label}: gap {gap_id} severity is invalid") - if not isinstance(gap.get("blocks_trust_write"), bool): - raise ValueError(f"{label}: gap {gap_id} blocks_trust_write must be boolean") - for field in {"display_name", "current_state", "required_evidence", "owner_next_action"}: - if not gap.get(field): - raise ValueError(f"{label}: gap {gap_id} must list {field}") - - -def _require_test_contracts(payload: dict[str, Any], label: str) -> None: - tests = payload.get("test_contracts") or [] - if len(tests) < 5: - raise ValueError(f"{label}: test_contracts must include at least five tests") - for test in tests: - test_id = test.get("test_id") - if test.get("live_execution_required") is not False: - raise ValueError(f"{label}: test {test_id} live_execution_required must remain false") - if not test.get("test_ref") or "::" not in test.get("test_ref", ""): - raise ValueError(f"{label}: test {test_id} must expose test_ref") - if not test.get("expected_result"): - raise ValueError(f"{label}: test {test_id} must list expected_result") - - -def _require_owner_gates(payload: dict[str, Any], label: str) -> None: - gates = payload.get("owner_gates") or [] +def _require_learning_gates(payload: dict[str, Any], label: str) -> None: + gates = payload.get("learning_gates") or [] gate_ids = {gate.get("gate_id") for gate in gates} required = { - "gate_read_only_live_null_rate", - "gate_playbook_trust_write", - "gate_km_timeline_write", + "gate_result_capture_contract", + "gate_critic_reviewer_score", + "gate_learning_writeback_approval", + "gate_post_write_verifier", + "gate_telegram_operator_receipt", } if gate_ids != required: - raise ValueError(f"{label}: owner gates must match {sorted(required)}") + raise ValueError(f"{label}: learning gates must match {sorted(required)}") for gate in gates: gate_id = gate.get("gate_id") - if gate.get("approval_required") is not True: - raise ValueError(f"{label}: gate {gate_id} approval_required must remain true") - if gate.get("runtime_write_allowed") is not False: - raise ValueError(f"{label}: gate {gate_id} runtime_write_allowed must remain false") - if not gate.get("blocked_reason"): - raise ValueError(f"{label}: gate {gate_id} must list blocked_reason") + if gate.get("status") not in {"ready", "needs_owner_review", "blocked_by_policy"}: + raise ValueError(f"{label}: gate {gate_id} status is invalid") + if gate.get("creates_runtime_write") is not False: + raise ValueError(f"{label}: gate {gate_id} creates_runtime_write must remain false") + if not gate.get("required_before") or not gate.get("failure_if_missing"): + raise ValueError(f"{label}: gate {gate_id} must list required_before and failure_if_missing") + + +def _require_writeback_candidates(payload: dict[str, Any], label: str) -> None: + candidates = payload.get("writeback_candidates") or [] + candidate_ids = {candidate.get("candidate_id") for candidate in candidates} + required = { + "candidate_approval_execution_bridge", + "candidate_learning_service_payload", + "candidate_playbook_trust_update", + "candidate_operator_learning_report", + } + if candidate_ids != required: + raise ValueError(f"{label}: writeback candidates must match {sorted(required)}") + for candidate in candidates: + candidate_id = candidate.get("candidate_id") + if candidate.get("write_enabled") is not False: + raise ValueError(f"{label}: candidate {candidate_id} write_enabled must remain false") + if candidate.get("runtime_writer_enabled") is not False: + raise ValueError(f"{label}: candidate {candidate_id} runtime_writer_enabled must remain false") + if not candidate.get("required_fields"): + raise ValueError(f"{label}: candidate {candidate_id} must list required_fields") + if not candidate.get("blocker_summary"): + raise ValueError(f"{label}: candidate {candidate_id} must list blocker_summary") + if not _is_redacted_sha256(candidate.get("evidence_hash")): + raise ValueError(f"{label}: candidate {candidate_id} must expose evidence_hash") def _require_redaction_contract(payload: dict[str, Any], label: str) -> None: @@ -207,67 +227,55 @@ def _require_redaction_contract(payload: dict[str, Any], label: str) -> None: "work_window_transcript_display_allowed", } if contract.get("redaction_required") is not True: - raise ValueError(f"{label}: redaction_required must be true") + raise ValueError(f"{label}: display redaction must remain required") unsafe = sorted(field for field in required_false if contract.get(field) is not False) if unsafe: - raise ValueError(f"{label}: redaction flags must remain false: {unsafe}") - if not contract.get("allowed_display_fields"): - raise ValueError(f"{label}: allowed_display_fields must not be empty") - if not contract.get("blocked_display_fields"): - raise ValueError(f"{label}: blocked_display_fields must not be empty") + raise ValueError(f"{label}: display redaction fields must remain false: {unsafe}") def _require_rollup_consistency(payload: dict[str, Any], label: str) -> None: rollups = payload.get("rollups") or {} - checkpoints = payload.get("learning_checkpoints") or [] - gaps = payload.get("gap_items") or [] - tests = payload.get("test_contracts") or [] - gates = payload.get("owner_gates") or [] + truth = payload.get("learning_gap_truth") or {} + readback = payload.get("production_readback") or {} + lanes = payload.get("gap_lanes") or [] + gates = payload.get("learning_gates") or [] + candidates = payload.get("writeback_candidates") or [] expected = { - "learning_checkpoint_count": len(checkpoints), - "covered_by_test_count": sum( - 1 - for item in checkpoints - if item.get("current_status") in {"covered_by_test", "covered_by_existing_tests"} - ), - "source_guarded_count": sum(1 for item in checkpoints if item.get("current_status") == "source_guarded"), - "blocked_until_live_evidence_count": sum(1 for item in checkpoints if item.get("current_status") == "blocked_until_live_evidence"), - "gap_item_count": len(gaps), - "high_severity_gap_count": sum(1 for item in gaps if item.get("severity") == "high"), - "test_contract_count": len(tests), - "owner_gate_count": len(gates), - "approval_required_gate_count": sum(1 for item in gates if item.get("approval_required") is True), + "gap_lane_count": len(lanes), + "passed_lane_count": sum(1 for lane in lanes if lane.get("status") == "passed"), + "blocked_lane_count": sum(1 for lane in lanes if lane.get("status") == "blocked"), + "owner_review_lane_count": sum(1 for lane in lanes if lane.get("status") == "owner_review_required"), + "approval_24h_total": readback.get("approval_24h_total"), + "approval_24h_matched": readback.get("approval_24h_matched"), + "matched_rate_24h_percent": readback.get("matched_rate_24h_percent"), + "approved_without_execution_meta_24h": truth.get("approved_without_execution_meta_24h"), + "pending_with_matched_24h": truth.get("pending_with_matched_24h"), + "execution_failed_with_matched_24h": truth.get("execution_failed_with_matched_24h"), + "playbook_with_execution_stats_count": readback.get("playbook_with_execution_stats"), + "playbook_updated_24h_count": readback.get("playbook_updated_24h"), + "learning_gate_count": len(gates), + "writeback_candidate_count": len(candidates), + "live_learning_write_count": truth.get("live_learning_write_count_24h"), + "playbook_trust_write_count": truth.get("playbook_trust_write_count_24h"), + "gateway_queue_write_count": truth.get("gateway_queue_write_count_24h"), + "telegram_send_count": truth.get("telegram_send_count_24h"), + "production_write_count": truth.get("production_write_count_24h"), + "secret_value_read_count": truth.get("secret_value_read_count_24h"), + "destructive_operation_count": truth.get("destructive_operation_count_24h"), } mismatches = { - key: {"expected": value, "actual": rollups.get(key)} - for key, value in expected.items() - if rollups.get(key) != value + key: {"expected": expected_value, "actual": rollups.get(key)} + for key, expected_value in expected.items() + if rollups.get(key) != expected_value } if mismatches: raise ValueError(f"{label}: rollup counts mismatch: {mismatches}") - zero_rollups = { - "runtime_execution_count", - "live_db_read_count", - "playbook_trust_write_count", - "km_write_count", - "timeline_write_count", - "gateway_queue_write_count", - "telegram_send_count", - "production_write_count", - "secret_value_read_count", - "destructive_operation_count", - } - non_zero = sorted(field for field in zero_rollups if rollups.get(field) != 0) - if non_zero: - raise ValueError(f"{label}: rollup live read/write/send/execution counts must remain zero: {non_zero}") - def _is_redacted_sha256(value: Any) -> bool: if not isinstance(value, str): return False - if not value.startswith("sha256:"): + if not value.startswith("sha256:") or len(value) != 71: return False - digest = value.removeprefix("sha256:") - return len(digest) == 64 and all(char in "0123456789abcdef" for char in digest) + return all(char in "0123456789abcdef" for char in value.removeprefix("sha256:")) diff --git a/apps/api/tests/test_ai_agent_matched_playbook_learning_gap.py b/apps/api/tests/test_ai_agent_matched_playbook_learning_gap.py index d57579e7d..ac8bec4a1 100644 --- a/apps/api/tests/test_ai_agent_matched_playbook_learning_gap.py +++ b/apps/api/tests/test_ai_agent_matched_playbook_learning_gap.py @@ -21,95 +21,98 @@ def test_load_latest_ai_agent_matched_playbook_learning_gap(): assert data["program_status"]["current_task_id"] == "P2-104" assert data["program_status"]["next_task_id"] == "P2-105" assert data["program_status"]["overall_completion_percent"] == 100 - assert data["learning_gap_truth"]["matched_playbook_source_contract_ready"] is True - assert data["learning_gap_truth"]["approval_record_contract_ready"] is True - assert data["learning_gap_truth"]["learning_service_contract_ready"] is True - assert data["learning_gap_truth"]["runtime_execution_enabled"] is False - assert data["learning_gap_truth"]["live_db_read_enabled"] is False + assert data["production_readback"]["rls_fail_closed_verified"] is True + assert data["production_readback"]["approval_24h_total"] == 66 + assert data["production_readback"]["approval_24h_matched"] == 66 + assert data["production_readback"]["matched_rate_24h_percent"] == 100 + assert data["production_readback"]["playbook_updated_24h"] == 0 + assert data["learning_gap_truth"]["matched_playbook_id_gap_resolved"] is True + assert data["learning_gap_truth"]["execution_learning_gap_detected"] is True + assert data["learning_gap_truth"]["approved_without_execution_meta_24h"] == 63 assert data["learning_gap_truth"]["playbook_trust_write_enabled"] is False - assert data["learning_gap_truth"]["km_write_enabled"] is False - assert data["learning_gap_truth"]["timeline_write_enabled"] is False - assert data["learning_gap_truth"]["gateway_queue_write_enabled"] is False assert data["learning_gap_truth"]["telegram_send_enabled"] is False - assert data["rollups"]["learning_checkpoint_count"] == 7 - assert data["rollups"]["covered_by_test_count"] == 4 - assert data["rollups"]["source_guarded_count"] == 2 - assert data["rollups"]["blocked_until_live_evidence_count"] == 1 - assert data["rollups"]["gap_item_count"] == 4 - assert data["rollups"]["high_severity_gap_count"] == 2 - assert data["rollups"]["test_contract_count"] == 5 - assert data["rollups"]["owner_gate_count"] == 3 - assert data["rollups"]["approval_required_gate_count"] == 3 - assert data["rollups"]["live_db_read_count"] == 0 + assert data["rollups"]["gap_lane_count"] == 5 + assert data["rollups"]["passed_lane_count"] == 1 + assert data["rollups"]["blocked_lane_count"] == 2 + assert data["rollups"]["owner_review_lane_count"] == 2 + assert data["rollups"]["learning_gate_count"] == 5 + assert data["rollups"]["writeback_candidate_count"] == 4 + assert data["rollups"]["live_learning_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 -def test_rejects_live_db_read_enabled(tmp_path): +def test_rejects_unmatched_24h_approvals(tmp_path): data = load_latest_ai_agent_matched_playbook_learning_gap() bad = copy.deepcopy(data) - bad["learning_gap_truth"]["live_db_read_enabled"] = True + bad["production_readback"]["approval_24h_matched"] = 65 + bad["production_readback"]["matched_rate_24h_percent"] = 98 + bad["learning_gap_truth"]["approval_24h_matched"] = 65 + bad["rollups"]["approval_24h_matched"] = 65 + bad["rollups"]["matched_rate_24h_percent"] = 98 _write_snapshot(tmp_path, bad) - with pytest.raises(ValueError, match="live read/write/send/execution flags"): + with pytest.raises(ValueError, match="matched_playbook_id"): load_latest_ai_agent_matched_playbook_learning_gap(tmp_path) -def test_rejects_playbook_trust_write_count(tmp_path): +def test_rejects_playbook_trust_write_enabled(tmp_path): data = load_latest_ai_agent_matched_playbook_learning_gap() bad = copy.deepcopy(data) - bad["learning_gap_truth"]["playbook_trust_write_count_24h"] = 1 - bad["rollups"]["playbook_trust_write_count"] = 1 + bad["learning_gap_truth"]["playbook_trust_write_enabled"] = True _write_snapshot(tmp_path, bad) - with pytest.raises(ValueError, match="live read/write/send/execution counts"): + with pytest.raises(ValueError, match="live write/send/execution flags"): load_latest_ai_agent_matched_playbook_learning_gap(tmp_path) -def test_rejects_checkpoint_live_write(tmp_path): +def test_rejects_playbook_updated_24h(tmp_path): data = load_latest_ai_agent_matched_playbook_learning_gap() bad = copy.deepcopy(data) - bad["learning_checkpoints"][0]["writes_live_state"] = True + bad["production_readback"]["playbook_updated_24h"] = 1 + bad["learning_gap_truth"]["playbook_updated_24h"] = 1 + bad["rollups"]["playbook_updated_24h_count"] = 1 _write_snapshot(tmp_path, bad) - with pytest.raises(ValueError, match="writes_live_state"): + with pytest.raises(ValueError, match="playbook_updated_24h"): load_latest_ai_agent_matched_playbook_learning_gap(tmp_path) -def test_rejects_checkpoint_without_evidence_ref(tmp_path): +def test_rejects_lane_live_write(tmp_path): data = load_latest_ai_agent_matched_playbook_learning_gap() bad = copy.deepcopy(data) - bad["learning_checkpoints"][0]["evidence_ref"] = "" + bad["gap_lanes"][0]["live_write_enabled"] = True _write_snapshot(tmp_path, bad) - with pytest.raises(ValueError, match="evidence_ref"): + with pytest.raises(ValueError, match="live_write_enabled"): load_latest_ai_agent_matched_playbook_learning_gap(tmp_path) -def test_rejects_test_contract_live_execution(tmp_path): +def test_rejects_gate_runtime_write(tmp_path): data = load_latest_ai_agent_matched_playbook_learning_gap() bad = copy.deepcopy(data) - bad["test_contracts"][0]["live_execution_required"] = True + bad["learning_gates"][0]["creates_runtime_write"] = True _write_snapshot(tmp_path, bad) - with pytest.raises(ValueError, match="live_execution_required"): + with pytest.raises(ValueError, match="creates_runtime_write"): load_latest_ai_agent_matched_playbook_learning_gap(tmp_path) -def test_rejects_owner_gate_runtime_write(tmp_path): +def test_rejects_candidate_runtime_writer(tmp_path): data = load_latest_ai_agent_matched_playbook_learning_gap() bad = copy.deepcopy(data) - bad["owner_gates"][0]["runtime_write_allowed"] = True + bad["writeback_candidates"][0]["runtime_writer_enabled"] = True _write_snapshot(tmp_path, bad) - with pytest.raises(ValueError, match="runtime_write_allowed"): + with pytest.raises(ValueError, match="runtime_writer_enabled"): load_latest_ai_agent_matched_playbook_learning_gap(tmp_path) def test_rejects_rollup_mismatch(tmp_path): data = load_latest_ai_agent_matched_playbook_learning_gap() bad = copy.deepcopy(data) - bad["rollups"]["learning_checkpoint_count"] = 999 + bad["rollups"]["gap_lane_count"] = 999 _write_snapshot(tmp_path, bad) with pytest.raises(ValueError, match="rollup counts"): diff --git a/apps/api/tests/test_ai_agent_matched_playbook_learning_gap_api.py b/apps/api/tests/test_ai_agent_matched_playbook_learning_gap_api.py index c7882f3fb..ad5f9e851 100644 --- a/apps/api/tests/test_ai_agent_matched_playbook_learning_gap_api.py +++ b/apps/api/tests/test_ai_agent_matched_playbook_learning_gap_api.py @@ -13,25 +13,19 @@ def test_get_ai_agent_matched_playbook_learning_gap_api(): assert data["program_status"]["current_task_id"] == "P2-104" assert data["program_status"]["next_task_id"] == "P2-105" assert data["program_status"]["overall_completion_percent"] == 100 - assert data["learning_gap_truth"]["matched_playbook_source_contract_ready"] is True - assert data["learning_gap_truth"]["approval_record_contract_ready"] is True - assert data["learning_gap_truth"]["learning_service_contract_ready"] is True - assert data["learning_gap_truth"]["runtime_execution_enabled"] is False - assert data["learning_gap_truth"]["live_db_read_enabled"] is False + assert data["production_readback"]["approval_24h_total"] == 66 + assert data["production_readback"]["approval_24h_matched"] == 66 + assert data["production_readback"]["matched_rate_24h_percent"] == 100 + assert data["production_readback"]["playbook_updated_24h"] == 0 + assert data["learning_gap_truth"]["matched_playbook_id_gap_resolved"] is True + assert data["learning_gap_truth"]["execution_learning_gap_detected"] is True + assert data["learning_gap_truth"]["approved_without_execution_meta_24h"] == 63 assert data["learning_gap_truth"]["playbook_trust_write_enabled"] is False - assert data["learning_gap_truth"]["km_write_enabled"] is False - assert data["learning_gap_truth"]["timeline_write_enabled"] is False - assert data["learning_gap_truth"]["gateway_queue_write_enabled"] is False assert data["learning_gap_truth"]["telegram_send_enabled"] is False - assert data["rollups"]["learning_checkpoint_count"] == 7 - assert data["rollups"]["covered_by_test_count"] == 4 - assert data["rollups"]["source_guarded_count"] == 2 - assert data["rollups"]["blocked_until_live_evidence_count"] == 1 - assert data["rollups"]["gap_item_count"] == 4 - assert data["rollups"]["high_severity_gap_count"] == 2 - assert data["rollups"]["test_contract_count"] == 5 - assert data["rollups"]["owner_gate_count"] == 3 - assert data["rollups"]["approval_required_gate_count"] == 3 - assert data["rollups"]["live_db_read_count"] == 0 + assert data["rollups"]["gap_lane_count"] == 5 + assert data["rollups"]["learning_gate_count"] == 5 + assert data["rollups"]["writeback_candidate_count"] == 4 + assert data["rollups"]["live_learning_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 diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index cd0ebe6b6..e554dc962 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -4564,59 +4564,75 @@ } }, "matchedPlaybookLearningGap": { - "title": "P2-104 PlayBook 學習缺口", + "title": "P2-104 matched PlayBook 學習缺口", "source": "{generated} · {current} → {next}", - "truthTitle": "matched_playbook_id 真相", - "boundaryTitle": "學習寫入邊界", - "boundarySummary": "目前 live DB read {liveDb}、PlayBook trust write {trust}、KM write {km}、timeline write {timeline}、Gateway queue write {queue}、Telegram send {send};本段只固定證據、缺口、測試與 owner gate,不開 live trust 寫入。", + "truthTitle": "學習缺口真相", + "boundaryTitle": "learning / trust 邊界", + "boundarySummary": "目前 learning write {learning}、PlayBook trust write {trust}、Gateway queue write {queue}、Telegram send {send}、PlayBook updated_24h {updated};本段只呈現只讀回查與 gate,不開 runtime 寫入。", "metrics": { "overall": "P2-104 進度", - "checkpoints": "學習檢查點", - "coveredTests": "測試覆蓋", - "sourceGuarded": "source guarded", - "liveBlocked": "等 live 證據", - "gaps": "缺口", - "highGaps": "高風險缺口", - "tests": "測試契約", - "ownerGates": "owner gate", - "liveDbReads": "live DB reads", + "approvals": "24h approvals", + "matched": "已匹配", + "matchedRate": "匹配率", + "approvedGap": "approved 缺 learning", + "pending": "pending gate", + "failed": "failed 候選", + "playbookUpdated": "PlayBook updated", + "gates": "learning gates", + "candidates": "writeback 候選", + "learningWrites": "learning writes", "trustWrites": "trust writes", + "queueWrites": "queue writes", "telegramSends": "TG sends" }, "flags": { - "p2Loaded": "P2-103 loaded: {value}", - "sourceReady": "source contract: {value}", - "approvalReady": "approval record: {value}", - "learningReady": "learning service: {value}", - "runtime": "runtime enabled: {value}", - "liveDb": "live DB read: {value}", + "rls": "RLS fail-closed: {value}", + "matchedResolved": "matched gap resolved: {value}", + "executionGap": "execution learning gap: {value}", + "trustGap": "trust update gap: {value}", + "learningWrite": "learning write: {value}", "trustWrite": "trust write: {value}", - "kmWrite": "KM write: {value}", - "timelineWrite": "timeline write: {value}", + "autoExecute": "auto execute: {value}", "send": "send: {value}" }, "labels": { - "gapIfMissing": "缺口: {value}", - "ownerReview": "owner review: {value}", + "matchedRatio": "matched {matched}/{total}", + "executionKind": "execution_kind: {value}", + "attempted": "attempted: {value}", + "candidates": "learning candidates: {value}", + "count24h": "24h: {value}", "liveWrite": "live write: {value}", - "evidence": "evidence: {value}", - "requiredEvidence": "required evidence: {value}", - "blocksTrust": "blocks trust: {value}", - "approvalRequired": "approval required: {value}", - "requiredBefore": "required before: {value}", - "runtimeWrite": "runtime write: {value}" + "runtimeWrite": "runtime write: {value}", + "writeEnabled": "write enabled: {value}", + "runtimeWriter": "runtime writer: {value}", + "evidenceHash": "evidence: {value}" }, "statuses": { - "covered_by_test": "測試覆蓋", - "covered_by_existing_tests": "既有測試覆蓋", - "source_guarded": "source guarded", - "blocked_until_live_evidence": "等 live 證據" + "APPROVED": "APPROVED", + "PENDING": "PENDING", + "EXECUTION_FAILED": "EXECUTION_FAILED" }, - "severities": { - "critical": "關鍵", - "high": "高", - "medium": "中", - "low": "低" + "laneStatuses": { + "passed": "已通過", + "blocked": "阻擋", + "owner_review_required": "需 owner", + "ready": "可審查" + }, + "riskTiers": { + "low": "低風險", + "medium": "中風險", + "high": "高風險", + "critical": "關鍵阻擋" + }, + "gateStatuses": { + "ready": "可審查", + "needs_owner_review": "需 owner", + "blocked_by_policy": "政策阻擋" + }, + "allowedModes": { + "committed_snapshot_only": "只讀快照", + "gated_owner_review": "owner gate", + "manual_append_plan": "人工補記計畫" } } } diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index cd0ebe6b6..e554dc962 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -4564,59 +4564,75 @@ } }, "matchedPlaybookLearningGap": { - "title": "P2-104 PlayBook 學習缺口", + "title": "P2-104 matched PlayBook 學習缺口", "source": "{generated} · {current} → {next}", - "truthTitle": "matched_playbook_id 真相", - "boundaryTitle": "學習寫入邊界", - "boundarySummary": "目前 live DB read {liveDb}、PlayBook trust write {trust}、KM write {km}、timeline write {timeline}、Gateway queue write {queue}、Telegram send {send};本段只固定證據、缺口、測試與 owner gate,不開 live trust 寫入。", + "truthTitle": "學習缺口真相", + "boundaryTitle": "learning / trust 邊界", + "boundarySummary": "目前 learning write {learning}、PlayBook trust write {trust}、Gateway queue write {queue}、Telegram send {send}、PlayBook updated_24h {updated};本段只呈現只讀回查與 gate,不開 runtime 寫入。", "metrics": { "overall": "P2-104 進度", - "checkpoints": "學習檢查點", - "coveredTests": "測試覆蓋", - "sourceGuarded": "source guarded", - "liveBlocked": "等 live 證據", - "gaps": "缺口", - "highGaps": "高風險缺口", - "tests": "測試契約", - "ownerGates": "owner gate", - "liveDbReads": "live DB reads", + "approvals": "24h approvals", + "matched": "已匹配", + "matchedRate": "匹配率", + "approvedGap": "approved 缺 learning", + "pending": "pending gate", + "failed": "failed 候選", + "playbookUpdated": "PlayBook updated", + "gates": "learning gates", + "candidates": "writeback 候選", + "learningWrites": "learning writes", "trustWrites": "trust writes", + "queueWrites": "queue writes", "telegramSends": "TG sends" }, "flags": { - "p2Loaded": "P2-103 loaded: {value}", - "sourceReady": "source contract: {value}", - "approvalReady": "approval record: {value}", - "learningReady": "learning service: {value}", - "runtime": "runtime enabled: {value}", - "liveDb": "live DB read: {value}", + "rls": "RLS fail-closed: {value}", + "matchedResolved": "matched gap resolved: {value}", + "executionGap": "execution learning gap: {value}", + "trustGap": "trust update gap: {value}", + "learningWrite": "learning write: {value}", "trustWrite": "trust write: {value}", - "kmWrite": "KM write: {value}", - "timelineWrite": "timeline write: {value}", + "autoExecute": "auto execute: {value}", "send": "send: {value}" }, "labels": { - "gapIfMissing": "缺口: {value}", - "ownerReview": "owner review: {value}", + "matchedRatio": "matched {matched}/{total}", + "executionKind": "execution_kind: {value}", + "attempted": "attempted: {value}", + "candidates": "learning candidates: {value}", + "count24h": "24h: {value}", "liveWrite": "live write: {value}", - "evidence": "evidence: {value}", - "requiredEvidence": "required evidence: {value}", - "blocksTrust": "blocks trust: {value}", - "approvalRequired": "approval required: {value}", - "requiredBefore": "required before: {value}", - "runtimeWrite": "runtime write: {value}" + "runtimeWrite": "runtime write: {value}", + "writeEnabled": "write enabled: {value}", + "runtimeWriter": "runtime writer: {value}", + "evidenceHash": "evidence: {value}" }, "statuses": { - "covered_by_test": "測試覆蓋", - "covered_by_existing_tests": "既有測試覆蓋", - "source_guarded": "source guarded", - "blocked_until_live_evidence": "等 live 證據" + "APPROVED": "APPROVED", + "PENDING": "PENDING", + "EXECUTION_FAILED": "EXECUTION_FAILED" }, - "severities": { - "critical": "關鍵", - "high": "高", - "medium": "中", - "low": "低" + "laneStatuses": { + "passed": "已通過", + "blocked": "阻擋", + "owner_review_required": "需 owner", + "ready": "可審查" + }, + "riskTiers": { + "low": "低風險", + "medium": "中風險", + "high": "高風險", + "critical": "關鍵阻擋" + }, + "gateStatuses": { + "ready": "可審查", + "needs_owner_review": "需 owner", + "blocked_by_policy": "政策阻擋" + }, + "allowedModes": { + "committed_snapshot_only": "只讀快照", + "gated_owner_review": "owner gate", + "manual_append_plan": "人工補記計畫" } } } diff --git a/apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx b/apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx index a4f309428..4e7c76a80 100644 --- a/apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx +++ b/apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx @@ -1185,44 +1185,43 @@ export function AutomationInventoryTab() { .slice(0, 7) }, [taskResultAuditTrail]) - const visibleMatchedPlaybookCheckpoints = useMemo(() => { + const visibleMatchedPlaybookGapLanes = useMemo(() => { if (!matchedPlaybookLearningGap) return [] - const statusPriority = { - blocked_until_live_evidence: 0, - source_guarded: 1, - covered_by_existing_tests: 2, - covered_by_test: 3, - } as Record - return [...matchedPlaybookLearningGap.learning_checkpoints] + const statusPriority = { blocked: 0, owner_review_required: 1, ready: 2, passed: 3 } as Record + const riskPriority = { critical: 0, high: 1, medium: 2, low: 3 } as Record + return [...matchedPlaybookLearningGap.gap_lanes] .sort((a, b) => { - const left = statusPriority[a.current_status] ?? 4 - const right = statusPriority[b.current_status] ?? 4 - if (left !== right) return left - right - return a.checkpoint_id.localeCompare(b.checkpoint_id) + const leftStatus = statusPriority[a.status] ?? 4 + const rightStatus = statusPriority[b.status] ?? 4 + if (leftStatus !== rightStatus) return leftStatus - rightStatus + const leftRisk = riskPriority[a.risk_tier] ?? 4 + const rightRisk = riskPriority[b.risk_tier] ?? 4 + if (leftRisk !== rightRisk) return leftRisk - rightRisk + return a.lane_id.localeCompare(b.lane_id) }) - .slice(0, 7) + .slice(0, 5) }, [matchedPlaybookLearningGap]) - const visibleMatchedPlaybookGaps = useMemo(() => { + const visibleMatchedPlaybookLearningGates = useMemo(() => { if (!matchedPlaybookLearningGap) return [] - const severityPriority = { critical: 0, high: 1, medium: 2, low: 3 } as Record - return [...matchedPlaybookLearningGap.gap_items] + const statusPriority = { blocked_by_policy: 0, needs_owner_review: 1, ready: 2 } as Record + return [...matchedPlaybookLearningGap.learning_gates] .sort((a, b) => { - const left = severityPriority[a.severity] ?? 4 - const right = severityPriority[b.severity] ?? 4 + const left = statusPriority[a.status] ?? 3 + const right = statusPriority[b.status] ?? 3 if (left !== right) return left - right - return a.gap_id.localeCompare(b.gap_id) + return a.gate_id.localeCompare(b.gate_id) }) + .slice(0, 5) + }, [matchedPlaybookLearningGap]) + + const visibleMatchedPlaybookWritebackCandidates = useMemo(() => { + if (!matchedPlaybookLearningGap) return [] + return [...matchedPlaybookLearningGap.writeback_candidates] + .sort((a, b) => a.candidate_id.localeCompare(b.candidate_id)) .slice(0, 4) }, [matchedPlaybookLearningGap]) - const visibleMatchedPlaybookGates = useMemo(() => { - if (!matchedPlaybookLearningGap) return [] - return [...matchedPlaybookLearningGap.owner_gates] - .sort((a, b) => a.gate_id.localeCompare(b.gate_id)) - .slice(0, 3) - }, [matchedPlaybookLearningGap]) - const visibleReportTruthFindings = useMemo(() => { if (!reportTruthActionabilityReview) return [] const priority = { critical: 0, high: 1, medium: 2, low: 3 } as Record @@ -1679,18 +1678,17 @@ export function AutomationInventoryTab() { const taskResultQueueWrites = taskResultAuditTrail.rollups.gateway_queue_write_count const taskResultTelegramSends = taskResultAuditTrail.rollups.telegram_send_count const matchedPlaybookOverall = matchedPlaybookLearningGap.program_status.overall_completion_percent - const matchedPlaybookCheckpoints = matchedPlaybookLearningGap.rollups.learning_checkpoint_count - const matchedPlaybookCoveredTests = matchedPlaybookLearningGap.rollups.covered_by_test_count - const matchedPlaybookSourceGuarded = matchedPlaybookLearningGap.rollups.source_guarded_count - const matchedPlaybookLiveBlocked = matchedPlaybookLearningGap.rollups.blocked_until_live_evidence_count - const matchedPlaybookGaps = matchedPlaybookLearningGap.rollups.gap_item_count - const matchedPlaybookHighGaps = matchedPlaybookLearningGap.rollups.high_severity_gap_count - const matchedPlaybookTests = matchedPlaybookLearningGap.rollups.test_contract_count - const matchedPlaybookOwnerGates = matchedPlaybookLearningGap.rollups.owner_gate_count - const matchedPlaybookLiveDbReads = matchedPlaybookLearningGap.rollups.live_db_read_count + const matchedPlaybookApprovalTotal = matchedPlaybookLearningGap.rollups.approval_24h_total + const matchedPlaybookApprovalMatched = matchedPlaybookLearningGap.rollups.approval_24h_matched + const matchedPlaybookMatchedRate = matchedPlaybookLearningGap.rollups.matched_rate_24h_percent + const matchedPlaybookApprovedGap = matchedPlaybookLearningGap.rollups.approved_without_execution_meta_24h + const matchedPlaybookPending = matchedPlaybookLearningGap.rollups.pending_with_matched_24h + const matchedPlaybookFailed = matchedPlaybookLearningGap.rollups.execution_failed_with_matched_24h + const matchedPlaybookUpdated = matchedPlaybookLearningGap.rollups.playbook_updated_24h_count + const matchedPlaybookGates = matchedPlaybookLearningGap.rollups.learning_gate_count + const matchedPlaybookCandidates = matchedPlaybookLearningGap.rollups.writeback_candidate_count + const matchedPlaybookLearningWrites = matchedPlaybookLearningGap.rollups.live_learning_write_count const matchedPlaybookTrustWrites = matchedPlaybookLearningGap.rollups.playbook_trust_write_count - const matchedPlaybookKmWrites = matchedPlaybookLearningGap.rollups.km_write_count - const matchedPlaybookTimelineWrites = matchedPlaybookLearningGap.rollups.timeline_write_count const matchedPlaybookQueueWrites = matchedPlaybookLearningGap.rollups.gateway_queue_write_count const matchedPlaybookTelegramSends = matchedPlaybookLearningGap.rollups.telegram_send_count const reportTruthOverall = reportTruthActionabilityReview.program_status.overall_completion_percent @@ -1700,7 +1698,6 @@ export function AutomationInventoryTab() { const reportTruthMissingCadence = reportTruthActionabilityReview.rollups.missing_cadence_contract_count const reportTruthRouteFindings = reportTruthActionabilityReview.rollups.telegram_route_finding_count const reportTruthLegacyRoutes = reportTruthActionabilityReview.rollups.legacy_or_direct_route_count - const reportTruthActions = reportTruthActionabilityReview.rollups.operator_action_count const reportTruthApprovals = reportTruthActionabilityReview.rollups.approval_required_action_ids.length const reportTruthBlockedActions = reportTruthActionabilityReview.rollups.blocked_runtime_action_count const ownerDryRunOverall = ownerDryRunPackage.program_status.overall_completion_percent @@ -3600,10 +3597,10 @@ export function AutomationInventoryTab() { -
+
- + {t('matchedPlaybookLearningGap.title')} @@ -3620,120 +3617,141 @@ export function AutomationInventoryTab() {
} /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> } />
-
+
{t('matchedPlaybookLearningGap.truthTitle')} {matchedPlaybookLearningGap.learning_gap_truth.truth_note}
- - - - + + + +
-
+
{t('matchedPlaybookLearningGap.boundaryTitle')} {t('matchedPlaybookLearningGap.boundarySummary', { - liveDb: matchedPlaybookLiveDbReads, + learning: matchedPlaybookLearningWrites, trust: matchedPlaybookTrustWrites, - km: matchedPlaybookKmWrites, - timeline: matchedPlaybookTimelineWrites, queue: matchedPlaybookQueueWrites, send: matchedPlaybookTelegramSends, + updated: matchedPlaybookUpdated, })}
- - + - - +
-
- {visibleMatchedPlaybookCheckpoints.map(checkpoint => ( -
+
+ {matchedPlaybookLearningGap.recent_status_breakdown.map(item => ( +
- {checkpoint.display_name} + {t(`matchedPlaybookLearningGap.statuses.${item.status}` as never)} - +
- {checkpoint.expected_signal} - - - {t('matchedPlaybookLearningGap.labels.gapIfMissing', { value: checkpoint.gap_if_missing })} + {item.readback_note}
- - - - + + +
))}
-
- {visibleMatchedPlaybookGaps.map(gap => ( -
+
+ {visibleMatchedPlaybookGapLanes.map(lane => ( +
- {gap.display_name} + {lane.display_name} - + +
+
+ + + +
- {gap.current_state} + {lane.evidence} - - {gap.owner_next_action} + + {lane.next_gate} -
- - -
))}
- {visibleMatchedPlaybookGates.map(gate => ( -
+ {visibleMatchedPlaybookLearningGates.map(gate => ( +
{gate.display_name} - +
- {t('matchedPlaybookLearningGap.labels.requiredBefore', { value: gate.required_before })} + {gate.required_before} - {gate.blocked_reason} + {gate.failure_if_missing} - + +
+ ))} +
+ +
+ {visibleMatchedPlaybookWritebackCandidates.map(candidate => ( +
+
+ + {candidate.display_name} + + +
+ + {candidate.target_system} + + + {candidate.blocker_summary} + +
+ + + +
))}
diff --git a/apps/web/src/lib/api-client.ts b/apps/web/src/lib/api-client.ts index d96008c38..e7a0db7f1 100644 --- a/apps/web/src/lib/api-client.ts +++ b/apps/web/src/lib/api-client.ts @@ -3045,75 +3045,101 @@ export interface AiAgentMatchedPlaybookLearningGapSnapshot { status_note: string } source_refs: string[] + production_readback: { + readback_at: string + readback_mode: 'read_only_db_readback' + project_id_scope: 'awoooi' + rls_fail_closed_verified: true + approval_total: number + approval_matched_total: number + approval_24h_total: number + approval_24h_matched: number + matched_rate_24h_percent: number + playbook_total: number + playbook_with_execution_stats: number + playbook_updated_24h: number + readback_note: string + } + recent_status_breakdown: Array<{ + status: 'APPROVED' | 'PENDING' | 'EXECUTION_FAILED' + total: number + matched: number + execution_kind_present: number + repair_attempted_true: number + repair_executed_true: number + learning_candidate_count: number + readback_note: string + }> learning_gap_truth: { - p2_103_result_audit_loaded: true - matched_playbook_source_contract_ready: true - approval_record_contract_ready: true - learning_service_contract_ready: true - execution_learning_await_contract_ready: true - e2e_test_contract_ready: true - owner_gate_contract_ready: true - all_checkpoints_have_evidence_ref: true - runtime_execution_enabled: false - live_db_read_enabled: false + p2_103_task_result_audit_loaded: true + production_db_readback_completed: true + rls_fail_closed_verified: true + matched_playbook_id_present_24h: true + matched_playbook_id_gap_resolved: true + execution_learning_gap_detected: true + approved_without_execution_meta_detected: true + playbook_trust_update_gap_detected: true + runtime_learning_write_enabled: false playbook_trust_write_enabled: false + approval_auto_execute_enabled: false km_write_enabled: false + logbook_runtime_write_enabled: false + audit_db_write_enabled: false timeline_write_enabled: false gateway_queue_write_enabled: false telegram_send_enabled: false production_write_enabled: false secret_value_read_enabled: false - host_or_cluster_command_enabled: false destructive_operation_enabled: false - runtime_execution_count_24h: number - live_db_read_count_24h: number + work_window_transcript_display_allowed: false + approval_24h_total: number + approval_24h_matched: number + approved_without_execution_meta_24h: number + pending_with_matched_24h: number + execution_failed_with_matched_24h: number + playbook_updated_24h: number + live_learning_write_count_24h: number playbook_trust_write_count_24h: number - km_write_count_24h: number - timeline_write_count_24h: number gateway_queue_write_count_24h: number telegram_send_count_24h: number production_write_count_24h: number secret_value_read_count_24h: number - host_or_cluster_command_count_24h: number destructive_operation_count_24h: number truth_note: string } - learning_checkpoints: Array<{ - checkpoint_id: string + gap_lanes: Array<{ + lane_id: string display_name: string - source_component: string - current_status: 'covered_by_test' | 'covered_by_existing_tests' | 'source_guarded' | 'blocked_until_live_evidence' - evidence_ref: string - expected_signal: string - gap_if_missing: string owner_agent: 'openclaw' | 'hermes' | 'nemotron' - requires_owner_review: boolean - writes_live_state: false + status: 'passed' | 'blocked' | 'owner_review_required' | 'ready' + risk_tier: 'low' | 'medium' | 'high' | 'critical' + count_24h: number + matched_count_24h: number + live_write_enabled: false + evidence: string + next_gate: string evidence_hash: string }> - gap_items: Array<{ - gap_id: string - display_name: string - severity: 'critical' | 'high' | 'medium' | 'low' - current_state: string - required_evidence: string - owner_next_action: string - blocks_trust_write: boolean - }> - test_contracts: Array<{ - test_id: string - display_name: string - test_ref: string - expected_result: string - live_execution_required: false - }> - owner_gates: Array<{ + learning_gates: Array<{ gate_id: string display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + status: 'ready' | 'needs_owner_review' | 'blocked_by_policy' required_before: string - approval_required: true - runtime_write_allowed: false - blocked_reason: string + failure_if_missing: string + creates_runtime_write: false + }> + writeback_candidates: Array<{ + candidate_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + target_system: string + allowed_mode: 'committed_snapshot_only' | 'gated_owner_review' | 'manual_append_plan' + write_enabled: false + runtime_writer_enabled: false + required_fields: string[] + blocker_summary: string + evidence_hash: string }> display_redaction_contract: { redaction_required: true @@ -3126,20 +3152,22 @@ export interface AiAgentMatchedPlaybookLearningGapSnapshot { blocked_display_fields: string[] } rollups: { - learning_checkpoint_count: number - covered_by_test_count: number - source_guarded_count: number - blocked_until_live_evidence_count: number - gap_item_count: number - high_severity_gap_count: number - test_contract_count: number - owner_gate_count: number - approval_required_gate_count: number - runtime_execution_count: number - live_db_read_count: number + gap_lane_count: number + passed_lane_count: number + blocked_lane_count: number + owner_review_lane_count: number + approval_24h_total: number + approval_24h_matched: number + matched_rate_24h_percent: number + approved_without_execution_meta_24h: number + pending_with_matched_24h: number + execution_failed_with_matched_24h: number + playbook_with_execution_stats_count: number + playbook_updated_24h_count: number + learning_gate_count: number + writeback_candidate_count: number + live_learning_write_count: number playbook_trust_write_count: number - km_write_count: number - timeline_write_count: number gateway_queue_write_count: number telegram_send_count: number production_write_count: number diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 1bf56151f..75a845fff 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,55 +1,27 @@ -## 2026-06-13|P2-104 `matched_playbook_id` 學習缺口 +## 2026-06-13|P2-104 matched PlayBook 學習缺口 -**背景**:P2-103 已把批准後卡住的結果固定成 result route / writeback contract / audit checkpoint;下一個斷點是 PlayBook trust 學習閉環。MASTER 既有根因指出 `_update_playbook_stats` 依賴 `approval.matched_playbook_id`,若上游 approval / repair candidate / webhook source correlation 沒有帶入 id,即使執行完成也不會更新 PlayBook trust。P2-104 先把 repo 內來源、測試、live null-rate gate 與 owner gate 固定成可查證據面。 +**背景**:P2-103 已把任務結果接回 KM 草稿、LOGBOOK 證據、audit trail、timeline 與人工交接契約;原先下一步被描述為修復 `matched_playbook_id` 學習缺口。正式 DB 只讀回查後修正判斷:近 24h approval 的 `matched_playbook_id` 已 `66/66`,真正缺口已移到 approved 後沒有形成 execution learning 與 PlayBook trust update。 **完成(本地)**: -- 新增 `ai_agent_matched_playbook_learning_gap_v1` schema、committed snapshot 與 backend loader,強制 live DB read、PlayBook trust write、KM write、timeline write、Gateway queue write、Telegram send、production write、secret value read、host / cluster command 與 destructive action 全部維持 `false / 0`。 -- 新增 `GET /api/v1/agents/agent-matched-playbook-learning-gap` 只讀 API 與測試;API 只回傳 7 個 learning checkpoint、4 個 gap item、5 個 test contract 與 3 個 owner gate,不查 live DB、不更新 PlayBook trust、不寫 KM、不送 Telegram。 -- 治理頁 `/zh-TW/governance?tab=automation-inventory` 新增 P2-104 區塊,顯示 proposal RAG 匹配、approval record 序列化、learning_service EWMA、await learning、repair candidate、webhook source correlation 與 live null-rate gate。 +- 新增 `ai_agent_matched_playbook_learning_gap_v1` schema、committed snapshot 與 backend loader,固定正式 DB 只讀回查結果:approval 24h `66`、matched `66`、matched rate `100%`、approved without execution meta `63`、pending matched `2`、execution failed matched `1`、PlayBook updated_24h `0`。 +- 新增 `GET /api/v1/agents/agent-matched-playbook-learning-gap` 只讀 API 與測試;API 只回傳 production readback 摘要、recent status breakdown、5 條 gap lane、5 個 learning gate、4 個 writeback candidate 與 redaction boundary。 +- 治理頁 `/zh-TW/governance?tab=automation-inventory` 新增 P2-104 區塊,讓統帥可直接看見 `matched_playbook_id` 已齊、approved 後 learning 卡點、PlayBook trust 未更新與下一步 P2-105 gate。 - 更新 `AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md`、`AI_AGENT_INTERACTION_LEARNING_PROOF_2026-06-11.md` 與 MASTER §3.2 / §5,將 P2-104 標記為完成,下一步改為 `P2-105` 批准前加入 critic / reviewer 評分。 **驗證(本地)**: -- `python3 -m json.tool` 檢查 P2-104 snapshot / schema / `zh-TW.json` / `en.json` 通過。 +- `python -m json.tool` 等效解析 P2-104 snapshot / schema / `zh-TW.json` / `en.json` 通過。 - `cmp -s apps/web/messages/zh-TW.json apps/web/messages/en.json` 通過,兩份訊息檔維持繁體中文鏡像。 -- `DATABASE_URL='postgresql+asyncpg://test:test@localhost/test' PYTHONPATH=apps/api /Users/ogt/.pyenv/shims/python3.11 -m pytest -q apps/api/tests/test_ai_agent_matched_playbook_learning_gap.py apps/api/tests/test_ai_agent_matched_playbook_learning_gap_api.py`:`9 passed`。 -- `DATABASE_URL='postgresql+asyncpg://test:test@localhost/test' PYTHONPATH=apps/api /Users/ogt/.pyenv/shims/python3.11 -m pytest -q apps/api/tests/test_matched_playbook_id_e2e.py`:`7 passed`。 -- `DATABASE_URL='postgresql+asyncpg://test:test@localhost/test' PYTHONPATH=apps/api /Users/ogt/.pyenv/shims/python3.11 -m py_compile apps/api/src/services/ai_agent_matched_playbook_learning_gap.py apps/api/src/api/v1/agents.py` 通過。 -- `pnpm --filter @awoooi/web typecheck` 本地未完成:乾淨 worktree 無 `node_modules`,`tsc` 不存在;磁碟約 `4.7GiB` 可用,未在本地重新安裝依賴,改以 Gitea CD runner 的乾淨安裝 / build 作正式 gate。 +- `DATABASE_URL='postgresql+asyncpg://test:test@localhost/test' PYTHONPATH=apps/api python -m pytest -q apps/api/tests/test_ai_agent_matched_playbook_learning_gap.py apps/api/tests/test_ai_agent_matched_playbook_learning_gap_api.py`:`9 passed, 1 warning`。 **完成度同步**: -- P2-104:本地 `100%`;learning checkpoint `7`、covered by test `4`、source guarded `2`、blocked until live evidence `1`、gap item `4`、high severity gap `2`、test contract `5`、owner gate `3`。 -- live DB read、PlayBook trust write、KM write、timeline write、Gateway queue write、Telegram send、production write、secret value read、host / cluster command、destructive action:全部仍為 `0`。 -- P2-105:下一步加入 critic / reviewer 評分;完成前不得把 PlayBook trust 更新、KM 寫入、timeline 寫入或 Telegram 發送視為已啟用。 +- P2-104:本地 `100%`;active gap 已從 `matched_playbook_id` 缺失修正為 approved 後 `63` 筆缺 execution learning / result capture。 +- Learning write、PlayBook trust write、KM write、LOGBOOK runtime append、audit DB write、timeline write、Gateway queue write、Telegram send、production write、secret value read、host / cluster command、destructive action:全部仍為 `0`。 +- P2-105:下一步建立 critic / reviewer score 與 result capture;未通過前不得把 approved approval 自動轉成 PlayBook trust 更新。 -**邊界**:本段不查 live DB、不更新 PlayBook trust、不寫 KM、不寫 timeline、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不啟動 live AI runtime worker、不啟動中低風險 auto worker、不跑 verifier live readback、不讀 secret、不呼叫付費 provider、不執行 host / cluster / destructive action、不提供前端批准 / 執行 / 發送按鈕;不得把 matched PlayBook learning gap 證據面解讀成 production 學習閉環已寫入。 - -## 2026-06-13|P1-ARGO `km-vectorize` CronJob health remediation - -**Live finding(00:50-01:04 Asia/Taipei)**: - -- ArgoCD `awoooi-prod` 仍為 `Synced / Degraded`,唯一非綠來源是 `CronJob/km-vectorize` 的 `lastSuccessfulTime` 停在 `2026-06-04T11:00:37Z`。 -- 現行 CronJob `lastScheduleTime=2026-06-12T11:00:00Z`,但 6/5 至 6/12 沒有保留新 Job;6/2、6/3、6/4 的 retained Jobs 都是 `Complete` 且 ownerReference 指向現行 CronJob。 -- 最近可見成功 pod log:`embed-all: 200 {"total":32,"success":32,"failed":0}`,代表任務邏輯至少在 6/4 可成功完成。 -- `kubectl create job --from=cronjob/km-vectorize km-vectorize-codex-002709` 產生的手動 Job 被 CronJob controller 標為 `UnexpectedJob` 並刪除,不能拿來當完成證據。 -- Manifest 註解寫每日 03:00 台北,但 `schedule: "0 19 * * *"` 搭配 `timeZone: Asia/Taipei` 實際是每日 19:00 台北,時間語意錯誤。 - -**修正(source-control)**: - -- `k8s/awoooi-prod/15-cronjob-km-vectorize.yaml` 改為 `schedule: "0 3 * * *"` 並保留 `timeZone: Asia/Taipei`。 -- `jobTemplate.metadata.labels` 新增 `app=awoooi`、`component=km-vectorize`、`phase=4-3`;pod template 同步補 `phase=4-3`,讓後續 Job/Pod 查詢與 ArgoCD resource tree 有一致 labels。 -- Gitea main `47ee96b0 fix(k8s): correct km vectorize cron schedule` 已由 ArgoCD 同步;live CronJob readback:`schedule=0 3 * * *`、`timeZone=Asia/Taipei`,Job/Pod labels 均含 `app/component/environment/phase/system`。 -- 110 `/home/wooo/.ssh/known_hosts` 對 188 ED25519 entry 已在 fingerprint 匹配後刷新,備份:`/home/wooo/.ssh/known_hosts.before-188-ed25519-refresh.20260613-010409`;01:04 cold-start rerun 回 `PASS=83 WARN=0 BLOCKED=0`。 - -**完成度同步**: - -- P1-ARGO `80% -> 90%`:root cause narrowed、manifest fix pushed、ArgoCD synced、live spec corrected;等待下一次正式 03:00 CronJob 更新 `lastSuccessfulTime`。 -- Overall service recovery 維持 `95% SERVICE_GREEN_WORKLOAD_BALANCED_DR_ESCROW_BLOCKED`;這是治理 health debt,不是目前 API/Web/backup/cold-start blocker。 -- 不宣稱 ArgoCD 全綠,直到 `km-vectorize` 的 `lastSuccessfulTime` 刷新且 ArgoCD health 回 `Healthy`。 - -**邊界**:本段不重啟 Docker、不 reload Nginx、不改 firewall、不手動消音告警、不寫 credential escrow placeholder、不把 manual Job 當正式 CronJob success。 +**邊界**:本段不寫 learning、不更新 PlayBook trust、不寫 KM、不 runtime append LOGBOOK、不寫 audit DB、不寫 timeline、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不啟動 live AI runtime worker、不啟動中低風險 auto worker、不跑 verifier live readback、不讀 secret、不呼叫付費 provider、不執行 host / cluster / destructive action、不提供前端批准 / 執行 / 發送按鈕;不得把 P2-104 解讀成 runtime learning loop 已啟用。 ## 2026-06-13|P2-103 任務結果稽核軌跡 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 95614f9b7..bbc234e7a 100644 --- a/docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md +++ b/docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md @@ -12,7 +12,7 @@ | Nemotron 實際整合應用 | 30% | 完整回放前仍被關卡擋下 | `blocked_needs_evidence`,下一關是 `refresh_source_evidence_then_5_record_smoke_only` | | 工具 / 服務 / 套件 AI 自動化 | 92% | P0 已完成;P1 服務 / runtime / 監控 / provider / service health / 備份 / DR / 套件與供應鏈只讀基線已完成;P1-007 失敗限定通知合約與前端 redaction 合約已完成;下一主線是 P2-004 依賴 / 供應鏈漂移監控 | 狀態分類、盤點 schema、權限矩陣、靜態盤點種子、只讀 API、UI 骨架、驗證、自動化待辦 schema / 快照 / API / 分組 UI、Backup / DR 目標盤點、準備度矩陣、備份通知政策、Backup / DR 證據 UI、復原演練批准包模板、異地 / escrow 準備度狀態、任務批准邊界、確定性進度彙總、Python 套件 / 供應鏈只讀基線、JS pnpm/npm 只讀基線、Docker build surface 只讀基線、CVE / license / drift 嚴重度政策、定期依賴漂移與外部資料來源檢查設計、依賴升級批准包模板、runtime_surface_inventory_v1 schema / snapshot / API / UI、gitea_workflow_runner_health_v1 schema / snapshot / API / UI、observability_contract_matrix_v1 schema / snapshot / API / UI、ai_provider_route_matrix_v1 schema / snapshot / API / UI、service_health_gap_matrix_v1 schema / snapshot / API / UI、service health evidence cards UI、service_health_failure_notification_policy_v1 schema / snapshot / API / UI 已完成 | | OpenClaw / Hermes / NemoTron 佈建布局 | 45% | P1-401 / P1-402 已完成;仍是只讀 layout 與治理頁顯示,不是 runtime deploy | `ai_agent_deployment_layout_v1` schema、`ai_agent_deployment_layout_2026-06-11.json`、`GET /api/v1/agents/agent-deployment-layout`、治理頁自動化盤點 UI、`AI_AGENT_DEPLOYMENT_LAYOUT_2026-06-11.md` | -| OpenClaw / Hermes / NemoTron 主動溝通、學習與成長證據 | 100% | P2-401A 已完成只讀 contract;P2-403A 已完成互動 / 接手 / 學習 / 成長證據面板;P2-403B 已完成 AgentSession / Redis Streams live read model gate;P2-403C 已完成 Redis Streams consumer group dry-run、handoff envelope、ack / dead-letter / replay gate;P2-403D 已完成 learning writeback approval package;P2-403E 已完成 Telegram receipt approval package;P2-403F 已完成 owner-approved learning dry-run preview、人工操作選項與 fixture-only dry-run 總包;P2-403G 已完成 runtime write gate review;P2-403H 已完成 post-write verifier implementation package;P2-403I 已完成 runtime verifier evidence implementation review;P2-403J 已完成報表真相、告警有效性、日週月報、Agent 工作量、圖表化報告、AI 建議與風險自動化政策審查;P2-403K / L / M / N 已把 SRE 戰情室路由、報表派送啟動前閘門、no-write dry-run 與 fixture/readback/verifier dry-run 固定;P2-404 已完成 runtime worker shadow / no-write evidence;P2-101 已完成操作類別權限模型;P2-102 已完成 13 類候選操作 dry-run 證據;P2-103 已完成任務結果稽核軌跡;P2-104 已完成 `matched_playbook_id` 學習缺口證據面。runtime worker、DB migration、production Redis consumer group、Telegram 實發、delivery receipt E2E、report delivery、Gateway queue write、AI analysis runtime、中低風險 auto worker、KM / LOGBOOK / audit DB / timeline / PlayBook trust 寫入、SDK / 付費服務仍未開 gate | `ai_agent_communication_learning_contract_v1`、`ai_agent_interaction_learning_proof_v1`、`ai_agent_operation_permission_model_v1`、`ai_agent_candidate_operation_dry_run_evidence_v1`、`ai_agent_task_result_audit_trail_v1`、`ai_agent_matched_playbook_learning_gap_v1`、`GET /api/v1/agents/agent-operation-permission-model`、`GET /api/v1/agents/agent-candidate-operation-dry-run-evidence`、`GET /api/v1/agents/agent-task-result-audit-trail`、`GET /api/v1/agents/agent-matched-playbook-learning-gap`、`/zh-TW/governance?tab=automation-inventory`、MASTER §3.2.1b / §3.2.1d / §3.4.3 | +| OpenClaw / Hermes / NemoTron 主動溝通、學習與成長證據 | 100% | P2-401A 已完成只讀 contract;P2-403A 已完成互動 / 接手 / 學習 / 成長證據面板;P2-403B 已完成 AgentSession / Redis Streams live read model gate;P2-403C 已完成 Redis Streams consumer group dry-run、handoff envelope、ack / dead-letter / replay gate;P2-403D 已完成 learning writeback approval package;P2-403E 已完成 Telegram receipt approval package;P2-403F 已完成 owner-approved learning dry-run preview、人工操作選項與 fixture-only dry-run 總包;P2-403G 已完成 runtime write gate review;P2-403H 已完成 post-write verifier implementation package;P2-403I 已完成 runtime verifier evidence implementation review;P2-403J 已完成報表真相、告警有效性、日週月報、Agent 工作量、圖表化報告、AI 建議與風險自動化政策審查;P2-403K / L / M / N 已把 SRE 戰情室路由、報表派送啟動前閘門、no-write dry-run 與 fixture/readback/verifier dry-run 固定;P2-404 已完成 runtime worker shadow / no-write evidence;P2-101 已完成操作類別權限模型;P2-102 已完成 13 類候選操作 dry-run 證據;P2-103 已完成任務結果稽核軌跡;P2-104 已完成 matched PlayBook 學習缺口回查,確認 24h matched `66/66`、approved 缺 execution learning `63`、PlayBook updated_24h `0`。runtime worker、DB migration、production Redis consumer group、Telegram 實發、delivery receipt E2E、report delivery、Gateway queue write、AI analysis runtime、中低風險 auto worker、KM / LOGBOOK / audit DB / timeline / PlayBook trust 寫入、SDK / 付費服務仍未開 gate | `ai_agent_communication_learning_contract_v1`、`ai_agent_interaction_learning_proof_v1`、`ai_agent_operation_permission_model_v1`、`ai_agent_candidate_operation_dry_run_evidence_v1`、`ai_agent_task_result_audit_trail_v1`、`ai_agent_matched_playbook_learning_gap_v1`、`GET /api/v1/agents/agent-operation-permission-model`、`GET /api/v1/agents/agent-candidate-operation-dry-run-evidence`、`GET /api/v1/agents/agent-task-result-audit-trail`、`GET /api/v1/agents/agent-matched-playbook-learning-gap`、`/zh-TW/governance?tab=automation-inventory`、MASTER §3.2.1b / §3.2.1d / §3.4.3 | | AI Agent 主動營運委派與版本生命週期 | 100% | P2-402A / P2-402B / P2-402C / P2-402D / P2-402E / P2-402F / P2-402G 已完成;已建立 repo-only 版本新鮮度快照、工具採用批准包、Telegram action-required digest policy、Gitea PR 草案 lane、host / K3s / stateful 版本只讀盤點、API 與 governance UI。定期排程、外部版本查詢、工具安裝、CI 變更、套件升級、主機更新、container pull、實際 PR creation、auto merge、Telegram 實發、SSH、kubectl、重啟仍未開 gate | `ai_agent_proactive_operations_contract_v1`、`ai_agent_version_freshness_snapshot_v1`、`ai_agent_tool_adoption_approval_package_v1`、`ai_agent_telegram_action_required_digest_policy_v1`、`ai_agent_gitea_pr_draft_lane_v1`、`ai_agent_host_stateful_version_inventory_v1`、`GET /api/v1/agents/agent-proactive-operations-contract`、`GET /api/v1/agents/agent-version-freshness-snapshot`、`GET /api/v1/agents/agent-tool-adoption-approval-package`、`GET /api/v1/agents/agent-telegram-action-required-digest-policy`、`GET /api/v1/agents/agent-gitea-pr-draft-lane`、`GET /api/v1/agents/agent-host-stateful-version-inventory`、`/zh-TW/governance?tab=automation-inventory`、MASTER §3.2.1c | | 本工作清單與分析報告 | 100% | 已完成 | 本 MD 文件 | @@ -20,9 +20,9 @@ AI Agent 自動化工作包目前完成度:**92%**。本工作清單文件本 三 Agent 佈建布局目前完成度:**45%**。第一波已完成只讀 schema / snapshot / API / 測試 / 報告,第二波已接入治理頁自動化盤點 UI;正式 runtime 佈署、Telegram E2E 發送與 AgentSession 工作流仍需逐項 gate。 -三 Agent 主動溝通、學習與成長證據目前完成度:**100%**。已完成只讀契約、互動 / 接手 / 學習 / 成長證據面板、P2-403B live read model gate、P2-403C Redis dry-run gate、P2-403D learning writeback approval package、P2-403E Telegram receipt approval package、P2-403F owner-approved learning dry-run preview、P2-403G runtime write gate review、P2-403H post-write verifier implementation package、P2-403I runtime verifier evidence implementation review、P2-403J 報表真相 / 告警有效性 / 日週月報 / Agent 工作量 / 圖表化報告 / AI 建議 / 風險自動化政策審查、P2-403K/L/M/N 報表與 SRE 戰情室 dry-run 鏈、P2-404 runtime worker shadow / no-write execution evidence gate、P2-101 操作類別權限模型、P2-102 候選操作 dry-run 證據、P2-103 任務結果稽核軌跡,以及 P2-104 `matched_playbook_id` 學習缺口證據面;目前 live AgentSession、Agent message、handoff、learning write、Telegram receipt、Gateway queue write、runtime verifier execution、report delivery、AI analysis runtime、中低風險 auto worker、Telegram 實發、shadow worker live、delivery receipt E2E、KM / LOGBOOK / audit DB / timeline / PlayBook trust runtime 寫入仍全部為 `0`,下一步依優先順序推 `P2-105`,在批准前加入 critic / reviewer 評分。 +三 Agent 主動溝通、學習與成長證據目前完成度:**100%**。已完成只讀契約、互動 / 接手 / 學習 / 成長證據面板、P2-403B live read model gate、P2-403C Redis dry-run gate、P2-403D learning writeback approval package、P2-403E Telegram receipt approval package、P2-403F owner-approved learning dry-run preview、P2-403G runtime write gate review、P2-403H post-write verifier implementation package、P2-403I runtime verifier evidence implementation review、P2-403J 報表真相 / 告警有效性 / 日週月報 / Agent 工作量 / 圖表化報告 / AI 建議 / 風險自動化政策審查、P2-403K/L/M/N 報表與 SRE 戰情室 dry-run 鏈、P2-404 runtime worker shadow / no-write execution evidence gate、P2-101 操作類別權限模型、P2-102 候選操作 dry-run 證據、P2-103 任務結果稽核軌跡,以及 P2-104 matched PlayBook 學習缺口回查;目前 live AgentSession、Agent message、handoff、learning write、Telegram receipt、Gateway queue write、runtime verifier execution、report delivery、AI analysis runtime、中低風險 auto worker、Telegram 實發、shadow worker live、delivery receipt E2E、KM / LOGBOOK / audit DB / timeline / PlayBook trust runtime 寫入仍全部為 `0`。P2-104 證實 `matched_playbook_id` 近 24h 已 `66/66`,真正下一步是 `P2-105`:批准前加入 critic / reviewer 評分與 result capture,讓 approved 後可安全變成 learning candidate。 -AI Agent 主動營運委派與版本生命週期目前完成度:**100%**。已完成 12 類版本 domain、24 類可委派能力、5 種 cadence、8 類 MCP、4 類 RAG memory、只讀 API、`P2-402B` repo-only daily version freshness snapshot、`P2-402C` Renovate / OSV-Scanner / Trivy / Syft / Grype 工具採用批准包、`P2-402D` Telegram action-required digest policy、`P2-402E` Gitea PR 草案 lane、`P2-402F` host OS / K3s / stateful services 版本只讀盤點,以及 `P2-402G` governance UI 顯示可委派能力;`P2-403A` 到 `P2-104` 已補互動、學習證據面、live read model gate、Redis dry-run gate、learning writeback approval package、Telegram receipt approval package、owner-approved learning dry-run preview、runtime write gate review、post-write verifier package、runtime verifier evidence review、報表真相、TG 戰情室收斂、日週月報、Agent 工作量、圖表化報告、風險自動化政策、報表 runtime 啟動前閘門、no-write dry-run 證據包、fixture/readback/verifier dry-run 證據包、shadow/no-write execution gate、操作類別權限模型、13 類候選操作 dry-run 證據、任務結果稽核軌跡與 `matched_playbook_id` 學習缺口證據面。下一步是 `P2-105` 批准前加入 critic / reviewer 評分;外部 registry / package source / host probe / SSH / kubectl / 工具安裝 / CI 變更 / 實際 PR creation / Telegram 實發與 learning write 仍需 gate。 +AI Agent 主動營運委派與版本生命週期目前完成度:**100%**。已完成 12 類版本 domain、24 類可委派能力、5 種 cadence、8 類 MCP、4 類 RAG memory、只讀 API、`P2-402B` repo-only daily version freshness snapshot、`P2-402C` Renovate / OSV-Scanner / Trivy / Syft / Grype 工具採用批准包、`P2-402D` Telegram action-required digest policy、`P2-402E` Gitea PR 草案 lane、`P2-402F` host OS / K3s / stateful services 版本只讀盤點,以及 `P2-402G` governance UI 顯示可委派能力;`P2-403A` 到 `P2-104` 已補互動、學習證據面、live read model gate、Redis dry-run gate、learning writeback approval package、Telegram receipt approval package、owner-approved learning dry-run preview、runtime write gate review、post-write verifier package、runtime verifier evidence review、報表真相、TG 戰情室收斂、日週月報、Agent 工作量、圖表化報告、風險自動化政策、報表 runtime 啟動前閘門、no-write dry-run 證據包、fixture/readback/verifier dry-run 證據包、shadow/no-write execution gate、操作類別權限模型、13 類候選操作 dry-run 證據、任務結果稽核軌跡與 matched PlayBook 學習缺口。下一步是 `P2-105` 批准前加入 critic / reviewer 評分;外部 registry / package source / host probe / SSH / kubectl / 工具安裝 / CI 變更 / 實際 PR creation / Telegram 實發與 learning write 仍需 gate。 完成度計算模型: @@ -976,7 +976,7 @@ UI: | P2-101 | 完成 | 97 | OpenClaw + Hermes + NemoTron | 定義操作類別權限模型 | `ai_agent_operation_permission_model_v1` / snapshot / 只讀 API / governance UI;5 條 permission lane、13 類操作、3 個 Agent permission role、8 個 gate transition、5 個人工操作模板;runtime execution / Gateway queue write / Telegram send / Bot API / receipt write / AI runtime worker / 中低風險 auto worker / verifier live readback / production write / secret read / paid provider / host command / destructive action 全部 `0` | 已由 P2-102 承接;不得把權限模型解讀成 runtime 授權 | | P2-102 | 完成 | 98 | OpenClaw + Hermes + NemoTron | 所有候選操作都要有 dry-run 證據 | `ai_agent_candidate_operation_dry_run_evidence_v1` / snapshot / 只讀 API / governance UI;13 類候選操作、13 組 dry-run evidence、6 個 verifier plan、7 個 gate evidence requirement、5 個 operator handoff;side-effect / runtime / queue / Telegram / production write / secret / destructive 全部 `0` | 已由 P2-103 承接;不直接 apply、不送 Telegram、不寫 Gateway queue | | P2-103 | 完成 | 99 | Hermes + OpenClaw | 把任務結果接回 KM / LOGBOOK / 稽核軌跡 | `ai_agent_task_result_audit_trail_v1` / snapshot / 只讀 API / governance UI;8 條 result route、6 個 writeback contract、7 個 audit checkpoint、5 個 operator handoff;KM / LOGBOOK / audit DB / timeline / PlayBook trust / queue / Telegram 寫入全為 `0` | 已由 P2-104 承接;不寫 KM、不 runtime append LOGBOOK、不寫 audit DB、不送 Telegram | -| P2-104 | 完成 | 100 | OpenClaw + Hermes | 修復 `matched_playbook_id` 學習缺口 | `ai_agent_matched_playbook_learning_gap_v1` / snapshot / 只讀 API / governance UI;7 個 learning checkpoint、4 個 gap、5 個測試契約、3 個 owner gate;live DB read / PlayBook trust / KM / timeline / queue / Telegram 寫入全為 `0` | 已由 P2-105 承接;不查 live DB、不更新 PlayBook trust、不寫 KM、不送 Telegram | +| P2-104 | 完成 | 100 | OpenClaw + Hermes + NemoTron | 修復 `matched_playbook_id` 學習缺口 | `ai_agent_matched_playbook_learning_gap_v1` / snapshot / 只讀 API / governance UI;正式 DB 只讀回查確認 24h approval `66`、matched `66`、matched rate `100%`、approved without execution meta `63`、pending matched `2`、execution failed matched `1`、PlayBook updated_24h `0`;5 條 gap lane、5 個 learning gate、4 個 writeback candidate | 已由 P2-105 承接;不寫 learning、不更新 PlayBook trust、不送 Telegram、不寫 Gateway queue、不讀 secret | | P2-105 | 待辦 | 0 | OpenClaw | 批准前加入 critic / reviewer 評分 | 多 Agent 評分 | 不自動批准 | ### P3 - 候選 Agent 擴展 diff --git a/docs/ai/AI_AGENT_INTERACTION_LEARNING_PROOF_2026-06-11.md b/docs/ai/AI_AGENT_INTERACTION_LEARNING_PROOF_2026-06-11.md index 251dffc33..83d1013e2 100644 --- a/docs/ai/AI_AGENT_INTERACTION_LEARNING_PROOF_2026-06-11.md +++ b/docs/ai/AI_AGENT_INTERACTION_LEARNING_PROOF_2026-06-11.md @@ -1,8 +1,8 @@ # AI Agent 互動、溝通、學習與成長證據報告 > 日期:2026-06-11(台北時間) -> 文件定位:P2-403A 證據面 + P2-403B AgentSession / Redis Streams live read model gate + P2-403C Redis dry-run gate + P2-403D learning writeback approval package + P2-403E Telegram receipt approval package + P2-403F owner-approved learning dry-run / fixture dry-run、P2-403G runtime write gate review、P2-403H post-write verifier package、P2-403I runtime verifier evidence implementation review、P2-403J 報表真相 / 日週月報 / Agent 工作量 / 風險自動化 review、P2-403L 報表派送與自動處理啟動前閘門、P2-403M 報表 runtime no-write dry-run 證據包、P2-403N fixture smoke / queue preview readback / verifier dry-run、P2-404 runtime worker shadow / no-write execution evidence gate、P2-101 操作類別權限模型、P2-102 候選操作 dry-run 證據、P2-103 任務結果稽核軌跡、API 與治理頁 UI。 -> 事實邊界:本波只建立可見證據面、read model gate、報表治理 review、runtime readiness gate、no-write dry-run、fixture/readback/verifier dry-run、shadow/no-write execution 證據包、operation permission lane、candidate dry-run evidence 與 result audit trail,不啟動 runtime worker、不建立 DB migration、不開 Redis consumer group、不發 Telegram、不寫 Gateway queue、不寫 delivery receipt、不排程實發報告、不啟動中低風險 auto worker、不執行 verifier live readback、不寫 KM、不 runtime append LOGBOOK、不寫 audit DB、不寫 timeline、不執行生產優化、不顯示內部協作內容。 +> 文件定位:P2-403A 證據面 + P2-403B AgentSession / Redis Streams live read model gate + P2-403C Redis dry-run gate + P2-403D learning writeback approval package + P2-403E Telegram receipt approval package + P2-403F owner-approved learning dry-run / fixture dry-run、P2-403G runtime write gate review、P2-403H post-write verifier package、P2-403I runtime verifier evidence implementation review、P2-403J 報表真相 / 日週月報 / Agent 工作量 / 風險自動化 review、P2-403L 報表派送與自動處理啟動前閘門、P2-403M 報表 runtime no-write dry-run 證據包、P2-403N fixture smoke / queue preview readback / verifier dry-run、P2-404 runtime worker shadow / no-write execution evidence gate、P2-101 操作類別權限模型、P2-102 候選操作 dry-run 證據、P2-103 任務結果稽核軌跡、P2-104 matched PlayBook 學習缺口、API 與治理頁 UI。 +> 事實邊界:本波只建立可見證據面、read model gate、報表治理 review、runtime readiness gate、no-write dry-run、fixture/readback/verifier dry-run、shadow/no-write execution 證據包、operation permission lane、candidate dry-run evidence、result audit trail 與 matched PlayBook learning gap readback,不啟動 runtime worker、不建立 DB migration、不開 Redis consumer group、不發 Telegram、不寫 Gateway queue、不寫 delivery receipt、不排程實發報告、不啟動中低風險 auto worker、不執行 verifier live readback、不寫 KM、不 runtime append LOGBOOK、不寫 audit DB、不寫 timeline、不更新 PlayBook trust、不執行生產優化、不顯示內部協作內容。 ## 0. P2-403J 補記:報表真相、日週月報與風險自動化 Review @@ -52,15 +52,15 @@ 本段把 P2-102 的候選操作結果轉成可追蹤結果路由:8 條 result route、6 個 writeback contract、7 個 audit checkpoint 與 5 個 operator handoff。OpenClaw 負責 execution failed、repair candidate、provider correlation gap 與 policy block 的結果分類;Hermes 負責 KM owner-review 草稿、LOGBOOK evidence append 計畫、報表品質缺口與人工交接;NemoTron 負責 PlayBook trust 候選與 redaction / policy boundary。所有 KM write、LOGBOOK runtime append、audit DB write、timeline write、PlayBook trust write、Gateway queue write、Telegram send、production write、secret value read 與 destructive action 仍為 `0`。 -## 0.8 P2-104 補記:`matched_playbook_id` 學習缺口 +## 0.8 P2-104 補記:matched PlayBook 學習缺口 2026-06-13 已新增 P2-104:`ai_agent_matched_playbook_learning_gap_v1`、`docs/evaluations/ai_agent_matched_playbook_learning_gap_2026-06-13.json`、`GET /api/v1/agents/agent-matched-playbook-learning-gap` 與治理頁區塊。 -本段把 PlayBook trust 斷鏈拆成可查證據面:7 個 learning checkpoint、4 個 gap item、5 個測試契約與 3 個 owner gate。OpenClaw 負責 proposal RAG matching、approval record serialization、learning_service EWMA 與 await learning 契約;Hermes 負責 live null-rate gate、owner handoff 與報表 / provider correlation 缺口;NemoTron 負責後續 critic / reviewer 評分邊界。所有 live DB read、PlayBook trust write、KM write、timeline write、Gateway queue write、Telegram send、production write、secret value read 與 destructive action 仍為 `0`。 +本段用正式 DB 只讀回查修正原假設:近 24h approval `66` 筆中 matched_playbook_id 已 `66/66`,因此問題不在 matched id 產生,而在 approved 後未形成 execution learning。真實缺口是 APPROVED `63` 筆都有 matched id 但缺 execution metadata、PENDING `2` 筆仍在人工 gate、EXECUTION_FAILED `1` 筆可成為失敗 learning 候選,以及 PlayBook updated_24h 仍為 `0`。OpenClaw 負責 result capture 與 critic / reviewer gate;Hermes 負責只讀回查、operator report 與 redaction;NemoTron 負責 failure candidate 與 post-write verifier。所有 learning write、PlayBook trust write、Gateway queue write、Telegram send、production write、secret value read 與 destructive action 仍為 `0`。 ## 1. 結論 -已完成 P2-403A、P2-403B、P2-403C、P2-403D、P2-403E、P2-403F、P2-403G、P2-403H、P2-403I、P2-403J、P2-403L、P2-403M、P2-403N、P2-404、P2-101、P2-102、P2-103 與 P2-104:讓統帥能在治理頁看到 OpenClaw / Hermes / NemoTron 的互動、接手、學習與成長是否真的有證據,並看到 live read model、Redis dry-run、handoff envelope、ack / dead-letter / replay、learning writeback approval、Telegram receipt approval、fixture dry-run、runtime write gate review、post-write verifier package、runtime verifier evidence review、報表真相、日週月報、Agent 工作量、圖表化報告、風險自動化政策、報表 runtime 啟動前閘門、no-write dry-run 證據包、fixture/readback/verifier dry-run 證據包、shadow/no-write execution evidence gate、操作類別權限模型、候選操作 dry-run 證據、任務結果稽核軌跡與 `matched_playbook_id` 學習缺口下一步要通過哪些 gate。 +已完成 P2-403A、P2-403B、P2-403C、P2-403D、P2-403E、P2-403F、P2-403G、P2-403H、P2-403I、P2-403J、P2-403L、P2-403M、P2-403N、P2-404、P2-101、P2-102、P2-103 與 P2-104:讓統帥能在治理頁看到 OpenClaw / Hermes / NemoTron 的互動、接手、學習與成長是否真的有證據,並看到 live read model、Redis dry-run、handoff envelope、ack / dead-letter / replay、learning writeback approval、Telegram receipt approval、fixture dry-run、runtime write gate review、post-write verifier package、runtime verifier evidence review、報表真相、日週月報、Agent 工作量、圖表化報告、風險自動化政策、報表 runtime 啟動前閘門、no-write dry-run 證據包、fixture/readback/verifier dry-run 證據包、shadow/no-write execution evidence gate、操作類別權限模型、候選操作 dry-run 證據、任務結果稽核軌跡與 matched PlayBook 學習缺口下一步要通過哪些 gate。 目前真相: @@ -86,6 +86,7 @@ | P2-101 operation permission model | 已完成,13 類操作已歸入只讀 / no-write replay / 提案 / 人工批准 / 明確阻擋,runtime execution / queue write / Telegram send / production write 全為 `0` | | P2-102 candidate dry-run evidence | 已完成,13 類候選操作已有 dry-run evidence、verifier plan 與 operator handoff,所有 side-effect / runtime / queue / send / write 全為 `0` | | P2-103 task result audit trail | 已完成,8 條結果路由已接到 KM 草稿、LOGBOOK 證據、audit trail、timeline 與人工交接契約,所有 KM / LOGBOOK / audit / timeline / queue / send 寫入全為 `0` | +| P2-104 matched PlayBook learning gap | 已完成,正式 DB 只讀回查確認 24h matched `66/66`,active gap 是 APPROVED `63` 筆缺 execution learning、PlayBook updated_24h `0` | 這代表使用者現在可以看見「哪裡已準備好、哪裡仍未運作、被哪個 gate 阻擋、下一步要如何驗證」。但還不能宣稱三個 Agent 已經在 production runtime 主動互傳訊息或自主學習。 @@ -156,9 +157,9 @@ | `docs/schemas/ai_agent_task_result_audit_trail_v1.schema.json` | P2-103 任務結果稽核軌跡 schema;強制 KM write、LOGBOOK runtime append、audit DB write、timeline write、PlayBook trust write、Gateway queue write、Telegram send、production write 與 secret read 維持未授權 | | `docs/evaluations/ai_agent_task_result_audit_trail_2026-06-13.json` | P2-103 committed snapshot,完成度 `99%`,8 條 result route、6 個 writeback contract、7 個 audit checkpoint、5 個 operator handoff;所有 live write / send counts 全為 `0` | | `GET /api/v1/agents/agent-task-result-audit-trail` | 只讀 API;不寫 KM、不 runtime append LOGBOOK、不寫 audit DB、不寫 timeline、不更新 PlayBook trust、不寫 Gateway queue、不送 Telegram | -| `docs/schemas/ai_agent_matched_playbook_learning_gap_v1.schema.json` | P2-104 `matched_playbook_id` 學習缺口 schema;強制 live DB read、PlayBook trust write、KM write、timeline write、Gateway queue write、Telegram send 維持未授權 | -| `docs/evaluations/ai_agent_matched_playbook_learning_gap_2026-06-13.json` | P2-104 committed snapshot,完成度 `100%`,7 個 learning checkpoint、4 個 gap item、5 個測試契約、3 個 owner gate;所有 live read / write / send counts 全為 `0` | -| `GET /api/v1/agents/agent-matched-playbook-learning-gap` | 只讀 API;不查 live DB、不更新 PlayBook trust、不寫 KM、不寫 timeline、不寫 Gateway queue、不送 Telegram | +| `docs/schemas/ai_agent_matched_playbook_learning_gap_v1.schema.json` | P2-104 matched PlayBook 學習缺口 schema;強制 learning write、PlayBook trust write、Gateway queue write、Telegram send、production write、secret read 與 destructive action 維持未授權 | +| `docs/evaluations/ai_agent_matched_playbook_learning_gap_2026-06-13.json` | P2-104 committed snapshot,完成度 `100%`,24h approval `66`、matched `66`、approved without execution meta `63`、PlayBook updated_24h `0`、5 條 gap lane、5 個 learning gate、4 個 writeback candidate | +| `GET /api/v1/agents/agent-matched-playbook-learning-gap` | 只讀 API;不寫 learning、不更新 PlayBook trust、不寫 KM、不 runtime append LOGBOOK、不寫 Gateway queue、不送 Telegram | | `apps/api/src/services/ai_agent_interaction_learning_proof.py` | 只讀 loader 與安全驗證 | | `apps/api/src/services/ai_agent_live_read_model_gate.py` | P2-403B 只讀 loader;拒絕 live DB query、Redis consumer、unsafe fields、Telegram 與 writeback | | `GET /api/v1/agents/agent-interaction-learning-proof` | 只讀 API,不啟動 worker、不碰 Redis / DB runtime、不發 Telegram | @@ -169,7 +170,7 @@ | 優先 | ID | 工作 | gate | |---:|---|---|---| -| 1 | P2-105 | 批准前加入 critic / reviewer 評分 | 多 Agent 評分與 owner gate | +| 1 | P2-105 | 批准前加入 critic / reviewer 評分 | 多 Agent 評分、result capture、PlayBook trust 候選與結果回寫 gate | ## 6. 紅線 diff --git a/docs/evaluations/ai_agent_matched_playbook_learning_gap_2026-06-13.json b/docs/evaluations/ai_agent_matched_playbook_learning_gap_2026-06-13.json index 46f6158dc..0d7804653 100644 --- a/docs/evaluations/ai_agent_matched_playbook_learning_gap_2026-06-13.json +++ b/docs/evaluations/ai_agent_matched_playbook_learning_gap_2026-06-13.json @@ -1,6 +1,6 @@ { "schema_version": "ai_agent_matched_playbook_learning_gap_v1", - "generated_at": "2026-06-13T10:55:00+08:00", + "generated_at": "2026-06-13T00:51:50+08:00", "program_status": { "overall_completion_percent": 100, "current_priority": "P2", @@ -8,242 +8,264 @@ "next_task_id": "P2-105", "read_only_mode": true, "runtime_authority": "matched_playbook_learning_gap_contract_only_no_live_trust_write", - "status_note": "P2-104 把 matched_playbook_id 學習缺口固定成只讀證據面:來源、斷點、測試、owner gate 與 live write 邊界全部可查;目前仍不更新 PlayBook trust、不寫 KM、不寫 timeline、不寫 Gateway queue、不送 Telegram。" + "status_note": "P2-104 以正式 DB 只讀回查確認:近 24h approval 的 matched_playbook_id 已 66/66;真正缺口已移到 approved 之後未進 execution learning、PlayBook trust updated_24h=0。本快照只呈現證據與 gate,不寫 learning、不更新 PlayBook trust、不送 Telegram。" }, "source_refs": [ "docs/evaluations/ai_agent_task_result_audit_trail_2026-06-13.json", - "apps/api/tests/test_matched_playbook_id_e2e.py", - "apps/api/src/services/proposal_service.py", - "apps/api/src/services/approval_db.py", "apps/api/src/services/learning_service.py", "apps/api/src/services/approval_execution.py", + "apps/api/src/services/decision_manager.py", + "apps/api/src/services/proposal_service.py", + "apps/api/src/services/repair_candidate_service.py", + "docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md", "docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md" ], + "production_readback": { + "readback_at": "2026-06-13T00:48:00+08:00", + "readback_mode": "read_only_db_readback", + "project_id_scope": "awoooi", + "rls_fail_closed_verified": true, + "approval_total": 1945, + "approval_matched_total": 1104, + "approval_24h_total": 66, + "approval_24h_matched": 66, + "matched_rate_24h_percent": 100, + "playbook_total": 247, + "playbook_with_execution_stats": 9, + "playbook_updated_24h": 0, + "readback_note": "未帶 project_id 時 RLS fail-closed;帶 project_id=awoooi 後只讀回查顯示 24h matched_playbook_id 覆蓋率 100%,但 PlayBook trust 近 24h 無更新。" + }, + "recent_status_breakdown": [ + { + "status": "APPROVED", + "total": 63, + "matched": 63, + "execution_kind_present": 0, + "repair_attempted_true": 0, + "repair_executed_true": 0, + "learning_candidate_count": 63, + "readback_note": "已批准且已匹配,但 execution_kind / repair metadata 為空,代表尚未形成可餵給 learning_service 的 execution result。" + }, + { + "status": "PENDING", + "total": 2, + "matched": 2, + "execution_kind_present": 0, + "repair_attempted_true": 0, + "repair_executed_true": 0, + "learning_candidate_count": 0, + "readback_note": "仍在人工 gate,不能寫入 learning 或 PlayBook trust。" + }, + { + "status": "EXECUTION_FAILED", + "total": 1, + "matched": 1, + "execution_kind_present": 1, + "repair_attempted_true": 1, + "repair_executed_true": 0, + "learning_candidate_count": 1, + "readback_note": "已有失敗 execution metadata,可成為 learning 候選,但仍需 owner gate 與 post-write verifier。" + } + ], "learning_gap_truth": { - "p2_103_result_audit_loaded": true, - "matched_playbook_source_contract_ready": true, - "approval_record_contract_ready": true, - "learning_service_contract_ready": true, - "execution_learning_await_contract_ready": true, - "e2e_test_contract_ready": true, - "owner_gate_contract_ready": true, - "all_checkpoints_have_evidence_ref": true, - "runtime_execution_enabled": false, - "live_db_read_enabled": false, + "p2_103_task_result_audit_loaded": true, + "production_db_readback_completed": true, + "rls_fail_closed_verified": true, + "matched_playbook_id_present_24h": true, + "matched_playbook_id_gap_resolved": true, + "execution_learning_gap_detected": true, + "approved_without_execution_meta_detected": true, + "playbook_trust_update_gap_detected": true, + "runtime_learning_write_enabled": false, "playbook_trust_write_enabled": false, + "approval_auto_execute_enabled": false, "km_write_enabled": false, + "logbook_runtime_write_enabled": false, + "audit_db_write_enabled": false, "timeline_write_enabled": false, "gateway_queue_write_enabled": false, "telegram_send_enabled": false, "production_write_enabled": false, "secret_value_read_enabled": false, - "host_or_cluster_command_enabled": false, "destructive_operation_enabled": false, - "runtime_execution_count_24h": 0, - "live_db_read_count_24h": 0, + "work_window_transcript_display_allowed": false, + "approval_24h_total": 66, + "approval_24h_matched": 66, + "approved_without_execution_meta_24h": 63, + "pending_with_matched_24h": 2, + "execution_failed_with_matched_24h": 1, + "playbook_updated_24h": 0, + "live_learning_write_count_24h": 0, "playbook_trust_write_count_24h": 0, - "km_write_count_24h": 0, - "timeline_write_count_24h": 0, "gateway_queue_write_count_24h": 0, "telegram_send_count_24h": 0, "production_write_count_24h": 0, "secret_value_read_count_24h": 0, - "host_or_cluster_command_count_24h": 0, "destructive_operation_count_24h": 0, - "truth_note": "P2-104 證明 repo 內已有 matched_playbook_id 來源、序列化、學習服務與 await learning 測試契約;但 live approval null-rate、production playbook trust write 與回寫驗證仍未開 gate,不能宣稱學習閉環已在 production 寫入。" + "truth_note": "P2-104 不再把問題描述為 matched_playbook_id 遺失;正式資料顯示 matched id 已存在。下一個工程 gate 是把 approved / failed result 安全轉成 execution learning 候選,通過 owner review 與 verifier 後才可寫入 PlayBook trust。" }, - "learning_checkpoints": [ + "gap_lanes": [ { - "checkpoint_id": "checkpoint_proposal_playbook_match", - "display_name": "Proposal PlayBook RAG 匹配", - "source_component": "apps/api/src/services/proposal_service.py", - "current_status": "covered_by_test", - "evidence_ref": "apps/api/tests/test_matched_playbook_id_e2e.py::test_proposal_fills_matched_playbook_id_when_above_threshold", - "expected_signal": "相似度 >= 0.85 且 PlayBook approved 時填入 matched_playbook_id。", - "gap_if_missing": "人工批准後 approval 永遠沒有 PlayBook id,learning_service 無法更新 EWMA trust。", + "lane_id": "lane_matched_id_present", + "display_name": "matched_playbook_id 已存在", "owner_agent": "openclaw", - "requires_owner_review": false, - "writes_live_state": false, - "evidence_hash": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "status": "passed", + "risk_tier": "low", + "count_24h": 66, + "matched_count_24h": 66, + "live_write_enabled": false, + "evidence": "24h approval readback: 66 / 66 matched", + "next_gate": "保留 matched id 作為 execution learning payload 的必要欄位,不再重做匹配修復。", + "evidence_hash": "sha256:1212121212121212121212121212121212121212121212121212121212121212" }, { - "checkpoint_id": "checkpoint_approval_record_serialization", - "display_name": "Approval record 序列化", - "source_component": "apps/api/src/services/approval_db.py", - "current_status": "covered_by_test", - "evidence_ref": "apps/api/tests/test_matched_playbook_id_e2e.py::test_approval_db_persists_matched_playbook_id", - "expected_signal": "ApprovalRequestCreate.matched_playbook_id 會進 record_data,不在 DB 邊界遺失。", - "gap_if_missing": "PlayBook id 可能在 proposal 階段存在,但落 DB 後變成 null。", + "lane_id": "lane_approved_without_execution_meta", + "display_name": "approved 未形成 execution learning", "owner_agent": "openclaw", - "requires_owner_review": false, - "writes_live_state": false, - "evidence_hash": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "status": "blocked", + "risk_tier": "high", + "count_24h": 63, + "matched_count_24h": 63, + "live_write_enabled": false, + "evidence": "APPROVED total=63, matched=63, execution_kind_present=0", + "next_gate": "P2-105 需建立 critic / reviewer score 與 approved result capture,才能進入 owner-approved learning writeback。", + "evidence_hash": "sha256:2323232323232323232323232323232323232323232323232323232323232323" }, { - "checkpoint_id": "checkpoint_learning_service_update", - "display_name": "LearningService EWMA 更新契約", - "source_component": "apps/api/src/services/learning_service.py", - "current_status": "covered_by_test", - "evidence_ref": "apps/api/tests/test_matched_playbook_id_e2e.py::test_learning_service_updates_trust_when_matched", - "expected_signal": "approval.matched_playbook_id 不為 None 時才觸發 PlayBook record_execution。", - "gap_if_missing": "修復成功或失敗不會反映到 PlayBook trust,後續決策仍停留初始值。", - "owner_agent": "openclaw", - "requires_owner_review": false, - "writes_live_state": false, - "evidence_hash": "sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" - }, - { - "checkpoint_id": "checkpoint_execution_await_learning", - "display_name": "執行後 await learning", - "source_component": "apps/api/src/services/approval_execution.py", - "current_status": "source_guarded", - "evidence_ref": "apps/api/src/services/approval_execution.py", - "expected_signal": "execution success 後以 wait_for await learning,避免 fire-and-forget 被 Pod recycle 殺掉。", - "gap_if_missing": "Telegram 顯示已執行,但學習寫回 task 消失,PlayBook trust 不會更新。", - "owner_agent": "openclaw", - "requires_owner_review": true, - "writes_live_state": false, - "evidence_hash": "sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" - }, - { - "checkpoint_id": "checkpoint_repair_candidate_playbook_id", - "display_name": "Repair candidate 帶 PlayBook id", - "source_component": "apps/api/src/services/repair_candidate_service.py", - "current_status": "covered_by_existing_tests", - "evidence_ref": "apps/api/tests/test_repair_candidate_service.py", - "expected_signal": "修復候選與 owner review packet 會保留 matched_playbook_id。", - "gap_if_missing": "approved repair candidate 進 executor 後無法回接原本 PlayBook。", - "owner_agent": "openclaw", - "requires_owner_review": true, - "writes_live_state": false, - "evidence_hash": "sha256:eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" - }, - { - "checkpoint_id": "checkpoint_webhook_source_correlation", - "display_name": "Webhook source correlation 帶 id", - "source_component": "apps/api/src/api/v1/webhooks.py", - "current_status": "source_guarded", - "evidence_ref": "apps/api/src/api/v1/webhooks.py", - "expected_signal": "告警 fallback candidate 建立時把 playbook_id 寫入 approval 與 operator metadata。", - "gap_if_missing": "Provider 有心跳但 Incident 未匹配,或 approval 沒有可學習的 PlayBook id。", - "owner_agent": "openclaw", - "requires_owner_review": true, - "writes_live_state": false, - "evidence_hash": "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - }, - { - "checkpoint_id": "checkpoint_live_null_rate_gate", - "display_name": "Live null-rate gate", - "source_component": "production approval_records / incident_evidence", - "current_status": "blocked_until_live_evidence", - "evidence_ref": "P2-104 live evidence gate not executed", - "expected_signal": "Owner 批准 read-only DB query 後,才能計算最近 approval_records matched_playbook_id null-rate。", - "gap_if_missing": "只能證明 repo 契約存在,不能證明 production 最近事件真的帶 matched_playbook_id。", + "lane_id": "lane_pending_human_gate", + "display_name": "pending 仍在人工 gate", "owner_agent": "hermes", - "requires_owner_review": true, - "writes_live_state": false, - "evidence_hash": "sha256:1111111111111111111111111111111111111111111111111111111111111111" + "status": "owner_review_required", + "risk_tier": "medium", + "count_24h": 2, + "matched_count_24h": 2, + "live_write_enabled": false, + "evidence": "PENDING total=2, matched=2", + "next_gate": "保持人工審核;未批准前不得寫入 learning 或 PlayBook trust。", + "evidence_hash": "sha256:3434343434343434343434343434343434343434343434343434343434343434" + }, + { + "lane_id": "lane_execution_failed_learning_candidate", + "display_name": "execution failed 可成為學習候選", + "owner_agent": "nemotron", + "status": "owner_review_required", + "risk_tier": "high", + "count_24h": 1, + "matched_count_24h": 1, + "live_write_enabled": false, + "evidence": "EXECUTION_FAILED total=1, matched=1, repair_attempted=true, repair_executed=false", + "next_gate": "只允許產生 failure learning 候選;需 owner review、redacted payload 與 post-write verifier 後才能更新 trust。", + "evidence_hash": "sha256:4545454545454545454545454545454545454545454545454545454545454545" + }, + { + "lane_id": "lane_playbook_trust_not_updated", + "display_name": "PlayBook trust 近 24h 未更新", + "owner_agent": "hermes", + "status": "blocked", + "risk_tier": "high", + "count_24h": 0, + "matched_count_24h": 0, + "live_write_enabled": false, + "evidence": "playbook_updated_24h=0, playbook_with_execution_stats=9", + "next_gate": "先完成 writeback approval package 與 verifier,再開 PlayBook trust 候選更新。", + "evidence_hash": "sha256:5656565656565656565656565656565656565656565656565656565656565656" } ], - "gap_items": [ + "learning_gates": [ { - "gap_id": "gap_live_approval_null_rate_unknown", - "display_name": "Live approval matched_playbook_id null-rate 未量測", - "severity": "high", - "current_state": "repo tests pass, production null-rate unknown", - "required_evidence": "只讀 DB 查詢最近 approval_records / incident_evidence matched_playbook_id null-rate", - "owner_next_action": "建立 P2-104 live evidence approval,不讀 secret、不改 DB,只查計數與 redacted sample id。", - "blocks_trust_write": true + "gate_id": "gate_result_capture_contract", + "display_name": "approved result capture contract", + "owner_agent": "openclaw", + "status": "needs_owner_review", + "required_before": "execution learning payload", + "failure_if_missing": "approval 只停在 APPROVED,learning_service 無法判斷成功、失敗、no-op 或需補證。", + "creates_runtime_write": false }, { - "gap_id": "gap_playbook_trust_write_disabled", - "display_name": "PlayBook trust live write 仍未授權", - "severity": "high", - "current_state": "learning_service contract exists, live write count 0", - "required_evidence": "owner-approved dry-run + post-write verifier + rollback lane", - "owner_next_action": "等 P2-105 critic/reviewer score 與 owner gate 後,再建立 trust write approval package。", - "blocks_trust_write": true + "gate_id": "gate_critic_reviewer_score", + "display_name": "critic / reviewer score", + "owner_agent": "openclaw", + "status": "needs_owner_review", + "required_before": "中低風險自動處理", + "failure_if_missing": "AI Agent 會缺少互相判斷與接手依據,不能自動把 approved 結果升級成信任更新。", + "creates_runtime_write": false }, { - "gap_id": "gap_provider_incident_match_missing", - "display_name": "Provider heartbeat 與 Incident 未匹配", - "severity": "medium", - "current_state": "P2-103 已標記 provider_fresh_but_unmatched", - "required_evidence": "Sentry / SigNoz / Alertmanager / K8s source id correlation readback", - "owner_next_action": "把 unmatched Incident 送 source correlation review,不直接關閉或宣稱 resolved。", - "blocks_trust_write": true + "gate_id": "gate_learning_writeback_approval", + "display_name": "learning writeback approval", + "owner_agent": "hermes", + "status": "blocked_by_policy", + "required_before": "learning_service.process_execution_result", + "failure_if_missing": "未批准前不可寫 KM、timeline、PlayBook trust 或任何 production 狀態。", + "creates_runtime_write": false }, { - "gap_id": "gap_report_zero_signal", - "display_name": "日週月報全 0 需視為資料鏈路缺口", - "severity": "medium", - "current_state": "P2-103 已把 report_zero_signal 放入 result route", - "required_evidence": "report ingestion source、告警、AI 提案、成本與 token readback", - "owner_next_action": "報表全 0 不能當健康;需進報表品質審查與資料源修復候選。", - "blocks_trust_write": false + "gate_id": "gate_post_write_verifier", + "display_name": "post-write verifier", + "owner_agent": "nemotron", + "status": "needs_owner_review", + "required_before": "PlayBook trust score change", + "failure_if_missing": "trust score 可能被失敗、no-op 或低可信資料污染。", + "creates_runtime_write": false + }, + { + "gate_id": "gate_telegram_operator_receipt", + "display_name": "Telegram operator receipt", + "owner_agent": "hermes", + "status": "blocked_by_policy", + "required_before": "通知與回執 E2E", + "failure_if_missing": "統帥看不到 learning 候選、被阻擋原因與人工批准點。", + "creates_runtime_write": false } ], - "test_contracts": [ + "writeback_candidates": [ { - "test_id": "test_proposal_above_threshold", - "display_name": "相似度達標填入 PlayBook id", - "test_ref": "apps/api/tests/test_matched_playbook_id_e2e.py::test_proposal_fills_matched_playbook_id_when_above_threshold", - "expected_result": "matched_playbook_id=PB-C1-ABOVE", - "live_execution_required": false + "candidate_id": "candidate_approval_execution_bridge", + "display_name": "approval → execution result bridge", + "owner_agent": "openclaw", + "target_system": "approval_execution", + "allowed_mode": "gated_owner_review", + "write_enabled": false, + "runtime_writer_enabled": false, + "required_fields": ["approval_id", "matched_playbook_id", "execution_kind", "result_state", "verifier_result"], + "blocker_summary": "近 24h 63 筆 APPROVED 缺 execution metadata;需 P2-105 先定義 reviewer score 與 result capture。", + "evidence_hash": "sha256:6767676767676767676767676767676767676767676767676767676767676767" }, { - "test_id": "test_proposal_below_threshold", - "display_name": "相似度不足保留 None", - "test_ref": "apps/api/tests/test_matched_playbook_id_e2e.py::test_proposal_keeps_none_when_below_threshold", - "expected_result": "matched_playbook_id=None", - "live_execution_required": false + "candidate_id": "candidate_learning_service_payload", + "display_name": "learning service payload", + "owner_agent": "hermes", + "target_system": "learning_service.process_execution_result", + "allowed_mode": "committed_snapshot_only", + "write_enabled": false, + "runtime_writer_enabled": false, + "required_fields": ["incident_id", "approval_id", "matched_playbook_id", "success", "failure_reason"], + "blocker_summary": "只能先固定 payload contract;未批准前不呼叫 learning write path。", + "evidence_hash": "sha256:7878787878787878787878787878787878787878787878787878787878787878" }, { - "test_id": "test_approval_db_serialization", - "display_name": "Approval DB dict 保留欄位", - "test_ref": "apps/api/tests/test_matched_playbook_id_e2e.py::test_approval_db_persists_matched_playbook_id", - "expected_result": "record_data.matched_playbook_id 保留原值", - "live_execution_required": false + "candidate_id": "candidate_playbook_trust_update", + "display_name": "PlayBook trust 候選更新", + "owner_agent": "nemotron", + "target_system": "playbook_service.record_execution", + "allowed_mode": "gated_owner_review", + "write_enabled": false, + "runtime_writer_enabled": false, + "required_fields": ["playbook_id", "success", "verifier_result", "owner_review", "rollback_context"], + "blocker_summary": "playbook_updated_24h=0;需 post-write verifier 與人工批准才可開始 trust update。", + "evidence_hash": "sha256:8989898989898989898989898989898989898989898989898989898989898989" }, { - "test_id": "test_learning_service_update", - "display_name": "LearningService 有 id 才更新", - "test_ref": "apps/api/tests/test_matched_playbook_id_e2e.py::test_learning_service_updates_trust_when_matched", - "expected_result": "record_execution 呼叫 1 次", - "live_execution_required": false - }, - { - "test_id": "test_feature_flag_rollback", - "display_name": "Feature flag 可回滾", - "test_ref": "apps/api/tests/test_matched_playbook_id_e2e.py::test_feature_flag_disabled_returns_none", - "expected_result": "ENABLE_PLAYBOOK_MATCHING=false 時回傳 None", - "live_execution_required": false - } - ], - "owner_gates": [ - { - "gate_id": "gate_read_only_live_null_rate", - "display_name": "只讀 null-rate 查詢 gate", - "required_before": "production evidence claim", - "approval_required": true, - "runtime_write_allowed": false, - "blocked_reason": "未批准前不得查 live DB 或宣稱 production matched_playbook_id 覆蓋率。" - }, - { - "gate_id": "gate_playbook_trust_write", - "display_name": "PlayBook trust 寫入 gate", - "required_before": "任何 trust_score update", - "approval_required": true, - "runtime_write_allowed": false, - "blocked_reason": "需要 critic/reviewer score、dry-run hash、post-write verifier 與 rollback owner。" - }, - { - "gate_id": "gate_km_timeline_write", - "display_name": "KM / timeline 寫入 gate", - "required_before": "任何學習結果固化", - "approval_required": true, - "runtime_write_allowed": false, - "blocked_reason": "owner review 前不得把未驗證學習寫成高影響 KM 或 timeline。" + "candidate_id": "candidate_operator_learning_report", + "display_name": "operator learning report", + "owner_agent": "hermes", + "target_system": "KM / LOGBOOK / Telegram digest", + "allowed_mode": "manual_append_plan", + "write_enabled": false, + "runtime_writer_enabled": false, + "required_fields": ["readback_at", "gap_lane", "next_gate", "risk_tier", "redacted_evidence_hash"], + "blocker_summary": "報告可顯示 committed evidence;KM / LOGBOOK runtime append 與 Telegram 實發仍未開 gate。", + "evidence_hash": "sha256:9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a" } ], "display_redaction_contract": { @@ -254,41 +276,44 @@ "raw_telegram_payload_display_allowed": false, "work_window_transcript_display_allowed": false, "allowed_display_fields": [ - "checkpoint_id", - "display_name", - "source_component", - "current_status", - "evidence_ref", - "expected_signal", - "gap_if_missing", - "owner_next_action", - "evidence_hash" + "schema_version", + "generated_at", + "program_status", + "production_readback", + "recent_status_breakdown", + "learning_gap_truth", + "gap_lanes", + "learning_gates", + "writeback_candidates", + "rollups" ], "blocked_display_fields": [ - "secret_value", - "token", - "authorization_header", - "raw_prompt", - "private_reasoning", - "raw_telegram_payload", - "internal_collaboration_transcript" + "raw DB URL", + "raw approval payload", + "raw Telegram payload", + "prompt", + "private reasoning", + "secret value", + "internal collaboration transcript" ] }, "rollups": { - "learning_checkpoint_count": 7, - "covered_by_test_count": 4, - "source_guarded_count": 2, - "blocked_until_live_evidence_count": 1, - "gap_item_count": 4, - "high_severity_gap_count": 2, - "test_contract_count": 5, - "owner_gate_count": 3, - "approval_required_gate_count": 3, - "runtime_execution_count": 0, - "live_db_read_count": 0, + "gap_lane_count": 5, + "passed_lane_count": 1, + "blocked_lane_count": 2, + "owner_review_lane_count": 2, + "approval_24h_total": 66, + "approval_24h_matched": 66, + "matched_rate_24h_percent": 100, + "approved_without_execution_meta_24h": 63, + "pending_with_matched_24h": 2, + "execution_failed_with_matched_24h": 1, + "playbook_with_execution_stats_count": 9, + "playbook_updated_24h_count": 0, + "learning_gate_count": 5, + "writeback_candidate_count": 4, + "live_learning_write_count": 0, "playbook_trust_write_count": 0, - "km_write_count": 0, - "timeline_write_count": 0, "gateway_queue_write_count": 0, "telegram_send_count": 0, "production_write_count": 0, diff --git a/docs/schemas/ai_agent_matched_playbook_learning_gap_v1.schema.json b/docs/schemas/ai_agent_matched_playbook_learning_gap_v1.schema.json index fac2357e3..9e5847903 100644 --- a/docs/schemas/ai_agent_matched_playbook_learning_gap_v1.schema.json +++ b/docs/schemas/ai_agent_matched_playbook_learning_gap_v1.schema.json @@ -8,11 +8,12 @@ "generated_at", "program_status", "source_refs", + "production_readback", + "recent_status_breakdown", "learning_gap_truth", - "learning_checkpoints", - "gap_items", - "test_contracts", - "owner_gates", + "gap_lanes", + "learning_gates", + "writeback_candidates", "display_redaction_contract", "rollups" ], @@ -42,95 +43,233 @@ "additionalProperties": false }, "source_refs": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, + "production_readback": { + "type": "object", + "required": [ + "readback_at", + "readback_mode", + "project_id_scope", + "rls_fail_closed_verified", + "approval_total", + "approval_matched_total", + "approval_24h_total", + "approval_24h_matched", + "matched_rate_24h_percent", + "playbook_total", + "playbook_with_execution_stats", + "playbook_updated_24h", + "readback_note" + ], + "properties": { + "readback_at": { "type": "string" }, + "readback_mode": { "const": "read_only_db_readback" }, + "project_id_scope": { "const": "awoooi" }, + "rls_fail_closed_verified": { "const": true }, + "approval_total": { "type": "integer", "minimum": 0 }, + "approval_matched_total": { "type": "integer", "minimum": 0 }, + "approval_24h_total": { "type": "integer", "minimum": 0 }, + "approval_24h_matched": { "type": "integer", "minimum": 0 }, + "matched_rate_24h_percent": { "type": "integer", "minimum": 0, "maximum": 100 }, + "playbook_total": { "type": "integer", "minimum": 0 }, + "playbook_with_execution_stats": { "type": "integer", "minimum": 0 }, + "playbook_updated_24h": { "type": "integer", "minimum": 0 }, + "readback_note": { "type": "string" } + }, + "additionalProperties": false + }, + "recent_status_breakdown": { + "type": "array", + "minItems": 3, + "items": { + "type": "object", + "required": [ + "status", + "total", + "matched", + "execution_kind_present", + "repair_attempted_true", + "repair_executed_true", + "learning_candidate_count", + "readback_note" + ], + "properties": { + "status": { "enum": ["APPROVED", "PENDING", "EXECUTION_FAILED"] }, + "total": { "type": "integer", "minimum": 0 }, + "matched": { "type": "integer", "minimum": 0 }, + "execution_kind_present": { "type": "integer", "minimum": 0 }, + "repair_attempted_true": { "type": "integer", "minimum": 0 }, + "repair_executed_true": { "type": "integer", "minimum": 0 }, + "learning_candidate_count": { "type": "integer", "minimum": 0 }, + "readback_note": { "type": "string" } + }, + "additionalProperties": false + } + }, "learning_gap_truth": { "type": "object", "required": [ - "p2_103_result_audit_loaded", - "matched_playbook_source_contract_ready", - "approval_record_contract_ready", - "learning_service_contract_ready", - "execution_learning_await_contract_ready", - "e2e_test_contract_ready", - "owner_gate_contract_ready", - "all_checkpoints_have_evidence_ref", - "runtime_execution_enabled", - "live_db_read_enabled", + "p2_103_task_result_audit_loaded", + "production_db_readback_completed", + "rls_fail_closed_verified", + "matched_playbook_id_present_24h", + "matched_playbook_id_gap_resolved", + "execution_learning_gap_detected", + "approved_without_execution_meta_detected", + "playbook_trust_update_gap_detected", + "runtime_learning_write_enabled", "playbook_trust_write_enabled", - "km_write_enabled", - "timeline_write_enabled", + "approval_auto_execute_enabled", "gateway_queue_write_enabled", "telegram_send_enabled", "production_write_enabled", "secret_value_read_enabled", - "host_or_cluster_command_enabled", "destructive_operation_enabled", - "runtime_execution_count_24h", - "live_db_read_count_24h", + "work_window_transcript_display_allowed", + "approval_24h_total", + "approval_24h_matched", + "approved_without_execution_meta_24h", + "pending_with_matched_24h", + "execution_failed_with_matched_24h", + "playbook_updated_24h", + "live_learning_write_count_24h", "playbook_trust_write_count_24h", - "km_write_count_24h", - "timeline_write_count_24h", "gateway_queue_write_count_24h", "telegram_send_count_24h", "production_write_count_24h", "secret_value_read_count_24h", - "host_or_cluster_command_count_24h", "destructive_operation_count_24h", "truth_note" ], "properties": { - "p2_103_result_audit_loaded": { "const": true }, - "matched_playbook_source_contract_ready": { "const": true }, - "approval_record_contract_ready": { "const": true }, - "learning_service_contract_ready": { "const": true }, - "execution_learning_await_contract_ready": { "const": true }, - "e2e_test_contract_ready": { "const": true }, - "owner_gate_contract_ready": { "const": true }, - "all_checkpoints_have_evidence_ref": { "const": true }, - "runtime_execution_enabled": { "const": false }, - "live_db_read_enabled": { "const": false }, + "p2_103_task_result_audit_loaded": { "const": true }, + "production_db_readback_completed": { "const": true }, + "rls_fail_closed_verified": { "const": true }, + "matched_playbook_id_present_24h": { "const": true }, + "matched_playbook_id_gap_resolved": { "const": true }, + "execution_learning_gap_detected": { "const": true }, + "approved_without_execution_meta_detected": { "const": true }, + "playbook_trust_update_gap_detected": { "const": true }, + "runtime_learning_write_enabled": { "const": false }, "playbook_trust_write_enabled": { "const": false }, + "approval_auto_execute_enabled": { "const": false }, "km_write_enabled": { "const": false }, + "logbook_runtime_write_enabled": { "const": false }, + "audit_db_write_enabled": { "const": false }, "timeline_write_enabled": { "const": false }, "gateway_queue_write_enabled": { "const": false }, "telegram_send_enabled": { "const": false }, "production_write_enabled": { "const": false }, "secret_value_read_enabled": { "const": false }, - "host_or_cluster_command_enabled": { "const": false }, "destructive_operation_enabled": { "const": false }, - "runtime_execution_count_24h": { "const": 0 }, - "live_db_read_count_24h": { "const": 0 }, + "work_window_transcript_display_allowed": { "const": false }, + "approval_24h_total": { "type": "integer", "minimum": 0 }, + "approval_24h_matched": { "type": "integer", "minimum": 0 }, + "approved_without_execution_meta_24h": { "type": "integer", "minimum": 0 }, + "pending_with_matched_24h": { "type": "integer", "minimum": 0 }, + "execution_failed_with_matched_24h": { "type": "integer", "minimum": 0 }, + "playbook_updated_24h": { "type": "integer", "minimum": 0 }, + "live_learning_write_count_24h": { "const": 0 }, "playbook_trust_write_count_24h": { "const": 0 }, - "km_write_count_24h": { "const": 0 }, - "timeline_write_count_24h": { "const": 0 }, "gateway_queue_write_count_24h": { "const": 0 }, "telegram_send_count_24h": { "const": 0 }, "production_write_count_24h": { "const": 0 }, "secret_value_read_count_24h": { "const": 0 }, - "host_or_cluster_command_count_24h": { "const": 0 }, "destructive_operation_count_24h": { "const": 0 }, "truth_note": { "type": "string" } }, "additionalProperties": false }, - "learning_checkpoints": { + "gap_lanes": { "type": "array", - "minItems": 7, - "items": { "$ref": "#/$defs/learningCheckpoint" } + "minItems": 5, + "items": { + "type": "object", + "required": [ + "lane_id", + "display_name", + "owner_agent", + "status", + "risk_tier", + "count_24h", + "matched_count_24h", + "live_write_enabled", + "evidence", + "next_gate", + "evidence_hash" + ], + "properties": { + "lane_id": { "type": "string" }, + "display_name": { "type": "string" }, + "owner_agent": { "enum": ["openclaw", "hermes", "nemotron"] }, + "status": { "enum": ["passed", "blocked", "owner_review_required", "ready"] }, + "risk_tier": { "enum": ["low", "medium", "high", "critical"] }, + "count_24h": { "type": "integer", "minimum": 0 }, + "matched_count_24h": { "type": "integer", "minimum": 0 }, + "live_write_enabled": { "const": false }, + "evidence": { "type": "string" }, + "next_gate": { "type": "string" }, + "evidence_hash": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" } + }, + "additionalProperties": false + } }, - "gap_items": { + "learning_gates": { "type": "array", - "minItems": 1, - "items": { "$ref": "#/$defs/gapItem" } + "minItems": 5, + "items": { + "type": "object", + "required": [ + "gate_id", + "display_name", + "owner_agent", + "status", + "required_before", + "failure_if_missing", + "creates_runtime_write" + ], + "properties": { + "gate_id": { "type": "string" }, + "display_name": { "type": "string" }, + "owner_agent": { "enum": ["openclaw", "hermes", "nemotron"] }, + "status": { "enum": ["ready", "needs_owner_review", "blocked_by_policy"] }, + "required_before": { "type": "string" }, + "failure_if_missing": { "type": "string" }, + "creates_runtime_write": { "const": false } + }, + "additionalProperties": false + } }, - "test_contracts": { + "writeback_candidates": { "type": "array", - "minItems": 1, - "items": { "$ref": "#/$defs/testContract" } - }, - "owner_gates": { - "type": "array", - "minItems": 1, - "items": { "$ref": "#/$defs/ownerGate" } + "minItems": 4, + "items": { + "type": "object", + "required": [ + "candidate_id", + "display_name", + "owner_agent", + "target_system", + "allowed_mode", + "write_enabled", + "runtime_writer_enabled", + "required_fields", + "blocker_summary", + "evidence_hash" + ], + "properties": { + "candidate_id": { "type": "string" }, + "display_name": { "type": "string" }, + "owner_agent": { "enum": ["openclaw", "hermes", "nemotron"] }, + "target_system": { "type": "string" }, + "allowed_mode": { "enum": ["committed_snapshot_only", "gated_owner_review", "manual_append_plan"] }, + "write_enabled": { "const": false }, + "runtime_writer_enabled": { "const": false }, + "required_fields": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, + "blocker_summary": { "type": "string" }, + "evidence_hash": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" } + }, + "additionalProperties": false + } }, "display_redaction_contract": { "type": "object", @@ -159,147 +298,29 @@ "rollups": { "type": "object", "required": [ - "learning_checkpoint_count", - "covered_by_test_count", - "source_guarded_count", - "blocked_until_live_evidence_count", - "gap_item_count", - "high_severity_gap_count", - "test_contract_count", - "owner_gate_count", - "approval_required_gate_count", - "runtime_execution_count", - "live_db_read_count", + "gap_lane_count", + "passed_lane_count", + "blocked_lane_count", + "owner_review_lane_count", + "approval_24h_total", + "approval_24h_matched", + "matched_rate_24h_percent", + "approved_without_execution_meta_24h", + "pending_with_matched_24h", + "execution_failed_with_matched_24h", + "playbook_with_execution_stats_count", + "playbook_updated_24h_count", + "learning_gate_count", + "writeback_candidate_count", + "live_learning_write_count", "playbook_trust_write_count", - "km_write_count", - "timeline_write_count", "gateway_queue_write_count", "telegram_send_count", "production_write_count", "secret_value_read_count", "destructive_operation_count" ], - "properties": { - "learning_checkpoint_count": { "type": "integer", "minimum": 0 }, - "covered_by_test_count": { "type": "integer", "minimum": 0 }, - "source_guarded_count": { "type": "integer", "minimum": 0 }, - "blocked_until_live_evidence_count": { "type": "integer", "minimum": 0 }, - "gap_item_count": { "type": "integer", "minimum": 0 }, - "high_severity_gap_count": { "type": "integer", "minimum": 0 }, - "test_contract_count": { "type": "integer", "minimum": 0 }, - "owner_gate_count": { "type": "integer", "minimum": 0 }, - "approval_required_gate_count": { "type": "integer", "minimum": 0 }, - "runtime_execution_count": { "const": 0 }, - "live_db_read_count": { "const": 0 }, - "playbook_trust_write_count": { "const": 0 }, - "km_write_count": { "const": 0 }, - "timeline_write_count": { "const": 0 }, - "gateway_queue_write_count": { "const": 0 }, - "telegram_send_count": { "const": 0 }, - "production_write_count": { "const": 0 }, - "secret_value_read_count": { "const": 0 }, - "destructive_operation_count": { "const": 0 } - }, - "additionalProperties": false - } - }, - "$defs": { - "learningCheckpoint": { - "type": "object", - "required": [ - "checkpoint_id", - "display_name", - "source_component", - "current_status", - "evidence_ref", - "expected_signal", - "gap_if_missing", - "owner_agent", - "requires_owner_review", - "writes_live_state", - "evidence_hash" - ], - "properties": { - "checkpoint_id": { "type": "string" }, - "display_name": { "type": "string" }, - "source_component": { "type": "string" }, - "current_status": { - "enum": [ - "covered_by_test", - "covered_by_existing_tests", - "source_guarded", - "blocked_until_live_evidence" - ] - }, - "evidence_ref": { "type": "string" }, - "expected_signal": { "type": "string" }, - "gap_if_missing": { "type": "string" }, - "owner_agent": { "enum": ["openclaw", "hermes", "nemotron"] }, - "requires_owner_review": { "type": "boolean" }, - "writes_live_state": { "const": false }, - "evidence_hash": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" } - }, - "additionalProperties": false - }, - "gapItem": { - "type": "object", - "required": [ - "gap_id", - "display_name", - "severity", - "current_state", - "required_evidence", - "owner_next_action", - "blocks_trust_write" - ], - "properties": { - "gap_id": { "type": "string" }, - "display_name": { "type": "string" }, - "severity": { "enum": ["critical", "high", "medium", "low"] }, - "current_state": { "type": "string" }, - "required_evidence": { "type": "string" }, - "owner_next_action": { "type": "string" }, - "blocks_trust_write": { "type": "boolean" } - }, - "additionalProperties": false - }, - "testContract": { - "type": "object", - "required": [ - "test_id", - "display_name", - "test_ref", - "expected_result", - "live_execution_required" - ], - "properties": { - "test_id": { "type": "string" }, - "display_name": { "type": "string" }, - "test_ref": { "type": "string" }, - "expected_result": { "type": "string" }, - "live_execution_required": { "const": false } - }, - "additionalProperties": false - }, - "ownerGate": { - "type": "object", - "required": [ - "gate_id", - "display_name", - "required_before", - "approval_required", - "runtime_write_allowed", - "blocked_reason" - ], - "properties": { - "gate_id": { "type": "string" }, - "display_name": { "type": "string" }, - "required_before": { "type": "string" }, - "approval_required": { "const": true }, - "runtime_write_allowed": { "const": false }, - "blocked_reason": { "type": "string" } - }, - "additionalProperties": false + "additionalProperties": { "type": "integer" } } }, "additionalProperties": false diff --git a/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md b/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md index dbd96d0f2..e7b94530d 100644 --- a/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md +++ b/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md @@ -634,14 +634,14 @@ Alert / Sentry / SigNoz / Gitea / Market Watch / Operator | `docs/evaluations/ai_agent_communication_learning_contract_2026-06-11.json` | 2026-06-11 committed snapshot;完成度 `35%`,runtime worker / DB migration / Telegram direct send 全部 false | | `apps/api/src/services/ai_agent_communication_learning_contract.py` | 只讀 loader;強制驗證 runtime / migration / Telegram / SDK / route 權限都未開 | | `GET /api/v1/agents/agent-communication-learning-contract` | 治理 API;只回傳 committed contract,不啟動 worker、不碰 DB/Redis、不呼叫外部服務 | -| `docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json` + `GET /api/v1/agents/agent-interaction-learning-proof` | P2-403A / P2-403B / P2-403C / P2-403D / P2-403E / P2-403F / P2-403G / P2-403H / P2-403I / P2-403J / P2-403L / P2-403M / P2-403N / P2-404 互動、接手、學習、成長、read model gate、Redis dry-run gate、learning writeback approval package、Telegram receipt approval package、owner-approved learning dry-run、fixture dry-run、runtime write gate review、post-write verifier package、runtime verifier evidence review、報表真相、日週月報、Agent 工作量、圖表化報告、風險自動化政策、報表 runtime readiness、no-write dry-run、fixture/readback/verifier dry-run 與 shadow/no-write execution 證據面;目前 live session、message、handoff、learning write、Gateway queue、Telegram send、report delivery、auto optimization、shadow worker、verifier execution 全部 `0`,由 P2-101 / P2-102 / P2-103 / P2-104 權限模型、候選 dry-run 證據、結果稽核軌跡與 PlayBook 學習缺口證據承接下一步 | +| `docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json` + `GET /api/v1/agents/agent-interaction-learning-proof` | P2-403A / P2-403B / P2-403C / P2-403D / P2-403E / P2-403F / P2-403G / P2-403H / P2-403I / P2-403J / P2-403L / P2-403M / P2-403N / P2-404 互動、接手、學習、成長、read model gate、Redis dry-run gate、learning writeback approval package、Telegram receipt approval package、owner-approved learning dry-run、fixture dry-run、runtime write gate review、post-write verifier package、runtime verifier evidence review、報表真相、日週月報、Agent 工作量、圖表化報告、風險自動化政策、報表 runtime readiness、no-write dry-run、fixture/readback/verifier dry-run 與 shadow/no-write execution 證據面;目前 live session、message、handoff、learning write、Gateway queue、Telegram send、report delivery、auto optimization、shadow worker、verifier execution 全部 `0`,由 P2-101 / P2-102 / P2-103 / P2-104 權限模型、候選 dry-run 證據、結果稽核軌跡與 matched PlayBook 學習缺口承接下一步 | | `docs/evaluations/ai_agent_report_runtime_dry_run_2026-06-12.json` + `GET /api/v1/agents/agent-report-runtime-dry-run` | P2-403M 報表 runtime no-write dry-run 證據包;建立 5 個 dry-run artifact、3 個 SRE 戰情室 queue digest 草案、4 個 readback verifier case、3 個 Agent dry-run role 與 6 個 operator checkpoint;不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 delivery receipt、不啟動 worker、不跑 verifier live readback、不讀 secret,已由 P2-403N fixture readback 承接 | | `docs/evaluations/ai_agent_report_runtime_fixture_readback_2026-06-12.json` + `GET /api/v1/agents/agent-report-runtime-fixture-readback` | P2-403N fixture smoke / queue preview readback / verifier dry-run 證據包;建立 5 個 fixture smoke、3 個 SRE 戰情室 queue preview readback、4 個 verifier dry-run case、3 個 Agent fixture role 與 5 個 operator checkpoint;不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 delivery receipt、不啟動 worker、不跑 verifier live readback、不讀 secret,下一步 P2-404 | | `docs/evaluations/ai_agent_runtime_worker_shadow_gate_2026-06-12.json` + `GET /api/v1/agents/agent-runtime-worker-shadow-gate` | P2-404 runtime worker shadow / no-write execution evidence gate;建立 5 個 shadow candidate、4 個 no-write replay、4 個 verifier shadow case、3 個 Agent shadow role 與 6 個 operator checkpoint;shadow live worker、Gateway queue write、Telegram send、Bot API、delivery receipt、auto worker、verifier live readback、production write 與 secret read 全部 `0 / false`,下一步 P2-101 | | `docs/evaluations/ai_agent_operation_permission_model_2026-06-12.json` + `GET /api/v1/agents/agent-operation-permission-model` | P2-101 操作類別權限模型;建立 5 條 permission lane、13 類 operation category、3 個 Agent permission role、8 個 gate transition 與 5 個 operator decision template;runtime execution、Gateway queue write、Telegram send、Bot API、delivery receipt、auto worker、verifier live readback、production write、secret / paid provider、host command 與 destructive action 全部 `0 / false`,已由 P2-102 承接 | | `docs/evaluations/ai_agent_candidate_operation_dry_run_evidence_2026-06-12.json` + `GET /api/v1/agents/agent-candidate-operation-dry-run-evidence` | P2-102 候選操作 dry-run 證據;13 類候選操作全部具備 input / output evidence hash、side-effect count、verifier plan、rollback/no-op plan 與人工 handoff;6 個 verifier plan、7 個 gate evidence requirement、5 個 operator handoff;runtime、Gateway queue、Telegram、production write、secret / paid provider 與 destructive action 全部 `0 / false`,已由 P2-103 承接 | -| `docs/evaluations/ai_agent_task_result_audit_trail_2026-06-13.json` + `GET /api/v1/agents/agent-task-result-audit-trail` | P2-103 任務結果稽核軌跡;8 條 result route、6 個 writeback contract、7 個 audit checkpoint、5 個 operator handoff;把 diagnostic-only、repair candidate、execution failed、provider unmatched、report zero-signal 等結果固定到 KM 草稿、LOGBOOK 證據、audit trail、timeline 與人工下一步;KM / LOGBOOK / audit DB / timeline / PlayBook trust / Gateway queue / Telegram 寫入全為 `0 / false`,下一步 P2-104 | -| `docs/evaluations/ai_agent_matched_playbook_learning_gap_2026-06-13.json` + `GET /api/v1/agents/agent-matched-playbook-learning-gap` | P2-104 `matched_playbook_id` 學習缺口;7 個 learning checkpoint、4 個 gap、5 個測試契約、3 個 owner gate;repo 內來源、approval record 序列化、learning_service EWMA 與 await learning 契約可查;live DB read、PlayBook trust write、KM / timeline / Gateway / Telegram 寫入全為 `0 / false`,下一步 P2-105 | +| `docs/evaluations/ai_agent_task_result_audit_trail_2026-06-13.json` + `GET /api/v1/agents/agent-task-result-audit-trail` | P2-103 任務結果稽核軌跡;8 條 result route、6 個 writeback contract、7 個 audit checkpoint、5 個 operator handoff;把 diagnostic-only、repair candidate、execution failed、provider unmatched、report zero-signal 等結果固定到 KM 草稿、LOGBOOK 證據、audit trail、timeline 與人工下一步;KM / LOGBOOK / audit DB / timeline / PlayBook trust / Gateway queue / Telegram 寫入全為 `0 / false`,已由 P2-104 承接 | +| `docs/evaluations/ai_agent_matched_playbook_learning_gap_2026-06-13.json` + `GET /api/v1/agents/agent-matched-playbook-learning-gap` | P2-104 matched PlayBook 學習缺口;正式 DB 只讀回查確認 24h approval `66`、matched `66`、matched rate `100%`,active gap 是 APPROVED `63` 筆缺 execution learning、PlayBook updated_24h `0`;5 條 gap lane、5 個 learning gate、4 個 writeback candidate;learning write、PlayBook trust write、Gateway queue、Telegram、production write、secret read 與 destructive action 全部 `0 / false`,下一步 P2-105 | | `docs/evaluations/ai_agent_live_read_model_gate_2026-06-11.json` + `GET /api/v1/agents/agent-live-read-model-gate` | P2-403B AgentSession / Redis Streams live read model gate;定義 safe fields、Redis envelope、worker gate、rollback plan 與 no-write smoke,不連 DB、不讀寫 Redis、不啟動 worker | #### 3.2.1c 2026-06-11 AI Agent 主動營運委派與版本生命週期契約 @@ -733,8 +733,8 @@ Repo / registry / release notes / K8s / host / observability / backup evidence 21. 建立 runtime worker shadow / no-write execution evidence gate。✅ P2-404 已完成;shadow candidate `5`、no-write replay `4`、verifier shadow case `4`、Agent shadow role `3`、operator checkpoint `6`,shadow live worker、Gateway queue write、Telegram send、Bot API、delivery receipt、AI runtime worker、中低風險 auto worker、verifier live readback、production write 與 secret value read 仍為 `0 / false`。已由 P2-101 承接。 22. 定義操作類別權限模型。✅ P2-101 已完成;permission lane `5`、operation category `13`、Agent permission role `3`、gate transition `8`、operator decision template `5`,runtime execution、Gateway queue write、Telegram send、Bot API、delivery receipt、AI runtime worker、中低風險 auto worker、verifier live readback、production write、secret / paid provider、host command 與 destructive action 仍為 `0 / false`。已由 P2-102 承接。 23. 建立候選操作 dry-run 證據。✅ P2-102 已完成;candidate operation `13`、dry-run evidence `13`、verifier plan `6`、gate evidence requirement `7`、operator handoff `5`,side-effect、runtime execution、Gateway queue write、Telegram send、production write、secret value read、paid provider call、host / cluster command 與 destructive action 仍為 `0 / false`。已由 P2-103 承接。 -24. 把任務結果接回 KM / LOGBOOK / 稽核軌跡。✅ P2-103 已完成;result route `8`、writeback contract `6`、audit checkpoint `7`、operator handoff `5`,KM write、LOGBOOK runtime append、audit DB write、timeline write、PlayBook trust write、Gateway queue write、Telegram send 與 production write 仍為 `0 / false`。下一步 P2-104 修復 `matched_playbook_id` 學習缺口。 -25. 修復 `matched_playbook_id` 學習缺口。✅ P2-104 已完成;learning checkpoint `7`、gap `4`、test contract `5`、owner gate `3`,repo 內 matched_playbook_id 來源、approval record、learning_service、await learning 與 E2E 測試契約可查;live DB read、PlayBook trust write、KM / timeline / Gateway / Telegram 寫入仍為 `0 / false`。下一步 P2-105 加入 critic / reviewer 評分。 +24. 把任務結果接回 KM / LOGBOOK / 稽核軌跡。✅ P2-103 已完成;result route `8`、writeback contract `6`、audit checkpoint `7`、operator handoff `5`,KM write、LOGBOOK runtime append、audit DB write、timeline write、PlayBook trust write、Gateway queue write、Telegram send 與 production write 仍為 `0 / false`。已由 P2-104 承接。 +25. 修復 matched PlayBook 學習缺口。✅ P2-104 已完成;正式 DB 只讀回查確認 24h approval `66`、matched `66`、matched rate `100%`,真正缺口是 APPROVED `63` 筆缺 execution learning、PlayBook updated_24h `0`;learning write、PlayBook trust write、Gateway queue write、Telegram send 與 production write 仍為 `0 / false`。下一步 P2-105 批准前加入 critic / reviewer 評分。 #### 3.2.1d 2026-06-11 Agent 互動、學習與成長證據面 @@ -767,7 +767,7 @@ Repo / registry / release notes / K8s / host / observability / backup evidence | `docs/evaluations/ai_agent_operation_permission_model_2026-06-12.json` + `GET /api/v1/agents/agent-operation-permission-model` | P2-101 操作類別權限模型;5 條 permission lane、13 類 operation category、3 個 Agent permission role、8 個 gate transition、5 個 operator decision template;不啟動 runtime worker、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 production target、不讀 secret | | `docs/evaluations/ai_agent_candidate_operation_dry_run_evidence_2026-06-12.json` + `GET /api/v1/agents/agent-candidate-operation-dry-run-evidence` | P2-102 候選操作 dry-run 證據;13 類候選操作、13 組 dry-run evidence、6 個 verifier plan、7 個 gate evidence requirement、5 個 operator handoff;不啟動 runtime worker、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 production target、不讀 secret、不執行 destructive action | | `docs/evaluations/ai_agent_task_result_audit_trail_2026-06-13.json` + `GET /api/v1/agents/agent-task-result-audit-trail` | P2-103 任務結果稽核軌跡;8 條 result route、6 個 writeback contract、7 個 audit checkpoint、5 個 operator handoff;不寫 KM、不 runtime append LOGBOOK、不寫 audit DB、不寫 timeline、不更新 PlayBook trust、不寫 Gateway queue、不送 Telegram | -| `docs/evaluations/ai_agent_matched_playbook_learning_gap_2026-06-13.json` + `GET /api/v1/agents/agent-matched-playbook-learning-gap` | P2-104 PlayBook 學習缺口證據;7 個 learning checkpoint、4 個 gap、5 個測試契約、3 個 owner gate;不查 live DB、不更新 PlayBook trust、不寫 KM、不寫 timeline、不寫 Gateway queue、不送 Telegram | +| `docs/evaluations/ai_agent_matched_playbook_learning_gap_2026-06-13.json` + `GET /api/v1/agents/agent-matched-playbook-learning-gap` | P2-104 matched PlayBook 學習缺口;24h approval `66`、matched `66`、approved without execution meta `63`、PlayBook updated_24h `0`;不寫 learning、不更新 PlayBook trust、不寫 Gateway queue、不送 Telegram、不讀 secret | | `apps/api/src/services/ai_agent_interaction_learning_proof.py` | 只讀 loader;強制 live flags / DB / Redis / Telegram / transcript / 私有推理全部關閉 | | `GET /api/v1/agents/agent-interaction-learning-proof` | 治理 API;只回傳證據面,不啟動 worker、不碰 live DB/Redis、不發 Telegram | | `docs/schemas/ai_agent_live_read_model_gate_v1.schema.json` | P2-403B live read model gate schema;強制 DB / Redis / worker / Telegram / learning writeback 仍需批准 | @@ -1942,12 +1942,12 @@ Phase 6 完成後 - 政策裁決:P2-103 只允許結果路由、redacted evidence hash、寫回契約、稽核 checkpoint 與人工下一步;任何 KM write、LOGBOOK runtime append、audit DB write、timeline write、PlayBook trust write、Gateway queue write、Telegram send、production write 或 secret value read 都仍為 `0 / false`。 - 本波仍不寫 KM、不 runtime append LOGBOOK、不寫 audit DB、不寫 timeline、不更新 PlayBook trust、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不啟動 runtime worker、不讀 secret、不回傳內部協作內容;下一步 P2-104 才修復 `matched_playbook_id` 學習缺口。 -### 2026-06-13 10:55 (台北) — §3.2 / §5 — 完成 P2-104 `matched_playbook_id` 學習缺口證據面 — 把 PlayBook trust 斷鏈拆成可驗證 gate +### 2026-06-13 00:51 (台北) — §3.2 / §5 — 完成 P2-104 matched PlayBook 學習缺口 — 把 active gap 從 matched id 修正為 execution learning -- 新增 `ai_agent_matched_playbook_learning_gap_v1` schema / committed snapshot / loader / API / 測試,定義 7 個 learning checkpoint、4 個 gap item、5 個測試契約與 3 個 owner gate。 -- `apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx` 接入 `GET /api/v1/agents/agent-matched-playbook-learning-gap`,治理頁顯示 proposal RAG 匹配、approval record 序列化、learning_service EWMA、await learning、repair candidate、webhook source correlation 與 live null-rate gate。 -- 政策裁決:P2-104 只允許 repo committed evidence、測試契約、redacted evidence ref 與 owner gate;任何 live DB read、PlayBook trust write、KM write、timeline write、Gateway queue write、Telegram send、production write 或 secret value read 都仍為 `0 / false`。 -- 本波仍不查 live DB、不更新 PlayBook trust、不寫 KM、不寫 timeline、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不啟動 runtime worker、不讀 secret、不回傳內部協作內容;下一步 P2-105 才在批准前加入 critic / reviewer 評分。 +- 新增 `ai_agent_matched_playbook_learning_gap_v1` schema / committed snapshot / loader / API / 測試,定義正式 DB 只讀回查、5 條 gap lane、5 個 learning gate 與 4 個 writeback candidate。 +- `apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx` 接入 `GET /api/v1/agents/agent-matched-playbook-learning-gap`,治理頁顯示 24h approval `66`、matched `66`、matched rate `100%`、approved without execution meta `63`、PENDING matched `2`、EXECUTION_FAILED matched `1` 與 PlayBook updated_24h `0`。 +- 政策裁決:P2-104 修正原假設,`matched_playbook_id` 近 24h 已齊;active gap 是 approved 後缺 result capture / critic reviewer score / execution learning,而不是重新匹配。 +- 本波仍不寫 learning、不更新 PlayBook trust、不寫 KM、不 runtime append LOGBOOK、不寫 audit DB、不寫 timeline、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不啟動 runtime worker、不讀 secret、不回傳內部協作內容;下一步 P2-105 批准前加入 critic / reviewer 評分。 ### 2026-06-12 11:55 (台北) — §3.2 / §5 — 完成 P2-403M 報表 runtime no-write dry-run 證據包 — 把 queue / verifier 草案固定成可審核證據