From 6982a674b475303f200586eef6d5f700d1f51003 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 11 Jun 2026 18:45:53 +0800 Subject: [PATCH] =?UTF-8?q?feat(governance):=20=E9=A1=AF=E7=A4=BA=20Agent?= =?UTF-8?q?=20=E4=BA=92=E5=8B=95=E5=AD=B8=E7=BF=92=E8=AD=89=E6=93=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/api/src/api/v1/agents.py | 30 ++ .../ai_agent_interaction_learning_proof.py | 197 +++++++++ ...est_ai_agent_interaction_learning_proof.py | 228 ++++++++++ ...ai_agent_interaction_learning_proof_api.py | 36 ++ ..._ai_agent_proactive_operations_contract.py | 4 +- ...agent_proactive_operations_contract_api.py | 4 +- apps/web/messages/en.json | 53 +++ apps/web/messages/zh-TW.json | 53 +++ .../tabs/automation-inventory-tab.tsx | 243 ++++++++++- apps/web/src/lib/api-client.ts | 112 +++++ docs/LOGBOOK.md | 39 ++ ...AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md | 9 +- ...T_INTERACTION_LEARNING_PROOF_2026-06-11.md | 71 ++++ ...I_AGENT_PROACTIVE_OPERATIONS_2026-06-11.md | 13 +- ...interaction_learning_proof_2026-06-11.json | 393 ++++++++++++++++++ ...active_operations_contract_2026-06-11.json | 21 +- ..._interaction_learning_proof_v1.schema.json | 377 +++++++++++++++++ ...-04-15-MASTER-ai-autonomous-flywheel-v2.md | 45 +- 18 files changed, 1909 insertions(+), 19 deletions(-) create mode 100644 apps/api/src/services/ai_agent_interaction_learning_proof.py create mode 100644 apps/api/tests/test_ai_agent_interaction_learning_proof.py create mode 100644 apps/api/tests/test_ai_agent_interaction_learning_proof_api.py create mode 100644 docs/ai/AI_AGENT_INTERACTION_LEARNING_PROOF_2026-06-11.md create mode 100644 docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json create mode 100644 docs/schemas/ai_agent_interaction_learning_proof_v1.schema.json diff --git a/apps/api/src/api/v1/agents.py b/apps/api/src/api/v1/agents.py index 6b292d346..2f55da0d8 100644 --- a/apps/api/src/api/v1/agents.py +++ b/apps/api/src/api/v1/agents.py @@ -61,6 +61,9 @@ from src.services.ai_agent_gitea_pr_draft_lane import ( from src.services.ai_agent_host_stateful_version_inventory import ( load_latest_ai_agent_host_stateful_version_inventory, ) +from src.services.ai_agent_interaction_learning_proof import ( + load_latest_ai_agent_interaction_learning_proof, +) from src.services.ai_agent_proactive_operations_contract import ( load_latest_ai_agent_proactive_operations_contract, ) @@ -572,6 +575,33 @@ async def get_agent_communication_learning_contract() -> dict[str, Any]: ) from exc +@router.get( + "/agent-interaction-learning-proof", + response_model=dict[str, Any], + summary="取得 AI Agent 互動與學習證據面", + description=( + "讀取最新已提交的 OpenClaw / Hermes / NemoTron 互動、接手、學習、成長與 Telegram 收據證據面;" + "此端點不啟動 worker、不讀寫 Redis consumer group、不建立 DB migration、不送 Telegram、" + "不顯示工作視窗對話、prompt、private reasoning 或 secret。" + ), +) +async def get_agent_interaction_learning_proof() -> dict[str, Any]: + """Return the latest read-only AI Agent interaction and learning proof surface.""" + try: + return await asyncio.to_thread(load_latest_ai_agent_interaction_learning_proof) + 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_interaction_learning_proof_invalid", error=str(exc)) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="AI Agent 互動與學習證據面無效", + ) from exc + + @router.get( "/agent-proactive-operations-contract", response_model=dict[str, Any], diff --git a/apps/api/src/services/ai_agent_interaction_learning_proof.py b/apps/api/src/services/ai_agent_interaction_learning_proof.py new file mode 100644 index 000000000..554286b83 --- /dev/null +++ b/apps/api/src/services/ai_agent_interaction_learning_proof.py @@ -0,0 +1,197 @@ +""" +AI Agent interaction and learning proof snapshot. + +Loads the latest committed, read-only proof surface for how operators can see +OpenClaw, Hermes, and NemoTron communicating, handing off work, learning, and +growing. This module is intentionally truth-gated: it never starts workers, +opens Redis consumer groups, writes database migrations, sends Telegram +messages, exposes transcripts, or marks live runtime as active. +""" + +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_interaction_learning_proof_*.json" +_SCHEMA_VERSION = "ai_agent_interaction_learning_proof_v1" + + +def load_latest_ai_agent_interaction_learning_proof( + evaluations_dir: Path | None = None, +) -> dict[str, Any]: + """Load the newest committed AI Agent interaction learning proof snapshot.""" + directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR + candidates = sorted(directory.glob(_SNAPSHOT_PATTERN)) + if not candidates: + raise FileNotFoundError( + f"no AI Agent interaction learning proof 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, _SCHEMA_VERSION, str(latest)) + _require_read_only_truth(payload, str(latest)) + _require_rollup_consistency(payload, str(latest)) + _require_agent_lanes(payload, str(latest)) + _require_frontend_redaction(payload, str(latest)) + return payload + + +def _require_schema(payload: dict[str, Any], expected: str, label: str) -> None: + actual = payload.get("schema_version") + if actual != expected: + raise ValueError(f"{label}: expected schema_version={expected}, got {actual!r}") + + +def _require_read_only_truth(payload: dict[str, Any], label: str) -> None: + program_status = payload.get("program_status") or {} + if program_status.get("read_only_mode") is not True: + raise ValueError(f"{label}: program_status.read_only_mode must be true") + if program_status.get("runtime_authority") != "proof_surface_only_no_live_worker": + raise ValueError( + f"{label}: runtime_authority must stay proof_surface_only_no_live_worker" + ) + + live_truth = payload.get("live_truth") or {} + live_flags = { + "runtime_loop_enabled", + "live_agent_session_readback_enabled", + "redis_consumer_group_enabled", + "telegram_send_enabled", + "learning_writeback_enabled", + } + enabled = sorted(flag for flag in live_flags if live_truth.get(flag) is not False) + if enabled: + raise ValueError(f"{label}: live truth flags must remain false: {enabled}") + + live_counts = { + "active_live_agent_sessions", + "live_agent_messages_24h", + "live_handoffs_24h", + "live_learning_writes_24h", + "telegram_digest_receipts_24h", + } + non_zero = sorted(key for key in live_counts if live_truth.get(key) != 0) + if non_zero: + raise ValueError(f"{label}: live truth counts must remain zero: {non_zero}") + + boundaries = payload.get("approval_boundaries") or {} + blocked_flags = { + "runtime_worker_allowed", + "db_migration_allowed", + "redis_consumer_group_allowed", + "telegram_direct_send_allowed", + "conversation_transcript_display_allowed", + "agent_private_reasoning_display_allowed", + "secret_plaintext_allowed", + "autonomous_self_modify_allowed", + } + allowed = sorted(flag for flag in blocked_flags if boundaries.get(flag) is not False) + if allowed: + raise ValueError(f"{label}: approval boundaries must remain false: {allowed}") + + +def _require_rollup_consistency(payload: dict[str, Any], label: str) -> None: + rollups = payload.get("rollups") or {} + proof_ladder = payload.get("proof_ladder") or [] + proof_signals = payload.get("proof_signals") or [] + operator_surfaces = payload.get("operator_surfaces") or [] + runtime_gates = payload.get("runtime_gates") or [] + + expected_counts = { + "proof_level_count": len(proof_ladder), + "signal_count": len(proof_signals), + "operator_surface_count": len(operator_surfaces), + "runtime_gate_count": len(runtime_gates), + } + 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}") + + contract_ready_ids = sorted( + level.get("level_id") + for level in proof_ladder + if level.get("status") in {"contract_ready", "proof_surface_ready"} + ) + if rollups.get("contract_ready_level_count") != len(contract_ready_ids): + raise ValueError(f"{label}: rollups.contract_ready_level_count mismatch") + + live_pending_ids = sorted( + level.get("level_id") + for level in proof_ladder + if level.get("status") in {"live_pending", "blocked_by_gate"} + ) + if sorted(rollups.get("live_pending_level_ids") or []) != live_pending_ids: + raise ValueError(f"{label}: rollups.live_pending_level_ids mismatch") + + live_signal_count = sum( + 1 for signal in proof_signals if signal.get("current_state") == "live_verified" + ) + if rollups.get("live_signal_count") != live_signal_count: + raise ValueError(f"{label}: rollups.live_signal_count mismatch") + + blocked_gate_ids = sorted( + gate.get("gate_id") + for gate in runtime_gates + if gate.get("status") in {"blocked", "approval_required"} + ) + if sorted(rollups.get("blocked_gate_ids") or []) != blocked_gate_ids: + raise ValueError(f"{label}: rollups.blocked_gate_ids mismatch") + + live_truth = payload.get("live_truth") or {} + for key in ( + "active_live_agent_sessions", + "live_agent_messages_24h", + "live_handoffs_24h", + "live_learning_writes_24h", + "telegram_digest_receipts_24h", + ): + if rollups.get(key) != live_truth.get(key): + raise ValueError(f"{label}: rollups.{key} must mirror live_truth.{key}") + + +def _require_agent_lanes(payload: dict[str, Any], label: str) -> None: + lanes = payload.get("agent_lanes") or [] + lane_ids = {lane.get("agent_id") for lane in lanes} + required_lanes = {"openclaw", "hermes", "nemotron"} + if not required_lanes.issubset(lane_ids): + raise ValueError(f"{label}: missing required agent lanes: {sorted(required_lanes - lane_ids)}") + + missing_visible_signal = [ + lane.get("agent_id") + for lane in lanes + if not lane.get("visible_signals") + ] + if missing_visible_signal: + raise ValueError(f"{label}: every agent lane needs visible_signals: {missing_visible_signal}") + + unsafe_lanes = [ + lane.get("agent_id") + for lane in lanes + if "conversation_transcript" in set(lane.get("visible_signals") or []) + ] + if unsafe_lanes: + raise ValueError(f"{label}: visible signals must not expose transcripts: {unsafe_lanes}") + + +def _require_frontend_redaction(payload: dict[str, Any], label: str) -> None: + redaction = payload.get("frontend_redaction") or {} + if redaction.get("operator_conversation_display_allowed") is not False: + raise ValueError(f"{label}: operator conversation display must stay false") + if redaction.get("agent_private_reasoning_display_allowed") is not False: + raise ValueError(f"{label}: agent private reasoning display must stay false") + if redaction.get("raw_prompt_display_allowed") is not False: + raise ValueError(f"{label}: raw prompt display must stay false") diff --git a/apps/api/tests/test_ai_agent_interaction_learning_proof.py b/apps/api/tests/test_ai_agent_interaction_learning_proof.py new file mode 100644 index 000000000..510ba7a23 --- /dev/null +++ b/apps/api/tests/test_ai_agent_interaction_learning_proof.py @@ -0,0 +1,228 @@ +from __future__ import annotations + +import json + +import pytest + +from src.services.ai_agent_interaction_learning_proof import ( + load_latest_ai_agent_interaction_learning_proof, +) + + +def test_load_latest_ai_agent_interaction_learning_proof_reads_committed_snapshot(): + 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"] == 45 + assert data["program_status"]["current_task_id"] == "P2-403A" + assert data["program_status"]["next_task_id"] == "P2-403B" + 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 + assert data["live_truth"]["active_live_agent_sessions"] == 0 + assert data["live_truth"]["live_learning_writes_24h"] == 0 + assert data["frontend_redaction"]["operator_conversation_display_allowed"] is False + assert data["frontend_redaction"]["agent_private_reasoning_display_allowed"] is False + assert data["frontend_redaction"]["raw_prompt_display_allowed"] is False + assert data["approval_boundaries"]["runtime_worker_allowed"] is False + assert data["approval_boundaries"]["telegram_direct_send_allowed"] is False + assert data["rollups"]["proof_level_count"] == len(data["proof_ladder"]) == 7 + assert data["rollups"]["signal_count"] == len(data["proof_signals"]) == 9 + assert data["rollups"]["operator_surface_count"] == len(data["operator_surfaces"]) == 5 + 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"]) == { + "live_read_model", + "message_bus_receipts", + "handoff_receipts", + "learning_growth", + "telegram_receipts", + } + assert {lane["agent_id"] for lane in data["agent_lanes"]} == { + "openclaw", + "hermes", + "nemotron", + } + + +def test_load_latest_ai_agent_interaction_learning_proof_rejects_runtime_worker(tmp_path): + snapshot = _snapshot() + snapshot["approval_boundaries"]["runtime_worker_allowed"] = True + (tmp_path / "ai_agent_interaction_learning_proof_2026-06-11.json").write_text( + json.dumps(snapshot), + encoding="utf-8", + ) + + with pytest.raises(ValueError, match="approval boundaries"): + load_latest_ai_agent_interaction_learning_proof(tmp_path) + + +def test_load_latest_ai_agent_interaction_learning_proof_rejects_live_truth(tmp_path): + snapshot = _snapshot() + snapshot["live_truth"]["runtime_loop_enabled"] = True + (tmp_path / "ai_agent_interaction_learning_proof_2026-06-11.json").write_text( + json.dumps(snapshot), + encoding="utf-8", + ) + + with pytest.raises(ValueError, match="live truth flags"): + load_latest_ai_agent_interaction_learning_proof(tmp_path) + + +def test_load_latest_ai_agent_interaction_learning_proof_rejects_rollup_mismatch(tmp_path): + snapshot = _snapshot() + snapshot["rollups"]["signal_count"] = 99 + (tmp_path / "ai_agent_interaction_learning_proof_2026-06-11.json").write_text( + json.dumps(snapshot), + encoding="utf-8", + ) + + with pytest.raises(ValueError, match="rollup counts"): + load_latest_ai_agent_interaction_learning_proof(tmp_path) + + +def test_load_latest_ai_agent_interaction_learning_proof_rejects_transcript_display(tmp_path): + snapshot = _snapshot() + snapshot["frontend_redaction"]["operator_conversation_display_allowed"] = True + (tmp_path / "ai_agent_interaction_learning_proof_2026-06-11.json").write_text( + json.dumps(snapshot), + encoding="utf-8", + ) + + with pytest.raises(ValueError, match="operator conversation display"): + load_latest_ai_agent_interaction_learning_proof(tmp_path) + + +def _snapshot() -> dict: + return { + "schema_version": "ai_agent_interaction_learning_proof_v1", + "generated_at": "2026-06-11T23:20:00+08:00", + "program_status": { + "overall_completion_percent": 45, + "current_priority": "P2", + "current_task_id": "P2-403A", + "next_task_id": "P2-403B", + "read_only_mode": True, + "runtime_authority": "proof_surface_only_no_live_worker", + }, + "live_truth": { + "runtime_loop_enabled": False, + "live_agent_session_readback_enabled": False, + "redis_consumer_group_enabled": False, + "telegram_send_enabled": False, + "learning_writeback_enabled": False, + "active_live_agent_sessions": 0, + "live_agent_messages_24h": 0, + "live_handoffs_24h": 0, + "live_learning_writes_24h": 0, + "telegram_digest_receipts_24h": 0, + }, + "proof_ladder": [ + _proof_level("contract_surface", "contract_ready"), + _proof_level("proof_dashboard", "proof_surface_ready"), + _proof_level("live_read_model", "live_pending"), + ], + "agent_lanes": [ + _agent_lane("openclaw"), + _agent_lane("hermes"), + _agent_lane("nemotron"), + ], + "proof_signals": [ + { + "signal_id": "agent_heartbeat", + "display_name": "Agent 心跳", + "category": "heartbeat", + "source_of_truth": "agent_sessions.last_seen_at", + "visible_surface": "governance", + "current_state": "live_pending", + "operator_interpretation": "測試。", + "next_gate": "P2-403B", + } + ], + "operator_surfaces": [ + { + "surface_id": "governance_agent_proof_panel", + "display_name": "治理頁 Agent 證據面板", + "route_or_channel": "/zh-TW/governance?tab=automation-inventory", + "operator_feel": "測試。", + "redaction_policy": "只顯示摘要。", + "current_state": "implemented_read_only", + } + ], + "runtime_gates": [ + { + "gate_id": "agent_session_read_model_gate", + "display_name": "AgentSession 唯讀 read model", + "status": "approval_required", + "required_before_green": "測試。", + "next_task_id": "P2-403B", + } + ], + "learning_memory_stack": [ + { + "layer_id": "hot_agent_session_memory", + "display_name": "Hot", + "storage_or_service": "agent_sessions", + "visible_growth_signal": "心跳", + "current_state": "pending", + } + ], + "telegram_receipt_contract": { + "direct_send_allowed": False, + "gateway_queue_write_allowed": False, + "receipt_visible_to_operator": True, + }, + "frontend_redaction": { + "operator_conversation_display_allowed": False, + "agent_private_reasoning_display_allowed": False, + "raw_prompt_display_allowed": False, + }, + "approval_boundaries": { + "runtime_worker_allowed": False, + "db_migration_allowed": False, + "redis_consumer_group_allowed": False, + "telegram_direct_send_allowed": False, + "conversation_transcript_display_allowed": False, + "agent_private_reasoning_display_allowed": False, + "secret_plaintext_allowed": False, + "autonomous_self_modify_allowed": False, + }, + "rollups": { + "proof_level_count": 3, + "contract_ready_level_count": 2, + "live_pending_level_ids": ["live_read_model"], + "signal_count": 1, + "live_signal_count": 0, + "operator_surface_count": 1, + "runtime_gate_count": 1, + "blocked_gate_ids": ["agent_session_read_model_gate"], + "active_live_agent_sessions": 0, + "live_agent_messages_24h": 0, + "live_handoffs_24h": 0, + "live_learning_writes_24h": 0, + "telegram_digest_receipts_24h": 0, + }, + } + + +def _proof_level(level_id: str, status: str) -> dict: + return { + "level_id": level_id, + "display_name": level_id, + "status": status, + "completion_percent": 100 if status != "live_pending" else 0, + "operator_meaning": "測試。", + "source_of_truth": "test", + "next_gate": "test", + } + + +def _agent_lane(agent_id: str) -> dict: + return { + "agent_id": agent_id, + "display_name": agent_id, + "primary_role": "測試。", + "current_visible_state": "contract_visible_live_runtime_pending", + "visible_signals": ["agent_heartbeat"], + "growth_metric": "測試。", + } 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 new file mode 100644 index 000000000..c19af159a --- /dev/null +++ b/apps/api/tests/test_ai_agent_interaction_learning_proof_api.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +from fastapi import FastAPI +from fastapi.testclient import TestClient + +from src.api.v1.agents import router + + +def test_ai_agent_interaction_learning_proof_endpoint_returns_committed_snapshot(): + app = FastAPI() + app.include_router(router, prefix="/api/v1") + client = TestClient(app) + + response = client.get("/api/v1/agents/agent-interaction-learning-proof") + + 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"] == 45 + assert data["program_status"]["current_task_id"] == "P2-403A" + assert data["program_status"]["next_task_id"] == "P2-403B" + 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 + assert data["live_truth"]["live_learning_writes_24h"] == 0 + assert data["frontend_redaction"]["operator_conversation_display_allowed"] is False + assert data["approval_boundaries"]["conversation_transcript_display_allowed"] is False + assert data["approval_boundaries"]["telegram_direct_send_allowed"] is False + assert data["rollups"]["proof_level_count"] == 7 + assert data["rollups"]["contract_ready_level_count"] == 2 + assert data["rollups"]["signal_count"] == 9 + assert data["rollups"]["live_signal_count"] == 0 + assert data["rollups"]["operator_surface_count"] == 5 + assert any(lane["agent_id"] == "openclaw" for lane in data["agent_lanes"]) + assert any(lane["agent_id"] == "hermes" for lane in data["agent_lanes"]) + assert any(lane["agent_id"] == "nemotron" for lane in data["agent_lanes"]) 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 c414cec9c..4060731cc 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-402G" - assert data["program_status"]["next_task_id"] == "P2-403A" + assert data["program_status"]["current_task_id"] == "P2-403A" + assert data["program_status"]["next_task_id"] == "P2-403B" 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 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 0a9701215..a3205149c 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-402G" - assert data["program_status"]["next_task_id"] == "P2-403A" + assert data["program_status"]["current_task_id"] == "P2-403A" + assert data["program_status"]["next_task_id"] == "P2-403B" 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 diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index e5b933e08..af7a70fd6 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -3031,6 +3031,59 @@ "no_direct_notify": "不直送" } }, + "interactionProof": { + "title": "Agent 互動與學習證據", + "source": "{generated} · {current} → {next}", + "truthTitle": "目前真相", + "ladderTitle": "證據階梯", + "signalsTitle": "可觀測訊號", + "agentLanesTitle": "三 Agent 可感知分工", + "gatesTitle": "還不能亮綠燈的 gate", + "redactionTitle": "前端顯示紅線", + "ladderSummary": "Live 待接 {pending}/{total}", + "signalsSummary": "訊號 {signals} · 表面 {surfaces}", + "truthFlags": { + "runtime": "runtime 迴圈: {value}", + "readback": "讀回: {value}", + "telegram": "Telegram 發送: {value}" + }, + "metrics": { + "overall": "P2-403 進度", + "contractReady": "合約/面板", + "liveSessions": "Live 會話", + "learningWrites": "學習回寫", + "telegramReceipts": "Telegram 收據", + "blockedGates": "阻擋 gate" + }, + "labels": { + "signals": "訊號", + "transcriptBlocked": "不顯示工作視窗對話", + "privateReasoningBlocked": "不顯示私有推理", + "secretBlocked": "不顯示機密值" + }, + "agents": { + "openclaw": "OpenClaw", + "hermes": "Hermes", + "nemotron": "NemoTron" + }, + "statuses": { + "contract_ready": "合約已定義", + "proof_surface_ready": "證據面已上線", + "live_pending": "待 live 接線", + "blocked_by_gate": "被 gate 阻擋", + "approval_required": "需批准", + "blocked": "阻擋", + "planned": "規劃中", + "ready": "就緒" + }, + "states": { + "contract_visible_live_runtime_pending": "合約可見,runtime 待接", + "contract_defined": "合約已定義", + "live_pending": "待 live 證據", + "live_verified": "Live 已驗證", + "blocked_by_gate": "被 gate 阻擋" + } + }, "proactiveOperations": { "title": "可委派能力與版本治理", "source": "{generated} · {current} → {next}", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index e5b933e08..af7a70fd6 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -3031,6 +3031,59 @@ "no_direct_notify": "不直送" } }, + "interactionProof": { + "title": "Agent 互動與學習證據", + "source": "{generated} · {current} → {next}", + "truthTitle": "目前真相", + "ladderTitle": "證據階梯", + "signalsTitle": "可觀測訊號", + "agentLanesTitle": "三 Agent 可感知分工", + "gatesTitle": "還不能亮綠燈的 gate", + "redactionTitle": "前端顯示紅線", + "ladderSummary": "Live 待接 {pending}/{total}", + "signalsSummary": "訊號 {signals} · 表面 {surfaces}", + "truthFlags": { + "runtime": "runtime 迴圈: {value}", + "readback": "讀回: {value}", + "telegram": "Telegram 發送: {value}" + }, + "metrics": { + "overall": "P2-403 進度", + "contractReady": "合約/面板", + "liveSessions": "Live 會話", + "learningWrites": "學習回寫", + "telegramReceipts": "Telegram 收據", + "blockedGates": "阻擋 gate" + }, + "labels": { + "signals": "訊號", + "transcriptBlocked": "不顯示工作視窗對話", + "privateReasoningBlocked": "不顯示私有推理", + "secretBlocked": "不顯示機密值" + }, + "agents": { + "openclaw": "OpenClaw", + "hermes": "Hermes", + "nemotron": "NemoTron" + }, + "statuses": { + "contract_ready": "合約已定義", + "proof_surface_ready": "證據面已上線", + "live_pending": "待 live 接線", + "blocked_by_gate": "被 gate 阻擋", + "approval_required": "需批准", + "blocked": "阻擋", + "planned": "規劃中", + "ready": "就緒" + }, + "states": { + "contract_visible_live_runtime_pending": "合約可見,runtime 待接", + "contract_defined": "合約已定義", + "live_pending": "待 live 證據", + "live_verified": "Live 已驗證", + "blocked_by_gate": "被 gate 阻擋" + } + }, "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 938c78fd7..7e08c9bc1 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 @@ -37,6 +37,7 @@ import { apiClient, type AiAgentDeploymentLayoutSnapshot, type AiAgentHostStatefulVersionInventorySnapshot, + type AiAgentInteractionLearningProofSnapshot, type AiAgentProactiveOperationsContractSnapshot, type AiProviderRouteMatrixSnapshot, type AiAgentAutomationBacklogSnapshot, @@ -316,6 +317,7 @@ export function AutomationInventoryTab() { const [providerRouteMatrix, setProviderRouteMatrix] = useState(null) const [deploymentLayout, setDeploymentLayout] = useState(null) const [proactiveOperations, setProactiveOperations] = useState(null) + const [interactionLearningProof, setInteractionLearningProof] = useState(null) const [hostStatefulInventory, setHostStatefulInventory] = useState(null) const [serviceHealthGapMatrix, setServiceHealthGapMatrix] = useState(null) const [serviceHealthNotificationPolicy, setServiceHealthNotificationPolicy] = useState(null) @@ -337,6 +339,7 @@ export function AutomationInventoryTab() { apiClient.getAiProviderRouteMatrix(), apiClient.getAiAgentDeploymentLayout(), apiClient.getAiAgentProactiveOperationsContract(), + apiClient.getAiAgentInteractionLearningProof(), apiClient.getAiAgentHostStatefulVersionInventory(), apiClient.getServiceHealthGapMatrix(), apiClient.getServiceHealthFailureNotificationPolicy(), @@ -357,6 +360,7 @@ export function AutomationInventoryTab() { providerRouteMatrixResult, deploymentLayoutResult, proactiveOperationsResult, + interactionLearningProofResult, hostStatefulInventoryResult, serviceHealthGapMatrixResult, serviceHealthNotificationPolicyResult, @@ -374,6 +378,7 @@ export function AutomationInventoryTab() { setProviderRouteMatrix(providerRouteMatrixResult.status === 'fulfilled' ? providerRouteMatrixResult.value : null) setDeploymentLayout(deploymentLayoutResult.status === 'fulfilled' ? deploymentLayoutResult.value : null) setProactiveOperations(proactiveOperationsResult.status === 'fulfilled' ? proactiveOperationsResult.value : null) + setInteractionLearningProof(interactionLearningProofResult.status === 'fulfilled' ? interactionLearningProofResult.value : null) setHostStatefulInventory(hostStatefulInventoryResult.status === 'fulfilled' ? hostStatefulInventoryResult.value : null) setServiceHealthGapMatrix(serviceHealthGapMatrixResult.status === 'fulfilled' ? serviceHealthGapMatrixResult.value : null) setServiceHealthNotificationPolicy(serviceHealthNotificationPolicyResult.status === 'fulfilled' ? serviceHealthNotificationPolicyResult.value : null) @@ -389,6 +394,7 @@ export function AutomationInventoryTab() { providerRouteMatrixResult, deploymentLayoutResult, proactiveOperationsResult, + interactionLearningProofResult, hostStatefulInventoryResult, serviceHealthGapMatrixResult, serviceHealthNotificationPolicyResult, @@ -506,6 +512,54 @@ export function AutomationInventoryTab() { .slice(0, 8) }, [hostStatefulInventory]) + const visibleProofLevels = useMemo(() => { + if (!interactionLearningProof) return [] + const priority = { + blocked_by_gate: 0, + live_pending: 1, + proof_surface_ready: 2, + contract_ready: 3, + } as Record + return [...interactionLearningProof.proof_ladder] + .sort((a, b) => { + const left = priority[a.status] ?? 4 + const right = priority[b.status] ?? 4 + if (left !== right) return left - right + return a.level_id.localeCompare(b.level_id) + }) + }, [interactionLearningProof]) + + const visibleProofSignals = useMemo(() => { + if (!interactionLearningProof) return [] + const priority = { + live_verified: 0, + live_pending: 1, + contract_defined: 2, + blocked_by_gate: 3, + } as Record + return [...interactionLearningProof.proof_signals] + .sort((a, b) => { + const left = priority[a.current_state] ?? 4 + const right = priority[b.current_state] ?? 4 + if (left !== right) return left - right + return a.signal_id.localeCompare(b.signal_id) + }) + .slice(0, 6) + }, [interactionLearningProof]) + + const visibleRuntimeGates = useMemo(() => { + if (!interactionLearningProof) return [] + const priority = { blocked: 0, approval_required: 1, planned: 2, ready: 3 } as Record + return [...interactionLearningProof.runtime_gates] + .sort((a, b) => { + const left = priority[a.status] ?? 4 + const right = priority[b.status] ?? 4 + if (left !== right) return left - right + return a.gate_id.localeCompare(b.gate_id) + }) + .slice(0, 5) + }, [interactionLearningProof]) + const visibleReadinessRows = useMemo(() => { if (!backupReadiness) return [] const priority = { blocked: 0, action_required: 1, deferred: 2, ready: 3 } as Record @@ -649,7 +703,7 @@ export function AutomationInventoryTab() { ) } - if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !proactiveOperations || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) { + if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !proactiveOperations || !interactionLearningProof || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) { return (
@@ -728,6 +782,15 @@ export function AutomationInventoryTab() { const proactiveBlockedVersionDomains = proactiveOperations.rollups.blocked_update_domain_ids.length const proactiveTelegramActionRequired = proactiveOperations.rollups.telegram_action_required_capability_ids.length const proactiveAutoExecuteAllowed = proactiveOperations.rollups.auto_execute_allowed_count + const proofOverall = interactionLearningProof.program_status.overall_completion_percent + const proofContractReadyLevels = interactionLearningProof.rollups.contract_ready_level_count + const proofLivePendingLevels = interactionLearningProof.rollups.live_pending_level_ids.length + const proofLiveSessions = interactionLearningProof.rollups.active_live_agent_sessions + const proofLearningWrites = interactionLearningProof.rollups.live_learning_writes_24h + const proofTelegramReceipts = interactionLearningProof.rollups.telegram_digest_receipts_24h + const proofVisibleSurfaces = interactionLearningProof.rollups.operator_surface_count + const proofSignalCount = interactionLearningProof.rollups.signal_count + const proofBlockedGates = interactionLearningProof.rollups.blocked_gate_ids.length const hostReadonlyDeniedCount = ( hostStatefulInventory.rollups.ssh_login_allowed_count + hostStatefulInventory.rollups.kubectl_command_execution_allowed_count @@ -913,6 +976,14 @@ export function AutomationInventoryTab() { } } + const proofValueLabel = (group: string, value: string) => { + try { + return t(`interactionProof.${group}.${value}` as never) + } catch { + return value + } + } + const hostStatefulValueLabel = (group: string, value: string) => { try { return t(`hostStateful.${group}.${value}` as never) @@ -1210,6 +1281,171 @@ export function AutomationInventoryTab() {
+ +
+
+
+ + + {t('interactionProof.title')} + +
+ +
+ +
+ } /> + } /> + 0 ? 'ok' : 'warn'} icon={} /> + 0 ? 'ok' : 'warn'} icon={} /> + 0 ? 'ok' : 'warn'} icon={} /> + 0 ? 'danger' : 'ok'} icon={} /> +
+ +
+
+ {t('interactionProof.truthTitle')} + + {interactionLearningProof.live_truth.truth_note} + +
+
+ + + +
+
+ +
+
+
+
+ + {t('interactionProof.ladderTitle')} + + +
+
+ {visibleProofLevels.map(level => ( +
+
+ + {level.display_name} + + +
+ + + {level.operator_meaning} + +
+ ))} +
+
+ +
+
+ + {t('interactionProof.signalsTitle')} + + +
+
+ {visibleProofSignals.map(signal => ( +
+
+ + {signal.signal_id} + + +
+ + {signal.display_name} + + + {signal.operator_interpretation} + +
+ + +
+
+ ))} +
+
+
+ +
+
+ {t('interactionProof.agentLanesTitle')} + {interactionLearningProof.agent_lanes.map(lane => ( +
+
+ + {lane.display_name} + + +
+ + {lane.what_operator_will_feel} + +
+ + +
+
+ ))} +
+ +
+ {t('interactionProof.gatesTitle')} + {visibleRuntimeGates.map(gate => ( +
+
+ + {gate.gate_id} + + +
+ + {gate.required_before_green} + +
+ ))} +
+ +
+ {t('interactionProof.redactionTitle')} + + {interactionLearningProof.frontend_redaction.display_policy} + +
+ + + +
+
+
+
+
+
+
@@ -2825,6 +3061,11 @@ export function AutomationInventoryTab() { .automation-inventory-deployment-layout-kpi-grid, .automation-inventory-deployment-layout-grid, .automation-inventory-deployment-layout-target-grid, + .automation-inventory-proof-kpi-grid, + .automation-inventory-proof-truth-grid, + .automation-inventory-proof-grid, + .automation-inventory-proof-ladder-grid, + .automation-inventory-proof-signal-grid, .automation-inventory-service-health-kpi-grid, .automation-inventory-service-health-map-grid, .automation-inventory-service-health-evidence-grid, diff --git a/apps/web/src/lib/api-client.ts b/apps/web/src/lib/api-client.ts index a64f2788d..32c826239 100644 --- a/apps/web/src/lib/api-client.ts +++ b/apps/web/src/lib/api-client.ts @@ -272,6 +272,11 @@ export const apiClient = { return handleResponse(res) }, + async getAiAgentInteractionLearningProof() { + const res = await fetch(`${API_BASE_URL}/agents/agent-interaction-learning-proof`) + return handleResponse(res) + }, + async getAiAgentHostStatefulVersionInventory() { const res = await fetch(`${API_BASE_URL}/agents/agent-host-stateful-version-inventory`) return handleResponse(res) @@ -1031,6 +1036,113 @@ export interface AiAgentProactiveOperationsContractSnapshot { } } +export interface AiAgentInteractionLearningProofSnapshot { + schema_version: 'ai_agent_interaction_learning_proof_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: 'proof_surface_only_no_live_worker' + status_note: string + } + live_truth: { + runtime_loop_enabled: false + live_agent_session_readback_enabled: false + redis_consumer_group_enabled: false + telegram_send_enabled: false + learning_writeback_enabled: false + active_live_agent_sessions: number + live_agent_messages_24h: number + live_handoffs_24h: number + live_learning_writes_24h: number + telegram_digest_receipts_24h: number + truth_note: string + } + proof_ladder: Array<{ + level_id: string + display_name: string + status: string + completion_percent: number + operator_meaning: string + source_of_truth: string + next_gate: string + }> + agent_lanes: Array<{ + agent_id: 'openclaw' | 'hermes' | 'nemotron' + display_name: string + primary_role: string + current_visible_state: string + visible_signals: string[] + growth_metric: string + what_operator_will_feel: string + }> + proof_signals: Array<{ + signal_id: string + display_name: string + category: string + source_of_truth: string + visible_surface: string + current_state: string + operator_interpretation: string + next_gate: string + }> + operator_surfaces: Array<{ + surface_id: string + display_name: string + route_or_channel: string + operator_feel: string + redaction_policy: string + current_state: string + }> + runtime_gates: Array<{ + gate_id: string + display_name: string + status: string + required_before_green: string + next_task_id: string + }> + learning_memory_stack: Array<{ + layer_id: string + display_name: string + storage_or_service: string + visible_growth_signal: string + current_state: string + }> + telegram_receipt_contract: { + direct_send_allowed: false + gateway_queue_write_allowed: false + receipt_visible_to_operator: true + allowed_future_notification_classes: string[] + success_policy: string + redaction_policy: string + } + frontend_redaction: { + operator_conversation_display_allowed: false + agent_private_reasoning_display_allowed: false + raw_prompt_display_allowed: false + display_policy: string + } + approval_boundaries: Record + rollups: { + proof_level_count: number + contract_ready_level_count: number + live_pending_level_ids: string[] + signal_count: number + live_signal_count: number + operator_surface_count: number + runtime_gate_count: number + blocked_gate_ids: string[] + active_live_agent_sessions: number + live_agent_messages_24h: number + live_handoffs_24h: number + live_learning_writes_24h: number + telegram_digest_receipts_24h: 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 e2f16bf1e..2b1276e8b 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,42 @@ +## 2026-06-11|P2-403A AI Agent 互動與學習證據面 + +**背景**:統帥要求能看見、感受到 OpenClaw / Hermes / NemoTron 的互動、溝通、學習與成長是否真的有在運作;同時要求前端不得顯示工作視窗對話內容。本階段先建立只讀證據面與治理頁顯示,明確標示目前 live count 全為 `0`,避免假綠燈。 + +**本輪完成**: + +- 新增 `docs/schemas/ai_agent_interaction_learning_proof_v1.schema.json` 與 `docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json`,定義證據階梯、live truth、Agent lanes、proof signals、operator surfaces、runtime gates、learning memory stack、Telegram receipt contract 與 frontend redaction。 +- 新增 `apps/api/src/services/ai_agent_interaction_learning_proof.py` 與 `GET /api/v1/agents/agent-interaction-learning-proof`,只讀回傳 committed snapshot;若 runtime worker、DB migration、Redis consumer group、Telegram 實發、逐字稿顯示或私有推理顯示被打開,loader 會拒絕快照。 +- `apps/web/src/lib/api-client.ts` 新增前端 API 方法與型別。 +- `apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx` 新增「Agent 互動與學習證據」區塊,顯示目前真相、證據階梯、三 Agent lane、可觀測訊號、runtime gates 與前端紅線。 +- `apps/web/messages/zh-TW.json`、`apps/web/messages/en.json` 補齊繁體中文文案。 +- 更新 `docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md`、新增 `docs/ai/AI_AGENT_INTERACTION_LEARNING_PROOF_2026-06-11.md`、同步 MASTER §3.2.1d / §5 / Living Changelog。 + +**本地驗證**: + +- `python -m json.tool`:新 snapshot / schema / proactive snapshot / zh-TW / en 全部通過。 +- `DATABASE_URL=postgresql+asyncpg://test:test@localhost:5432/test PYTHONPATH=apps/api pytest apps/api/tests/test_ai_agent_interaction_learning_proof.py apps/api/tests/test_ai_agent_interaction_learning_proof_api.py apps/api/tests/test_ai_agent_proactive_operations_contract.py apps/api/tests/test_ai_agent_proactive_operations_contract_api.py -q`:`11 passed`。 +- `pnpm --filter @awoooi/web typecheck`:通過。 +- `NEXT_PUBLIC_API_URL=https://awoooi.wooo.work NEXT_PRIVATE_BUILD_WORKER_COUNT=1 SENTRY_SUPPRESS_GLOBAL_ERROR_HANDLER_FILE_WARNING=1 pnpm --filter @awoooi/web build`:通過,`/zh-TW/governance` route 進 build summary。 +- `python3 scripts/ops/doc-secrets-sanity-check.py docs .gitea`:`DOC_SECRET_SANITY_OK scanned_files=666`。 +- `git diff --check`:通過。 +- 本地 desktop `http://127.0.0.1:3011/zh-TW/governance?tab=automation-inventory&_v=p2-403a-local`:Agent 互動與學習證據可見、`P2-403A → P2-403B` 可見、Live 會話 / 學習回寫 / Telegram 收據皆為 `0`、危險操作按鈕 `0`、水平溢出 `0`、工作視窗對話外露 `0`、英文敏感紅線詞外露 `0`。 +- 本地 mobile `390x844`:Agent 互動與學習證據可見、`P2-403A → P2-403B` 可見、Live 會話 / 學習回寫 / Telegram 收據皆為 `0`、危險操作按鈕 `0`、水平溢出 `0`、工作視窗對話外露 `0`、英文敏感紅線詞外露 `0`。 + +**完成度同步**: + +- P2-403A:`100%`。 +- 三 Agent 主動溝通、學習與成長證據:`45%`。 +- live AgentSession:`0`。 +- live Agent message:`0`。 +- live handoff:`0`。 +- live learning write:`0`。 +- Telegram digest receipt:`0`。 +- Next task:`P2-403B` AgentSession / Redis Streams live read model 與 worker gate planning。 + +**邊界**: + +- 本波仍不啟動 worker、不建立 DB migration、不開 Redis consumer group、不發 Telegram、不寫 learning、不 SSH、不 kubectl、不升級、不重啟、不讀取或輸出 secret、不顯示工作視窗對話內容、不提供前端執行按鈕。 + ## 2026-06-11|P0 MCP evidence / PlayBook 修復候選 D3 **背景**:D2 已把缺修復候選的 Telegram 卡片補成「阻擋原因 / 下一步 / PlayBook 草案欄位」,但人工仍缺 AwoooP 可追蹤入口。本段把 blocked repair candidate 接到 deterministic read-only work item projection,不新增 DB 表、不開 runtime gate。 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 6ba7193f2..e65daaca1 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 主動溝通與學習契約 | 35% | P2-401A 已完成只讀 contract;runtime worker、DB migration、Telegram 實發、SDK / 付費服務仍未開 gate | `ai_agent_communication_learning_contract_v1` schema、`ai_agent_communication_learning_contract_2026-06-11.json`、`GET /api/v1/agents/agent-communication-learning-contract`、MASTER §3.2.1b / §3.4.3 | +| OpenClaw / Hermes / NemoTron 主動溝通、學習與成長證據 | 45% | P2-401A 已完成只讀 contract;P2-403A 已完成互動 / 接手 / 學習 / 成長證據面板、API 與治理頁顯示。runtime worker、DB migration、Redis consumer group、Telegram 實發、learning writeback、SDK / 付費服務仍未開 gate | `ai_agent_communication_learning_contract_v1`、`ai_agent_interaction_learning_proof_v1`、`GET /api/v1/agents/agent-communication-learning-contract`、`GET /api/v1/agents/agent-interaction-learning-proof`、`/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 主動溝通與學習契約目前完成度:**35%**。已完成只讀 schema / snapshot / API / 測試與 MASTER 同步;下一步依優先順序推 `P2-401B` AgentSession / Redis Streams migration 與 worker gate,但在批准前仍不得啟動 runtime loop。 +三 Agent 主動溝通、學習與成長證據目前完成度:**45%**。已完成只讀契約、互動 / 接手 / 學習 / 成長證據面板、API、治理頁顯示、測試與 MASTER 同步;目前 live AgentSession、Agent message、handoff、learning write、Telegram receipt 仍全部為 `0`,下一步依優先順序推 `P2-403B` AgentSession / Redis Streams read model 與 worker gate,但在批准前仍不得啟動 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` runtime gate planning,外部 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` live AgentSession / Redis read model,外部 registry / package source / host probe / SSH / kubectl / 工具安裝 / CI 變更 / 實際 PR creation / Telegram 實發仍需 gate。 完成度計算模型: @@ -76,6 +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,`ai_agent_interaction_learning_proof_v1` + `GET /api/v1/agents/agent-interaction-learning-proof` + governance UI;live count 仍為 0 | | NemoTron 3 Ultra smoke | 待辦:P3-401,需 source refresh + cost/data approval | ## 4. 工作流總覽 @@ -958,6 +959,8 @@ UI: | P2-402E | 完成 | 100 | Hermes | 設計 Gitea PR 草案 lane | `ai_agent_gitea_pr_draft_lane_v1` / snapshot / 只讀 API / 測試;6 條 grouping rule、7 個 lane step、9 個 required check、6 條 rollback requirement、4 個 draft template | 只讀;branch push、PR creation、workflow trigger、lockfile、package upgrade、auto merge、Telegram 全部未啟用 | | P2-402F | 完成 | 100 | OpenClaw | 建立 host OS / K3s / stateful services 版本只讀盤點 | `ai_agent_host_stateful_version_inventory_v1` / snapshot / 只讀 API / 測試;5 台主機、2 個 K3s 節點、12 個 stateful / ops 服務、6 個只讀 probe step、maintenance window approval package | 只讀;SSH、kubectl、apt / K3s upgrade、node drain、reboot、stateful restart、Telegram 全部未啟用 | | P2-402G | 完成 | 100 | Hermes | 接入 governance UI 顯示可委派能力 | 自主等級、gate、owner、Telegram policy、Host / K3s / stateful 只讀關卡與 redaction 狀態 | 只讀;不顯示敏感端點、不發 Telegram、不提供執行按鈕 | +| 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 | 待辦 | 0 | OpenClaw | AgentSession / Redis Streams live read model 與 worker gate planning | migration proposal、唯讀查詢、回滾計畫、無寫入 smoke | DB / Redis approval | | 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 new file mode 100644 index 000000000..e1e62f37e --- /dev/null +++ b/docs/ai/AI_AGENT_INTERACTION_LEARNING_PROOF_2026-06-11.md @@ -0,0 +1,71 @@ +# AI Agent 互動、溝通、學習與成長證據報告 + +> 日期:2026-06-11(台北時間) +> 文件定位:P2-403A 只讀證據面、API、治理頁 UI 與後續 runtime gate 分析。 +> 事實邊界:本波只建立可見證據面,不啟動 runtime worker、不建立 DB migration、不開 Redis consumer group、不發 Telegram、不顯示工作視窗對話內容。 + +## 1. 結論 + +已完成 P2-403A:讓統帥能在治理頁看到 OpenClaw / Hermes / NemoTron 的互動、接手、學習與成長是否真的有證據。 + +目前真相: + +| 項目 | 狀態 | +|---|---| +| 契約與證據面板 | 已完成 | +| `GET /api/v1/agents/agent-interaction-learning-proof` | 已完成 | +| `/zh-TW/governance?tab=automation-inventory` 顯示 | 已完成 | +| live AgentSession readback | 未啟用,數量 `0` | +| Agent message / handoff receipts | 未啟用,數量 `0` | +| learning writeback | 未啟用,數量 `0` | +| Telegram digest receipts | 未啟用,數量 `0` | + +這代表使用者現在可以看見「哪裡已準備好、哪裡仍未運作、被哪個 gate 阻擋」。但還不能宣稱三個 Agent 已經在 production runtime 主動互傳訊息或自主學習。 + +## 2. 你可以怎麼看到、感受到 + +| 感知方式 | UI / 通道 | 目前狀態 | 之後亮綠燈條件 | +|---|---|---|---| +| Agent 心跳 | governance proof panel | 待 live read model | `agent_sessions.last_seen_at` 有資料 | +| Agent 發話 / 收話收據 | governance proof panel | 待 Redis consumer group | `Redis Streams XADD + consumer ack` 可 replay | +| 互相接手 | AwoooP timeline / governance proof panel | 待 handoff envelope | `parent_turn_id` 串起 OpenClaw / Hermes / NemoTron turns | +| 互相挑戰 | AwoooP timeline | 契約已定義 | `turn_type=challenge` 且有補證 / 拒收紀錄 | +| 學習回寫 | governance proof panel | 待 learning writeback gate | `knowledge_entries`、`playbook_trust_history`、`learning_failure_log` 有新增 | +| 成長曲線 | governance proof panel | 待 replay / scorecard 趨勢 | replay 分數改善、誤判率下降、補證率下降 | +| Telegram 摘要 | Telegram Bot + governance receipt | policy 已定義,實發未啟用 | Gateway dry-run、E2E token 注入與送達驗證 | + +## 3. 三 Agent 分工 + +| Agent | 可被看見的證據 | 成長指標 | +|---|---|---| +| OpenClaw | 仲裁請求、challenge count、approval gate decision、post-verification learning receipt | 錯誤批准率下降、人工覆核退回率下降、風險分類穩定度上升 | +| Hermes | evidence dossier、runbook update proposal、knowledge entry、Telegram digest draft | 證據包完整率上升、缺欄位率下降、runbook reuse 次數上升 | +| NemoTron | replay job score、candidate model comparison、failure pattern label、promotion gate recommendation | replay 通過率上升、失敗模式覆蓋率上升、候選模型誤判率下降 | + +## 4. 本波產出 + +| 產物 | 內容 | +|---|---| +| `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 committed snapshot,完成度 `45%`,live count 全為 `0` | +| `apps/api/src/services/ai_agent_interaction_learning_proof.py` | 只讀 loader 與安全驗證 | +| `GET /api/v1/agents/agent-interaction-learning-proof` | 只讀 API,不啟動 worker、不碰 Redis / DB runtime、不發 Telegram | +| governance UI | 新增證據階梯、目前真相、Agent lane、可觀測訊號、runtime gates、前端 redaction | + +## 5. 後續優先順序 + +| 優先 | ID | 工作 | gate | +|---:|---|---|---| +| 1 | P2-403B | AgentSession / Redis Streams live read model 與 worker gate planning | DB / Redis approval | +| 2 | P2-403C | Redis Streams consumer group dry-run、handoff envelope、ack / dead letter / replay | runtime dry-run approval | +| 3 | P2-403D | learning writeback approval package、KM / playbook trust / replay score 趨勢 | writeback approval | +| 4 | P2-403E | Telegram gateway dry-run、E2E 送達與 receipt 顯示 | Telegram E2E approval | +| 5 | P2-403F | 成長趨勢週報與 operator feedback applied 指標 | trend evidence | + +## 6. 紅線 + +- 不顯示工作視窗對話內容。 +- 不顯示提示詞、私有推理、推理鏈。 +- 不顯示機密值、token、credential、raw payload。 +- 不把 live count `0` 說成已運作。 +- 不讓 Agent 互相自行批准 production route、升級、重啟、Telegram 實發或 paid API。 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 e665c7e76..ef802ceda 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 只讀契約與治理 UI 摘要。權威細節以 MASTER §3.2.1c、`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` 為準。 +> 文件定位:P2-402A / P2-402B / P2-402C / P2-402D / P2-402E / P2-402F / P2-402G / P2-403A 只讀契約與治理 UI 摘要。權威細節以 MASTER §3.2.1c / §3.2.1d、`ai_agent_proactive_operations_contract_v1`、`ai_agent_interaction_learning_proof_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. 本波完成度 @@ -14,7 +14,8 @@ | Gitea PR 草案 lane | 100% | P2-402E 已完成 grouping、automerge=false、測試證據、rollback、owner response schema / committed snapshot / API / 測試 | | Host / K3s / stateful 版本只讀盤點 | 100% | P2-402F 已完成 5 台主機、2 個 K3s 節點、12 個 stateful / ops 服務與 maintenance window 批准包 schema / committed snapshot / API / 測試 | | Governance UI 可委派能力顯示 | 100% | P2-402G 已把可委派能力、版本生命週期、Host / K3s / stateful 只讀盤點、maintenance window 與 Telegram / redaction gate 接入治理頁 | -| 整體主動營運與版本生命週期 | 100% | P2-402A~G 只讀契約、snapshot、API、測試與治理 UI 已完成;runtime 排程、工具安裝、CI 變更、實際 PR 建立與更新、host probe、升級、重啟仍未開 gate | +| Agent 互動與學習證據面 | 100% | P2-403A 已把目前真相、證據階梯、三 Agent lane、可觀測訊號、runtime gates 與 redaction policy 接入治理頁;live counts 全為 `0` | +| 整體主動營運與版本生命週期 | 100% | P2-402A~G 與 P2-403A 只讀契約、snapshot、API、測試與治理 UI 已完成;runtime 排程、工具安裝、CI 變更、實際 PR 建立與更新、host probe、升級、重啟、learning write、Telegram receipt 仍未開 gate | ## 2. 可交給 AI Agent 的工作分類 @@ -51,6 +52,9 @@ | `docs/schemas/ai_agent_host_stateful_version_inventory_v1.schema.json` | Host / K3s / stateful 版本只讀盤點 schema;SSH、kubectl、upgrade、drain、reboot、restart、Telegram 全部預設 false | | `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;live counts 全部 `0` | +| `GET /api/v1/agents/agent-interaction-learning-proof` | 只讀 API;不啟動 worker、不開 Redis consumer、不 DB migration、不發 Telegram、不顯示工作視窗對話 | ## 4. P2-402B Repo-only 版本新鮮度快照 @@ -61,7 +65,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-403A runtime gate planning;現階段仍只讀 | +| K8s / Gitea / observability / Ansible / backup / web surfaces | OpenClaw + Hermes | baseline_ready / planned_next | 下一步進入 P2-403B live AgentSession / Redis read model;現階段仍只讀 | 本波只把「每天要看哪些 repo 內版本來源」定義成可驗證資料面。每日排程、外部 registry 查詢、主機/K3s live probe、Telegram digest 與 Gitea PR lane 都仍是下一階段 gate。 @@ -130,7 +134,8 @@ P2-402G 的重點是把前面六個資料契約接回治理頁,讓統帥可以 | P2-402E | 1 | Gitea PR 草案 lane | 已完成,只讀;branch push / PR creation / workflow trigger 未啟用 | | P2-402F | 2 | host OS / K3s / stateful services 版本只讀盤點 | 已完成,只讀;SSH / kubectl / upgrade / reboot 未啟用 | | P2-402G | 3 | governance UI 顯示可委派能力 | 已完成,只讀;不顯示敏感端點或工作對話內容 | -| P2-403A | 4 | runtime gate planning:排程、工具、PR 草案、host probe 的逐項批准模型 | operator approval package | +| P2-403A | 4 | Agent 互動、接手、學習、成長與 Telegram receipt 證據面 | 已完成,只讀;live counts 全為 `0` | +| P2-403B | 5 | live AgentSession / Redis read model:心跳、訊息、接手、學習回寫的逐項批准模型 | DB / Redis approval package | ## 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 new file mode 100644 index 000000000..79c71397f --- /dev/null +++ b/docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json @@ -0,0 +1,393 @@ +{ + "schema_version": "ai_agent_interaction_learning_proof_v1", + "generated_at": "2026-06-11T23:20:00+08:00", + "program_status": { + "overall_completion_percent": 45, + "current_priority": "P2", + "current_task_id": "P2-403A", + "next_task_id": "P2-403B", + "read_only_mode": true, + "runtime_authority": "proof_surface_only_no_live_worker", + "status_note": "本快照建立使用者可感知的 Agent 互動、溝通、學習與成長證據面;目前只讀證據面已落地,live AgentSession/Redis/Telegram/learning writeback 尚未開 gate。" + }, + "live_truth": { + "runtime_loop_enabled": false, + "live_agent_session_readback_enabled": false, + "redis_consumer_group_enabled": false, + "telegram_send_enabled": false, + "learning_writeback_enabled": false, + "active_live_agent_sessions": 0, + "live_agent_messages_24h": 0, + "live_handoffs_24h": 0, + "live_learning_writes_24h": 0, + "telegram_digest_receipts_24h": 0, + "truth_note": "目前能證明的是合約、面板與證據需求已建立;還不能宣稱 OpenClaw / Hermes / NemoTron runtime 正在互傳訊息或自主學習。" + }, + "proof_ladder": [ + { + "level_id": "contract_surface", + "display_name": "協作與學習契約可見", + "status": "contract_ready", + "completion_percent": 100, + "operator_meaning": "你可以看到三個 Agent 如何分工、用哪些 MCP/RAG/記憶層互相交接。", + "source_of_truth": "ai_agent_communication_learning_contract_v1", + "next_gate": "保持只讀,等待 live read model 接線。" + }, + { + "level_id": "proof_dashboard", + "display_name": "互動證據面板可見", + "status": "proof_surface_ready", + "completion_percent": 100, + "operator_meaning": "治理頁會顯示哪些證據真的有資料、哪些仍是 0 與原因。", + "source_of_truth": "ai_agent_interaction_learning_proof_v1", + "next_gate": "P2-403B live AgentSession / Redis readback。" + }, + { + "level_id": "live_read_model", + "display_name": "Live AgentSession 讀回", + "status": "live_pending", + "completion_percent": 0, + "operator_meaning": "啟用後你會看到每個 Agent 最後心跳、最近工作、目前狀態與資料時間。", + "source_of_truth": "agent_sessions + timeline_events read model", + "next_gate": "P2-403B migration proposal、唯讀查詢、回滾計畫。" + }, + { + "level_id": "message_bus_receipts", + "display_name": "訊息匯流收據", + "status": "live_pending", + "completion_percent": 0, + "operator_meaning": "啟用後你會看到 Agent 發出、收到、挑戰、審查、決策的脫敏事件收據。", + "source_of_truth": "Redis Streams + agent_sessions", + "next_gate": "P2-403C consumer group dry-run 與重放驗證。" + }, + { + "level_id": "handoff_receipts", + "display_name": "互相接手紀錄", + "status": "live_pending", + "completion_percent": 0, + "operator_meaning": "啟用後你會看到 OpenClaw 要求 Hermes 補證、NemoTron 回傳 replay 分數、再由 OpenClaw 仲裁的接手鏈。", + "source_of_truth": "agent_sessions.parent_turn_id + timeline_events", + "next_gate": "P2-403C handoff envelope schema 與拒收測試。" + }, + { + "level_id": "learning_growth", + "display_name": "學習回寫與成長曲線", + "status": "live_pending", + "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。" + }, + { + "level_id": "telegram_receipts", + "display_name": "Telegram 摘要收據", + "status": "live_pending", + "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 注入驗證。" + } + ], + "agent_lanes": [ + { + "agent_id": "openclaw", + "display_name": "OpenClaw", + "primary_role": "仲裁者、風險 owner、HITL 守門者", + "current_visible_state": "contract_visible_live_runtime_pending", + "visible_signals": [ + "arbitration_request_count", + "challenge_count", + "approval_gate_decision", + "post_verification_learning_receipt" + ], + "growth_metric": "錯誤批准率下降、人工覆核退回率下降、風險分類穩定度上升", + "what_operator_will_feel": "你會看到 OpenClaw 不是只給結論,而是保留它要求補證、拒收、批准或升級的每一步摘要。" + }, + { + "agent_id": "hermes", + "display_name": "Hermes", + "primary_role": "治理文件、證據打包、變更草案與知識整理", + "current_visible_state": "contract_visible_live_runtime_pending", + "visible_signals": [ + "evidence_dossier_created", + "runbook_update_proposed", + "knowledge_entry_written", + "telegram_digest_drafted" + ], + "growth_metric": "證據包完整率上升、缺欄位率下降、runbook reuse 次數上升", + "what_operator_will_feel": "你會看到 Hermes 把雜訊整理成可審查證據包,並留下哪些知識被沉澱。" + }, + { + "agent_id": "nemotron", + "display_name": "NemoTron", + "primary_role": "離線 replay、模型候選評分、策略壓力測試", + "current_visible_state": "contract_visible_live_runtime_pending", + "visible_signals": [ + "replay_job_scored", + "candidate_model_compared", + "failure_pattern_labeled", + "promotion_gate_recommendation" + ], + "growth_metric": "replay 通過率上升、失敗模式覆蓋率上升、候選模型誤判率下降", + "what_operator_will_feel": "你會看到 NemoTron 用離線分數證明自己是否值得被納入某個任務,而不是直接進生產替換。" + } + ], + "proof_signals": [ + { + "signal_id": "agent_heartbeat", + "display_name": "Agent 心跳", + "category": "heartbeat", + "source_of_truth": "agent_sessions.last_seen_at", + "visible_surface": "governance_agent_proof_panel", + "current_state": "live_pending", + "operator_interpretation": "有心跳才代表 runtime worker 真正在回報。", + "next_gate": "P2-403B" + }, + { + "signal_id": "agent_message_created", + "display_name": "Agent 發話收據", + "category": "message", + "source_of_truth": "Redis Streams XADD + agent_sessions.turn_id", + "visible_surface": "governance_agent_proof_panel", + "current_state": "live_pending", + "operator_interpretation": "只能顯示摘要與 event id,不顯示工作視窗對話或私有推理。", + "next_gate": "P2-403C" + }, + { + "signal_id": "agent_message_consumed", + "display_name": "Agent 收話收據", + "category": "message", + "source_of_truth": "Redis Streams consumer group ack", + "visible_surface": "governance_agent_proof_panel", + "current_state": "live_pending", + "operator_interpretation": "有 ack 才能證明不是單向寫入,而是對方 Agent 已接手處理。", + "next_gate": "P2-403C" + }, + { + "signal_id": "handoff_accepted", + "display_name": "接手成功", + "category": "handoff", + "source_of_truth": "agent_sessions.parent_turn_id + timeline_events", + "visible_surface": "AwoooP timeline", + "current_state": "live_pending", + "operator_interpretation": "你會看到誰把任務交給誰、被接受或拒收,以及下一步。", + "next_gate": "P2-403C" + }, + { + "signal_id": "critic_challenge", + "display_name": "互相挑戰", + "category": "quality_gate", + "source_of_truth": "agent_sessions.turn_type=challenge", + "visible_surface": "AwoooP timeline", + "current_state": "contract_defined", + "operator_interpretation": "多 Agent 穩定度不是互相附和,而是可記錄的挑戰、拒收與補證。", + "next_gate": "P2-403C" + }, + { + "signal_id": "learning_write_receipt", + "display_name": "學習回寫收據", + "category": "learning", + "source_of_truth": "knowledge_entries + playbook_trust_history + learning_failure_log", + "visible_surface": "governance_agent_proof_panel", + "current_state": "live_pending", + "operator_interpretation": "只有寫入知識或 trust history,才算真正把經驗沉澱。", + "next_gate": "P2-403D" + }, + { + "signal_id": "growth_delta", + "display_name": "成長趨勢", + "category": "growth", + "source_of_truth": "replay_results + evaluation scorecard", + "visible_surface": "governance_agent_proof_panel", + "current_state": "live_pending", + "operator_interpretation": "用 replay 分數、拒收率、誤判率與補證率看 Agent 是否真的變好。", + "next_gate": "P2-403D" + }, + { + "signal_id": "telegram_digest_queued", + "display_name": "Telegram 摘要排隊", + "category": "telegram", + "source_of_truth": "telegram_gateway_queue", + "visible_surface": "Telegram Bot + governance receipts", + "current_state": "live_pending", + "operator_interpretation": "先證明排隊與脫敏,再證明送達;成功噪音不即時推播。", + "next_gate": "P2-403E" + }, + { + "signal_id": "operator_feedback_applied", + "display_name": "人工回饋採納", + "category": "learning", + "source_of_truth": "approval_records + learning_service feedback", + "visible_surface": "governance_agent_proof_panel", + "current_state": "contract_defined", + "operator_interpretation": "你按下接受、拒絕或要求補證後,Agent 要能把結果回寫成後續策略。", + "next_gate": "P2-403D" + } + ], + "operator_surfaces": [ + { + "surface_id": "governance_agent_proof_panel", + "display_name": "治理頁 Agent 證據面板", + "route_or_channel": "/zh-TW/governance?tab=automation-inventory", + "operator_feel": "一眼看到目前是真的 live、只有合約,或被哪個 gate 阻擋。", + "redaction_policy": "只顯示狀態、證據 id、來源表、摘要與下一步,不顯示對話逐字稿。", + "current_state": "implemented_read_only" + }, + { + "surface_id": "aiops_timeline", + "display_name": "AwoooP Timeline", + "route_or_channel": "/zh-TW/aiops/timeline", + "operator_feel": "事件會串成觀察、提案、挑戰、審查、決策、驗證、學習的時間線。", + "redaction_policy": "顯示脫敏 event envelope,不顯示提示詞或私有推理。", + "current_state": "existing_surface_needs_agent_read_model" + }, + { + "surface_id": "telegram_action_digest", + "display_name": "Telegram Bot 處置摘要", + "route_or_channel": "Telegram gateway", + "operator_feel": "只有需處置、需批准、失敗或風險升級時被打擾。", + "redaction_policy": "只送摘要、風險、批准連結與證據 id,不送機密值或完整對話。", + "current_state": "policy_defined_send_blocked" + }, + { + "surface_id": "learning_growth_cards", + "display_name": "學習成長卡", + "route_or_channel": "governance proof panel", + "operator_feel": "能看到某個 Agent 的 replay 分數是否上升、失敗類型是否下降。", + "redaction_policy": "顯示聚合指標與趨勢,不顯示訓練原文。", + "current_state": "planned" + }, + { + "surface_id": "audit_evidence_drawer", + "display_name": "稽核證據抽屜", + "route_or_channel": "governance proof panel", + "operator_feel": "點開後只看來源表、事件 id、驗證狀態與下一 gate。", + "redaction_policy": "所有 payload 需脫敏,敏感值僅顯示欄位名稱。", + "current_state": "planned" + } + ], + "runtime_gates": [ + { + "gate_id": "agent_session_read_model_gate", + "display_name": "AgentSession 唯讀 read model", + "status": "approval_required", + "required_before_green": "必須先提供 migration proposal、查詢索引、回滾計畫與無寫入 smoke。", + "next_task_id": "P2-403B" + }, + { + "gate_id": "redis_stream_consumer_gate", + "display_name": "Redis Streams consumer group dry-run", + "status": "approval_required", + "required_before_green": "必須先證明 consumer ack、dead letter、重放與停用開關。", + "next_task_id": "P2-403C" + }, + { + "gate_id": "learning_writeback_gate", + "display_name": "Learning writeback 批准包", + "status": "approval_required", + "required_before_green": "必須定義可寫表、資料保留、錯誤補償、人工回饋回滾。", + "next_task_id": "P2-403D" + }, + { + "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" + }, + { + "gate_id": "frontend_redaction_gate", + "display_name": "前端脫敏與內容紅線", + "status": "blocked", + "required_before_green": "任何面板不得顯示工作視窗對話、提示詞、私有推理、機密值、未脫敏 payload。", + "next_task_id": "P2-403B" + } + ], + "learning_memory_stack": [ + { + "layer_id": "hot_agent_session_memory", + "display_name": "Hot AgentSession Memory", + "storage_or_service": "agent_sessions + Redis Streams", + "visible_growth_signal": "心跳、turn count、handoff accepted、challenge count", + "current_state": "schema_existing_read_model_pending" + }, + { + "layer_id": "warm_knowledge_memory", + "display_name": "Warm Knowledge Memory", + "storage_or_service": "knowledge_entries + playbook_trust_history", + "visible_growth_signal": "知識新增數、trust delta、人工拒收率", + "current_state": "service_existing_writeback_gate_pending" + }, + { + "layer_id": "cold_replay_memory", + "display_name": "Cold Replay Memory", + "storage_or_service": "agent_replay_results + finetune_exporter", + "visible_growth_signal": "replay 分數、失敗分類、候選模型比較結果", + "current_state": "offline_adapter_existing_surface_pending" + }, + { + "layer_id": "market_model_memory", + "display_name": "Market Model Memory", + "storage_or_service": "agent_market_scorecard + governance snapshot", + "visible_growth_signal": "候選 Agent 市場分數、晉升/降級建議、取代評估證據", + "current_state": "read_only_governance_existing" + } + ], + "telegram_receipt_contract": { + "direct_send_allowed": false, + "gateway_queue_write_allowed": false, + "receipt_visible_to_operator": true, + "allowed_future_notification_classes": [ + "action_required", + "approval_required", + "failure", + "risk_escalation", + "daily_digest" + ], + "success_policy": "成功摘要預設不即時推播,只在日報或被追問時顯示。", + "redaction_policy": "Telegram 僅允許脫敏摘要、證據 id、風險、批准連結與下一步,不允許機密值或完整對話。" + }, + "frontend_redaction": { + "operator_conversation_display_allowed": false, + "agent_private_reasoning_display_allowed": false, + "raw_prompt_display_allowed": false, + "display_policy": "前端只顯示 Agent 狀態、證據摘要、來源、gate、聚合指標與下一步;工作視窗對話、提示詞、session 私有上下文與原始推理鏈全部禁止。" + }, + "approval_boundaries": { + "runtime_worker_allowed": false, + "db_migration_allowed": false, + "redis_consumer_group_allowed": false, + "telegram_direct_send_allowed": false, + "conversation_transcript_display_allowed": false, + "agent_private_reasoning_display_allowed": false, + "secret_plaintext_allowed": false, + "autonomous_self_modify_allowed": false + }, + "rollups": { + "proof_level_count": 7, + "contract_ready_level_count": 2, + "live_pending_level_ids": [ + "handoff_receipts", + "learning_growth", + "live_read_model", + "message_bus_receipts", + "telegram_receipts" + ], + "signal_count": 9, + "live_signal_count": 0, + "operator_surface_count": 5, + "runtime_gate_count": 5, + "blocked_gate_ids": [ + "agent_session_read_model_gate", + "frontend_redaction_gate", + "learning_writeback_gate", + "redis_stream_consumer_gate", + "telegram_receipt_gate" + ], + "active_live_agent_sessions": 0, + "live_agent_messages_24h": 0, + "live_handoffs_24h": 0, + "live_learning_writes_24h": 0, + "telegram_digest_receipts_24h": 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 a04ce10e3..84c3a2f9a 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 @@ -1,14 +1,14 @@ { "schema_version": "ai_agent_proactive_operations_contract_v1", - "generated_at": "2026-06-11T21:30:00+08:00", + "generated_at": "2026-06-11T23:20:00+08:00", "program_status": { "overall_completion_percent": 100, "current_priority": "P2", - "current_task_id": "P2-402G", - "next_task_id": "P2-403A", + "current_task_id": "P2-403A", + "next_task_id": "P2-403B", "read_only_mode": true, "runtime_authority": "contract_only_no_version_or_runtime_update", - "status_note": "P2-402G 已把可委派能力、版本生命週期、Host / K3s / stateful 只讀盤點與 Telegram / redaction gate 接入 governance UI;本波仍不 SSH、不執行 kubectl、不升級主機 / K3s / stateful service、不 drain、不 reboot、不發 Telegram。" + "status_note": "P2-403A 已把 Agent 互動、接手、學習、成長與 Telegram receipt 證據面接入 governance UI;live AgentSession / message / handoff / learning write / Telegram receipt 目前全為 0,下一步是 P2-403B live read model。" }, "external_source_evidence": [ { @@ -664,7 +664,16 @@ "completion_percent": 100, "owner_agent": "Hermes", "summary": "把可委派能力、版本生命週期、Host / K3s / stateful 只讀盤點、maintenance window 批准包與 Telegram / redaction gate 接入 governance UI;不顯示敏感端點或工作對話內容。", - "next_gate": "P2-403A_runtime_gate_planning" + "next_gate": "P2-403A_completed" + }, + { + "task_id": "P2-403A", + "priority": "P2", + "status": "done", + "completion_percent": 100, + "owner_agent": "Hermes + OpenClaw", + "summary": "建立 Agent 互動、接手、學習、成長與 Telegram receipt 證據面;治理頁顯示目前真相、證據階梯、Agent lanes、可觀測訊號、runtime gates 與 redaction policy。", + "next_gate": "P2-403B_live_read_model" } ], "approval_boundaries": { @@ -685,7 +694,7 @@ "cadence_count": 5, "mcp_tool_count": 8, "rag_memory_count": 4, - "rollout_task_count": 7, + "rollout_task_count": 8, "auto_execute_allowed_count": 0, "approval_required_capability_count": 23, "blocked_update_domain_ids": [ diff --git a/docs/schemas/ai_agent_interaction_learning_proof_v1.schema.json b/docs/schemas/ai_agent_interaction_learning_proof_v1.schema.json new file mode 100644 index 000000000..ef7d16ee9 --- /dev/null +++ b/docs/schemas/ai_agent_interaction_learning_proof_v1.schema.json @@ -0,0 +1,377 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://awoooi.wooo.work/schemas/ai_agent_interaction_learning_proof_v1.schema.json", + "title": "AI Agent Interaction Learning Proof v1", + "type": "object", + "required": [ + "schema_version", + "generated_at", + "program_status", + "live_truth", + "proof_ladder", + "agent_lanes", + "proof_signals", + "operator_surfaces", + "runtime_gates", + "learning_memory_stack", + "telegram_receipt_contract", + "frontend_redaction", + "approval_boundaries", + "rollups" + ], + "properties": { + "schema_version": { + "const": "ai_agent_interaction_learning_proof_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" + ], + "properties": { + "overall_completion_percent": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "current_priority": { + "type": "string" + }, + "current_task_id": { + "type": "string" + }, + "next_task_id": { + "type": "string" + }, + "read_only_mode": { + "const": true + }, + "runtime_authority": { + "const": "proof_surface_only_no_live_worker" + } + }, + "additionalProperties": true + }, + "live_truth": { + "type": "object", + "required": [ + "runtime_loop_enabled", + "live_agent_session_readback_enabled", + "redis_consumer_group_enabled", + "telegram_send_enabled", + "learning_writeback_enabled", + "active_live_agent_sessions", + "live_agent_messages_24h", + "live_handoffs_24h", + "live_learning_writes_24h", + "telegram_digest_receipts_24h" + ], + "properties": { + "runtime_loop_enabled": { + "const": false + }, + "live_agent_session_readback_enabled": { + "const": false + }, + "redis_consumer_group_enabled": { + "const": false + }, + "telegram_send_enabled": { + "const": false + }, + "learning_writeback_enabled": { + "const": false + }, + "active_live_agent_sessions": { + "const": 0 + }, + "live_agent_messages_24h": { + "const": 0 + }, + "live_handoffs_24h": { + "const": 0 + }, + "live_learning_writes_24h": { + "const": 0 + }, + "telegram_digest_receipts_24h": { + "const": 0 + } + }, + "additionalProperties": true + }, + "proof_ladder": { + "type": "array", + "items": { + "$ref": "#/$defs/proof_level" + }, + "minItems": 1 + }, + "agent_lanes": { + "type": "array", + "items": { + "$ref": "#/$defs/agent_lane" + }, + "minItems": 3 + }, + "proof_signals": { + "type": "array", + "items": { + "$ref": "#/$defs/proof_signal" + }, + "minItems": 1 + }, + "operator_surfaces": { + "type": "array", + "items": { + "$ref": "#/$defs/operator_surface" + }, + "minItems": 1 + }, + "runtime_gates": { + "type": "array", + "items": { + "$ref": "#/$defs/runtime_gate" + }, + "minItems": 1 + }, + "learning_memory_stack": { + "type": "array", + "items": { + "$ref": "#/$defs/memory_layer" + }, + "minItems": 1 + }, + "telegram_receipt_contract": { + "type": "object", + "required": [ + "direct_send_allowed", + "gateway_queue_write_allowed", + "receipt_visible_to_operator" + ], + "properties": { + "direct_send_allowed": { + "const": false + }, + "gateway_queue_write_allowed": { + "const": false + }, + "receipt_visible_to_operator": { + "const": true + } + }, + "additionalProperties": true + }, + "frontend_redaction": { + "type": "object", + "required": [ + "operator_conversation_display_allowed", + "agent_private_reasoning_display_allowed", + "raw_prompt_display_allowed" + ], + "properties": { + "operator_conversation_display_allowed": { + "const": false + }, + "agent_private_reasoning_display_allowed": { + "const": false + }, + "raw_prompt_display_allowed": { + "const": false + } + }, + "additionalProperties": true + }, + "approval_boundaries": { + "type": "object", + "required": [ + "runtime_worker_allowed", + "db_migration_allowed", + "redis_consumer_group_allowed", + "telegram_direct_send_allowed", + "conversation_transcript_display_allowed", + "agent_private_reasoning_display_allowed", + "secret_plaintext_allowed", + "autonomous_self_modify_allowed" + ], + "properties": { + "runtime_worker_allowed": { + "const": false + }, + "db_migration_allowed": { + "const": false + }, + "redis_consumer_group_allowed": { + "const": false + }, + "telegram_direct_send_allowed": { + "const": false + }, + "conversation_transcript_display_allowed": { + "const": false + }, + "agent_private_reasoning_display_allowed": { + "const": false + }, + "secret_plaintext_allowed": { + "const": false + }, + "autonomous_self_modify_allowed": { + "const": false + } + }, + "additionalProperties": true + }, + "rollups": { + "type": "object", + "required": [ + "proof_level_count", + "contract_ready_level_count", + "live_pending_level_ids", + "signal_count", + "live_signal_count", + "operator_surface_count", + "runtime_gate_count", + "blocked_gate_ids", + "active_live_agent_sessions", + "live_agent_messages_24h", + "live_handoffs_24h", + "live_learning_writes_24h", + "telegram_digest_receipts_24h" + ], + "additionalProperties": true + } + }, + "$defs": { + "proof_level": { + "type": "object", + "required": [ + "level_id", + "display_name", + "status", + "completion_percent", + "operator_meaning", + "source_of_truth", + "next_gate" + ], + "properties": { + "level_id": { + "type": "string" + }, + "display_name": { + "type": "string" + }, + "status": { + "type": "string" + }, + "completion_percent": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "operator_meaning": { + "type": "string" + }, + "source_of_truth": { + "type": "string" + }, + "next_gate": { + "type": "string" + } + }, + "additionalProperties": true + }, + "agent_lane": { + "type": "object", + "required": [ + "agent_id", + "display_name", + "primary_role", + "current_visible_state", + "visible_signals", + "growth_metric" + ], + "properties": { + "agent_id": { + "type": "string" + }, + "display_name": { + "type": "string" + }, + "primary_role": { + "type": "string" + }, + "current_visible_state": { + "type": "string" + }, + "visible_signals": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1 + }, + "growth_metric": { + "type": "string" + } + }, + "additionalProperties": true + }, + "proof_signal": { + "type": "object", + "required": [ + "signal_id", + "display_name", + "category", + "source_of_truth", + "visible_surface", + "current_state", + "operator_interpretation", + "next_gate" + ], + "additionalProperties": true + }, + "operator_surface": { + "type": "object", + "required": [ + "surface_id", + "display_name", + "route_or_channel", + "operator_feel", + "redaction_policy", + "current_state" + ], + "additionalProperties": true + }, + "runtime_gate": { + "type": "object", + "required": [ + "gate_id", + "display_name", + "status", + "required_before_green", + "next_task_id" + ], + "additionalProperties": true + }, + "memory_layer": { + "type": "object", + "required": [ + "layer_id", + "display_name", + "storage_or_service", + "visible_growth_signal", + "current_state" + ], + "additionalProperties": true + } + } +} 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 e7ee166ac..26847fa3c 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,6 +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 互動 / 接手 / 學習 / 成長證據面;目前 live session、message、handoff、learning write、Telegram receipt 全部 `0`,下一步 P2-403B | #### 3.2.1c 2026-06-11 AI Agent 主動營運委派與版本生命週期契約 @@ -698,7 +699,41 @@ Repo / registry / release notes / K8s / host / observability / backup evidence 4. 再進 Gitea PR 草案 lane:grouping、automerge=false、tests、rollback、owner response。✅ P2-402E 已建立 draft lane snapshot/API;branch push、PR creation、workflow trigger、lockfile、package upgrade、auto merge 仍未授權。 5. 建立 host OS / K3s / stateful services 版本只讀盤點,先固定維護窗口、備份、rollback 與 smoke gate。✅ P2-402F 已建立 snapshot/API;SSH、kubectl、upgrade、drain、reboot、stateful restart 仍未授權。 6. 把可委派能力、版本生命週期、Host / K3s / stateful 只讀關卡接入 governance UI。✅ P2-402G 已完成;不顯示敏感端點、不提供執行按鈕。 -7. 最後才進人工批准後的 dry-run / smoke / canary / production rollout。下一步 P2-403A runtime gate planning。 +7. 先建立可被統帥看見的互動 / 接手 / 學習 / 成長證據面。✅ P2-403A 已完成;live count 仍為 `0`,不宣稱 runtime 已運作。 +8. 最後才進人工批准後的 live read model / dry-run / smoke / canary / production rollout。下一步 P2-403B AgentSession / Redis read model gate planning。 + +#### 3.2.1d 2026-06-11 Agent 互動、學習與成長證據面 + +**核心裁決**:要讓統帥感受到 Agent 真正在運作,不能靠文字宣告,必須靠可 replay、可稽核、可歸零的證據面。若 live session / message / handoff / learning write / Telegram receipt 為 `0`,前端必須明確顯示 `0` 與 gate,不得包裝成已運作。 + +**可感知證據階梯:** + +| 階段 | 使用者看到什麼 | 目前狀態 | +|---|---|---| +| 契約可見 | 三 Agent 分工、MCP/RAG、Telegram/redaction 邊界 | 已完成 | +| 證據面板 | 「目前真相」、證據階梯、Agent lane、runtime gate | 已完成 | +| Live read model | Agent 心跳、最近狀態、資料時間 | P2-403B 待辦 | +| 訊息收據 | 發話、收話、ack、dead letter、replay | P2-403C 待辦 | +| 接手紀錄 | OpenClaw / Hermes / NemoTron parent turn / handoff chain | P2-403C 待辦 | +| 學習回寫 | KM、Playbook trust、learning failure、replay score | P2-403D 待辦 | +| Telegram 收據 | action-required / approval / failure digest queued / delivered / acknowledged | P2-403E 待辦 | + +**本波已建立的可執行契約(只讀,不授權 runtime):** + +| 檔案 / 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 committed snapshot;完成度 `45%`,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 | +| `/zh-TW/governance?tab=automation-inventory` | 顯示證據階梯、目前真相、三 Agent lane、可觀測訊號、runtime gates 與 redaction policy | + +**硬性紅線:** + +- 前端不得顯示工作視窗對話、提示詞、session 私有上下文、私有推理、推理鏈。 +- Telegram 不得直發;必須先走 gateway dry-run、E2E token 注入與送達證據。 +- live count 為 `0` 時必須顯示 `0`,不得視為成功。 +- Agent 可互相挑戰與接手,但不得互相自行批准 production route、升級、重啟或付費 API。 #### 3.2.2 核心缺口與災難場景 @@ -1332,6 +1367,7 @@ Repo / registry / release notes / K8s / host / observability / backup evidence | Agent Session 表 | DB migration | 新增 `agent_sessions` 表(session_id / agent_role / input_hash / output / latency)| L7×D2 | | 決策路由 | `services/decision_manager.py` | 新路徑:收到 EvidenceSnapshot → 送 Orchestrator → 等 Coordinator 結果 | L4×D2 | | 主動溝通與學習契約 | `docs/evaluations/ai_agent_communication_learning_contract_2026-06-11.json` + `GET /api/v1/agents/agent-communication-learning-contract` | 先固定 OpenClaw / Hermes / NemoTron 主動溝通、MCP、RAG、學習與 redaction 邊界;不啟動 runtime worker | L4×D2 / L7×D4 | +| 互動與學習證據面 | `docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json` + `GET /api/v1/agents/agent-interaction-learning-proof` | P2-403A:讓治理頁可見心跳、訊息、接手、學習、成長與 Telegram receipt 的真實狀態;目前 live count 全部為 `0`,不宣稱 runtime 已運作 | L4×D2 / L7×D4 / L6×D6 | | 主動營運委派與版本生命週期契約 | `docs/evaluations/ai_agent_proactive_operations_contract_2026-06-11.json` + `GET /api/v1/agents/agent-proactive-operations-contract` | 先固定 12 類版本 domain、24 類可委派能力、MCP/RAG/Telegram 邊界;不啟用排程、不自動升版 | L4×D2 / L7×D4 / L6×D6 | | Repo-only 版本新鮮度快照 | `docs/evaluations/ai_agent_version_freshness_snapshot_2026-06-11.json` + `GET /api/v1/agents/agent-version-freshness-snapshot` | P2-402B:讓 Hermes 可每日產生 repo-only freshness evidence packet;目前只讀 API,不啟用 schedule、不查外部、不升級 | L4×D2 / L7×D4 / L6×D6 | | 工具採用批准包 | `docs/evaluations/ai_agent_tool_adoption_approval_package_2026-06-11.json` + `GET /api/v1/agents/agent-tool-adoption-approval-package` | P2-402C:讓 OpenClaw / Hermes / NemoTron 用官方來源評估 Renovate / OSV-Scanner / Trivy / Syft / Grype;目前只讀 API,不安裝工具、不改 CI、不查外部、不建 PR、不發 Telegram | L4×D2 / L7×D4 / L6×D6 | @@ -1744,6 +1780,13 @@ Phase 6 完成後 - 更新 `ai_agent_proactive_operations_contract_2026-06-11.json`:整體完成度 `100%`,current task `P2-402G`,next task `P2-403A`。 - 本波仍不 SSH、不執行 host command、不執行 kubectl、不 apt / kernel / K3s upgrade、不 node drain、不 kubelet restart、不 reboot、不 stateful restart、不 DB migration、不 restore、不 pull image、不發 Telegram、不讀取或輸出 secret、不回傳工作視窗對話內容;P2-403A 才設計 runtime gate planning。 +### 2026-06-11 23:59 (台北) — §3.2 / §5 — 完成 P2-403A Agent 互動與學習證據面 — 回應統帥要求看見並感受到 Agent 是否真的運作 + +- 新增 §3.2.1d,定義可感知證據階梯:契約、證據面板、live read model、訊息收據、接手紀錄、學習回寫、Telegram 收據。 +- 新增 `ai_agent_interaction_learning_proof_v1` schema / committed snapshot / loader / API / 測試,完成度 `45%`;目前 live AgentSession、Agent message、handoff、learning write、Telegram receipt 全部為 `0`。 +- `apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx` 接入 `GET /api/v1/agents/agent-interaction-learning-proof`,顯示「目前真相」、證據階梯、三 Agent lane、可觀測訊號、runtime gates 與前端 redaction。 +- 本波仍不啟動 worker、不建立 DB migration、不開 Redis consumer group、不發 Telegram、不寫 learning、不讀取或輸出 secret、不回傳工作視窗對話內容;下一步 P2-403B 才規劃 AgentSession / Redis live read model。 + ### 2026-04-15 (台北) — 全檔 — 建立 v2 骨架,§0/§1 完成 — 統帥批准「單 MASTER + 4 道閘門」結構 - 從 v1(plans/2026-04-15-MASTER-ai-autonomous-flywheel.md)繼承核心發現