From 6e17051b4d32e9cb547baab3f6ef631facd89553 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 11 Jun 2026 21:43:09 +0800 Subject: [PATCH] =?UTF-8?q?feat(governance):=20=E6=96=B0=E5=A2=9E=20learni?= =?UTF-8?q?ng=20writeback=20approval=20package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/api/src/api/v1/agents.py | 30 +++ ...ent_learning_writeback_approval_package.py | 157 ++++++++++++++++ ...est_ai_agent_interaction_learning_proof.py | 7 +- ...ai_agent_interaction_learning_proof_api.py | 6 +- ...ent_learning_writeback_approval_package.py | 52 ++++++ ...learning_writeback_approval_package_api.py | 17 ++ ..._ai_agent_proactive_operations_contract.py | 6 +- ...agent_proactive_operations_contract_api.py | 6 +- apps/web/messages/en.json | 25 +++ apps/web/messages/zh-TW.json | 25 +++ .../tabs/automation-inventory-tab.tsx | 149 ++++++++++++++- apps/web/src/lib/api-client.ts | 79 ++++++++ docs/LOGBOOK.md | 30 +++ ...AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md | 9 +- ...T_INTERACTION_LEARNING_PROOF_2026-06-11.md | 16 +- ...I_AGENT_PROACTIVE_OPERATIONS_2026-06-11.md | 11 +- ...interaction_learning_proof_2026-06-11.json | 21 ++- ...writeback_approval_package_2026-06-11.json | 175 ++++++++++++++++++ ...active_operations_contract_2026-06-11.json | 17 +- ..._writeback_approval_package_v1.schema.json | 162 ++++++++++++++++ ...-04-15-MASTER-ai-autonomous-flywheel-v2.md | 22 ++- 21 files changed, 970 insertions(+), 52 deletions(-) create mode 100644 apps/api/src/services/ai_agent_learning_writeback_approval_package.py create mode 100644 apps/api/tests/test_ai_agent_learning_writeback_approval_package.py create mode 100644 apps/api/tests/test_ai_agent_learning_writeback_approval_package_api.py create mode 100644 docs/evaluations/ai_agent_learning_writeback_approval_package_2026-06-11.json create mode 100644 docs/schemas/ai_agent_learning_writeback_approval_package_v1.schema.json diff --git a/apps/api/src/api/v1/agents.py b/apps/api/src/api/v1/agents.py index c6da20f8e..b9e275c34 100644 --- a/apps/api/src/api/v1/agents.py +++ b/apps/api/src/api/v1/agents.py @@ -64,6 +64,9 @@ from src.services.ai_agent_host_stateful_version_inventory import ( from src.services.ai_agent_interaction_learning_proof import ( load_latest_ai_agent_interaction_learning_proof, ) +from src.services.ai_agent_learning_writeback_approval_package import ( + load_latest_ai_agent_learning_writeback_approval_package, +) from src.services.ai_agent_live_read_model_gate import ( load_latest_ai_agent_live_read_model_gate, ) @@ -663,6 +666,33 @@ async def get_agent_redis_dry_run_gate() -> dict[str, Any]: ) from exc +@router.get( + "/agent-learning-writeback-approval-package", + response_model=dict[str, Any], + summary="取得 AI Agent learning writeback approval package", + description=( + "讀取最新已提交的 KM / PlayBook trust / timeline learning / replay score 回寫批准包;" + "此端點不寫 KM、不更新 PlayBook trust、不寫 timeline、不寫 replay score、不送 Telegram、" + "不啟動 runtime worker、不回傳未核准內部細節。" + ), +) +async def get_agent_learning_writeback_approval_package() -> dict[str, Any]: + """Return the latest read-only AI Agent learning writeback approval package.""" + try: + return await asyncio.to_thread(load_latest_ai_agent_learning_writeback_approval_package) + 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_learning_writeback_approval_package_invalid", error=str(exc)) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="AI Agent learning writeback approval package 無效", + ) from exc + + @router.get( "/agent-proactive-operations-contract", response_model=dict[str, Any], diff --git a/apps/api/src/services/ai_agent_learning_writeback_approval_package.py b/apps/api/src/services/ai_agent_learning_writeback_approval_package.py new file mode 100644 index 000000000..b5bdedb92 --- /dev/null +++ b/apps/api/src/services/ai_agent_learning_writeback_approval_package.py @@ -0,0 +1,157 @@ +""" +AI Agent learning writeback approval package snapshot. + +Loads the latest committed P2-403D approval package for KM, PlayBook trust, +timeline learning, and replay score writeback. This module never writes KM, +updates PlayBook trust, writes timeline events, sends Telegram messages, or +starts runtime workers. +""" + +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_learning_writeback_approval_package_*.json" +_SCHEMA_VERSION = "ai_agent_learning_writeback_approval_package_v1" + + +def load_latest_ai_agent_learning_writeback_approval_package( + evaluations_dir: Path | None = None, +) -> dict[str, Any]: + """Load the newest committed AI Agent learning writeback approval package.""" + directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR + candidates = sorted(directory.glob(_SNAPSHOT_PATTERN)) + if not candidates: + raise FileNotFoundError( + f"no AI Agent learning writeback approval package snapshots found in {directory}" + ) + + latest = candidates[-1] + with latest.open(encoding="utf-8") as handle: + payload = json.load(handle) + + if not isinstance(payload, dict): + raise ValueError(f"{latest}: expected JSON object") + _require_schema(payload, str(latest)) + _require_read_only_boundaries(payload, str(latest)) + _require_package_safety(payload, str(latest)) + _require_rollup_consistency(payload, str(latest)) + return payload + + +def _require_schema(payload: dict[str, Any], label: str) -> None: + actual = payload.get("schema_version") + if actual != _SCHEMA_VERSION: + raise ValueError(f"{label}: expected schema_version={_SCHEMA_VERSION}, got {actual!r}") + 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") != "approval_package_only_no_learning_writeback": + raise ValueError(f"{label}: runtime_authority must stay approval_package_only_no_learning_writeback") + + +def _require_read_only_boundaries(payload: dict[str, Any], label: str) -> None: + boundaries = payload.get("approval_boundaries") or {} + enabled = sorted(key for key, value in boundaries.items() if value is not False) + if enabled: + raise ValueError(f"{label}: approval boundaries must remain false: {enabled}") + + truth = payload.get("learning_truth") or {} + false_flags = { + "km_write_allowed", + "playbook_trust_write_allowed", + "timeline_learning_write_allowed", + "agent_replay_score_write_allowed", + "telegram_send_allowed", + "runtime_worker_allowed", + } + unsafe = sorted(flag for flag in false_flags if truth.get(flag) is not False) + if unsafe: + raise ValueError(f"{label}: learning truth flags must remain false: {unsafe}") + + zero_counts = { + "live_learning_write_count", + "live_playbook_trust_update_count", + "live_km_update_count", + } + non_zero = sorted(key for key in zero_counts if truth.get(key) != 0) + if non_zero: + raise ValueError(f"{label}: live learning write counts must remain zero: {non_zero}") + + +def _require_package_safety(payload: dict[str, Any], label: str) -> None: + package = payload.get("writeback_package") or {} + required_fields = set(package.get("required_fields") or []) + required_minimum = { + "learning_event_id", + "incident_id", + "target_surface", + "proposed_delta_summary", + "redacted_evidence_ref", + "owner_review_required", + "rollback_plan_ref", + } + missing = sorted(required_minimum - required_fields) + if missing: + raise ValueError(f"{label}: writeback package missing required fields: {missing}") + if package.get("owner_review_required") is not True: + raise ValueError(f"{label}: owner review must be required") + if package.get("rollback_required") is not True: + raise ValueError(f"{label}: rollback must be required") + + redaction = payload.get("display_redaction_contract") or {} + if redaction.get("redaction_required") is not True: + raise ValueError(f"{label}: frontend redaction must be required") + for flag in ("raw_payload_display_allowed", "private_reasoning_display_allowed", "secret_value_display_allowed"): + if redaction.get(flag) is not False: + raise ValueError(f"{label}: {flag} must remain false") + + rollback = payload.get("rollback_contract") or {} + if rollback.get("rollback_required") is not True: + raise ValueError(f"{label}: rollback_contract.rollback_required must be true") + if not rollback.get("rollback_steps"): + raise ValueError(f"{label}: rollback steps must not be empty") + + +def _require_rollup_consistency(payload: dict[str, Any], label: str) -> None: + rollups = payload.get("rollups") or {} + gates = payload.get("review_gates") or [] + lanes = payload.get("learning_lanes") or [] + package = payload.get("writeback_package") or {} + truth = payload.get("learning_truth") or {} + expected_counts = { + "review_gate_count": len(gates), + "learning_lane_count": len(lanes), + "blocked_write_action_count": len({gate.get("blocked_write_action") for gate in gates}), + "required_field_count": len(package.get("required_fields") or []), + "forbidden_field_count": len(package.get("forbidden_fields") or []), + } + mismatched = { + key: {"expected": expected, "actual": rollups.get(key)} + for key, expected in expected_counts.items() + if rollups.get(key) != expected + } + if mismatched: + raise ValueError(f"{label}: rollup counts must match payload sections: {mismatched}") + + approval_required = sorted( + gate.get("gate_id") for gate in gates if gate.get("status") == "approval_required" + ) + if sorted(rollups.get("approval_required_gate_ids") or []) != approval_required: + raise ValueError(f"{label}: rollups.approval_required_gate_ids mismatch") + + live_total = sum( + int(truth.get(key) or 0) + for key in ( + "live_learning_write_count", + "live_playbook_trust_update_count", + "live_km_update_count", + ) + ) + if rollups.get("live_write_count_total") != live_total: + raise ValueError(f"{label}: rollups.live_write_count_total mismatch") diff --git a/apps/api/tests/test_ai_agent_interaction_learning_proof.py b/apps/api/tests/test_ai_agent_interaction_learning_proof.py index bc0990b03..df89d3892 100644 --- a/apps/api/tests/test_ai_agent_interaction_learning_proof.py +++ b/apps/api/tests/test_ai_agent_interaction_learning_proof.py @@ -13,9 +13,9 @@ def test_load_latest_ai_agent_interaction_learning_proof_reads_committed_snapsho data = load_latest_ai_agent_interaction_learning_proof() assert data["schema_version"] == "ai_agent_interaction_learning_proof_v1" - assert data["program_status"]["overall_completion_percent"] == 65 - assert data["program_status"]["current_task_id"] == "P2-403C" - assert data["program_status"]["next_task_id"] == "P2-403D" + assert data["program_status"]["overall_completion_percent"] == 72 + assert data["program_status"]["current_task_id"] == "P2-403D" + assert data["program_status"]["next_task_id"] == "P2-403E" assert data["program_status"]["read_only_mode"] is True assert data["program_status"]["runtime_authority"] == "proof_surface_only_no_live_worker" assert data["live_truth"]["runtime_loop_enabled"] is False @@ -32,7 +32,6 @@ def test_load_latest_ai_agent_interaction_learning_proof_reads_committed_snapsho assert data["rollups"]["runtime_gate_count"] == len(data["runtime_gates"]) == 5 assert data["rollups"]["live_signal_count"] == 0 assert set(data["rollups"]["live_pending_level_ids"]) == { - "learning_growth", "telegram_receipts", } assert {lane["agent_id"] for lane in data["agent_lanes"]} == { diff --git a/apps/api/tests/test_ai_agent_interaction_learning_proof_api.py b/apps/api/tests/test_ai_agent_interaction_learning_proof_api.py index 05ff804cc..c748b97ae 100644 --- a/apps/api/tests/test_ai_agent_interaction_learning_proof_api.py +++ b/apps/api/tests/test_ai_agent_interaction_learning_proof_api.py @@ -16,9 +16,9 @@ def test_ai_agent_interaction_learning_proof_endpoint_returns_committed_snapshot assert response.status_code == 200 data = response.json() assert data["schema_version"] == "ai_agent_interaction_learning_proof_v1" - assert data["program_status"]["overall_completion_percent"] == 65 - assert data["program_status"]["current_task_id"] == "P2-403C" - assert data["program_status"]["next_task_id"] == "P2-403D" + assert data["program_status"]["overall_completion_percent"] == 72 + assert data["program_status"]["current_task_id"] == "P2-403D" + assert data["program_status"]["next_task_id"] == "P2-403E" assert data["program_status"]["read_only_mode"] is True assert data["live_truth"]["runtime_loop_enabled"] is False assert data["live_truth"]["active_live_agent_sessions"] == 0 diff --git a/apps/api/tests/test_ai_agent_learning_writeback_approval_package.py b/apps/api/tests/test_ai_agent_learning_writeback_approval_package.py new file mode 100644 index 000000000..4b42fcea1 --- /dev/null +++ b/apps/api/tests/test_ai_agent_learning_writeback_approval_package.py @@ -0,0 +1,52 @@ +import copy + +import pytest + +from src.services.ai_agent_learning_writeback_approval_package import ( + load_latest_ai_agent_learning_writeback_approval_package, +) + + +def test_load_latest_ai_agent_learning_writeback_approval_package(): + data = load_latest_ai_agent_learning_writeback_approval_package() + + assert data["schema_version"] == "ai_agent_learning_writeback_approval_package_v1" + assert data["program_status"]["current_task_id"] == "P2-403D" + assert data["program_status"]["next_task_id"] == "P2-403E" + assert data["learning_truth"]["km_write_allowed"] is False + assert data["learning_truth"]["playbook_trust_write_allowed"] is False + assert data["learning_truth"]["live_learning_write_count"] == 0 + assert data["rollups"]["review_gate_count"] == len(data["review_gates"]) + + +def test_rejects_learning_write_enabled(tmp_path): + data = load_latest_ai_agent_learning_writeback_approval_package() + bad = copy.deepcopy(data) + bad["learning_truth"]["km_write_allowed"] = True + path = tmp_path / "ai_agent_learning_writeback_approval_package_2026-06-11.json" + path.write_text(__import__("json").dumps(bad), encoding="utf-8") + + with pytest.raises(ValueError, match="learning truth flags"): + load_latest_ai_agent_learning_writeback_approval_package(tmp_path) + + +def test_rejects_missing_owner_review(tmp_path): + data = load_latest_ai_agent_learning_writeback_approval_package() + bad = copy.deepcopy(data) + bad["writeback_package"]["owner_review_required"] = False + path = tmp_path / "ai_agent_learning_writeback_approval_package_2026-06-11.json" + path.write_text(__import__("json").dumps(bad), encoding="utf-8") + + with pytest.raises(ValueError, match="owner review"): + load_latest_ai_agent_learning_writeback_approval_package(tmp_path) + + +def test_rejects_rollup_mismatch(tmp_path): + data = load_latest_ai_agent_learning_writeback_approval_package() + bad = copy.deepcopy(data) + bad["rollups"]["review_gate_count"] = 999 + path = tmp_path / "ai_agent_learning_writeback_approval_package_2026-06-11.json" + path.write_text(__import__("json").dumps(bad), encoding="utf-8") + + with pytest.raises(ValueError, match="rollup counts"): + load_latest_ai_agent_learning_writeback_approval_package(tmp_path) diff --git a/apps/api/tests/test_ai_agent_learning_writeback_approval_package_api.py b/apps/api/tests/test_ai_agent_learning_writeback_approval_package_api.py new file mode 100644 index 000000000..3bc573c07 --- /dev/null +++ b/apps/api/tests/test_ai_agent_learning_writeback_approval_package_api.py @@ -0,0 +1,17 @@ +from fastapi.testclient import TestClient + +from src.main import app + + +def test_get_ai_agent_learning_writeback_approval_package_api(): + client = TestClient(app) + response = client.get("/api/v1/agents/agent-learning-writeback-approval-package") + + assert response.status_code == 200 + data = response.json() + assert data["schema_version"] == "ai_agent_learning_writeback_approval_package_v1" + assert data["program_status"]["current_task_id"] == "P2-403D" + assert data["program_status"]["next_task_id"] == "P2-403E" + assert data["learning_truth"]["km_write_allowed"] is False + assert data["learning_truth"]["telegram_send_allowed"] is False + assert data["rollups"]["live_write_count_total"] == 0 diff --git a/apps/api/tests/test_ai_agent_proactive_operations_contract.py b/apps/api/tests/test_ai_agent_proactive_operations_contract.py index 8a33422ab..c7370e799 100644 --- a/apps/api/tests/test_ai_agent_proactive_operations_contract.py +++ b/apps/api/tests/test_ai_agent_proactive_operations_contract.py @@ -14,8 +14,8 @@ def test_load_latest_ai_agent_proactive_operations_contract_reads_committed_snap assert data["schema_version"] == "ai_agent_proactive_operations_contract_v1" assert data["program_status"]["overall_completion_percent"] == 100 - assert data["program_status"]["current_task_id"] == "P2-403C" - assert data["program_status"]["next_task_id"] == "P2-403D" + assert data["program_status"]["current_task_id"] == "P2-403D" + assert data["program_status"]["next_task_id"] == "P2-403E" assert data["program_status"]["read_only_mode"] is True assert data["program_status"]["runtime_authority"] == "contract_only_no_version_or_runtime_update" assert data["approval_boundaries"]["runtime_version_update_allowed"] is False @@ -25,7 +25,7 @@ def test_load_latest_ai_agent_proactive_operations_contract_reads_committed_snap assert data["approval_boundaries"]["telegram_direct_send_allowed"] is False assert data["rollups"]["version_domain_count"] == len(data["version_lifecycle_domains"]) == 12 assert data["rollups"]["delegable_capability_count"] == len(data["delegable_capabilities"]) == 24 - assert data["rollups"]["rollout_task_count"] == len(data["rollout_tasks"]) == 10 + assert data["rollups"]["rollout_task_count"] == len(data["rollout_tasks"]) == 11 assert data["rollups"]["auto_execute_allowed_count"] == 0 assert any(domain["domain_id"] == "ai_agents_models" for domain in data["version_lifecycle_domains"]) assert any( diff --git a/apps/api/tests/test_ai_agent_proactive_operations_contract_api.py b/apps/api/tests/test_ai_agent_proactive_operations_contract_api.py index 1325cf146..822b668b1 100644 --- a/apps/api/tests/test_ai_agent_proactive_operations_contract_api.py +++ b/apps/api/tests/test_ai_agent_proactive_operations_contract_api.py @@ -17,8 +17,8 @@ def test_ai_agent_proactive_operations_contract_endpoint_returns_committed_snaps data = response.json() assert data["schema_version"] == "ai_agent_proactive_operations_contract_v1" assert data["program_status"]["overall_completion_percent"] == 100 - assert data["program_status"]["current_task_id"] == "P2-403C" - assert data["program_status"]["next_task_id"] == "P2-403D" + assert data["program_status"]["current_task_id"] == "P2-403D" + assert data["program_status"]["next_task_id"] == "P2-403E" assert data["program_status"]["read_only_mode"] is True assert data["approval_boundaries"]["runtime_version_update_allowed"] is False assert data["approval_boundaries"]["package_upgrade_allowed"] is False @@ -26,7 +26,7 @@ def test_ai_agent_proactive_operations_contract_endpoint_returns_committed_snaps assert data["approval_boundaries"]["telegram_direct_send_allowed"] is False assert data["rollups"]["version_domain_count"] == 12 assert data["rollups"]["delegable_capability_count"] == 24 - assert data["rollups"]["rollout_task_count"] == 10 + assert data["rollups"]["rollout_task_count"] == 11 assert data["rollups"]["auto_execute_allowed_count"] == 0 assert any(domain["domain_id"] == "host_os_packages" for domain in data["version_lifecycle_domains"]) assert any( diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 681f9dc8a..df171bdce 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -3164,6 +3164,31 @@ "ready": "就緒" } }, + "learningWritebackPackage": { + "title": "P2-403D Learning Writeback Approval", + "source": "{generated} · {current} → {next}", + "packageTitle": "Writeback 批准包", + "truthTitle": "目前寫入真相", + "redactionTitle": "Learning 顯示紅線", + "metrics": { + "overall": "P2-403D 進度", + "gates": "Review gates", + "lanes": "Learning lanes", + "approval": "需批准 gates", + "blocked": "阻擋寫入", + "live": "Live writes" + }, + "flags": { + "km": "KM write: {value}", + "playbook": "PlayBook trust: {value}", + "telegram": "Telegram send: {value}" + }, + "labels": { + "requiredFields": "必填欄位 {count}", + "forbiddenFields": "禁止欄位 {count}", + "rollback": "rollback required: {value}" + } + }, "proactiveOperations": { "title": "可委派能力與版本治理", "source": "{generated} · {current} → {next}", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 681f9dc8a..df171bdce 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -3164,6 +3164,31 @@ "ready": "就緒" } }, + "learningWritebackPackage": { + "title": "P2-403D Learning Writeback Approval", + "source": "{generated} · {current} → {next}", + "packageTitle": "Writeback 批准包", + "truthTitle": "目前寫入真相", + "redactionTitle": "Learning 顯示紅線", + "metrics": { + "overall": "P2-403D 進度", + "gates": "Review gates", + "lanes": "Learning lanes", + "approval": "需批准 gates", + "blocked": "阻擋寫入", + "live": "Live writes" + }, + "flags": { + "km": "KM write: {value}", + "playbook": "PlayBook trust: {value}", + "telegram": "Telegram send: {value}" + }, + "labels": { + "requiredFields": "必填欄位 {count}", + "forbiddenFields": "禁止欄位 {count}", + "rollback": "rollback required: {value}" + } + }, "proactiveOperations": { "title": "可委派能力與版本治理", "source": "{generated} · {current} → {next}", diff --git a/apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx b/apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx index d17b8a72e..f2be4f86e 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 @@ -38,6 +38,7 @@ import { type AiAgentDeploymentLayoutSnapshot, type AiAgentHostStatefulVersionInventorySnapshot, type AiAgentInteractionLearningProofSnapshot, + type AiAgentLearningWritebackApprovalPackageSnapshot, type AiAgentLiveReadModelGateSnapshot, type AiAgentProactiveOperationsContractSnapshot, type AiAgentRedisDryRunGateSnapshot, @@ -322,6 +323,7 @@ export function AutomationInventoryTab() { const [interactionLearningProof, setInteractionLearningProof] = useState(null) const [liveReadModelGate, setLiveReadModelGate] = useState(null) const [redisDryRunGate, setRedisDryRunGate] = useState(null) + const [learningWritebackPackage, setLearningWritebackPackage] = useState(null) const [hostStatefulInventory, setHostStatefulInventory] = useState(null) const [serviceHealthGapMatrix, setServiceHealthGapMatrix] = useState(null) const [serviceHealthNotificationPolicy, setServiceHealthNotificationPolicy] = useState(null) @@ -346,6 +348,7 @@ export function AutomationInventoryTab() { apiClient.getAiAgentInteractionLearningProof(), apiClient.getAiAgentLiveReadModelGate(), apiClient.getAiAgentRedisDryRunGate(), + apiClient.getAiAgentLearningWritebackApprovalPackage(), apiClient.getAiAgentHostStatefulVersionInventory(), apiClient.getServiceHealthGapMatrix(), apiClient.getServiceHealthFailureNotificationPolicy(), @@ -369,6 +372,7 @@ export function AutomationInventoryTab() { interactionLearningProofResult, liveReadModelGateResult, redisDryRunGateResult, + learningWritebackPackageResult, hostStatefulInventoryResult, serviceHealthGapMatrixResult, serviceHealthNotificationPolicyResult, @@ -389,6 +393,7 @@ export function AutomationInventoryTab() { setInteractionLearningProof(interactionLearningProofResult.status === 'fulfilled' ? interactionLearningProofResult.value : null) setLiveReadModelGate(liveReadModelGateResult.status === 'fulfilled' ? liveReadModelGateResult.value : null) setRedisDryRunGate(redisDryRunGateResult.status === 'fulfilled' ? redisDryRunGateResult.value : null) + setLearningWritebackPackage(learningWritebackPackageResult.status === 'fulfilled' ? learningWritebackPackageResult.value : null) setHostStatefulInventory(hostStatefulInventoryResult.status === 'fulfilled' ? hostStatefulInventoryResult.value : null) setServiceHealthGapMatrix(serviceHealthGapMatrixResult.status === 'fulfilled' ? serviceHealthGapMatrixResult.value : null) setServiceHealthNotificationPolicy(serviceHealthNotificationPolicyResult.status === 'fulfilled' ? serviceHealthNotificationPolicyResult.value : null) @@ -407,6 +412,7 @@ export function AutomationInventoryTab() { interactionLearningProofResult, liveReadModelGateResult, redisDryRunGateResult, + learningWritebackPackageResult, hostStatefulInventoryResult, serviceHealthGapMatrixResult, serviceHealthNotificationPolicyResult, @@ -624,6 +630,30 @@ export function AutomationInventoryTab() { }) }, [redisDryRunGate]) + const visibleLearningWritebackGates = useMemo(() => { + if (!learningWritebackPackage) return [] + const priority = { approval_required: 0, blocked_by_runtime_gate: 1, contract_ready: 2 } as Record + return [...learningWritebackPackage.review_gates] + .sort((a, b) => { + const left = priority[a.status] ?? 3 + const right = priority[b.status] ?? 3 + if (left !== right) return left - right + return a.gate_id.localeCompare(b.gate_id) + }) + }, [learningWritebackPackage]) + + const visibleLearningWritebackLanes = useMemo(() => { + if (!learningWritebackPackage) return [] + const priority = { blocked_by_runtime_gate: 0, approval_required: 1, contract_ready: 2 } as Record + return [...learningWritebackPackage.learning_lanes] + .sort((a, b) => { + const left = priority[a.status] ?? 3 + const right = priority[b.status] ?? 3 + if (left !== right) return left - right + return a.lane_id.localeCompare(b.lane_id) + }) + }, [learningWritebackPackage]) + const visibleReadinessRows = useMemo(() => { if (!backupReadiness) return [] const priority = { blocked: 0, action_required: 1, deferred: 2, ready: 3 } as Record @@ -767,7 +797,7 @@ export function AutomationInventoryTab() { ) } - if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !proactiveOperations || !interactionLearningProof || !liveReadModelGate || !redisDryRunGate || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) { + if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !proactiveOperations || !interactionLearningProof || !liveReadModelGate || !redisDryRunGate || !learningWritebackPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) { return (
@@ -867,6 +897,12 @@ export function AutomationInventoryTab() { const redisApprovalSteps = redisDryRunGate.rollups.approval_required_step_ids.length const redisBlockedActions = redisDryRunGate.rollups.blocked_runtime_action_count const redisLiveTotal = redisDryRunGate.rollups.live_truth_count_total + const learningWritebackOverall = learningWritebackPackage.program_status.overall_completion_percent + const learningWritebackGates = learningWritebackPackage.rollups.review_gate_count + const learningWritebackLanes = learningWritebackPackage.rollups.learning_lane_count + const learningWritebackApprovals = learningWritebackPackage.rollups.approval_required_gate_ids.length + const learningWritebackBlockedWrites = learningWritebackPackage.rollups.blocked_write_action_count + const learningWritebackLiveWrites = learningWritebackPackage.rollups.live_write_count_total const hostReadonlyDeniedCount = ( hostStatefulInventory.rollups.ssh_login_allowed_count + hostStatefulInventory.rollups.kubectl_command_execution_allowed_count @@ -1631,9 +1667,9 @@ export function AutomationInventoryTab() {
-
- {visibleRedisHandoffLanes.map(lane => ( -
+
+ {visibleRedisHandoffLanes.map(lane => ( +
{lane.display_name} @@ -1651,6 +1687,111 @@ export function AutomationInventoryTab() {
+
+
+
+ + + {t('learningWritebackPackage.title')} + +
+ +
+ +
+ } /> + } /> + } /> + 0 ? 'danger' : 'ok'} icon={} /> + 0 ? 'danger' : 'ok'} icon={} /> + } /> +
+ +
+
+
+ {t('learningWritebackPackage.packageTitle')} + + {learningWritebackPackage.writeback_package.operator_meaning} + +
+ + + +
+
+ +
+ {t('learningWritebackPackage.truthTitle')} + + {learningWritebackPackage.learning_truth.truth_note} + +
+ + + +
+
+ +
+ {t('learningWritebackPackage.redactionTitle')} + + {learningWritebackPackage.display_redaction_contract.frontend_display_policy} + +
+
+ +
+ {visibleLearningWritebackGates.map(gate => ( +
+
+ + {gate.gate_id} + + +
+ + {gate.display_name} + + + {gate.required_evidence} + +
+ + +
+
+ ))} +
+
+ +
+ {visibleLearningWritebackLanes.map(lane => ( +
+
+ + {lane.display_name} + + +
+ + {redisDryRunValueLabel('agents', lane.owner_agent)} · {lane.target_surface} · {lane.review_owner} + + + {lane.required_review} + +
+ ))} +
+
+
diff --git a/apps/web/src/lib/api-client.ts b/apps/web/src/lib/api-client.ts index dc660bb51..d3fbbbf1f 100644 --- a/apps/web/src/lib/api-client.ts +++ b/apps/web/src/lib/api-client.ts @@ -287,6 +287,11 @@ export const apiClient = { return handleResponse(res) }, + async getAiAgentLearningWritebackApprovalPackage() { + const res = await fetch(`${API_BASE_URL}/agents/agent-learning-writeback-approval-package`) + return handleResponse(res) + }, + async getAiAgentHostStatefulVersionInventory() { const res = await fetch(`${API_BASE_URL}/agents/agent-host-stateful-version-inventory`) return handleResponse(res) @@ -1350,6 +1355,80 @@ export interface AiAgentRedisDryRunGateSnapshot { } } +export interface AiAgentLearningWritebackApprovalPackageSnapshot { + schema_version: 'ai_agent_learning_writeback_approval_package_v1' + generated_at: string + program_status: { + overall_completion_percent: number + current_priority: 'P0' | 'P1' | 'P2' | 'P3' + current_task_id: string + next_task_id: string + read_only_mode: true + runtime_authority: 'approval_package_only_no_learning_writeback' + status_note: string + } + source_refs: string[] + learning_truth: { + km_write_allowed: false + playbook_trust_write_allowed: false + timeline_learning_write_allowed: false + agent_replay_score_write_allowed: false + telegram_send_allowed: false + runtime_worker_allowed: false + live_learning_write_count: number + live_playbook_trust_update_count: number + live_km_update_count: number + truth_note: string + } + writeback_package: { + required_fields: string[] + forbidden_fields: string[] + owner_review_required: true + rollback_required: true + operator_meaning: string + } + review_gates: Array<{ + gate_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + status: string + required_evidence: string + blocked_write_action: string + }> + learning_lanes: Array<{ + lane_id: string + display_name: string + target_surface: string + status: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + review_owner: string + required_review: string + }> + rollback_contract: { + rollback_required: true + rollback_steps: string[] + } + approval_boundaries: Record + display_redaction_contract: { + redaction_required: true + raw_payload_display_allowed: false + private_reasoning_display_allowed: false + secret_value_display_allowed: false + allowed_frontend_content: string[] + forbidden_frontend_content: string[] + frontend_display_policy: string + } + rollups: { + review_gate_count: number + learning_lane_count: number + approval_required_gate_ids: string[] + blocked_write_action_count: number + required_field_count: number + forbidden_field_count: number + live_write_count_total: number + } +} + export interface AiAgentHostStatefulVersionInventorySnapshot { schema_version: 'ai_agent_host_stateful_version_inventory_v1' generated_at: string diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 6c0de7977..ec9ac4196 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -73,6 +73,36 @@ **完成度同步**:P2-403C 三 Agent 互動學習證據仍為 `65%`;本 hotfix 只收斂前端可見紅線語彙,Redis / Telegram / learning / worker runtime 仍全部維持 `0 / false`。 **邊界**:本段不連 Redis、不建立 consumer group、不 XADD / XREADGROUP / XACK、不 replay、不發 Telegram、不寫 learning、不啟動 worker、不 SSH、不 kubectl、不升級、不重啟、不讀取或輸出 secret、不新增任何前端執行按鈕。 +## 2026-06-11|P2-403D Learning Writeback Approval Package + +**背景**:P2-403C 已把 Redis dry-run、handoff envelope、ack / dead-letter / replay gate 固定成只讀契約,但統帥指出「批准後沒有真正自動化,也沒有人工處理選項」的核心缺口仍在。這一段不假裝已自動學習,而是先把 KM、PlayBook trust、timeline learning、replay score 的回寫拆成可審查、可回滾、可被前端看見的批准包;owner review 前不得寫入 canonical KM、不得更新 PlayBook trust、不得寫 timeline learning、不得發 Telegram。 + +**完成**: + +- 新增 `ai_agent_learning_writeback_approval_package_v1` schema、committed snapshot、只讀 loader、API route 與測試。 +- 新增 `GET /api/v1/agents/agent-learning-writeback-approval-package`,只回傳 committed approval package;不寫 KM、不更新 PlayBook trust、不寫 timeline / replay score、不發 Telegram、不啟動 runtime worker。 +- Snapshot 固定 `12` 個批准包必填欄位、`7` 個 forbidden fields、`4` 個 review gates、`3` 條 learning lanes、rollback contract、redaction contract 與 live write total `0`。 +- `agent-interaction-learning-proof` 與 `agent-proactive-operations-contract` 已同步 current / next:`P2-403D -> P2-403E`;三 Agent 互動學習證據完成度 `65% -> 72%`。 +- Governance automation inventory 頁新增 Learning Writeback Approval Package 區塊,顯示 KPI、批准包欄位、禁止欄位、truth flags、review gates、learning lanes 與 live write count,仍明確顯示 live write total 為 `0`。 +- MASTER §3.2.1c / §3.2.1d、AI Agent 自動化工作清單、互動學習證據報告與主動營運報告已同步 P2-403D;下一步為 `P2-403E` Telegram receipt approval package。 + +**本地驗證**: + +- JSON parse:P2-403D schema / snapshot、P2-403 interaction snapshot、P2-403 proactive snapshot、`zh-TW.json`、`en.json` 通過。 +- `python3 -m py_compile apps/api/src/services/ai_agent_learning_writeback_approval_package.py apps/api/src/api/v1/agents.py`:通過。 +- API/service pytest:P2-403D learning writeback approval package、P2-403C Redis dry-run gate、P2-403 interaction proof、P2-403 proactive contract 目標測試 `22 passed`。 +- `pnpm --filter @awoooi/web typecheck`:通過。 +- `source-control-owner-response-guard.py`、`security-mirror-progress-guard.py`、`doc-secrets-sanity-check.py docs .gitea`、`git diff --check` 通過。 + +**完成度同步**: + +- P2-403D learning writeback approval package:本地 `100%`。 +- 三 Agent 主動溝通、學習與成長證據:`72%`。 +- P2-403E Telegram receipt approval package:`0%`,尚未開始。 +- live learning write、KM update、PlayBook trust update、timeline learning、replay score write、Telegram send、runtime worker:全部仍為 `0 / false`。 +- IwoooS 整體仍維持 `64%`;active runtime gate 仍 `0`。 + +**邊界**:本段只做只讀批准包、snapshot、schema、API、測試、前端可視化與文件;未寫 KM、未更新 PlayBook trust、未寫 timeline learning、未寫 replay score、未發 Telegram、未啟動 worker、未連 Redis、未 SSH、未 active scan、未收 secret value、未開 runtime gate、未建立任何執行按鈕。正式站部署與 production desktop / mobile smoke 尚待 Gitea CD 完成後補驗。 ## 2026-06-11|IwoooS 高價值配置控管覆蓋矩陣 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 e109a1478..0dc66a572 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 主動溝通、學習與成長證據 | 65% | 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。runtime worker、DB migration、production Redis consumer group、Telegram 實發、learning writeback、SDK / 付費服務仍未開 gate | `ai_agent_communication_learning_contract_v1`、`ai_agent_interaction_learning_proof_v1`、`ai_agent_live_read_model_gate_v1`、`ai_agent_redis_dry_run_gate_v1`、`GET /api/v1/agents/agent-communication-learning-contract`、`GET /api/v1/agents/agent-interaction-learning-proof`、`GET /api/v1/agents/agent-live-read-model-gate`、`GET /api/v1/agents/agent-redis-dry-run-gate`、`/zh-TW/governance?tab=automation-inventory`、MASTER §3.2.1b / §3.2.1d / §3.4.3 | +| OpenClaw / Hermes / NemoTron 主動溝通、學習與成長證據 | 72% | 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。runtime worker、DB migration、production Redis consumer group、Telegram 實發、KM / PlayBook trust / timeline / replay score 寫入、SDK / 付費服務仍未開 gate | `ai_agent_communication_learning_contract_v1`、`ai_agent_interaction_learning_proof_v1`、`ai_agent_live_read_model_gate_v1`、`ai_agent_redis_dry_run_gate_v1`、`ai_agent_learning_writeback_approval_package_v1`、`GET /api/v1/agents/agent-communication-learning-contract`、`GET /api/v1/agents/agent-interaction-learning-proof`、`GET /api/v1/agents/agent-live-read-model-gate`、`GET /api/v1/agents/agent-redis-dry-run-gate`、`GET /api/v1/agents/agent-learning-writeback-approval-package`、`/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 主動溝通、學習與成長證據目前完成度:**65%**。已完成只讀契約、互動 / 接手 / 學習 / 成長證據面板、P2-403B live read model gate、P2-403C Redis dry-run gate、API、治理頁顯示、測試與 MASTER 同步;目前 live AgentSession、Agent message、handoff、learning write、Telegram receipt 仍全部為 `0`,下一步依優先順序推 `P2-403D` learning writeback approval package,但在批准前仍不得啟動 runtime loop。 +三 Agent 主動溝通、學習與成長證據目前完成度:**72%**。已完成只讀契約、互動 / 接手 / 學習 / 成長證據面板、P2-403B live read model gate、P2-403C Redis dry-run gate、P2-403D learning writeback approval package、API、治理頁顯示、測試與 MASTER 同步;目前 live AgentSession、Agent message、handoff、learning write、Telegram receipt 仍全部為 `0`,下一步依優先順序推 `P2-403E` Telegram receipt approval package,但在批准前仍不得啟動 runtime loop。 -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-403B` 與 `P2-403C` 已先補互動、學習證據面、live read model gate 與 Redis dry-run gate。下一步是 `P2-403D` learning writeback approval package,外部 registry / package source / host probe / SSH / kubectl / 工具安裝 / CI 變更 / 實際 PR creation / Telegram 實發仍需 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-403B`、`P2-403C` 與 `P2-403D` 已先補互動、學習證據面、live read model gate、Redis dry-run gate 與 learning writeback approval package。下一步是 `P2-403E` Telegram receipt approval package,外部 registry / package source / host probe / SSH / kubectl / 工具安裝 / CI 變更 / 實際 PR creation / Telegram 實發仍需 gate。 完成度計算模型: @@ -76,7 +76,7 @@ AI Agent 主動營運委派與版本生命週期目前完成度:**100%**。已 | AgentSession / Redis Streams runtime loop | 待辦:P2-401,需 migration / worker gate | | 主動溝通與學習契約 | 已完成:P2-401A,`ai_agent_communication_learning_contract_v1` + `GET /api/v1/agents/agent-communication-learning-contract` | | 主動營運委派與版本生命週期契約 | 已完成:P2-402A,`ai_agent_proactive_operations_contract_v1` + `GET /api/v1/agents/agent-proactive-operations-contract` | -| 互動、接手、學習與成長證據面 | 已完成:P2-403A + P2-403B + P2-403C,`ai_agent_interaction_learning_proof_v1`、`ai_agent_live_read_model_gate_v1`、`ai_agent_redis_dry_run_gate_v1`、`GET /api/v1/agents/agent-interaction-learning-proof`、`GET /api/v1/agents/agent-live-read-model-gate`、`GET /api/v1/agents/agent-redis-dry-run-gate` + governance UI;live count 仍為 0 | +| 互動、接手、學習與成長證據面 | 已完成:P2-403A + P2-403B + P2-403C + P2-403D,`ai_agent_interaction_learning_proof_v1`、`ai_agent_live_read_model_gate_v1`、`ai_agent_redis_dry_run_gate_v1`、`GET /api/v1/agents/agent-interaction-learning-proof`、`GET /api/v1/agents/agent-live-read-model-gate`、`GET /api/v1/agents/agent-redis-dry-run-gate`、`GET /api/v1/agents/agent-learning-writeback-approval-package` + governance UI;live count 仍為 0 | | NemoTron 3 Ultra smoke | 待辦:P3-401,需 source refresh + cost/data approval | ## 4. 工作流總覽 @@ -962,6 +962,7 @@ UI: | P2-403A | 完成 | 100 | Hermes + OpenClaw | 建立 Agent 互動、接手、學習、成長與 Telegram 收據證據面 | `ai_agent_interaction_learning_proof_v1` / snapshot / 只讀 API / governance UI;證據階梯、live truth、Agent lanes、runtime gates、redaction policy | 只讀;live session / message / handoff / learning write / Telegram receipt 目前全為 0;不啟動 worker、不 DB migration、不 Redis consumer、不發 Telegram、不顯示工作對話 | | P2-403B | 完成 | 100 | OpenClaw + Hermes | AgentSession / Redis Streams live read model 與 worker gate planning | `ai_agent_live_read_model_gate_v1` / snapshot / 只讀 API / governance UI;既有 `agent_sessions` safe fields、Redis envelope、worker gate、rollback plan、無寫入 smoke | DB / Redis approval;live DB query / Redis consumer / worker / Telegram / learning writeback 仍未啟用 | | P2-403C | 完成 | 100 | Hermes + OpenClaw + Nemotron | Redis Streams consumer group dry-run、handoff envelope、ack / dead-letter / replay gate | `ai_agent_redis_dry_run_gate_v1` / snapshot / 只讀 API / governance UI;fixture-only dry-run、handoff 必填欄位、idempotency、redacted evidence、ack / dead-letter / replay preconditions | 不連 Redis、不建立 consumer group、不 XADD / XREADGROUP / XACK、不寫 dead-letter、不 runtime replay、不發 Telegram、不 learning writeback | +| P2-403D | 完成 | 100 | Hermes + OpenClaw + Nemotron | Learning writeback approval package、KM / PlayBook trust / timeline learning / replay score gate | `ai_agent_learning_writeback_approval_package_v1` / snapshot / 只讀 API / governance UI;owner review、rollback、redaction、blocked write actions | 不寫 KM、不更新 PlayBook trust、不寫 timeline learning、不寫 replay score、不發 Telegram、不啟動 runtime worker | | P2-101 | 待辦 | 0 | OpenClaw | 定義操作類別權限模型 | 操作政策 schema | HITL 關卡 | | P2-102 | 待辦 | 0 | OpenClaw | 所有候選操作都要有 dry-run 證據 | dry-run 合約 | 不直接 apply | | P2-103 | 待辦 | 0 | Hermes | 把任務結果接回 KM / LOGBOOK / 稽核軌跡 | 證據寫入器 | 不洩漏 secret | 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 140a81b16..0e87fe230 100644 --- a/docs/ai/AI_AGENT_INTERACTION_LEARNING_PROOF_2026-06-11.md +++ b/docs/ai/AI_AGENT_INTERACTION_LEARNING_PROOF_2026-06-11.md @@ -1,12 +1,12 @@ # AI Agent 互動、溝通、學習與成長證據報告 > 日期:2026-06-11(台北時間) -> 文件定位:P2-403A 證據面 + P2-403B AgentSession / Redis Streams live read model gate + P2-403C Redis dry-run gate、API、治理頁 UI 與後續 runtime gate 分析。 +> 文件定位:P2-403A 證據面 + P2-403B AgentSession / Redis Streams live read model gate + P2-403C Redis dry-run gate + P2-403D learning writeback approval package、API、治理頁 UI 與後續 runtime gate 分析。 > 事實邊界:本波只建立可見證據面與 read model gate,不啟動 runtime worker、不建立 DB migration、不開 Redis consumer group、不發 Telegram、不顯示工作視窗對話內容。 ## 1. 結論 -已完成 P2-403A、P2-403B 與 P2-403C:讓統帥能在治理頁看到 OpenClaw / Hermes / NemoTron 的互動、接手、學習與成長是否真的有證據,並看到 live read model、Redis dry-run、handoff envelope、ack / dead-letter / replay 下一步要通過哪些 gate。 +已完成 P2-403A、P2-403B、P2-403C 與 P2-403D:讓統帥能在治理頁看到 OpenClaw / Hermes / NemoTron 的互動、接手、學習與成長是否真的有證據,並看到 live read model、Redis dry-run、handoff envelope、ack / dead-letter / replay、learning writeback approval 下一步要通過哪些 gate。 目前真相: @@ -51,24 +51,24 @@ | 產物 | 內容 | |---|---| | `docs/schemas/ai_agent_interaction_learning_proof_v1.schema.json` | 強制 live flags / counts / Telegram / transcript / 私有推理維持安全邊界 | -| `docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json` | P2-403A + P2-403B + P2-403C committed snapshot,完成度 `65%`,live count 全為 `0` | +| `docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json` | P2-403A + P2-403B + P2-403C + P2-403D committed snapshot,完成度 `72%`,live count 全為 `0` | | `docs/schemas/ai_agent_live_read_model_gate_v1.schema.json` | 強制 DB / Redis / worker / Telegram / learning writeback gate 維持未批准 | | `docs/evaluations/ai_agent_live_read_model_gate_2026-06-11.json` | P2-403B committed snapshot,完成度 `55%`,live count 全為 `0` | | `docs/evaluations/ai_agent_redis_dry_run_gate_2026-06-11.json` | P2-403C committed snapshot,完成度 `65%`,live count 全為 `0` | +| `docs/evaluations/ai_agent_learning_writeback_approval_package_2026-06-11.json` | P2-403D committed snapshot,完成度 `72%`,KM / PlayBook trust / timeline / replay score live write count 全為 `0` | | `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、Agent lane、可觀測訊號、runtime gates、前端 redaction | +| governance UI | 新增證據階梯、目前真相、P2-403B live read gate、P2-403C Redis dry-run gate、P2-403D learning writeback approval package、Agent lane、可觀測訊號、runtime gates、前端 redaction | ## 5. 後續優先順序 | 優先 | ID | 工作 | gate | |---:|---|---|---| -| 1 | P2-403D | learning writeback approval package、KM / playbook trust / replay score 趨勢 | writeback approval | -| 2 | P2-403E | learning writeback approval package、KM / playbook trust / replay score 趨勢 | writeback approval | -| 3 | P2-403E | Telegram gateway dry-run、E2E 送達與 receipt 顯示 | Telegram E2E approval | -| 4 | P2-403F | 成長趨勢週報與 operator feedback applied 指標 | trend evidence | +| 1 | P2-403E | Telegram gateway dry-run、E2E 送達與 receipt 顯示 | Telegram E2E approval | +| 2 | P2-403F | owner-approved learning writeback dry-run、KM / PlayBook trust / replay score 趨勢 | writeback approval | +| 3 | P2-403G | 成長趨勢週報與 operator feedback applied 指標 | trend evidence | ## 6. 紅線 diff --git a/docs/ai/AI_AGENT_PROACTIVE_OPERATIONS_2026-06-11.md b/docs/ai/AI_AGENT_PROACTIVE_OPERATIONS_2026-06-11.md index 84130b0f2..026a825b4 100644 --- a/docs/ai/AI_AGENT_PROACTIVE_OPERATIONS_2026-06-11.md +++ b/docs/ai/AI_AGENT_PROACTIVE_OPERATIONS_2026-06-11.md @@ -1,7 +1,7 @@ # AI Agent 主動營運委派與版本生命週期分析報告 > 日期:2026-06-11(台北時間) -> 文件定位:P2-402A / P2-402B / P2-402C / P2-402D / P2-402E / P2-402F / P2-402G / P2-403A / P2-403B / P2-403C 只讀契約與治理 UI 摘要。權威細節以 MASTER §3.2.1c / §3.2.1d、`ai_agent_proactive_operations_contract_v1`、`ai_agent_interaction_learning_proof_v1`、`ai_agent_live_read_model_gate_v1`、`ai_agent_redis_dry_run_gate_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` 為準。 +> 文件定位:P2-402A / P2-402B / P2-402C / P2-402D / P2-402E / P2-402F / P2-402G / P2-403A / P2-403B / P2-403C / P2-403D 只讀契約與治理 UI 摘要。權威細節以 MASTER §3.2.1c / §3.2.1d、`ai_agent_proactive_operations_contract_v1`、`ai_agent_interaction_learning_proof_v1`、`ai_agent_live_read_model_gate_v1`、`ai_agent_redis_dry_run_gate_v1`、`ai_agent_learning_writeback_approval_package_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` 為準。 ## 1. 本波完成度 @@ -16,7 +16,8 @@ | Governance UI 可委派能力顯示 | 100% | P2-402G 已把可委派能力、版本生命週期、Host / K3s / stateful 只讀盤點、maintenance window 與 Telegram / redaction gate 接入治理頁 | | Agent 互動與學習證據面 | 100% | P2-403A 已把目前真相、證據階梯、三 Agent lane、可觀測訊號、runtime gates 與 redaction policy 接入治理頁;live counts 全為 `0` | | Redis dry-run gate | 100% | P2-403C 已把 consumer group dry-run、handoff envelope、ack / dead-letter / replay idempotency 與治理頁顯示接入;live counts 全為 `0` | -| 整體主動營運與版本生命週期 | 100% | P2-402A~G、P2-403A、P2-403B 與 P2-403C 只讀契約、snapshot、API、測試與治理 UI 已完成;runtime 排程、工具安裝、CI 變更、實際 PR 建立與更新、host probe、升級、重啟、learning write、Telegram receipt 仍未開 gate | +| Learning writeback approval package | 100% | P2-403D 已把 KM / PlayBook trust / timeline learning / replay score 的 owner review、rollback、redaction 與 blocked write actions 接入;live writes 全為 `0` | +| 整體主動營運與版本生命週期 | 100% | P2-402A~G、P2-403A、P2-403B、P2-403C 與 P2-403D 只讀契約、snapshot、API、測試與治理 UI 已完成;runtime 排程、工具安裝、CI 變更、實際 PR 建立與更新、host probe、升級、重啟、learning write、Telegram receipt 仍未開 gate | ## 2. 可交給 AI Agent 的工作分類 @@ -54,7 +55,7 @@ | `docs/evaluations/ai_agent_host_stateful_version_inventory_2026-06-11.json` | 5 台主機、2 個 K3s 節點、12 個 stateful / ops 服務、6 個只讀 probe 步驟、maintenance window approval package | | `GET /api/v1/agents/agent-host-stateful-version-inventory` | 只讀 API;不 SSH、不 kubectl、不升級、不 drain、不 reboot、不重啟 stateful、不發 Telegram | | `docs/schemas/ai_agent_interaction_learning_proof_v1.schema.json` | P2-403A Agent 互動、接手、學習、成長與 Telegram receipt 證據面 schema | -| `docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json` | 證據階梯、live truth、三 Agent lane、可觀測訊號、runtime gates;P2-403C 後完成度 `65%`,live counts 全部 `0` | +| `docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json` | 證據階梯、live truth、三 Agent lane、可觀測訊號、runtime gates;P2-403D 後完成度 `72%`,live counts 全部 `0` | | `GET /api/v1/agents/agent-interaction-learning-proof` | 只讀 API;不啟動 worker、不開 Redis consumer、不 DB migration、不發 Telegram、不顯示工作視窗對話 | | `docs/schemas/ai_agent_live_read_model_gate_v1.schema.json` | P2-403B AgentSession / Redis Streams live read model gate schema | | `docs/evaluations/ai_agent_live_read_model_gate_2026-06-11.json` | AgentSession safe fields、Redis envelope、worker gate、rollback plan、no-write smoke、frontend redaction;live counts 全部 `0` | @@ -69,7 +70,7 @@ | Dockerfiles | Hermes | action_required | P2-402C 評估 Trivy / Syft / Grype / Docker Scout 採用,不 build / pull | | Committed evaluation snapshots | Hermes | action_required | 將 2026-06-04~06-05 舊基線列入 stale refs,不假裝是外部最新 | | Agent / model governance snapshots | NemoTron | action_required | 只做離線 freshness note,不進 shadow / canary / production route | -| K8s / Gitea / observability / Ansible / backup / web surfaces | OpenClaw + Hermes | baseline_ready / planned_next | 下一步進入 P2-403D learning writeback approval package;現階段仍只讀 | +| K8s / Gitea / observability / Ansible / backup / web surfaces | OpenClaw + Hermes | baseline_ready / planned_next | 下一步進入 P2-403E Telegram receipt approval package;現階段仍只讀 | 本波只把「每天要看哪些 repo 內版本來源」定義成可驗證資料面。每日排程、外部 registry 查詢、主機/K3s live probe、Telegram digest 與 Gitea PR lane 都仍是下一階段 gate。 @@ -141,7 +142,7 @@ P2-402G 的重點是把前面六個資料契約接回治理頁,讓統帥可以 | P2-403A | 4 | Agent 互動、接手、學習、成長與 Telegram receipt 證據面 | 已完成,只讀;live counts 全為 `0` | | P2-403B | 5 | live AgentSession / Redis read model:safe fields、Redis envelope、worker gate、rollback、no-write smoke | 已完成,只讀;live DB query / Redis consumer / worker 未啟用 | | P2-403C | 6 | Redis Streams consumer group dry-run、handoff envelope、ack / dead letter / replay | 已完成,只讀;production Redis consumer / worker / ACK / replay 未啟用 | -| P2-403D | 7 | Learning writeback approval package、資料保留、錯誤補償、人工回饋回滾 | learning writeback approval | +| P2-403D | 7 | Learning writeback approval package、資料保留、錯誤補償、人工回饋回滾 | 已完成,只讀;KM / PlayBook trust / timeline learning / replay score 寫入未啟用 | ## 11. 仍維持 false 的安全邊界 diff --git a/docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json b/docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json index cb6d3f383..e68564b8e 100644 --- a/docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json +++ b/docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json @@ -2,13 +2,13 @@ "schema_version": "ai_agent_interaction_learning_proof_v1", "generated_at": "2026-06-11T23:20:00+08:00", "program_status": { - "overall_completion_percent": 65, + "overall_completion_percent": 72, "current_priority": "P2", - "current_task_id": "P2-403C", - "next_task_id": "P2-403D", + "current_task_id": "P2-403D", + "next_task_id": "P2-403E", "read_only_mode": true, "runtime_authority": "proof_surface_only_no_live_worker", - "status_note": "P2-403C 已把 Redis Streams consumer group dry-run、handoff envelope、ack / dead-letter / replay gate 接入證據鏈;live Redis consumer、runtime worker、Telegram receipt 與 learning writeback 仍未開 gate。" + "status_note": "P2-403D 已把 KM、PlayBook trust、timeline learning 與 replay score 的 learning writeback approval package 接入證據鏈;live learning write、PlayBook trust update、KM update 與 Telegram receipt 仍未開 gate。" }, "live_truth": { "runtime_loop_enabled": false, @@ -72,11 +72,11 @@ { "level_id": "learning_growth", "display_name": "學習回寫與成長曲線", - "status": "live_pending", + "status": "approval_required", "completion_percent": 0, "operator_meaning": "啟用後你會看到知識庫新增、playbook trust 變化、replay 分數改善與錯誤類型下降。", "source_of_truth": "knowledge_entries + playbook_trust_history + replay_results + finetune_exporter", - "next_gate": "P2-403D learning writeback approval package。" + "next_gate": "P2-403D learning writeback approval package 已接入;實際 writeback 仍需 owner approval。" }, { "level_id": "telegram_receipts", @@ -85,7 +85,7 @@ "completion_percent": 0, "operator_meaning": "啟用後 Telegram 只推送需處置、需批准或失敗摘要,治理頁保留已排隊/已送達/已確認收據。", "source_of_truth": "telegram_gateway_queue + alert_operation_log", - "next_gate": "P2-403E Telegram gateway dry-run、E2E token 注入驗證。" + "next_gate": "P2-403E Telegram receipt approval package。" } ], "agent_lanes": [ @@ -286,14 +286,16 @@ "display_name": "Learning writeback 批准包", "status": "approval_required", "required_before_green": "必須定義可寫表、資料保留、錯誤補償、人工回饋回滾。", - "next_task_id": "P2-403D" + "next_task_id": "P2-403D", + "next_gate": "P2-403D learning writeback approval package 已接入;實際 writeback 仍需 owner approval。" }, { "gate_id": "telegram_receipt_gate", "display_name": "Telegram 摘要與收據 gate", "status": "approval_required", "required_before_green": "必須完成 gateway dry-run、token 注入、E2E 送達、成功降噪與 failure fallback。", - "next_task_id": "P2-403E" + "next_task_id": "P2-403E", + "next_gate": "P2-403E Telegram receipt approval package。" }, { "gate_id": "frontend_redaction_gate", @@ -367,7 +369,6 @@ "proof_level_count": 7, "contract_ready_level_count": 5, "live_pending_level_ids": [ - "learning_growth", "telegram_receipts" ], "signal_count": 9, diff --git a/docs/evaluations/ai_agent_learning_writeback_approval_package_2026-06-11.json b/docs/evaluations/ai_agent_learning_writeback_approval_package_2026-06-11.json new file mode 100644 index 000000000..919befeea --- /dev/null +++ b/docs/evaluations/ai_agent_learning_writeback_approval_package_2026-06-11.json @@ -0,0 +1,175 @@ +{ + "schema_version": "ai_agent_learning_writeback_approval_package_v1", + "generated_at": "2026-06-11T23:59:30+08:00", + "program_status": { + "overall_completion_percent": 72, + "current_priority": "P2", + "current_task_id": "P2-403D", + "next_task_id": "P2-403E", + "read_only_mode": true, + "runtime_authority": "approval_package_only_no_learning_writeback", + "status_note": "P2-403D 已把 KM、PlayBook trust、timeline learning 與 replay score 的回寫批准包固定為只讀契約;尚未寫 KM、未更新 PlayBook trust、未寫 timeline learning、未發 Telegram、未啟動 runtime worker。" + }, + "source_refs": [ + "docs/evaluations/ai_agent_redis_dry_run_gate_2026-06-11.json", + "docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md", + "docs/ai/AI_AGENT_INTERACTION_LEARNING_PROOF_2026-06-11.md" + ], + "learning_truth": { + "km_write_allowed": false, + "playbook_trust_write_allowed": false, + "timeline_learning_write_allowed": false, + "agent_replay_score_write_allowed": false, + "telegram_send_allowed": false, + "runtime_worker_allowed": false, + "live_learning_write_count": 0, + "live_playbook_trust_update_count": 0, + "live_km_update_count": 0, + "truth_note": "目前只允許產生 owner review 前的學習回寫批准包;所有 production writeback 與通知仍為 0 / false。" + }, + "writeback_package": { + "required_fields": [ + "learning_event_id", + "incident_id", + "source_stage", + "learning_type", + "target_surface", + "proposed_delta_summary", + "redacted_evidence_ref", + "confidence_score", + "risk_level", + "owner_review_required", + "rollback_plan_ref", + "created_at" + ], + "forbidden_fields": [ + "secret_value", + "credential_value", + "raw_prompt", + "conversation_transcript", + "private_reasoning", + "chain_of_thought", + "raw_tool_output" + ], + "owner_review_required": true, + "rollback_required": true, + "operator_meaning": "每個學習回寫候選都必須說清楚來源事件、要寫到哪裡、要改什麼、信心分數、風險、證據與 rollback;owner review 前不得寫入 canonical KM 或 PlayBook trust。" + }, + "review_gates": [ + { + "gate_id": "km_owner_review_gate", + "display_name": "KM owner review gate", + "owner_agent": "hermes", + "status": "approval_required", + "required_evidence": "stale KM ref、incident ref、proposed delta、owner reviewer、rollback note。", + "blocked_write_action": "knowledge_entries_write" + }, + { + "gate_id": "playbook_trust_gate", + "display_name": "PlayBook trust gate", + "owner_agent": "openclaw", + "status": "approval_required", + "required_evidence": "repair result、verifier result、blast radius、trust delta reason。", + "blocked_write_action": "playbook_trust_update" + }, + { + "gate_id": "replay_score_gate", + "display_name": "Replay score gate", + "owner_agent": "nemotron", + "status": "approval_required", + "required_evidence": "sanitized replay fixture、idempotency key、score delta、no-write proof。", + "blocked_write_action": "agent_replay_score_write" + }, + { + "gate_id": "timeline_learning_gate", + "display_name": "Timeline learning gate", + "owner_agent": "openclaw", + "status": "contract_ready", + "required_evidence": "incident timeline ref、stage outcome、blocked reason、next action。", + "blocked_write_action": "timeline_learning_event_write" + } + ], + "learning_lanes": [ + { + "lane_id": "incident_to_km_draft", + "display_name": "Incident → KM 草稿", + "target_surface": "knowledge_base", + "status": "approval_required", + "owner_agent": "hermes", + "review_owner": "km_owner", + "required_review": "owner 必須確認引用來源、過期條目、改寫摘要與 rollback note。" + }, + { + "lane_id": "repair_to_playbook_trust", + "display_name": "Repair → PlayBook trust", + "target_surface": "playbook_trust_history", + "status": "approval_required", + "owner_agent": "openclaw", + "review_owner": "sre_owner", + "required_review": "owner 必須確認修復是否真的執行、verifier 是否通過、信任分數是否可調整。" + }, + { + "lane_id": "replay_to_agent_score", + "display_name": "Replay → Agent score", + "target_surface": "agent_replay_results", + "status": "blocked_by_runtime_gate", + "owner_agent": "nemotron", + "review_owner": "ai_governance_owner", + "required_review": "owner 必須確認 replay fixture 已脫敏、沒有 production route 影響、沒有付費 API 未授權。" + } + ], + "rollback_contract": { + "rollback_required": true, + "rollback_steps": [ + "保留 pre-write snapshot ref", + "保留 owner approval record", + "每筆 writeback 必須有 idempotency key", + "發現錯誤學習時先標記 deprecated,不直接刪 canonical", + "rollback 後回寫 incident timeline 的 learning_reverted 事件" + ] + }, + "approval_boundaries": { + "km_write_allowed": false, + "playbook_trust_write_allowed": false, + "timeline_learning_write_allowed": false, + "agent_replay_score_write_allowed": false, + "runtime_worker_allowed": false, + "telegram_send_allowed": false, + "secret_plaintext_allowed": false + }, + "display_redaction_contract": { + "redaction_required": true, + "raw_payload_display_allowed": false, + "private_reasoning_display_allowed": false, + "secret_value_display_allowed": false, + "allowed_frontend_content": [ + "learning lane", + "target surface", + "owner review status", + "required evidence", + "blocked write action", + "rollback requirement" + ], + "forbidden_frontend_content": [ + "未脫敏 payload", + "提示內容", + "未核准內部細節", + "機密值", + "raw tool output" + ], + "frontend_display_policy": "治理頁只顯示 learning lane、目標 surface、owner review、阻擋寫入動作與 rollback 要求;未脫敏 payload、未核准內部細節、機密值與 raw tool output 不進前端。" + }, + "rollups": { + "review_gate_count": 4, + "learning_lane_count": 3, + "approval_required_gate_ids": [ + "km_owner_review_gate", + "playbook_trust_gate", + "replay_score_gate" + ], + "blocked_write_action_count": 4, + "required_field_count": 12, + "forbidden_field_count": 7, + "live_write_count_total": 0 + } +} diff --git a/docs/evaluations/ai_agent_proactive_operations_contract_2026-06-11.json b/docs/evaluations/ai_agent_proactive_operations_contract_2026-06-11.json index 071437c91..0e380e2d2 100644 --- a/docs/evaluations/ai_agent_proactive_operations_contract_2026-06-11.json +++ b/docs/evaluations/ai_agent_proactive_operations_contract_2026-06-11.json @@ -4,11 +4,11 @@ "program_status": { "overall_completion_percent": 100, "current_priority": "P2", - "current_task_id": "P2-403C", - "next_task_id": "P2-403D", + "current_task_id": "P2-403D", + "next_task_id": "P2-403E", "read_only_mode": true, "runtime_authority": "contract_only_no_version_or_runtime_update", - "status_note": "P2-403C 已把 Redis Streams consumer group dry-run、handoff envelope、ack / dead-letter / replay gate 接入治理證據;live AgentSession / Redis consumer / runtime worker / learning write / Telegram receipt 目前全為 0,下一步是 P2-403D learning writeback approval package。" + "status_note": "P2-403D 已把 learning writeback approval package 接入治理證據;live AgentSession / Redis consumer / runtime worker / learning write / Telegram receipt 目前全為 0,下一步是 P2-403E Telegram receipt approval package。" }, "external_source_evidence": [ { @@ -846,6 +846,15 @@ "owner_agent": "Hermes + OpenClaw + Nemotron", "summary": "建立 Redis Streams consumer group dry-run、handoff envelope、ack / dead-letter / replay idempotency gate、只讀 API 與 governance UI 顯示;不連 Redis、不建立 consumer group、不 XADD、不 ACK、不 replay、不發 Telegram。", "next_gate": "P2-403D_learning_writeback_approval_package" + }, + { + "task_id": "P2-403D", + "priority": "P2", + "status": "done", + "completion_percent": 100, + "owner_agent": "Hermes + OpenClaw + Nemotron", + "summary": "建立 learning writeback approval package;固定 KM、PlayBook trust、timeline learning 與 replay score 回寫前的 owner review、redaction、rollback 與 blocked write actions。", + "next_gate": "P2-403E_telegram_receipt_approval_package" } ], "approval_boundaries": { @@ -866,7 +875,7 @@ "cadence_count": 5, "mcp_tool_count": 8, "rag_memory_count": 4, - "rollout_task_count": 10, + "rollout_task_count": 11, "auto_execute_allowed_count": 0, "approval_required_capability_count": 23, "blocked_update_domain_ids": [ diff --git a/docs/schemas/ai_agent_learning_writeback_approval_package_v1.schema.json b/docs/schemas/ai_agent_learning_writeback_approval_package_v1.schema.json new file mode 100644 index 000000000..5117827bf --- /dev/null +++ b/docs/schemas/ai_agent_learning_writeback_approval_package_v1.schema.json @@ -0,0 +1,162 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://awoooi.wooo.work/schemas/ai_agent_learning_writeback_approval_package_v1.schema.json", + "title": "AI Agent Learning Writeback Approval Package", + "type": "object", + "required": [ + "schema_version", + "generated_at", + "program_status", + "learning_truth", + "writeback_package", + "review_gates", + "learning_lanes", + "rollback_contract", + "approval_boundaries", + "display_redaction_contract", + "rollups" + ], + "properties": { + "schema_version": { + "const": "ai_agent_learning_writeback_approval_package_v1" + }, + "generated_at": { + "type": "string" + }, + "program_status": { + "type": "object", + "required": [ + "overall_completion_percent", + "current_task_id", + "next_task_id", + "read_only_mode", + "runtime_authority" + ], + "properties": { + "overall_completion_percent": { "type": "integer" }, + "current_priority": { "type": "string" }, + "current_task_id": { "const": "P2-403D" }, + "next_task_id": { "const": "P2-403E" }, + "read_only_mode": { "const": true }, + "runtime_authority": { "const": "approval_package_only_no_learning_writeback" }, + "status_note": { "type": "string" } + }, + "additionalProperties": false + }, + "learning_truth": { + "type": "object", + "properties": { + "km_write_allowed": { "const": false }, + "playbook_trust_write_allowed": { "const": false }, + "timeline_learning_write_allowed": { "const": false }, + "agent_replay_score_write_allowed": { "const": false }, + "telegram_send_allowed": { "const": false }, + "runtime_worker_allowed": { "const": false }, + "live_learning_write_count": { "const": 0 }, + "live_playbook_trust_update_count": { "const": 0 }, + "live_km_update_count": { "const": 0 }, + "truth_note": { "type": "string" } + }, + "additionalProperties": false + }, + "writeback_package": { + "type": "object", + "required": [ + "required_fields", + "forbidden_fields", + "owner_review_required", + "rollback_required" + ], + "properties": { + "required_fields": { "type": "array", "items": { "type": "string" } }, + "forbidden_fields": { "type": "array", "items": { "type": "string" } }, + "owner_review_required": { "const": true }, + "rollback_required": { "const": true }, + "operator_meaning": { "type": "string" } + }, + "additionalProperties": false + }, + "review_gates": { + "type": "array", + "items": { + "type": "object", + "required": ["gate_id", "display_name", "owner_agent", "status", "required_evidence", "blocked_write_action"], + "properties": { + "gate_id": { "type": "string" }, + "display_name": { "type": "string" }, + "owner_agent": { "enum": ["openclaw", "hermes", "nemotron"] }, + "status": { "type": "string" }, + "required_evidence": { "type": "string" }, + "blocked_write_action": { "type": "string" } + }, + "additionalProperties": false + } + }, + "learning_lanes": { + "type": "array", + "items": { + "type": "object", + "required": ["lane_id", "display_name", "target_surface", "status", "owner_agent", "review_owner", "required_review"], + "properties": { + "lane_id": { "type": "string" }, + "display_name": { "type": "string" }, + "target_surface": { "type": "string" }, + "status": { "type": "string" }, + "owner_agent": { "enum": ["openclaw", "hermes", "nemotron"] }, + "review_owner": { "type": "string" }, + "required_review": { "type": "string" } + }, + "additionalProperties": false + } + }, + "rollback_contract": { + "type": "object", + "required": ["rollback_required", "rollback_steps"], + "properties": { + "rollback_required": { "const": true }, + "rollback_steps": { "type": "array", "items": { "type": "string" } } + }, + "additionalProperties": false + }, + "approval_boundaries": { + "type": "object", + "additionalProperties": { "const": false } + }, + "display_redaction_contract": { + "type": "object", + "properties": { + "redaction_required": { "const": true }, + "raw_payload_display_allowed": { "const": false }, + "private_reasoning_display_allowed": { "const": false }, + "secret_value_display_allowed": { "const": false }, + "allowed_frontend_content": { "type": "array", "items": { "type": "string" } }, + "forbidden_frontend_content": { "type": "array", "items": { "type": "string" } }, + "frontend_display_policy": { "type": "string" } + }, + "additionalProperties": false + }, + "rollups": { + "type": "object", + "required": [ + "review_gate_count", + "learning_lane_count", + "approval_required_gate_ids", + "blocked_write_action_count", + "required_field_count", + "forbidden_field_count", + "live_write_count_total" + ], + "properties": { + "review_gate_count": { "type": "integer" }, + "learning_lane_count": { "type": "integer" }, + "approval_required_gate_ids": { "type": "array", "items": { "type": "string" } }, + "blocked_write_action_count": { "type": "integer" }, + "required_field_count": { "type": "integer" }, + "forbidden_field_count": { "type": "integer" }, + "live_write_count_total": { "const": 0 } + }, + "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 8bee2724d..14dc7ca70 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,7 +634,7 @@ 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 互動、接手、學習、成長、read model gate 與 Redis dry-run gate 證據面;目前 live session、message、handoff、learning write、Telegram receipt 全部 `0`,下一步 P2-403D | +| `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 互動、接手、學習、成長、read model gate、Redis dry-run gate 與 learning writeback approval package 證據面;目前 live session、message、handoff、learning write、Telegram receipt 全部 `0`,下一步 P2-403E | | `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 主動營運委派與版本生命週期契約 @@ -696,6 +696,9 @@ Repo / registry / release notes / K8s / host / observability / backup evidence | `docs/schemas/ai_agent_redis_dry_run_gate_v1.schema.json` | P2-403C Redis Streams consumer group dry-run gate schema;鎖定 Redis connection / consumer group / XADD / XREADGROUP / ACK / dead-letter / replay / Telegram / learning writeback 全部 false | | `docs/evaluations/ai_agent_redis_dry_run_gate_2026-06-11.json` | P2-403C committed snapshot:fixture-only consumer group dry-run、handoff envelope、ack / dead-letter / replay idempotency、frontend redaction;live counts 全部 `0` | | `GET /api/v1/agents/agent-redis-dry-run-gate` | 只讀 API;只回傳 Redis dry-run gate,不連 Redis、不建立 consumer group、不 XADD / XREADGROUP / ACK、不寫 dead-letter、不 replay、不發 Telegram | +| `docs/schemas/ai_agent_learning_writeback_approval_package_v1.schema.json` | P2-403D learning writeback approval package schema;鎖定 KM write / PlayBook trust update / timeline learning / replay score / Telegram / runtime worker 全部 false | +| `docs/evaluations/ai_agent_learning_writeback_approval_package_2026-06-11.json` | P2-403D committed snapshot:owner review、rollback、redaction、blocked write actions;live writes 全部 `0` | +| `GET /api/v1/agents/agent-learning-writeback-approval-package` | 只讀 API;只回傳 learning writeback approval package,不寫 KM、不更新 PlayBook trust、不寫 timeline / replay score、不發 Telegram | | `/zh-TW/governance?tab=automation-inventory` | P2-402G governance UI:顯示可委派能力、版本生命週期、Host / K3s / stateful 只讀關卡與 Telegram / redaction gate;不提供執行按鈕 | **採用順序:** @@ -709,7 +712,7 @@ Repo / registry / release notes / K8s / host / observability / backup evidence 7. 先建立可被統帥看見的互動 / 接手 / 學習 / 成長證據面。✅ P2-403A 已完成;live count 仍為 `0`,不宣稱 runtime 已運作。 8. 建立 AgentSession / Redis live read model gate。✅ P2-403B 已完成;safe fields、Redis envelope、worker gate、rollback plan、no-write smoke 已接入治理頁,但 live DB query / Redis consumer / worker 仍未授權。 9. 建立 Redis Streams consumer group dry-run、handoff envelope、ack / dead-letter / replay gate。✅ P2-403C 已完成;fixture-only dry-run、idempotency、redacted evidence 與治理頁已接入,但 Redis runtime consumer / ACK / replay 仍未授權。 -10. 最後才進人工批准後的 learning writeback / smoke / canary / production rollout。下一步 P2-403D learning writeback approval package。 +10. 建立 learning writeback approval package,先固定 owner review、rollback、redaction 與 blocked write actions。✅ P2-403D 已完成;KM / PlayBook trust / timeline learning / replay score live write 仍未授權。下一步 P2-403E Telegram receipt approval package。 #### 3.2.1d 2026-06-11 Agent 互動、學習與成長證據面 @@ -724,7 +727,7 @@ Repo / registry / release notes / K8s / host / observability / backup evidence | Live read model | Agent 心跳、最近狀態、資料時間 | P2-403B gate 已完成;live count 仍為 `0` | | 訊息收據 | 發話、收話、ack、dead letter、replay | P2-403C dry-run gate 已完成;live receipt count 仍為 `0` | | 接手紀錄 | OpenClaw / Hermes / NemoTron parent turn / handoff chain | P2-403C handoff envelope 已完成;runtime handoff count 仍為 `0` | -| 學習回寫 | KM、Playbook trust、learning failure、replay score | P2-403D 待辦 | +| 學習回寫 | KM、Playbook trust、learning failure、replay score | P2-403D approval package 已完成;live learning write count 仍為 `0` | | Telegram 收據 | action-required / approval / failure digest queued / delivered / acknowledged | P2-403E 待辦 | **本波已建立的可執行契約(只讀,不授權 runtime):** @@ -732,7 +735,7 @@ Repo / registry / release notes / K8s / host / observability / backup evidence | 檔案 / API | 用途 | |---|---| | `docs/schemas/ai_agent_interaction_learning_proof_v1.schema.json` | 互動、接手、學習、成長、Telegram receipt 與前端 redaction schema | -| `docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json` | P2-403A + P2-403B + P2-403C committed snapshot;完成度 `65%`,live truth counts 全部 `0` | +| `docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json` | P2-403A + P2-403B + P2-403C + P2-403D committed snapshot;完成度 `72%`,live truth counts 全部 `0` | | `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 仍需批准 | @@ -743,6 +746,10 @@ Repo / registry / release notes / K8s / host / observability / backup evidence | `docs/evaluations/ai_agent_redis_dry_run_gate_2026-06-11.json` | P2-403C committed snapshot;fixture-only dry-run、handoff envelope、ack / dead-letter / replay idempotency、frontend redaction | | `apps/api/src/services/ai_agent_redis_dry_run_gate.py` | 只讀 loader;拒絕 Redis network call、consumer group creation、runtime replay、Telegram send 與 writeback | | `GET /api/v1/agents/agent-redis-dry-run-gate` | 治理 API;只回傳 Redis dry-run gate,不連 Redis、不建立 consumer group、不 XADD / XREADGROUP / ACK、不 replay、不發 Telegram | +| `docs/schemas/ai_agent_learning_writeback_approval_package_v1.schema.json` | P2-403D learning writeback approval package schema;強制 KM / PlayBook trust / timeline learning / replay score / Telegram / runtime worker 全部維持未授權 | +| `docs/evaluations/ai_agent_learning_writeback_approval_package_2026-06-11.json` | P2-403D committed snapshot;owner review、rollback、redaction、blocked write actions 與 live write total `0` | +| `apps/api/src/services/ai_agent_learning_writeback_approval_package.py` | 只讀 loader;拒絕 KM write、PlayBook trust update、timeline learning、replay score write、Telegram send 與 runtime worker | +| `GET /api/v1/agents/agent-learning-writeback-approval-package` | 治理 API;只回傳 learning writeback approval package,不寫 KM、不更新 PlayBook trust、不寫 timeline / replay score、不發 Telegram | | `/zh-TW/governance?tab=automation-inventory` | 顯示證據階梯、目前真相、三 Agent lane、可觀測訊號、runtime gates 與 redaction policy | **硬性紅線:** @@ -1818,6 +1825,13 @@ Phase 6 完成後 - 更新 `ai_agent_interaction_learning_proof_2026-06-11.json`:整體完成度 `65%`,current task `P2-403C`,next task `P2-403D`;live AgentSession / Redis events / handoff / learning write / Telegram digest receipt 全部仍為 `0`。 - 本波仍不連 Redis、不建立 consumer group、不 XADD / XREADGROUP / XACK、不寫 dead-letter、不 runtime replay、不發 Telegram、不做 learning writeback、不讀取或輸出 secret;下一步 P2-403D 才做 learning writeback approval package。 +### 2026-06-11 23:59 (台北) — §3.2 / §5 — 完成 P2-403D Learning Writeback Approval Package — 先把學習回寫拆成人工批准包,不再用 no-action 包裝自動化 + +- 新增 `ai_agent_learning_writeback_approval_package_v1` schema / committed snapshot / loader / API / 測試,定義 KM、PlayBook trust、timeline learning、replay score 的 proposed delta、owner review、rollback、redaction 與 blocked write actions。 +- `apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx` 接入 `GET /api/v1/agents/agent-learning-writeback-approval-package`,顯示 learning writeback KPI、批准包欄位、禁止欄位、review gates、learning lanes、truth flags 與 live write count。 +- 更新 `ai_agent_interaction_learning_proof_2026-06-11.json`:整體完成度 `72%`,current task `P2-403D`,next task `P2-403E`;live AgentSession / Redis events / handoff / learning write / Telegram digest receipt 全部仍為 `0`。 +- 本波仍不寫 KM、不更新 PlayBook trust、不寫 timeline learning、不寫 replay score、不發 Telegram、不啟動 runtime worker、不讀取或輸出 secret;下一步 P2-403E 才做 Telegram receipt approval package。 + ### 2026-04-15 (台北) — 全檔 — 建立 v2 骨架,§0/§1 完成 — 統帥批准「單 MASTER + 4 道閘門」結構 - 從 v1(plans/2026-04-15-MASTER-ai-autonomous-flywheel.md)繼承核心發現