From 3928e3ae674e0aadb75e2fc09170b9be2d32888e Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 13 Jun 2026 01:05:48 +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?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/api/src/api/v1/agents.py | 31 ++ .../ai_agent_matched_playbook_learning_gap.py | 273 ++++++++++++++++ ..._ai_agent_matched_playbook_learning_gap.py | 116 +++++++ ...agent_matched_playbook_learning_gap_api.py | 37 +++ apps/web/messages/en.json | 56 ++++ apps/web/messages/zh-TW.json | 56 ++++ .../tabs/automation-inventory-tab.tsx | 200 +++++++++++- apps/web/src/lib/api-client.ts | 121 +++++++ docs/LOGBOOK.md | 28 ++ ...AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md | 8 +- ...T_INTERACTION_LEARNING_PROOF_2026-06-11.md | 15 +- ...ched_playbook_learning_gap_2026-06-13.json | 298 +++++++++++++++++ ...tched_playbook_learning_gap_v1.schema.json | 306 ++++++++++++++++++ ...-04-15-MASTER-ai-autonomous-flywheel-v2.md | 12 +- 14 files changed, 1548 insertions(+), 9 deletions(-) create mode 100644 apps/api/src/services/ai_agent_matched_playbook_learning_gap.py create mode 100644 apps/api/tests/test_ai_agent_matched_playbook_learning_gap.py create mode 100644 apps/api/tests/test_ai_agent_matched_playbook_learning_gap_api.py create mode 100644 docs/evaluations/ai_agent_matched_playbook_learning_gap_2026-06-13.json create mode 100644 docs/schemas/ai_agent_matched_playbook_learning_gap_v1.schema.json diff --git a/apps/api/src/api/v1/agents.py b/apps/api/src/api/v1/agents.py index a4b403cd3..ec8ff1bd3 100644 --- a/apps/api/src/api/v1/agents.py +++ b/apps/api/src/api/v1/agents.py @@ -73,6 +73,9 @@ from src.services.ai_agent_learning_writeback_approval_package import ( from src.services.ai_agent_live_read_model_gate import ( load_latest_ai_agent_live_read_model_gate, ) +from src.services.ai_agent_matched_playbook_learning_gap import ( + load_latest_ai_agent_matched_playbook_learning_gap, +) from src.services.ai_agent_owner_approved_fixture_dry_run import ( load_latest_ai_agent_owner_approved_fixture_dry_run, ) @@ -1128,6 +1131,34 @@ async def get_agent_task_result_audit_trail() -> dict[str, Any]: ) from exc +@router.get( + "/agent-matched-playbook-learning-gap", + 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、" + "不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 production target、不讀 secret。" + ), +) +async def get_agent_matched_playbook_learning_gap() -> dict[str, Any]: + """Return the latest read-only AI Agent matched PlayBook learning gap contract.""" + try: + return await asyncio.to_thread(load_latest_ai_agent_matched_playbook_learning_gap) + except FileNotFoundError as exc: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=str(exc), + ) from exc + except (json.JSONDecodeError, ValueError) as exc: + logger.error("ai_agent_matched_playbook_learning_gap_invalid", error=str(exc)) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="AI Agent matched PlayBook 學習缺口無效", + ) from exc + + @router.get( "/agent-owner-approved-fixture-dry-run", response_model=dict[str, Any], 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 new file mode 100644 index 000000000..1b76fd9d6 --- /dev/null +++ b/apps/api/src/services/ai_agent_matched_playbook_learning_gap.py @@ -0,0 +1,273 @@ +""" +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. +""" + +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + +from src.services.snapshot_paths import default_evaluations_dir + +_DEFAULT_EVALUATIONS_DIR = default_evaluations_dir(Path(__file__)) +_SNAPSHOT_PATTERN = "ai_agent_matched_playbook_learning_gap_*.json" +_SCHEMA_VERSION = "ai_agent_matched_playbook_learning_gap_v1" +_RUNTIME_AUTHORITY = "matched_playbook_learning_gap_contract_only_no_live_trust_write" + + +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.""" + directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR + candidates = sorted(directory.glob(_SNAPSHOT_PATTERN)) + if not candidates: + raise FileNotFoundError(f"no AI Agent matched PlayBook learning gap snapshots found in {directory}") + + latest = candidates[-1] + with latest.open(encoding="utf-8") as handle: + payload = json.load(handle) + + if not isinstance(payload, dict): + raise ValueError(f"{latest}: expected JSON object") + _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_redaction_contract(payload, str(latest)) + _require_rollup_consistency(payload, str(latest)) + return payload + + +def _require_schema(payload: dict[str, Any], label: str) -> None: + if payload.get("schema_version") != _SCHEMA_VERSION: + raise ValueError(f"{label}: expected schema_version={_SCHEMA_VERSION}") + status = payload.get("program_status") or {} + if status.get("read_only_mode") is not True: + raise ValueError(f"{label}: program_status.read_only_mode must be true") + if status.get("runtime_authority") != _RUNTIME_AUTHORITY: + raise ValueError(f"{label}: runtime_authority must remain {_RUNTIME_AUTHORITY}") + if status.get("current_task_id") != "P2-104": + raise ValueError(f"{label}: current_task_id must be P2-104") + if status.get("next_task_id") != "P2-105": + raise ValueError(f"{label}: next_task_id must be P2-105") + + +def _require_no_live_boundaries(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", + } + 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", + "playbook_trust_write_enabled", + "km_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", + } + 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}") + + zero_counts = { + "runtime_execution_count_24h", + "live_db_read_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}") + + +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} + 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", + } + if checkpoint_ids != required: + raise ValueError(f"{label}: learning checkpoints 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") + + +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 [] + 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", + } + if gate_ids != required: + raise ValueError(f"{label}: owner 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") + + +def _require_redaction_contract(payload: dict[str, Any], label: str) -> None: + contract = payload.get("display_redaction_contract") or {} + required_false = { + "raw_prompt_display_allowed", + "private_reasoning_display_allowed", + "secret_value_display_allowed", + "raw_telegram_payload_display_allowed", + "work_window_transcript_display_allowed", + } + if contract.get("redaction_required") is not True: + raise ValueError(f"{label}: redaction_required must be true") + 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") + + +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 [] + + 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), + } + mismatches = { + key: {"expected": value, "actual": rollups.get(key)} + for key, value in expected.items() + if rollups.get(key) != 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:"): + return False + digest = value.removeprefix("sha256:") + return len(digest) == 64 and all(char in "0123456789abcdef" for char in digest) 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 new file mode 100644 index 000000000..d57579e7d --- /dev/null +++ b/apps/api/tests/test_ai_agent_matched_playbook_learning_gap.py @@ -0,0 +1,116 @@ +import copy +import json + +import pytest + +from src.services.ai_agent_matched_playbook_learning_gap import ( + load_latest_ai_agent_matched_playbook_learning_gap, +) + + +def _write_snapshot(tmp_path, payload): + path = tmp_path / "ai_agent_matched_playbook_learning_gap_2026-06-13.json" + path.write_text(json.dumps(payload), encoding="utf-8") + return path + + +def test_load_latest_ai_agent_matched_playbook_learning_gap(): + data = load_latest_ai_agent_matched_playbook_learning_gap() + + assert data["schema_version"] == "ai_agent_matched_playbook_learning_gap_v1" + 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["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"]["playbook_trust_write_count"] == 0 + assert data["rollups"]["telegram_send_count"] == 0 + + +def test_rejects_live_db_read_enabled(tmp_path): + data = load_latest_ai_agent_matched_playbook_learning_gap() + bad = copy.deepcopy(data) + bad["learning_gap_truth"]["live_db_read_enabled"] = True + _write_snapshot(tmp_path, bad) + + with pytest.raises(ValueError, match="live read/write/send/execution flags"): + load_latest_ai_agent_matched_playbook_learning_gap(tmp_path) + + +def test_rejects_playbook_trust_write_count(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 + _write_snapshot(tmp_path, bad) + + with pytest.raises(ValueError, match="live read/write/send/execution counts"): + load_latest_ai_agent_matched_playbook_learning_gap(tmp_path) + + +def test_rejects_checkpoint_live_write(tmp_path): + data = load_latest_ai_agent_matched_playbook_learning_gap() + bad = copy.deepcopy(data) + bad["learning_checkpoints"][0]["writes_live_state"] = True + _write_snapshot(tmp_path, bad) + + with pytest.raises(ValueError, match="writes_live_state"): + load_latest_ai_agent_matched_playbook_learning_gap(tmp_path) + + +def test_rejects_checkpoint_without_evidence_ref(tmp_path): + data = load_latest_ai_agent_matched_playbook_learning_gap() + bad = copy.deepcopy(data) + bad["learning_checkpoints"][0]["evidence_ref"] = "" + _write_snapshot(tmp_path, bad) + + with pytest.raises(ValueError, match="evidence_ref"): + load_latest_ai_agent_matched_playbook_learning_gap(tmp_path) + + +def test_rejects_test_contract_live_execution(tmp_path): + data = load_latest_ai_agent_matched_playbook_learning_gap() + bad = copy.deepcopy(data) + bad["test_contracts"][0]["live_execution_required"] = True + _write_snapshot(tmp_path, bad) + + with pytest.raises(ValueError, match="live_execution_required"): + load_latest_ai_agent_matched_playbook_learning_gap(tmp_path) + + +def test_rejects_owner_gate_runtime_write(tmp_path): + data = load_latest_ai_agent_matched_playbook_learning_gap() + bad = copy.deepcopy(data) + bad["owner_gates"][0]["runtime_write_allowed"] = True + _write_snapshot(tmp_path, bad) + + with pytest.raises(ValueError, match="runtime_write_allowed"): + 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 + _write_snapshot(tmp_path, bad) + + with pytest.raises(ValueError, match="rollup counts"): + load_latest_ai_agent_matched_playbook_learning_gap(tmp_path) 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 new file mode 100644 index 000000000..c7882f3fb --- /dev/null +++ b/apps/api/tests/test_ai_agent_matched_playbook_learning_gap_api.py @@ -0,0 +1,37 @@ +from fastapi.testclient import TestClient + +from src.main import app + + +def test_get_ai_agent_matched_playbook_learning_gap_api(): + client = TestClient(app) + response = client.get("/api/v1/agents/agent-matched-playbook-learning-gap") + + assert response.status_code == 200 + data = response.json() + assert data["schema_version"] == "ai_agent_matched_playbook_learning_gap_v1" + 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["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"]["playbook_trust_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 e2a057e2d..cd0ebe6b6 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -4562,6 +4562,62 @@ "needs_owner_review": "需 owner", "blocked_by_policy": "政策阻擋" } + }, + "matchedPlaybookLearningGap": { + "title": "P2-104 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 寫入。", + "metrics": { + "overall": "P2-104 進度", + "checkpoints": "學習檢查點", + "coveredTests": "測試覆蓋", + "sourceGuarded": "source guarded", + "liveBlocked": "等 live 證據", + "gaps": "缺口", + "highGaps": "高風險缺口", + "tests": "測試契約", + "ownerGates": "owner gate", + "liveDbReads": "live DB reads", + "trustWrites": "trust 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}", + "trustWrite": "trust write: {value}", + "kmWrite": "KM write: {value}", + "timelineWrite": "timeline write: {value}", + "send": "send: {value}" + }, + "labels": { + "gapIfMissing": "缺口: {value}", + "ownerReview": "owner review: {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}" + }, + "statuses": { + "covered_by_test": "測試覆蓋", + "covered_by_existing_tests": "既有測試覆蓋", + "source_guarded": "source guarded", + "blocked_until_live_evidence": "等 live 證據" + }, + "severities": { + "critical": "關鍵", + "high": "高", + "medium": "中", + "low": "低" + } } } }, diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index e2a057e2d..cd0ebe6b6 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -4562,6 +4562,62 @@ "needs_owner_review": "需 owner", "blocked_by_policy": "政策阻擋" } + }, + "matchedPlaybookLearningGap": { + "title": "P2-104 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 寫入。", + "metrics": { + "overall": "P2-104 進度", + "checkpoints": "學習檢查點", + "coveredTests": "測試覆蓋", + "sourceGuarded": "source guarded", + "liveBlocked": "等 live 證據", + "gaps": "缺口", + "highGaps": "高風險缺口", + "tests": "測試契約", + "ownerGates": "owner gate", + "liveDbReads": "live DB reads", + "trustWrites": "trust 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}", + "trustWrite": "trust write: {value}", + "kmWrite": "KM write: {value}", + "timelineWrite": "timeline write: {value}", + "send": "send: {value}" + }, + "labels": { + "gapIfMissing": "缺口: {value}", + "ownerReview": "owner review: {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}" + }, + "statuses": { + "covered_by_test": "測試覆蓋", + "covered_by_existing_tests": "既有測試覆蓋", + "source_guarded": "source guarded", + "blocked_until_live_evidence": "等 live 證據" + }, + "severities": { + "critical": "關鍵", + "high": "高", + "medium": "中", + "low": "低" + } } } }, 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 2b9884524..a4f309428 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 @@ -41,6 +41,7 @@ import { type AiAgentInteractionLearningProofSnapshot, type AiAgentLearningWritebackApprovalPackageSnapshot, type AiAgentLiveReadModelGateSnapshot, + type AiAgentMatchedPlaybookLearningGapSnapshot, type AiAgentOwnerApprovedFixtureDryRunSnapshot, type AiAgentOwnerApprovedLearningDryRunSnapshot, type AiAgentOperationPermissionModelSnapshot, @@ -352,6 +353,7 @@ export function AutomationInventoryTab() { const [operationPermissionModel, setOperationPermissionModel] = useState(null) const [candidateOperationDryRunEvidence, setCandidateOperationDryRunEvidence] = useState(null) const [taskResultAuditTrail, setTaskResultAuditTrail] = useState(null) + const [matchedPlaybookLearningGap, setMatchedPlaybookLearningGap] = useState(null) const [reportTruthActionabilityReview, setReportTruthActionabilityReview] = useState(null) const [ownerDryRunPackage, setOwnerDryRunPackage] = useState(null) const [hostStatefulInventory, setHostStatefulInventory] = useState(null) @@ -392,6 +394,7 @@ export function AutomationInventoryTab() { apiClient.getAiAgentOperationPermissionModel(), apiClient.getAiAgentCandidateOperationDryRunEvidence(), apiClient.getAiAgentTaskResultAuditTrail(), + apiClient.getAiAgentMatchedPlaybookLearningGap(), apiClient.getAiAgentReportTruthActionabilityReview(), apiClient.getAiAgentOwnerApprovedFixtureDryRun(), apiClient.getAiAgentHostStatefulVersionInventory(), @@ -431,6 +434,7 @@ export function AutomationInventoryTab() { operationPermissionModelResult, candidateOperationDryRunEvidenceResult, taskResultAuditTrailResult, + matchedPlaybookLearningGapResult, reportTruthActionabilityReviewResult, ownerDryRunPackageResult, hostStatefulInventoryResult, @@ -467,6 +471,7 @@ export function AutomationInventoryTab() { setOperationPermissionModel(operationPermissionModelResult.status === 'fulfilled' ? operationPermissionModelResult.value : null) setCandidateOperationDryRunEvidence(candidateOperationDryRunEvidenceResult.status === 'fulfilled' ? candidateOperationDryRunEvidenceResult.value : null) setTaskResultAuditTrail(taskResultAuditTrailResult.status === 'fulfilled' ? taskResultAuditTrailResult.value : null) + setMatchedPlaybookLearningGap(matchedPlaybookLearningGapResult.status === 'fulfilled' ? matchedPlaybookLearningGapResult.value : null) setReportTruthActionabilityReview(reportTruthActionabilityReviewResult.status === 'fulfilled' ? reportTruthActionabilityReviewResult.value : null) setOwnerDryRunPackage(ownerDryRunPackageResult.status === 'fulfilled' ? ownerDryRunPackageResult.value : null) setHostStatefulInventory(hostStatefulInventoryResult.status === 'fulfilled' ? hostStatefulInventoryResult.value : null) @@ -501,6 +506,7 @@ export function AutomationInventoryTab() { operationPermissionModelResult, candidateOperationDryRunEvidenceResult, taskResultAuditTrailResult, + matchedPlaybookLearningGapResult, reportTruthActionabilityReviewResult, ownerDryRunPackageResult, hostStatefulInventoryResult, @@ -1179,6 +1185,44 @@ export function AutomationInventoryTab() { .slice(0, 7) }, [taskResultAuditTrail]) + const visibleMatchedPlaybookCheckpoints = 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] + .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) + }) + .slice(0, 7) + }, [matchedPlaybookLearningGap]) + + const visibleMatchedPlaybookGaps = useMemo(() => { + if (!matchedPlaybookLearningGap) return [] + const severityPriority = { critical: 0, high: 1, medium: 2, low: 3 } as Record + return [...matchedPlaybookLearningGap.gap_items] + .sort((a, b) => { + const left = severityPriority[a.severity] ?? 4 + const right = severityPriority[b.severity] ?? 4 + if (left !== right) return left - right + return a.gap_id.localeCompare(b.gap_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 @@ -1398,7 +1442,7 @@ export function AutomationInventoryTab() { ) } - if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !proactiveOperations || !interactionLearningProof || !liveReadModelGate || !redisDryRunGate || !learningWritebackPackage || !telegramReceiptPackage || !ownerApprovedLearningDryRun || !runtimeWriteGateReview || !postWriteVerifierPackage || !runtimeVerifierEvidenceReview || !reportAutomationReview || !reportRuntimeReadiness || !reportRuntimeDryRun || !reportRuntimeFixtureReadback || !runtimeWorkerShadowGate || !operationPermissionModel || !candidateOperationDryRunEvidence || !taskResultAuditTrail || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) { + if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !proactiveOperations || !interactionLearningProof || !liveReadModelGate || !redisDryRunGate || !learningWritebackPackage || !telegramReceiptPackage || !ownerApprovedLearningDryRun || !runtimeWriteGateReview || !postWriteVerifierPackage || !runtimeVerifierEvidenceReview || !reportAutomationReview || !reportRuntimeReadiness || !reportRuntimeDryRun || !reportRuntimeFixtureReadback || !runtimeWorkerShadowGate || !operationPermissionModel || !candidateOperationDryRunEvidence || !taskResultAuditTrail || !matchedPlaybookLearningGap || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) { return (
@@ -1634,6 +1678,21 @@ export function AutomationInventoryTab() { const taskResultTimelineWrites = taskResultAuditTrail.rollups.timeline_write_count 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 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 const reportTruthFindings = reportTruthActionabilityReview.rollups.zero_signal_finding_count const reportTruthCritical = reportTruthActionabilityReview.rollups.critical_finding_count @@ -3541,6 +3600,145 @@ export function AutomationInventoryTab() {
+
+
+
+ + + {t('matchedPlaybookLearningGap.title')} + +
+ +
+ +
+ } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> +
+ +
+
+ {t('matchedPlaybookLearningGap.truthTitle')} + + {matchedPlaybookLearningGap.learning_gap_truth.truth_note} + +
+ + + + +
+
+ +
+ {t('matchedPlaybookLearningGap.boundaryTitle')} + + {t('matchedPlaybookLearningGap.boundarySummary', { + liveDb: matchedPlaybookLiveDbReads, + trust: matchedPlaybookTrustWrites, + km: matchedPlaybookKmWrites, + timeline: matchedPlaybookTimelineWrites, + queue: matchedPlaybookQueueWrites, + send: matchedPlaybookTelegramSends, + })} + +
+ + + + + + +
+
+
+ +
+ {visibleMatchedPlaybookCheckpoints.map(checkpoint => ( +
+
+ + {checkpoint.display_name} + + +
+ + {checkpoint.expected_signal} + + + {t('matchedPlaybookLearningGap.labels.gapIfMissing', { value: checkpoint.gap_if_missing })} + +
+ + + + +
+
+ ))} +
+ +
+ {visibleMatchedPlaybookGaps.map(gap => ( +
+
+ + {gap.display_name} + + +
+ + {gap.current_state} + + + {gap.owner_next_action} + +
+ + +
+
+ ))} +
+ +
+ {visibleMatchedPlaybookGates.map(gate => ( +
+
+ + {gate.display_name} + + +
+ + {t('matchedPlaybookLearningGap.labels.requiredBefore', { value: gate.required_before })} + + + {gate.blocked_reason} + + +
+ ))} +
+
+
diff --git a/apps/web/src/lib/api-client.ts b/apps/web/src/lib/api-client.ts index 3e8e7944e..d96008c38 100644 --- a/apps/web/src/lib/api-client.ts +++ b/apps/web/src/lib/api-client.ts @@ -362,6 +362,11 @@ export const apiClient = { return handleResponse(res) }, + async getAiAgentMatchedPlaybookLearningGap() { + const res = await fetch(`${API_BASE_URL}/agents/agent-matched-playbook-learning-gap`) + return handleResponse(res) + }, + async getAiAgentOwnerApprovedFixtureDryRun() { const res = await fetch(`${API_BASE_URL}/agents/agent-owner-approved-fixture-dry-run`) return handleResponse(res) @@ -3027,6 +3032,122 @@ export interface AiAgentTaskResultAuditTrailSnapshot { } } +export interface AiAgentMatchedPlaybookLearningGapSnapshot { + schema_version: 'ai_agent_matched_playbook_learning_gap_v1' + generated_at: string + program_status: { + overall_completion_percent: number + current_priority: 'P0' | 'P1' | 'P2' | 'P3' + current_task_id: 'P2-104' + next_task_id: 'P2-105' + read_only_mode: true + runtime_authority: 'matched_playbook_learning_gap_contract_only_no_live_trust_write' + status_note: string + } + source_refs: 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 + playbook_trust_write_enabled: false + km_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 + 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 + 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 + 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<{ + gate_id: string + display_name: string + required_before: string + approval_required: true + runtime_write_allowed: false + blocked_reason: string + }> + display_redaction_contract: { + redaction_required: true + raw_prompt_display_allowed: false + private_reasoning_display_allowed: false + secret_value_display_allowed: false + raw_telegram_payload_display_allowed: false + work_window_transcript_display_allowed: false + allowed_display_fields: string[] + 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 + 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 + secret_value_read_count: number + destructive_operation_count: number + } +} + export interface AiAgentOwnerApprovedFixtureDryRunSnapshot { schema_version: 'ai_agent_owner_approved_fixture_dry_run_v1' generated_at: string diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index fb9b6434e..1bf56151f 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,31 @@ +## 2026-06-13|P2-104 `matched_playbook_id` 學習缺口 + +**背景**: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 固定成可查證據面。 + +**完成(本地)**: + +- 新增 `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_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` 通過。 +- `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。 + +**完成度同步**: + +- 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 發送視為已啟用。 + +**邊界**:本段不查 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)**: 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 05abf108e..95614f9b7 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 已完成任務結果稽核軌跡。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`、`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`、`/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_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 | | 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 任務結果稽核軌跡;目前 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` 學習缺口。 +三 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 評分。 -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-103` 已補互動、學習證據面、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 證據與任務結果稽核軌跡。下一步是 `P2-104` 修復 `matched_playbook_id` 學習缺口;外部 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_id` 學習缺口證據面。下一步是 `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 | 待辦 | 0 | OpenClaw | 修復 `matched_playbook_id` 學習缺口 | playbook trust 更新 | 測試 + live 證據 | +| 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-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 f57c5a233..251dffc33 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 @@ -52,9 +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` 學習缺口 + +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`。 + ## 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:讓統帥能在治理頁看到 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 證據與任務結果稽核軌跡下一步要通過哪些 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_id` 學習缺口下一步要通過哪些 gate。 目前真相: @@ -150,17 +156,20 @@ | `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 | | `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 | | `GET /api/v1/agents/agent-live-read-model-gate` | 只讀 API,不連 DB、不讀寫 Redis、不發 Telegram | -| governance UI | 新增證據階梯、目前真相、P2-403B live read 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 review、P2-403J 報表真相 / 日週月報 / Agent 工作量 / 圖表 / AI 建議、P2-403L 報表 runtime readiness、P2-403M no-write dry-run、P2-403N fixture readback、P2-404 shadow gate、P2-101 operation permission model、P2-102 candidate dry-run evidence、P2-103 task result audit trail、Agent lane、可觀測訊號、runtime gates、前端 redaction | +| governance UI | 新增證據階梯、目前真相、P2-403B live read 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 review、P2-403J 報表真相 / 日週月報 / Agent 工作量 / 圖表 / AI 建議、P2-403L 報表 runtime readiness、P2-403M no-write dry-run、P2-403N fixture readback、P2-404 shadow gate、P2-101 operation permission model、P2-102 candidate dry-run evidence、P2-103 task result audit trail、P2-104 matched PlayBook learning gap、Agent lane、可觀測訊號、runtime gates、前端 redaction | ## 5. 後續優先順序 | 優先 | ID | 工作 | gate | |---:|---|---|---| -| 1 | P2-104 | 修復 `matched_playbook_id` 學習缺口 | PlayBook trust 候選與結果回寫 gate | +| 1 | P2-105 | 批准前加入 critic / reviewer 評分 | 多 Agent 評分與 owner 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 new file mode 100644 index 000000000..46f6158dc --- /dev/null +++ b/docs/evaluations/ai_agent_matched_playbook_learning_gap_2026-06-13.json @@ -0,0 +1,298 @@ +{ + "schema_version": "ai_agent_matched_playbook_learning_gap_v1", + "generated_at": "2026-06-13T10:55:00+08:00", + "program_status": { + "overall_completion_percent": 100, + "current_priority": "P2", + "current_task_id": "P2-104", + "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。" + }, + "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", + "docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md" + ], + "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, + "playbook_trust_write_enabled": false, + "km_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, + "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 寫入。" + }, + "learning_checkpoints": [ + { + "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。", + "owner_agent": "openclaw", + "requires_owner_review": false, + "writes_live_state": false, + "evidence_hash": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }, + { + "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。", + "owner_agent": "openclaw", + "requires_owner_review": false, + "writes_live_state": false, + "evidence_hash": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + }, + { + "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。", + "owner_agent": "hermes", + "requires_owner_review": true, + "writes_live_state": false, + "evidence_hash": "sha256:1111111111111111111111111111111111111111111111111111111111111111" + } + ], + "gap_items": [ + { + "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 + }, + { + "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 + }, + { + "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 + }, + { + "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 + } + ], + "test_contracts": [ + { + "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 + }, + { + "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 + }, + { + "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 + }, + { + "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。" + } + ], + "display_redaction_contract": { + "redaction_required": true, + "raw_prompt_display_allowed": false, + "private_reasoning_display_allowed": false, + "secret_value_display_allowed": false, + "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" + ], + "blocked_display_fields": [ + "secret_value", + "token", + "authorization_header", + "raw_prompt", + "private_reasoning", + "raw_telegram_payload", + "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, + "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, + "secret_value_read_count": 0, + "destructive_operation_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 new file mode 100644 index 000000000..fac2357e3 --- /dev/null +++ b/docs/schemas/ai_agent_matched_playbook_learning_gap_v1.schema.json @@ -0,0 +1,306 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://awoooi.wooo.work/schemas/ai_agent_matched_playbook_learning_gap_v1.schema.json", + "title": "AI Agent Matched PlayBook Learning Gap v1", + "type": "object", + "required": [ + "schema_version", + "generated_at", + "program_status", + "source_refs", + "learning_gap_truth", + "learning_checkpoints", + "gap_items", + "test_contracts", + "owner_gates", + "display_redaction_contract", + "rollups" + ], + "properties": { + "schema_version": { "const": "ai_agent_matched_playbook_learning_gap_v1" }, + "generated_at": { "type": "string" }, + "program_status": { + "type": "object", + "required": [ + "overall_completion_percent", + "current_priority", + "current_task_id", + "next_task_id", + "read_only_mode", + "runtime_authority", + "status_note" + ], + "properties": { + "overall_completion_percent": { "type": "integer", "minimum": 0, "maximum": 100 }, + "current_priority": { "enum": ["P0", "P1", "P2", "P3"] }, + "current_task_id": { "const": "P2-104" }, + "next_task_id": { "const": "P2-105" }, + "read_only_mode": { "const": true }, + "runtime_authority": { "const": "matched_playbook_learning_gap_contract_only_no_live_trust_write" }, + "status_note": { "type": "string" } + }, + "additionalProperties": false + }, + "source_refs": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, + "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", + "playbook_trust_write_enabled", + "km_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", + "runtime_execution_count_24h", + "live_db_read_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 }, + "playbook_trust_write_enabled": { "const": false }, + "km_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 }, + "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": { + "type": "array", + "minItems": 7, + "items": { "$ref": "#/$defs/learningCheckpoint" } + }, + "gap_items": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#/$defs/gapItem" } + }, + "test_contracts": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#/$defs/testContract" } + }, + "owner_gates": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#/$defs/ownerGate" } + }, + "display_redaction_contract": { + "type": "object", + "required": [ + "redaction_required", + "raw_prompt_display_allowed", + "private_reasoning_display_allowed", + "secret_value_display_allowed", + "raw_telegram_payload_display_allowed", + "work_window_transcript_display_allowed", + "allowed_display_fields", + "blocked_display_fields" + ], + "properties": { + "redaction_required": { "const": true }, + "raw_prompt_display_allowed": { "const": false }, + "private_reasoning_display_allowed": { "const": false }, + "secret_value_display_allowed": { "const": false }, + "raw_telegram_payload_display_allowed": { "const": false }, + "work_window_transcript_display_allowed": { "const": false }, + "allowed_display_fields": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, + "blocked_display_fields": { "type": "array", "items": { "type": "string" }, "minItems": 1 } + }, + "additionalProperties": false + }, + "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", + "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": 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 2b184d2dc..dbd96d0f2 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,13 +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 權限模型、候選 dry-run 證據與結果稽核軌跡承接下一步 | +| `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_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_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,6 +734,7 @@ Repo / registry / release notes / K8s / host / observability / backup evidence 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 評分。 #### 3.2.1d 2026-06-11 Agent 互動、學習與成長證據面 @@ -765,6 +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 | | `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 仍需批准 | @@ -1939,6 +1942,13 @@ 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 + +- 新增 `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 評分。 + ### 2026-06-12 11:55 (台北) — §3.2 / §5 — 完成 P2-403M 報表 runtime no-write dry-run 證據包 — 把 queue / verifier 草案固定成可審核證據 - 新增 `ai_agent_report_runtime_dry_run_v1` schema / committed snapshot / loader / API / 測試,定義 report_run snapshot preview、Telegram digest payload preview、AI post-report analysis packet、中低風險 no-op plan、post-action verifier readback plan。