From 80fa116e0a9dd383ad4c5386800771bec81cfe86 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 12 Jun 2026 14:03:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(governance):=20=E6=96=B0=E5=A2=9E=20runtim?= =?UTF-8?q?e=20worker=20shadow=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/api/src/api/v1/agents.py | 31 ++ .../ai_agent_runtime_worker_shadow_gate.py | 266 ++++++++++++ ...est_ai_agent_runtime_worker_shadow_gate.py | 119 ++++++ ...ai_agent_runtime_worker_shadow_gate_api.py | 32 ++ apps/web/messages/en.json | 53 +++ apps/web/messages/zh-TW.json | 53 +++ .../tabs/automation-inventory-tab.tsx | 245 ++++++++++- apps/web/src/lib/api-client.ts | 141 +++++++ docs/LOGBOOK.md | 30 ++ ...AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md | 6 +- ...T_INTERACTION_LEARNING_PROOF_2026-06-11.md | 20 +- ...runtime_worker_shadow_gate_2026-06-12.json | 398 ++++++++++++++++++ ..._runtime_worker_shadow_gate_v1.schema.json | 370 ++++++++++++++++ ...-04-15-MASTER-ai-autonomous-flywheel-v2.md | 14 +- 14 files changed, 1767 insertions(+), 11 deletions(-) create mode 100644 apps/api/src/services/ai_agent_runtime_worker_shadow_gate.py create mode 100644 apps/api/tests/test_ai_agent_runtime_worker_shadow_gate.py create mode 100644 apps/api/tests/test_ai_agent_runtime_worker_shadow_gate_api.py create mode 100644 docs/evaluations/ai_agent_runtime_worker_shadow_gate_2026-06-12.json create mode 100644 docs/schemas/ai_agent_runtime_worker_shadow_gate_v1.schema.json diff --git a/apps/api/src/api/v1/agents.py b/apps/api/src/api/v1/agents.py index 939555609..dda80e149 100644 --- a/apps/api/src/api/v1/agents.py +++ b/apps/api/src/api/v1/agents.py @@ -100,6 +100,9 @@ from src.services.ai_agent_report_runtime_readiness import ( from src.services.ai_agent_report_truth_actionability_review import ( load_latest_ai_agent_report_truth_actionability_review, ) +from src.services.ai_agent_runtime_worker_shadow_gate import ( + load_latest_ai_agent_runtime_worker_shadow_gate, +) from src.services.ai_agent_runtime_write_gate_review import ( load_latest_ai_agent_runtime_write_gate_review, ) @@ -1004,6 +1007,34 @@ async def get_agent_report_runtime_fixture_readback() -> dict[str, Any]: ) from exc +@router.get( + "/agent-runtime-worker-shadow-gate", + response_model=dict[str, Any], + summary="取得 AI Agent runtime worker shadow/no-write 證據閘門", + description=( + "讀取最新已提交的 P2-404 runtime worker shadow / no-write execution evidence gate;" + "此端點只回傳 shadow candidate、no-write replay、verifier shadow case 與 operator checkpoint," + "不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫讀報回執、不啟動 live AI runtime worker、" + "不啟動中低風險 auto worker、不執行 verifier live readback、不寫 production target、不讀 secret。" + ), +) +async def get_agent_runtime_worker_shadow_gate() -> dict[str, Any]: + """Return the latest read-only AI Agent runtime worker shadow gate.""" + try: + return await asyncio.to_thread(load_latest_ai_agent_runtime_worker_shadow_gate) + 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_runtime_worker_shadow_gate_invalid", error=str(exc)) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="AI Agent runtime worker shadow/no-write 證據閘門無效", + ) from exc + + @router.get( "/agent-owner-approved-fixture-dry-run", response_model=dict[str, Any], diff --git a/apps/api/src/services/ai_agent_runtime_worker_shadow_gate.py b/apps/api/src/services/ai_agent_runtime_worker_shadow_gate.py new file mode 100644 index 000000000..672318360 --- /dev/null +++ b/apps/api/src/services/ai_agent_runtime_worker_shadow_gate.py @@ -0,0 +1,266 @@ +""" +AI Agent runtime worker shadow gate snapshot. + +Loads the latest committed P2-404 shadow/no-write execution evidence gate. +This module validates repo-committed evidence only; it never starts workers, +writes Telegram Gateway queues, sends Telegram messages, reads secrets, or +writes production targets. +""" + +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_runtime_worker_shadow_gate_*.json" +_SCHEMA_VERSION = "ai_agent_runtime_worker_shadow_gate_v1" +_RUNTIME_AUTHORITY = "runtime_worker_shadow_no_write_execution_evidence_gate_only_no_live_send_or_write" + + +def load_latest_ai_agent_runtime_worker_shadow_gate( + evaluations_dir: Path | None = None, +) -> dict[str, Any]: + """Load the newest committed AI Agent runtime worker shadow gate.""" + directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR + candidates = sorted(directory.glob(_SNAPSHOT_PATTERN)) + if not candidates: + raise FileNotFoundError(f"no AI Agent runtime worker shadow gate snapshots found in {directory}") + + latest = candidates[-1] + with latest.open(encoding="utf-8") as handle: + payload = json.load(handle) + + if not isinstance(payload, dict): + raise ValueError(f"{latest}: expected JSON object") + _require_schema(payload, str(latest)) + _require_no_write_boundaries(payload, str(latest)) + _require_shadow_candidates(payload, str(latest)) + _require_replay_contract(payload, str(latest)) + _require_verifier_contract(payload, str(latest)) + _require_agent_roles(payload, str(latest)) + _require_redaction_contract(payload, str(latest)) + _require_rollup_consistency(payload, str(latest)) + return payload + + +def _require_schema(payload: dict[str, Any], label: str) -> None: + if payload.get("schema_version") != _SCHEMA_VERSION: + raise ValueError(f"{label}: expected schema_version={_SCHEMA_VERSION}") + status = payload.get("program_status") or {} + if status.get("read_only_mode") is not True: + raise ValueError(f"{label}: program_status.read_only_mode must be true") + if status.get("runtime_authority") != _RUNTIME_AUTHORITY: + raise ValueError(f"{label}: runtime_authority must remain {_RUNTIME_AUTHORITY}") + if status.get("current_task_id") != "P2-404": + raise ValueError(f"{label}: current_task_id must be P2-404") + if status.get("next_task_id") != "P2-101": + raise ValueError(f"{label}: next_task_id must be P2-101") + + +def _require_no_write_boundaries(payload: dict[str, Any], label: str) -> None: + truth = payload.get("shadow_gate_truth") or {} + required_true = { + "shadow_worker_evidence_gate_ready", + "promotion_from_fixture_readback_ready", + "no_write_replay_plan_ready", + "action_candidate_selection_ready", + "mcp_evidence_reuse_ready", + "verifier_dry_run_binding_ready", + "failure_lane_ready", + "operator_review_packet_ready", + } + missing = sorted(field for field in required_true if truth.get(field) is not True) + if missing: + raise ValueError(f"{label}: shadow readiness flags must remain true: {missing}") + + required_false = { + "production_delivery_enabled", + "gateway_queue_write_enabled", + "telegram_send_enabled", + "telegram_bot_api_call_enabled", + "delivery_receipt_write_enabled", + "shadow_worker_live_enabled", + "ai_runtime_worker_enabled", + "medium_low_auto_worker_enabled", + "post_action_verifier_live_readback_enabled", + "production_write_enabled", + "secret_value_read_enabled", + "work_window_transcript_display_allowed", + } + unsafe = sorted(field for field in required_false if truth.get(field) is not False) + if unsafe: + raise ValueError(f"{label}: live write/send/runtime flags must remain false: {unsafe}") + + zero_counts = { + "shadow_worker_live_run_count_24h", + "gateway_queue_write_count_24h", + "telegram_send_count_24h", + "telegram_bot_api_call_count_24h", + "delivery_receipt_write_count_24h", + "ai_runtime_worker_run_count_24h", + "medium_low_auto_execution_count_24h", + "post_action_verifier_live_readback_count_24h", + "production_write_count_24h", + } + non_zero = sorted(field for field in zero_counts if truth.get(field) != 0) + if non_zero: + raise ValueError(f"{label}: live write/send/runtime counts must remain zero: {non_zero}") + + +def _require_shadow_candidates(payload: dict[str, Any], label: str) -> None: + candidates = payload.get("shadow_worker_candidates") or [] + candidate_ids = {candidate.get("candidate_id") for candidate in candidates} + required = { + "shadow_report_daily_digest_candidate", + "shadow_report_weekly_digest_candidate", + "shadow_report_monthly_digest_candidate", + "shadow_medium_low_noop_repair_candidate", + "shadow_post_action_verifier_candidate", + } + if candidate_ids != required: + raise ValueError(f"{label}: shadow candidates must match {sorted(required)}") + + for candidate in candidates: + candidate_id = candidate.get("candidate_id") + if not _is_redacted_sha256(candidate.get("promotion_hash")): + raise ValueError(f"{label}: candidate {candidate_id} must expose a redacted sha256 promotion_hash") + if candidate.get("writes_production") is not False: + raise ValueError(f"{label}: candidate {candidate_id} must not write production") + if candidate.get("sends_telegram") is not False: + raise ValueError(f"{label}: candidate {candidate_id} must not send Telegram") + if candidate.get("reads_secret_value") is not False: + raise ValueError(f"{label}: candidate {candidate_id} must not read secret value") + if candidate.get("live_shadow_run_count_24h") != 0: + raise ValueError(f"{label}: candidate {candidate_id} live_shadow_run_count_24h must remain zero") + + +def _require_replay_contract(payload: dict[str, Any], label: str) -> None: + replays = payload.get("no_write_execution_replays") or [] + replay_ids = {replay.get("replay_id") for replay in replays} + required = { + "daily_report_shadow_replay", + "weekly_report_shadow_replay", + "medium_low_noop_shadow_replay", + "verifier_shadow_replay", + } + if replay_ids != required: + raise ValueError(f"{label}: no-write replays must match {sorted(required)}") + + for replay in replays: + replay_id = replay.get("replay_id") + if not _is_redacted_sha256(replay.get("evidence_hash")): + raise ValueError(f"{label}: replay {replay_id} must expose a redacted sha256 evidence_hash") + if replay.get("verifier_bound") is not True: + raise ValueError(f"{label}: replay {replay_id} must remain verifier bound") + if replay.get("writes_result") is not False: + raise ValueError(f"{label}: replay {replay_id} must not write result") + if replay.get("production_side_effect_count") != 0: + raise ValueError(f"{label}: replay {replay_id} production_side_effect_count must remain zero") + + +def _require_verifier_contract(payload: dict[str, Any], label: str) -> None: + cases = payload.get("verifier_shadow_cases") or [] + case_ids = {case.get("case_id") for case in cases} + required = { + "shadow_promotion_verifier_case", + "queue_write_block_verifier_case", + "telegram_send_block_verifier_case", + "production_write_block_verifier_case", + } + if case_ids != required: + raise ValueError(f"{label}: verifier shadow cases must match {sorted(required)}") + + for case in cases: + case_id = case.get("case_id") + if not _is_redacted_sha256(case.get("evidence_hash")): + raise ValueError(f"{label}: verifier case {case_id} must expose a redacted sha256 evidence_hash") + if case.get("live_readback_enabled") is not False: + raise ValueError(f"{label}: verifier case {case_id} must not run live readback") + if case.get("writes_result") is not False: + raise ValueError(f"{label}: verifier case {case_id} must not write result") + if case.get("requires_secret_value") is not False: + raise ValueError(f"{label}: verifier case {case_id} must not require secret value") + + +def _require_agent_roles(payload: dict[str, Any], label: str) -> None: + roles = payload.get("agent_shadow_roles") or [] + agents = {role.get("agent_id") for role in roles} + if agents != {"openclaw", "hermes", "nemotron"}: + raise ValueError(f"{label}: shadow roles must include OpenClaw, Hermes, and NemoTron") + for role in roles: + if role.get("live_action_count_24h") != 0: + raise ValueError(f"{label}: agent {role.get('agent_id')} live_action_count_24h must remain zero") + + +def _require_redaction_contract(payload: dict[str, Any], label: str) -> None: + contract = payload.get("display_redaction_contract") or {} + required_false = { + "raw_report_payload_display_allowed", + "raw_telegram_payload_display_allowed", + "raw_shadow_payload_display_allowed", + "private_reasoning_display_allowed", + "secret_value_display_allowed", + "work_window_transcript_display_allowed", + } + if contract.get("redaction_required") is not True: + raise ValueError(f"{label}: display redaction must remain required") + unsafe = sorted(field for field in required_false if contract.get(field) is not False) + if unsafe: + raise ValueError(f"{label}: display redaction fields must remain false: {unsafe}") + + +def _require_rollup_consistency(payload: dict[str, Any], label: str) -> None: + rollups = payload.get("rollups") or {} + truth = payload.get("shadow_gate_truth") or {} + candidates = payload.get("shadow_worker_candidates") or [] + replays = payload.get("no_write_execution_replays") or [] + cases = payload.get("verifier_shadow_cases") or [] + roles = payload.get("agent_shadow_roles") or [] + checkpoints = payload.get("operator_checkpoints") or [] + + expected = { + "shadow_candidate_count": len(candidates), + "passed_no_write_candidate_count": sum(1 for item in candidates if item.get("shadow_status") == "passed_no_write_replay"), + "blocked_candidate_count": sum(1 for item in candidates if item.get("shadow_status") == "blocked_by_runtime_gate"), + "needs_owner_review_candidate_count": sum(1 for item in candidates if item.get("shadow_status") == "needs_owner_review"), + "no_write_replay_count": len(replays), + "passed_no_write_replay_count": sum(1 for item in replays if item.get("replay_status") == "passed_no_write"), + "verifier_shadow_case_count": len(cases), + "agent_role_count": len(roles), + "operator_checkpoint_count": len(checkpoints), + } + mismatches = sorted(field for field, value in expected.items() if rollups.get(field) != value) + if mismatches: + raise ValueError(f"{label}: rollup counts must match source arrays: {mismatches}") + + approval_ids = sorted(item.get("checkpoint_id") for item in checkpoints if item.get("approval_required") is True) + if sorted(rollups.get("approval_required_checkpoint_ids") or []) != approval_ids: + raise ValueError(f"{label}: approval_required_checkpoint_ids must match operator checkpoints") + + zero_pairs = { + "shadow_worker_live_run_count": truth.get("shadow_worker_live_run_count_24h"), + "gateway_queue_write_count": truth.get("gateway_queue_write_count_24h"), + "telegram_send_count": truth.get("telegram_send_count_24h"), + "telegram_bot_api_call_count": truth.get("telegram_bot_api_call_count_24h"), + "delivery_receipt_write_count": truth.get("delivery_receipt_write_count_24h"), + "ai_runtime_worker_run_count": truth.get("ai_runtime_worker_run_count_24h"), + "medium_low_auto_execution_count": truth.get("medium_low_auto_execution_count_24h"), + "post_action_verifier_live_readback_count": truth.get("post_action_verifier_live_readback_count_24h"), + "production_write_count": truth.get("production_write_count_24h"), + } + non_zero = sorted(field for field, value in zero_pairs.items() if rollups.get(field) != 0 or value != 0) + if non_zero: + raise ValueError(f"{label}: rollup live counts must remain zero: {non_zero}") + + +def _is_redacted_sha256(value: Any) -> bool: + if not isinstance(value, str): + return False + if not value.startswith("sha256:"): + return False + digest = value.removeprefix("sha256:") + return len(digest) == 64 and all(char in "0123456789abcdef" for char in digest) diff --git a/apps/api/tests/test_ai_agent_runtime_worker_shadow_gate.py b/apps/api/tests/test_ai_agent_runtime_worker_shadow_gate.py new file mode 100644 index 000000000..ae1a3d5ff --- /dev/null +++ b/apps/api/tests/test_ai_agent_runtime_worker_shadow_gate.py @@ -0,0 +1,119 @@ +import copy +import json + +import pytest + +from src.services.ai_agent_runtime_worker_shadow_gate import ( + load_latest_ai_agent_runtime_worker_shadow_gate, +) + + +def _write_snapshot(tmp_path, payload): + path = tmp_path / "ai_agent_runtime_worker_shadow_gate_2026-06-12.json" + path.write_text(json.dumps(payload), encoding="utf-8") + return path + + +def test_load_latest_ai_agent_runtime_worker_shadow_gate(): + data = load_latest_ai_agent_runtime_worker_shadow_gate() + + assert data["schema_version"] == "ai_agent_runtime_worker_shadow_gate_v1" + assert data["program_status"]["current_task_id"] == "P2-404" + assert data["program_status"]["next_task_id"] == "P2-101" + assert data["program_status"]["overall_completion_percent"] == 96 + assert data["shadow_gate_truth"]["shadow_worker_evidence_gate_ready"] is True + assert data["shadow_gate_truth"]["promotion_from_fixture_readback_ready"] is True + assert data["shadow_gate_truth"]["no_write_replay_plan_ready"] is True + assert data["shadow_gate_truth"]["gateway_queue_write_enabled"] is False + assert data["shadow_gate_truth"]["telegram_send_enabled"] is False + assert data["shadow_gate_truth"]["telegram_bot_api_call_enabled"] is False + assert data["shadow_gate_truth"]["shadow_worker_live_enabled"] is False + assert data["shadow_gate_truth"]["ai_runtime_worker_enabled"] is False + assert data["shadow_gate_truth"]["medium_low_auto_worker_enabled"] is False + assert data["shadow_gate_truth"]["production_write_enabled"] is False + assert data["rollups"]["shadow_candidate_count"] == 5 + assert data["rollups"]["passed_no_write_candidate_count"] == 2 + assert data["rollups"]["blocked_candidate_count"] == 2 + assert data["rollups"]["needs_owner_review_candidate_count"] == 1 + assert data["rollups"]["no_write_replay_count"] == 4 + assert data["rollups"]["passed_no_write_replay_count"] == 2 + assert data["rollups"]["verifier_shadow_case_count"] == 4 + assert data["rollups"]["agent_role_count"] == 3 + assert data["rollups"]["operator_checkpoint_count"] == 6 + assert len(data["rollups"]["approval_required_checkpoint_ids"]) == 5 + assert data["rollups"]["shadow_worker_live_run_count"] == 0 + assert data["rollups"]["gateway_queue_write_count"] == 0 + assert data["rollups"]["telegram_send_count"] == 0 + assert data["rollups"]["telegram_bot_api_call_count"] == 0 + assert data["rollups"]["production_write_count"] == 0 + + +def test_rejects_telegram_send_enabled(tmp_path): + data = load_latest_ai_agent_runtime_worker_shadow_gate() + bad = copy.deepcopy(data) + bad["shadow_gate_truth"]["telegram_send_enabled"] = True + _write_snapshot(tmp_path, bad) + + with pytest.raises(ValueError, match="live write/send/runtime flags"): + load_latest_ai_agent_runtime_worker_shadow_gate(tmp_path) + + +def test_rejects_shadow_worker_live_count(tmp_path): + data = load_latest_ai_agent_runtime_worker_shadow_gate() + bad = copy.deepcopy(data) + bad["shadow_gate_truth"]["shadow_worker_live_run_count_24h"] = 1 + bad["rollups"]["shadow_worker_live_run_count"] = 1 + _write_snapshot(tmp_path, bad) + + with pytest.raises(ValueError, match="live write/send/runtime counts"): + load_latest_ai_agent_runtime_worker_shadow_gate(tmp_path) + + +def test_rejects_candidate_secret_read(tmp_path): + data = load_latest_ai_agent_runtime_worker_shadow_gate() + bad = copy.deepcopy(data) + bad["shadow_worker_candidates"][0]["reads_secret_value"] = True + _write_snapshot(tmp_path, bad) + + with pytest.raises(ValueError, match="secret value"): + load_latest_ai_agent_runtime_worker_shadow_gate(tmp_path) + + +def test_rejects_replay_side_effect(tmp_path): + data = load_latest_ai_agent_runtime_worker_shadow_gate() + bad = copy.deepcopy(data) + bad["no_write_execution_replays"][0]["production_side_effect_count"] = 1 + _write_snapshot(tmp_path, bad) + + with pytest.raises(ValueError, match="production_side_effect_count"): + load_latest_ai_agent_runtime_worker_shadow_gate(tmp_path) + + +def test_rejects_verifier_live_readback(tmp_path): + data = load_latest_ai_agent_runtime_worker_shadow_gate() + bad = copy.deepcopy(data) + bad["verifier_shadow_cases"][0]["live_readback_enabled"] = True + _write_snapshot(tmp_path, bad) + + with pytest.raises(ValueError, match="live readback"): + load_latest_ai_agent_runtime_worker_shadow_gate(tmp_path) + + +def test_rejects_raw_shadow_payload_display(tmp_path): + data = load_latest_ai_agent_runtime_worker_shadow_gate() + bad = copy.deepcopy(data) + bad["display_redaction_contract"]["raw_shadow_payload_display_allowed"] = True + _write_snapshot(tmp_path, bad) + + with pytest.raises(ValueError, match="display redaction"): + load_latest_ai_agent_runtime_worker_shadow_gate(tmp_path) + + +def test_rejects_rollup_mismatch(tmp_path): + data = load_latest_ai_agent_runtime_worker_shadow_gate() + bad = copy.deepcopy(data) + bad["rollups"]["shadow_candidate_count"] = 999 + _write_snapshot(tmp_path, bad) + + with pytest.raises(ValueError, match="rollup counts"): + load_latest_ai_agent_runtime_worker_shadow_gate(tmp_path) diff --git a/apps/api/tests/test_ai_agent_runtime_worker_shadow_gate_api.py b/apps/api/tests/test_ai_agent_runtime_worker_shadow_gate_api.py new file mode 100644 index 000000000..2da877723 --- /dev/null +++ b/apps/api/tests/test_ai_agent_runtime_worker_shadow_gate_api.py @@ -0,0 +1,32 @@ +from fastapi.testclient import TestClient + +from src.main import app + + +def test_get_ai_agent_runtime_worker_shadow_gate_api(): + client = TestClient(app) + response = client.get("/api/v1/agents/agent-runtime-worker-shadow-gate") + + assert response.status_code == 200 + data = response.json() + assert data["schema_version"] == "ai_agent_runtime_worker_shadow_gate_v1" + assert data["program_status"]["current_task_id"] == "P2-404" + assert data["program_status"]["next_task_id"] == "P2-101" + assert data["program_status"]["overall_completion_percent"] == 96 + assert data["shadow_gate_truth"]["shadow_worker_evidence_gate_ready"] is True + assert data["shadow_gate_truth"]["gateway_queue_write_enabled"] is False + assert data["shadow_gate_truth"]["telegram_send_enabled"] is False + assert data["shadow_gate_truth"]["telegram_bot_api_call_enabled"] is False + assert data["shadow_gate_truth"]["shadow_worker_live_enabled"] is False + assert data["shadow_gate_truth"]["ai_runtime_worker_enabled"] is False + assert data["shadow_gate_truth"]["production_write_enabled"] is False + assert data["rollups"]["shadow_candidate_count"] == 5 + assert data["rollups"]["no_write_replay_count"] == 4 + assert data["rollups"]["verifier_shadow_case_count"] == 4 + assert data["rollups"]["agent_role_count"] == 3 + assert data["rollups"]["operator_checkpoint_count"] == 6 + assert data["rollups"]["shadow_worker_live_run_count"] == 0 + assert data["rollups"]["gateway_queue_write_count"] == 0 + assert data["rollups"]["telegram_send_count"] == 0 + assert data["rollups"]["telegram_bot_api_call_count"] == 0 + assert data["rollups"]["production_write_count"] == 0 diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index d7f6151bd..f79c32de9 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -4320,6 +4320,59 @@ "high": "高風險", "critical": "關鍵阻擋" } + }, + "runtimeWorkerShadowGate": { + "title": "P2-404 runtime worker shadow / no-write execution evidence gate", + "source": "{generated} · {current} → {next}", + "truthTitle": "shadow gate 真相", + "boundaryTitle": "live 邊界", + "boundarySummary": "目前 live worker {live}、Gateway queue write {queue}、Telegram send {send}、production write {write};這段只允許 shadow/no-write evidence。", + "metrics": { + "overall": "P2-404 進度", + "candidates": "shadow 候選", + "passed": "no-write 通過", + "blocked": "阻擋候選", + "review": "需審查", + "replays": "no-write replay", + "verifierCases": "verifier cases", + "approvals": "需批准", + "liveRuns": "live worker", + "queueWrites": "queue writes", + "sends": "Telegram sends", + "productionWrites": "prod writes" + }, + "flags": { + "shadowReady": "shadow evidence: {value}", + "promotionReady": "fixture promotion: {value}", + "replayReady": "no-write replay: {value}", + "operatorReview": "operator packet: {value}", + "shadowLive": "shadow live: {value}", + "queueWrite": "queue write: {value}", + "send": "send: {value}", + "productionWrite": "prod write: {value}", + "secret": "secret value: {value}", + "resultWrite": "result write: {value}", + "verifier": "verifier live: {value}" + }, + "labels": { + "promotionHash": "promotion: {value}", + "evidenceHash": "evidence: {value}", + "approvalRequired": "需審核: {value}", + "liveCount": "live {count}", + "sideEffect": "side effects {count}" + }, + "statuses": { + "passed_no_write_replay": "no-write replay 通過", + "passed_no_write": "no-write 通過", + "needs_owner_review": "需 owner 審查", + "blocked_by_runtime_gate": "runtime 阻擋" + }, + "riskTiers": { + "low": "低風險", + "medium": "中風險", + "high": "高風險", + "critical": "關鍵阻擋" + } } } }, diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index d7f6151bd..f79c32de9 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -4320,6 +4320,59 @@ "high": "高風險", "critical": "關鍵阻擋" } + }, + "runtimeWorkerShadowGate": { + "title": "P2-404 runtime worker shadow / no-write execution evidence gate", + "source": "{generated} · {current} → {next}", + "truthTitle": "shadow gate 真相", + "boundaryTitle": "live 邊界", + "boundarySummary": "目前 live worker {live}、Gateway queue write {queue}、Telegram send {send}、production write {write};這段只允許 shadow/no-write evidence。", + "metrics": { + "overall": "P2-404 進度", + "candidates": "shadow 候選", + "passed": "no-write 通過", + "blocked": "阻擋候選", + "review": "需審查", + "replays": "no-write replay", + "verifierCases": "verifier cases", + "approvals": "需批准", + "liveRuns": "live worker", + "queueWrites": "queue writes", + "sends": "Telegram sends", + "productionWrites": "prod writes" + }, + "flags": { + "shadowReady": "shadow evidence: {value}", + "promotionReady": "fixture promotion: {value}", + "replayReady": "no-write replay: {value}", + "operatorReview": "operator packet: {value}", + "shadowLive": "shadow live: {value}", + "queueWrite": "queue write: {value}", + "send": "send: {value}", + "productionWrite": "prod write: {value}", + "secret": "secret value: {value}", + "resultWrite": "result write: {value}", + "verifier": "verifier live: {value}" + }, + "labels": { + "promotionHash": "promotion: {value}", + "evidenceHash": "evidence: {value}", + "approvalRequired": "需審核: {value}", + "liveCount": "live {count}", + "sideEffect": "side effects {count}" + }, + "statuses": { + "passed_no_write_replay": "no-write replay 通過", + "passed_no_write": "no-write 通過", + "needs_owner_review": "需 owner 審查", + "blocked_by_runtime_gate": "runtime 阻擋" + }, + "riskTiers": { + "low": "低風險", + "medium": "中風險", + "high": "高風險", + "critical": "關鍵阻擋" + } } } }, 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 d72e646c5..cd7d65695 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 @@ -50,6 +50,7 @@ import { type AiAgentReportRuntimeFixtureReadbackSnapshot, type AiAgentReportRuntimeReadinessSnapshot, type AiAgentReportTruthActionabilityReviewSnapshot, + type AiAgentRuntimeWorkerShadowGateSnapshot, type AiAgentRuntimeVerifierEvidenceReviewSnapshot, type AiAgentRuntimeWriteGateReviewSnapshot, type AiAgentTelegramReceiptApprovalPackageSnapshot, @@ -344,6 +345,7 @@ export function AutomationInventoryTab() { const [reportRuntimeReadiness, setReportRuntimeReadiness] = useState(null) const [reportRuntimeDryRun, setReportRuntimeDryRun] = useState(null) const [reportRuntimeFixtureReadback, setReportRuntimeFixtureReadback] = useState(null) + const [runtimeWorkerShadowGate, setRuntimeWorkerShadowGate] = useState(null) const [reportTruthActionabilityReview, setReportTruthActionabilityReview] = useState(null) const [ownerDryRunPackage, setOwnerDryRunPackage] = useState(null) const [hostStatefulInventory, setHostStatefulInventory] = useState(null) @@ -380,6 +382,7 @@ export function AutomationInventoryTab() { apiClient.getAiAgentReportRuntimeReadiness(), apiClient.getAiAgentReportRuntimeDryRun(), apiClient.getAiAgentReportRuntimeFixtureReadback(), + apiClient.getAiAgentRuntimeWorkerShadowGate(), apiClient.getAiAgentReportTruthActionabilityReview(), apiClient.getAiAgentOwnerApprovedFixtureDryRun(), apiClient.getAiAgentHostStatefulVersionInventory(), @@ -415,6 +418,7 @@ export function AutomationInventoryTab() { reportRuntimeReadinessResult, reportRuntimeDryRunResult, reportRuntimeFixtureReadbackResult, + runtimeWorkerShadowGateResult, reportTruthActionabilityReviewResult, ownerDryRunPackageResult, hostStatefulInventoryResult, @@ -447,6 +451,7 @@ export function AutomationInventoryTab() { setReportRuntimeReadiness(reportRuntimeReadinessResult.status === 'fulfilled' ? reportRuntimeReadinessResult.value : null) setReportRuntimeDryRun(reportRuntimeDryRunResult.status === 'fulfilled' ? reportRuntimeDryRunResult.value : null) setReportRuntimeFixtureReadback(reportRuntimeFixtureReadbackResult.status === 'fulfilled' ? reportRuntimeFixtureReadbackResult.value : null) + setRuntimeWorkerShadowGate(runtimeWorkerShadowGateResult.status === 'fulfilled' ? runtimeWorkerShadowGateResult.value : null) setReportTruthActionabilityReview(reportTruthActionabilityReviewResult.status === 'fulfilled' ? reportTruthActionabilityReviewResult.value : null) setOwnerDryRunPackage(ownerDryRunPackageResult.status === 'fulfilled' ? ownerDryRunPackageResult.value : null) setHostStatefulInventory(hostStatefulInventoryResult.status === 'fulfilled' ? hostStatefulInventoryResult.value : null) @@ -477,6 +482,7 @@ export function AutomationInventoryTab() { reportRuntimeReadinessResult, reportRuntimeDryRunResult, reportRuntimeFixtureReadbackResult, + runtimeWorkerShadowGateResult, reportTruthActionabilityReviewResult, ownerDryRunPackageResult, hostStatefulInventoryResult, @@ -999,6 +1005,48 @@ export function AutomationInventoryTab() { .slice(0, 5) }, [reportRuntimeFixtureReadback]) + const visibleRuntimeWorkerShadowCandidates = useMemo(() => { + if (!runtimeWorkerShadowGate) return [] + const statusPriority = { blocked_by_runtime_gate: 0, needs_owner_review: 1, passed_no_write_replay: 2 } as Record + return [...runtimeWorkerShadowGate.shadow_worker_candidates] + .sort((a, b) => { + const left = statusPriority[a.shadow_status] ?? 3 + const right = statusPriority[b.shadow_status] ?? 3 + if (left !== right) return left - right + return a.candidate_id.localeCompare(b.candidate_id) + }) + .slice(0, 5) + }, [runtimeWorkerShadowGate]) + + const visibleRuntimeWorkerShadowReplays = useMemo(() => { + if (!runtimeWorkerShadowGate) return [] + const statusPriority = { blocked_by_runtime_gate: 0, passed_no_write: 1 } as Record + return [...runtimeWorkerShadowGate.no_write_execution_replays] + .sort((a, b) => { + const left = statusPriority[a.replay_status] ?? 2 + const right = statusPriority[b.replay_status] ?? 2 + if (left !== right) return left - right + return a.replay_id.localeCompare(b.replay_id) + }) + }, [runtimeWorkerShadowGate]) + + const visibleRuntimeWorkerShadowCheckpoints = useMemo(() => { + if (!runtimeWorkerShadowGate) return [] + const statusPriority = { blocked_by_runtime_gate: 0, needs_owner_review: 1, passed_no_write: 2 } as Record + const riskPriority = { critical: 0, high: 1, medium: 2, low: 3 } as Record + return [...runtimeWorkerShadowGate.operator_checkpoints] + .sort((a, b) => { + const left = statusPriority[a.status] ?? 3 + const right = statusPriority[b.status] ?? 3 + if (left !== right) return left - right + const leftRisk = riskPriority[a.risk_tier] ?? 4 + const rightRisk = riskPriority[b.risk_tier] ?? 4 + if (leftRisk !== rightRisk) return leftRisk - rightRisk + return a.checkpoint_id.localeCompare(b.checkpoint_id) + }) + .slice(0, 6) + }, [runtimeWorkerShadowGate]) + const visibleReportTruthFindings = useMemo(() => { if (!reportTruthActionabilityReview) return [] const priority = { critical: 0, high: 1, medium: 2, low: 3 } as Record @@ -1218,7 +1266,7 @@ export function AutomationInventoryTab() { ) } - if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !proactiveOperations || !interactionLearningProof || !liveReadModelGate || !redisDryRunGate || !learningWritebackPackage || !telegramReceiptPackage || !ownerApprovedLearningDryRun || !runtimeWriteGateReview || !postWriteVerifierPackage || !runtimeVerifierEvidenceReview || !reportAutomationReview || !reportRuntimeReadiness || !reportRuntimeDryRun || !reportRuntimeFixtureReadback || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) { + if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !proactiveOperations || !interactionLearningProof || !liveReadModelGate || !redisDryRunGate || !learningWritebackPackage || !telegramReceiptPackage || !ownerApprovedLearningDryRun || !runtimeWriteGateReview || !postWriteVerifierPackage || !runtimeVerifierEvidenceReview || !reportAutomationReview || !reportRuntimeReadiness || !reportRuntimeDryRun || !reportRuntimeFixtureReadback || !runtimeWorkerShadowGate || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) { return (
@@ -1400,6 +1448,18 @@ export function AutomationInventoryTab() { const reportFixtureWorkerRuns = reportRuntimeFixtureReadback.rollups.ai_runtime_worker_run_count const reportFixtureVerifierLive = reportRuntimeFixtureReadback.rollups.post_action_verifier_live_readback_count const reportFixturePrimaryReadback = visibleReportRuntimeQueueReadbacks[0] + const runtimeShadowOverall = runtimeWorkerShadowGate.program_status.overall_completion_percent + const runtimeShadowCandidates = runtimeWorkerShadowGate.rollups.shadow_candidate_count + const runtimeShadowPassed = runtimeWorkerShadowGate.rollups.passed_no_write_candidate_count + const runtimeShadowBlocked = runtimeWorkerShadowGate.rollups.blocked_candidate_count + const runtimeShadowNeedsReview = runtimeWorkerShadowGate.rollups.needs_owner_review_candidate_count + const runtimeShadowReplays = runtimeWorkerShadowGate.rollups.no_write_replay_count + const runtimeShadowVerifierCases = runtimeWorkerShadowGate.rollups.verifier_shadow_case_count + const runtimeShadowApprovals = runtimeWorkerShadowGate.rollups.approval_required_checkpoint_ids.length + const runtimeShadowLiveRuns = runtimeWorkerShadowGate.rollups.shadow_worker_live_run_count + const runtimeShadowQueueWrites = runtimeWorkerShadowGate.rollups.gateway_queue_write_count + const runtimeShadowSends = runtimeWorkerShadowGate.rollups.telegram_send_count + const runtimeShadowProductionWrites = runtimeWorkerShadowGate.rollups.production_write_count const reportTruthOverall = reportTruthActionabilityReview.program_status.overall_completion_percent const reportTruthFindings = reportTruthActionabilityReview.rollups.zero_signal_finding_count const reportTruthCritical = reportTruthActionabilityReview.rollups.critical_finding_count @@ -2648,6 +2708,189 @@ export function AutomationInventoryTab() {
+
+
+
+ + + {t('runtimeWorkerShadowGate.title')} + +
+ +
+ +
+ } /> + } /> + } /> + 0 ? 'danger' : 'ok'} icon={} /> + 0 ? 'warn' : 'ok'} icon={} /> + } /> + } /> + 0 ? 'danger' : 'ok'} icon={} /> + } /> + } /> + } /> + } /> +
+ +
+
+ {t('runtimeWorkerShadowGate.truthTitle')} + + {runtimeWorkerShadowGate.shadow_gate_truth.truth_note} + +
+ + + + +
+
+ +
+ {t('runtimeWorkerShadowGate.boundaryTitle')} + + {t('runtimeWorkerShadowGate.boundarySummary', { + live: runtimeShadowLiveRuns, + queue: runtimeShadowQueueWrites, + send: runtimeShadowSends, + write: runtimeShadowProductionWrites, + })} + +
+ + + + + +
+
+
+ +
+ {visibleRuntimeWorkerShadowCandidates.map(candidate => ( +
+
+ + {candidate.display_name} + + +
+
+ + + +
+ + {candidate.blocked_reason} + + + {candidate.next_no_write_step} + + +
+ ))} +
+ +
+ {visibleRuntimeWorkerShadowReplays.map(replay => ( +
+
+ + {replay.display_name} + + +
+
+ + + + +
+ + {replay.simulated_outcome} + + +
+ ))} +
+ +
+ {runtimeWorkerShadowGate.agent_shadow_roles.map(role => ( +
+
+ + {role.display_name} + + +
+ + {role.shadow_responsibility} + +
+ {role.observed_work.slice(0, 2).map(item => ( + + ))} + {role.blocked_now.slice(0, 2).map(item => ( + + ))} +
+
+ ))} +
+ +
+ {runtimeWorkerShadowGate.verifier_shadow_cases.map(verifierCase => ( +
+
+ + {verifierCase.display_name} + + +
+
+ + + +
+ + {verifierCase.observed_signal} + + +
+ ))} +
+ +
+ {visibleRuntimeWorkerShadowCheckpoints.map(checkpoint => ( +
+
+ + {checkpoint.display_name} + + +
+
+ + + +
+ + {checkpoint.next_safe_step} + +
+ ))} +
+
+
diff --git a/apps/web/src/lib/api-client.ts b/apps/web/src/lib/api-client.ts index 971450a35..d5bad7b46 100644 --- a/apps/web/src/lib/api-client.ts +++ b/apps/web/src/lib/api-client.ts @@ -342,6 +342,11 @@ export const apiClient = { return handleResponse(res) }, + async getAiAgentRuntimeWorkerShadowGate() { + const res = await fetch(`${API_BASE_URL}/agents/agent-runtime-worker-shadow-gate`) + return handleResponse(res) + }, + async getAiAgentOwnerApprovedFixtureDryRun() { const res = await fetch(`${API_BASE_URL}/agents/agent-owner-approved-fixture-dry-run`) return handleResponse(res) @@ -2461,6 +2466,142 @@ export interface AiAgentReportRuntimeFixtureReadbackSnapshot { } } +export interface AiAgentRuntimeWorkerShadowGateSnapshot { + schema_version: 'ai_agent_runtime_worker_shadow_gate_v1' + generated_at: string + program_status: { + overall_completion_percent: number + current_priority: 'P0' | 'P1' | 'P2' | 'P3' + current_task_id: 'P2-404' + next_task_id: 'P2-101' + read_only_mode: true + runtime_authority: 'runtime_worker_shadow_no_write_execution_evidence_gate_only_no_live_send_or_write' + status_note: string + } + source_refs: string[] + shadow_gate_truth: { + shadow_worker_evidence_gate_ready: true + promotion_from_fixture_readback_ready: true + no_write_replay_plan_ready: true + action_candidate_selection_ready: true + mcp_evidence_reuse_ready: true + verifier_dry_run_binding_ready: true + failure_lane_ready: true + operator_review_packet_ready: true + production_delivery_enabled: false + gateway_queue_write_enabled: false + telegram_send_enabled: false + telegram_bot_api_call_enabled: false + delivery_receipt_write_enabled: false + shadow_worker_live_enabled: false + ai_runtime_worker_enabled: false + medium_low_auto_worker_enabled: false + post_action_verifier_live_readback_enabled: false + production_write_enabled: false + secret_value_read_enabled: false + work_window_transcript_display_allowed: false + shadow_worker_live_run_count_24h: number + gateway_queue_write_count_24h: number + telegram_send_count_24h: number + telegram_bot_api_call_count_24h: number + delivery_receipt_write_count_24h: number + ai_runtime_worker_run_count_24h: number + medium_low_auto_execution_count_24h: number + post_action_verifier_live_readback_count_24h: number + production_write_count_24h: number + truth_note: string + } + shadow_worker_candidates: Array<{ + candidate_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + source_fixture_id: string + target_surface: string + shadow_status: 'passed_no_write_replay' | 'needs_owner_review' | 'blocked_by_runtime_gate' + promotion_hash: string + dry_run_ref: string + writes_production: false + sends_telegram: false + reads_secret_value: false + live_shadow_run_count_24h: number + blocked_reason: string + next_no_write_step: string + }> + no_write_execution_replays: Array<{ + replay_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + input_source: string + expected_action: string + simulated_outcome: string + replay_status: 'passed_no_write' | 'blocked_by_runtime_gate' + evidence_hash: string + verifier_bound: true + writes_result: false + production_side_effect_count: number + }> + verifier_shadow_cases: Array<{ + case_id: string + display_name: string + owner_agent: 'hermes' | 'nemotron' + expected_signal: string + observed_signal: string + evidence_hash: string + live_readback_enabled: false + writes_result: false + requires_secret_value: false + }> + agent_shadow_roles: Array<{ + agent_id: 'openclaw' | 'hermes' | 'nemotron' + display_name: string + shadow_responsibility: string + observed_work: string[] + blocked_now: string[] + live_action_count_24h: number + }> + operator_checkpoints: Array<{ + checkpoint_id: string + display_name: string + owner_agent: 'openclaw' | 'hermes' | 'nemotron' + risk_tier: 'low' | 'medium' | 'high' | 'critical' + approval_required: boolean + status: 'passed_no_write' | 'needs_owner_review' | 'blocked_by_runtime_gate' + next_safe_step: string + }> + display_redaction_contract: { + redaction_required: true + raw_report_payload_display_allowed: false + raw_telegram_payload_display_allowed: false + raw_shadow_payload_display_allowed: false + private_reasoning_display_allowed: false + secret_value_display_allowed: false + work_window_transcript_display_allowed: false + allowed_display_fields: string[] + blocked_display_fields: string[] + } + rollups: { + shadow_candidate_count: number + passed_no_write_candidate_count: number + blocked_candidate_count: number + needs_owner_review_candidate_count: number + no_write_replay_count: number + passed_no_write_replay_count: number + verifier_shadow_case_count: number + agent_role_count: number + operator_checkpoint_count: number + approval_required_checkpoint_ids: string[] + shadow_worker_live_run_count: number + gateway_queue_write_count: number + telegram_send_count: number + telegram_bot_api_call_count: number + delivery_receipt_write_count: number + ai_runtime_worker_run_count: number + medium_low_auto_execution_count: number + post_action_verifier_live_readback_count: number + production_write_count: number + } +} + export interface AiAgentOwnerApprovedFixtureDryRunSnapshot { schema_version: 'ai_agent_owner_approved_fixture_dry_run_v1' generated_at: string diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 541270f71..a9ec57f4b 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,33 @@ +## 2026-06-12|P2-404 runtime worker shadow / no-write execution evidence gate + +**背景**:P2-403N 已把報表 dry-run 草案提升到 fixture smoke、queue preview readback 與 verifier dry-run;統帥要求不要停在報表與 UI,而要往真正 AI Agent 自動化流程推進。本段將 P2-403N 的 promotion 轉成 runtime worker shadow / no-write execution evidence gate,但仍不啟動 live worker 或任何 production write。 + +**完成(本地)**: + +- 新增 `ai_agent_runtime_worker_shadow_gate_v1` schema、committed snapshot 與 backend loader,強制 shadow live worker、Gateway queue write、Telegram send、Bot API、delivery receipt write、AI runtime worker、中低風險 auto worker、verifier live readback、production write、secret value read 與內部對話顯示全部維持 `false / 0`。 +- 新增 `GET /api/v1/agents/agent-runtime-worker-shadow-gate` 只讀 API 與測試;API 只回傳 shadow candidate、no-write replay、verifier shadow case、Agent role 與 operator checkpoint,不寫 queue、不送 Telegram、不啟動 worker。 +- 治理頁 `/zh-TW/governance?tab=automation-inventory` 新增 P2-404 區塊,顯示 5 個 shadow candidate、4 個 no-write replay、4 個 verifier shadow case、OpenClaw / Hermes / NemoTron shadow 分工與 6 個 operator checkpoint。 +- 更新 `AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md`、`AI_AGENT_INTERACTION_LEARNING_PROOF_2026-06-11.md` 與 MASTER §3.2 / §5,將 P2-404 標記為完成,下一步改為 `P2-101` 操作類別權限模型。 + +**驗證(本地)**: + +- `python3 -m json.tool` 檢查 P2-404 snapshot / schema / `zh-TW.json` / `en.json` 通過。 +- `python3 -m py_compile apps/api/src/services/ai_agent_runtime_worker_shadow_gate.py apps/api/src/api/v1/agents.py` 通過。 +- `DATABASE_URL='postgresql+asyncpg://test:test@localhost/test' PYTHONPATH=apps/api pytest -q apps/api/tests/test_ai_agent_runtime_worker_shadow_gate.py apps/api/tests/test_ai_agent_runtime_worker_shadow_gate_api.py`:`9 passed`。 +- `cmp -s apps/web/messages/zh-TW.json apps/web/messages/en.json` 通過,兩份訊息檔維持繁體中文鏡像。 +- `pnpm --filter @awoooi/web typecheck` 通過;未執行 production build。 +- `git diff --check`、`source-control-owner-response-guard.py`、`security-mirror-progress-guard.py` 通過。 + +**完成度同步**: + +- P2-404:本地完成度 `96%`;shadow candidate `5`、passed no-write candidate `2`、blocked candidate `2`、needs owner review `1`、no-write replay `4`、verifier shadow case `4`、operator checkpoint `6`。 +- shadow live worker、Gateway queue write、Telegram send、Telegram Bot API、delivery receipt write、AI runtime worker、中低風險 auto worker、verifier live readback、production write:全部仍為 `0`。 +- P2-101:下一步要定義操作類別權限模型;完成前不得 live worker、queue write、Telegram send、production write 或 verifier live readback。 + +**正式站狀態**:本段尚未推送 Gitea / 未觸發 CD / 未做 production smoke;依 110 主機負載協調,重啟前先避免新增 heavy CD/build。 + +**邊界**:本段不送 Telegram、不寫 Gateway queue、不呼叫 Bot API、不寫 delivery receipt、不啟動 live AI runtime worker、不啟動中低風險 auto worker、不跑 verifier live readback、不讀 secret、不顯示內部對話內容、不提供前端批准 / 執行 / 發送按鈕;不得把 shadow/no-write evidence 解讀成 runtime loop 已運作。 + ## 2026-06-12|P2-403N fixture smoke / queue preview readback / verifier dry-run **背景**:P2-403M 已建立報表 runtime no-write dry-run、SRE 戰情室 Gateway queue 草案與 readback verifier 草案;本段依序推進 P2-403N,把 committed dry-run 證據轉成 fixture smoke、queue preview readback 與 verifier dry-run 的可審查證據。 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 63ba434f2..0f6a381e8 100644 --- a/docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md +++ b/docs/ai/AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md @@ -20,9 +20,9 @@ AI Agent 自動化工作包目前完成度:**92%**。本工作清單文件本 三 Agent 佈建布局目前完成度:**45%**。第一波已完成只讀 schema / snapshot / API / 測試 / 報告,第二波已接入治理頁自動化盤點 UI;正式 runtime 佈署、Telegram E2E 發送與 AgentSession 工作流仍需逐項 gate。 -三 Agent 主動溝通、學習與成長證據目前完成度:**100%**。已完成只讀契約、互動 / 接手 / 學習 / 成長證據面板、P2-403B live read model gate、P2-403C Redis dry-run gate、P2-403D learning writeback approval package、P2-403E Telegram receipt approval package、P2-403F owner-approved learning dry-run preview、人工操作選項與 fixture-only dry-run 總包、P2-403G runtime write gate review、P2-403H post-write verifier implementation package、P2-403I runtime verifier evidence implementation review、P2-403J 報表真相 / 告警有效性 / 日週月報 / Agent 工作量 / 圖表化報告 / AI 建議 / 風險自動化政策審查、P2-403K SRE 戰情室路由程式收斂、P2-403L 報表派送 / Telegram queue / 讀報回執 / AI 讀報分析 / 中低風險自動處理 / 高風險審核啟動前閘門、P2-403M no-write dry-run / SRE 戰情室 Gateway queue 草案 / readback verifier,以及 P2-403N fixture smoke / queue preview readback / verifier dry-run;目前 live AgentSession、Agent message、handoff、learning write、Telegram receipt、Gateway queue write、runtime verifier execution、report delivery、AI analysis runtime、中低風險 auto worker、Telegram 實發與 delivery receipt E2E 仍全部為 `0`,下一步依優先順序推 `P2-404` runtime worker shadow / no-write execution evidence gate,但在批准前仍不得啟動 runtime loop。 +三 Agent 主動溝通、學習與成長證據目前完成度:**100%**。已完成只讀契約、互動 / 接手 / 學習 / 成長證據面板、P2-403B live read model gate、P2-403C Redis dry-run gate、P2-403D learning writeback approval package、P2-403E Telegram receipt approval package、P2-403F owner-approved learning dry-run preview、人工操作選項與 fixture-only dry-run 總包、P2-403G runtime write gate review、P2-403H post-write verifier implementation package、P2-403I runtime verifier evidence implementation review、P2-403J 報表真相 / 告警有效性 / 日週月報 / Agent 工作量 / 圖表化報告 / AI 建議 / 風險自動化政策審查、P2-403K SRE 戰情室路由程式收斂、P2-403L 報表派送 / Telegram queue / 讀報回執 / AI 讀報分析 / 中低風險自動處理 / 高風險審核啟動前閘門、P2-403M no-write dry-run / SRE 戰情室 Gateway queue 草案 / readback verifier、P2-403N fixture smoke / queue preview readback / verifier dry-run,以及 P2-404 runtime worker shadow / no-write execution evidence gate;目前 live AgentSession、Agent message、handoff、learning write、Telegram receipt、Gateway queue write、runtime verifier execution、report delivery、AI analysis runtime、中低風險 auto worker、Telegram 實發、shadow worker live 與 delivery receipt E2E 仍全部為 `0`,下一步依優先順序推 `P2-101` 操作類別權限模型,但在批准前仍不得啟動 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-403N` 已先補互動、學習證據面、live read model gate、Redis dry-run gate、learning writeback approval package、Telegram receipt approval package、owner-approved learning dry-run preview、runtime write gate review、post-write verifier package、runtime verifier evidence review、報表真相、TG 戰情室收斂、日週月報、Agent 工作量、圖表化報告、風險自動化政策、報表 runtime 啟動前閘門、no-write dry-run 證據包與 fixture/readback/verifier dry-run 證據包。下一步是 `P2-404` runtime worker shadow / no-write execution evidence gate,外部 registry / package source / host probe / SSH / kubectl / 工具安裝 / CI 變更 / 實際 PR creation / Telegram 實發與 learning write 仍需 gate。 +AI Agent 主動營運委派與版本生命週期目前完成度:**100%**。已完成 12 類版本 domain、24 類可委派能力、5 種 cadence、8 類 MCP、4 類 RAG memory、只讀 API、`P2-402B` repo-only daily version freshness snapshot、`P2-402C` Renovate / OSV-Scanner / Trivy / Syft / Grype 工具採用批准包、`P2-402D` Telegram action-required digest policy、`P2-402E` Gitea PR 草案 lane、`P2-402F` host OS / K3s / stateful services 版本只讀盤點,以及 `P2-402G` governance UI 顯示可委派能力;`P2-403A` 到 `P2-404` 已先補互動、學習證據面、live read model gate、Redis dry-run gate、learning writeback approval package、Telegram receipt approval package、owner-approved learning dry-run preview、runtime write gate review、post-write verifier package、runtime verifier evidence review、報表真相、TG 戰情室收斂、日週月報、Agent 工作量、圖表化報告、風險自動化政策、報表 runtime 啟動前閘門、no-write dry-run 證據包、fixture/readback/verifier dry-run 證據包與 shadow/no-write execution gate。下一步是 `P2-101` 操作類別權限模型,外部 registry / package source / host probe / SSH / kubectl / 工具安裝 / CI 變更 / 實際 PR creation / Telegram 實發與 learning write 仍需 gate。 完成度計算模型: @@ -972,7 +972,7 @@ UI: | P2-403L | 完成 | 86 | OpenClaw + Hermes + NemoTron | 報表派送、Telegram Gateway queue、讀報回執、AI 讀報後分析、中低風險自動處理、高風險審核與 post-action verifier 啟動前閘門 | `ai_agent_report_runtime_readiness_v1` / snapshot / 只讀 API / governance UI;7 個 runtime lane、3 個報表週期 gate、4 個風險政策、7 個 operator decision、SRE 戰情室路由 contract;live delivery / queue write / AI runtime / 中低風險執行全部 `0` | 不排程實發、不寫 Gateway queue、不呼叫 Bot API、不啟動 AI runtime worker、不啟動中低風險 auto worker、不執行生產優化、不讀 secret、不顯示內部對話內容 | | P2-403M | 完成 | 91 | OpenClaw + Hermes + NemoTron | 報表 runtime no-write dry-run、SRE 戰情室 Gateway queue 草案、readback verifier 草案 | `ai_agent_report_runtime_dry_run_v1` / snapshot / 只讀 API / governance UI;5 個 dry-run artifact、3 個 queue digest 草案、4 個 readback verifier case、3 個 Agent dry-run role、6 個 operator checkpoint;live delivery / queue write / Bot API / receipt write / AI runtime / 中低風險 auto worker / verifier live readback 全部 `0` | 不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 delivery receipt、不啟動 AI runtime worker、不啟動中低風險 auto worker、不執行 verifier live readback、不讀 secret、不顯示內部對話內容 | | P2-403N | 完成 | 94 | Hermes + NemoTron + OpenClaw | fixture smoke / queue preview readback / verifier dry-run | `ai_agent_report_runtime_fixture_readback_v1` / snapshot / 只讀 API / governance UI;5 個 fixture smoke、3 個 queue preview readback、4 個 verifier dry-run case、3 個 Agent fixture role、5 個 operator checkpoint;live delivery / queue write / Telegram send / Bot API / receipt write / AI runtime / 中低風險 auto worker / verifier live readback 全部 `0` | 仍不得 live send / live write;中低風險自動處理與高風險審核需另行批准 | -| P2-404 | 待辦 | 0 | OpenClaw + Hermes + NemoTron | runtime worker shadow / no-write execution evidence gate | 以 P2-403N fixture/readback/verifier dry-run promotion 建立 shadow worker evidence | 不寫 Gateway queue、不送 Telegram、不 production write;所有 shadow result 需 redacted evidence 與 verifier dry-run | +| P2-404 | 完成 | 96 | OpenClaw + Hermes + NemoTron | runtime worker shadow / no-write execution evidence gate | `ai_agent_runtime_worker_shadow_gate_v1` / snapshot / 只讀 API / governance UI;5 個 shadow candidate、4 個 no-write replay、4 個 verifier shadow case、3 個 Agent shadow role、6 個 operator checkpoint;shadow live / Gateway queue write / Telegram send / Bot API / receipt write / AI runtime / 中低風險 auto worker / verifier live readback / production write 全部 `0` | 下一步 P2-101 操作類別權限模型;未完成前不得 live worker、queue write、Telegram send 或 production write | | 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 26ec7f349..2b605a196 100644 --- a/docs/ai/AI_AGENT_INTERACTION_LEARNING_PROOF_2026-06-11.md +++ b/docs/ai/AI_AGENT_INTERACTION_LEARNING_PROOF_2026-06-11.md @@ -1,8 +1,8 @@ # AI Agent 互動、溝通、學習與成長證據報告 > 日期:2026-06-11(台北時間) -> 文件定位:P2-403A 證據面 + P2-403B AgentSession / Redis Streams live read model gate + P2-403C Redis dry-run gate + P2-403D learning writeback approval package + P2-403E Telegram receipt approval package + P2-403F owner-approved learning dry-run / fixture dry-run、P2-403G runtime write gate review、P2-403H post-write verifier package、P2-403I runtime verifier evidence implementation review、P2-403J 報表真相 / 日週月報 / Agent 工作量 / 風險自動化 review、P2-403L 報表派送與自動處理啟動前閘門、P2-403M 報表 runtime no-write dry-run 證據包、P2-403N fixture smoke / queue preview readback / verifier dry-run、API 與治理頁 UI。 -> 事實邊界:本波只建立可見證據面、read model gate、報表治理 review、runtime readiness gate、no-write dry-run 與 fixture/readback/verifier dry-run 證據包,不啟動 runtime worker、不建立 DB migration、不開 Redis consumer group、不發 Telegram、不寫 Gateway queue、不寫 delivery receipt、不排程實發報告、不啟動中低風險 auto worker、不執行 verifier live readback、不執行生產優化、不顯示工作視窗對話內容。 +> 文件定位:P2-403A 證據面 + P2-403B AgentSession / Redis Streams live read model gate + P2-403C Redis dry-run gate + P2-403D learning writeback approval package + P2-403E Telegram receipt approval package + P2-403F owner-approved learning dry-run / fixture dry-run、P2-403G runtime write gate review、P2-403H post-write verifier package、P2-403I runtime verifier evidence implementation review、P2-403J 報表真相 / 日週月報 / Agent 工作量 / 風險自動化 review、P2-403L 報表派送與自動處理啟動前閘門、P2-403M 報表 runtime no-write dry-run 證據包、P2-403N fixture smoke / queue preview readback / verifier dry-run、P2-404 runtime worker shadow / no-write execution evidence gate、API 與治理頁 UI。 +> 事實邊界:本波只建立可見證據面、read model gate、報表治理 review、runtime readiness gate、no-write dry-run、fixture/readback/verifier dry-run 與 shadow/no-write execution 證據包,不啟動 runtime worker、不建立 DB migration、不開 Redis consumer group、不發 Telegram、不寫 Gateway queue、不寫 delivery receipt、不排程實發報告、不啟動中低風險 auto worker、不執行 verifier live readback、不執行生產優化、不顯示工作視窗對話內容。 ## 0. P2-403J 補記:報表真相、日週月報與風險自動化 Review @@ -28,9 +28,15 @@ 本段把 P2-403M committed dry-run 證據轉成可審查 fixture/readback/verifier 證據:5 個 fixture smoke、3 個 SRE 戰情室 queue preview readback、4 個 verifier dry-run case、3 個 Agent fixture role 與 5 個 operator checkpoint。Hermes 負責 report snapshot / Telegram digest / queue preview / receipt redaction 的 readback hash;NemoTron 負責 verifier dry-run 與 no-op replay failure mode;OpenClaw 負責判斷哪些 promotion 必須保持 no-write 或等待高風險審核。本段仍不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 delivery receipt、不啟動 AI runtime worker、不啟動中低風險 auto worker、不跑 verifier live readback、不讀 secret,所有 live count 仍為 `0`。 +## 0.4 P2-404 補記:runtime worker shadow / no-write execution evidence gate + +2026-06-12 已新增 P2-404:`ai_agent_runtime_worker_shadow_gate_v1`、`docs/evaluations/ai_agent_runtime_worker_shadow_gate_2026-06-12.json`、`GET /api/v1/agents/agent-runtime-worker-shadow-gate` 與治理頁區塊。 + +本段把 P2-403N fixture/readback/verifier dry-run promotion 成 shadow worker no-write 證據:5 個 shadow candidate、4 個 no-write replay、4 個 verifier shadow case、3 個 Agent shadow role 與 6 個 operator checkpoint。Hermes 負責日週月報與 SRE 戰情室 queue candidate preview;OpenClaw 負責中低風險 no-op action 分類與 P2-101 操作權限模型 handoff;NemoTron 負責 shadow candidate 的 verifier binding、failure lane 與 no-write replay hash。本段仍不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 delivery receipt、不啟動 live AI runtime worker、不啟動中低風險 auto worker、不跑 verifier live readback、不讀 secret,所有 live count 仍為 `0`。 + ## 1. 結論 -已完成 P2-403A、P2-403B、P2-403C、P2-403D、P2-403E、P2-403F、P2-403G、P2-403H、P2-403I、P2-403J、P2-403L、P2-403M 與 P2-403N:讓統帥能在治理頁看到 OpenClaw / Hermes / NemoTron 的互動、接手、學習與成長是否真的有證據,並看到 live read model、Redis dry-run、handoff envelope、ack / dead-letter / replay、learning writeback approval、Telegram receipt approval、fixture dry-run、runtime write gate review、post-write verifier package、runtime verifier evidence review、報表真相、日週月報、Agent 工作量、圖表化報告、風險自動化政策、報表 runtime 啟動前閘門、no-write dry-run 證據包與 fixture/readback/verifier dry-run 證據包下一步要通過哪些 gate。 +已完成 P2-403A、P2-403B、P2-403C、P2-403D、P2-403E、P2-403F、P2-403G、P2-403H、P2-403I、P2-403J、P2-403L、P2-403M、P2-403N 與 P2-404:讓統帥能在治理頁看到 OpenClaw / Hermes / NemoTron 的互動、接手、學習與成長是否真的有證據,並看到 live read model、Redis dry-run、handoff envelope、ack / dead-letter / replay、learning writeback approval、Telegram receipt approval、fixture dry-run、runtime write gate review、post-write verifier package、runtime verifier evidence review、報表真相、日週月報、Agent 工作量、圖表化報告、風險自動化政策、報表 runtime 啟動前閘門、no-write dry-run 證據包、fixture/readback/verifier dry-run 證據包與 shadow/no-write execution evidence gate 下一步要通過哪些 gate。 目前真相: @@ -52,6 +58,7 @@ | Telegram Gateway queue / 中低風險 auto worker | 未啟用,數量 `0` | | P2-403M no-write dry-run package | 已完成,正式寫入 / 發送 / worker / verifier live readback 全為 `0` | | P2-403N fixture readback package | 已完成,queue write / Telegram send / Bot API / worker / verifier live readback 全為 `0` | +| P2-404 runtime worker shadow gate | 已完成,shadow worker live / queue write / Telegram send / production write 全為 `0` | 這代表使用者現在可以看見「哪裡已準備好、哪裡仍未運作、被哪個 gate 阻擋、下一步要如何驗證」。但還不能宣稱三個 Agent 已經在 production runtime 主動互傳訊息或自主學習。 @@ -110,17 +117,20 @@ | `docs/schemas/ai_agent_report_runtime_fixture_readback_v1.schema.json` | P2-403N fixture smoke / queue preview readback / verifier dry-run schema;強制 queue write、Telegram send、Bot API、receipt write、worker、verifier live readback、production write 與 secret read 維持未授權 | | `docs/evaluations/ai_agent_report_runtime_fixture_readback_2026-06-12.json` | P2-403N committed snapshot,完成度 `94%`,5 個 fixture smoke、3 個 queue preview readback、4 個 verifier dry-run case、3 個 Agent fixture role、5 個 operator checkpoint;所有 live counts 全為 `0` | | `GET /api/v1/agents/agent-report-runtime-fixture-readback` | 只讀 API;不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 delivery receipt、不啟動 worker、不讀 secret | +| `docs/schemas/ai_agent_runtime_worker_shadow_gate_v1.schema.json` | P2-404 runtime worker shadow / no-write execution evidence gate schema;強制 shadow live worker、queue write、Telegram send、Bot API、receipt write、auto worker、verifier live readback、production write 與 secret read 維持未授權 | +| `docs/evaluations/ai_agent_runtime_worker_shadow_gate_2026-06-12.json` | P2-404 committed snapshot,完成度 `96%`,5 個 shadow candidate、4 個 no-write replay、4 個 verifier shadow case、3 個 Agent shadow role、6 個 operator checkpoint;所有 live counts 全為 `0` | +| `GET /api/v1/agents/agent-runtime-worker-shadow-gate` | 只讀 API;不啟動 live worker、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 production target | | `apps/api/src/services/ai_agent_interaction_learning_proof.py` | 只讀 loader 與安全驗證 | | `apps/api/src/services/ai_agent_live_read_model_gate.py` | P2-403B 只讀 loader;拒絕 live DB query、Redis consumer、unsafe fields、Telegram 與 writeback | | `GET /api/v1/agents/agent-interaction-learning-proof` | 只讀 API,不啟動 worker、不碰 Redis / DB runtime、不發 Telegram | | `GET /api/v1/agents/agent-live-read-model-gate` | 只讀 API,不連 DB、不讀寫 Redis、不發 Telegram | -| governance UI | 新增證據階梯、目前真相、P2-403B live read gate、P2-403C Redis dry-run gate、P2-403D learning writeback approval package、P2-403E Telegram receipt approval package、P2-403F owner-approved learning dry-run / fixture dry-run、P2-403G runtime write gate review、P2-403H post-write verifier package、P2-403I runtime verifier evidence review、P2-403J 報表真相 / 日週月報 / Agent 工作量 / 圖表 / AI 建議、P2-403L 報表 runtime readiness、P2-403M no-write dry-run、P2-403N fixture readback、Agent lane、可觀測訊號、runtime gates、前端 redaction | +| governance UI | 新增證據階梯、目前真相、P2-403B live read gate、P2-403C Redis dry-run gate、P2-403D learning writeback approval package、P2-403E Telegram receipt approval package、P2-403F owner-approved learning dry-run / fixture dry-run、P2-403G runtime write gate review、P2-403H post-write verifier package、P2-403I runtime verifier evidence review、P2-403J 報表真相 / 日週月報 / Agent 工作量 / 圖表 / AI 建議、P2-403L 報表 runtime readiness、P2-403M no-write dry-run、P2-403N fixture readback、P2-404 shadow gate、Agent lane、可觀測訊號、runtime gates、前端 redaction | ## 5. 後續優先順序 | 優先 | ID | 工作 | gate | |---:|---|---|---| -| 1 | P2-404 | runtime worker shadow / no-write execution evidence gate | runtime shadow evidence | +| 1 | P2-101 | 定義操作類別權限模型 | HITL 關卡 | ## 6. 紅線 diff --git a/docs/evaluations/ai_agent_runtime_worker_shadow_gate_2026-06-12.json b/docs/evaluations/ai_agent_runtime_worker_shadow_gate_2026-06-12.json new file mode 100644 index 000000000..13f262adc --- /dev/null +++ b/docs/evaluations/ai_agent_runtime_worker_shadow_gate_2026-06-12.json @@ -0,0 +1,398 @@ +{ + "schema_version": "ai_agent_runtime_worker_shadow_gate_v1", + "generated_at": "2026-06-12T14:10:00+08:00", + "program_status": { + "overall_completion_percent": 96, + "current_priority": "P2", + "current_task_id": "P2-404", + "next_task_id": "P2-101", + "read_only_mode": true, + "runtime_authority": "runtime_worker_shadow_no_write_execution_evidence_gate_only_no_live_send_or_write", + "status_note": "P2-404 只把 P2-403N fixture/readback/verifier dry-run promotion 成 shadow worker no-write 證據包;目前仍不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫讀報回執、不啟動 live AI runtime worker、不啟動中低風險 auto worker、不寫 production target。" + }, + "source_refs": [ + "docs/evaluations/ai_agent_report_runtime_fixture_readback_2026-06-12.json", + "docs/evaluations/ai_agent_report_runtime_dry_run_2026-06-12.json", + "docs/evaluations/ai_agent_runtime_verifier_evidence_review_2026-06-12.json", + "docs/evaluations/ai_agent_report_automation_review_2026-06-12.json", + "docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md" + ], + "shadow_gate_truth": { + "shadow_worker_evidence_gate_ready": true, + "promotion_from_fixture_readback_ready": true, + "no_write_replay_plan_ready": true, + "action_candidate_selection_ready": true, + "mcp_evidence_reuse_ready": true, + "verifier_dry_run_binding_ready": true, + "failure_lane_ready": true, + "operator_review_packet_ready": true, + "production_delivery_enabled": false, + "gateway_queue_write_enabled": false, + "telegram_send_enabled": false, + "telegram_bot_api_call_enabled": false, + "delivery_receipt_write_enabled": false, + "shadow_worker_live_enabled": false, + "ai_runtime_worker_enabled": false, + "medium_low_auto_worker_enabled": false, + "post_action_verifier_live_readback_enabled": false, + "production_write_enabled": false, + "secret_value_read_enabled": false, + "work_window_transcript_display_allowed": false, + "shadow_worker_live_run_count_24h": 0, + "gateway_queue_write_count_24h": 0, + "telegram_send_count_24h": 0, + "telegram_bot_api_call_count_24h": 0, + "delivery_receipt_write_count_24h": 0, + "ai_runtime_worker_run_count_24h": 0, + "medium_low_auto_execution_count_24h": 0, + "post_action_verifier_live_readback_count_24h": 0, + "production_write_count_24h": 0, + "truth_note": "本段把候選工作推到 shadow/no-write evidence gate;所有正式 queue write、Telegram send、Bot API、receipt write、live worker、auto worker、verifier live readback 與 production write 仍保持 0。" + }, + "shadow_worker_candidates": [ + { + "candidate_id": "shadow_report_daily_digest_candidate", + "display_name": "日報派送 shadow worker candidate", + "owner_agent": "hermes", + "source_fixture_id": "daily_report_digest_readback", + "target_surface": "telegram_gateway.queue_preview", + "shadow_status": "passed_no_write_replay", + "promotion_hash": "sha256:07b39f3fdd7f4d9fb51b13b7bf2e740ab0870fe3e6968bbd59e18ea1d9db2691", + "dry_run_ref": "docs/evaluations/ai_agent_report_runtime_fixture_readback_2026-06-12.json", + "writes_production": false, + "sends_telegram": false, + "reads_secret_value": false, + "live_shadow_run_count_24h": 0, + "blocked_reason": "Gateway queue write 尚未通過 P2-101 操作權限模型與 receipt E2E gate", + "next_no_write_step": "以 shadow worker replay 讀取 redacted digest metadata,產出 queue candidate diff,不寫 queue。" + }, + { + "candidate_id": "shadow_report_weekly_digest_candidate", + "display_name": "週報派送 shadow worker candidate", + "owner_agent": "hermes", + "source_fixture_id": "weekly_report_digest_readback", + "target_surface": "telegram_gateway.queue_preview", + "shadow_status": "passed_no_write_replay", + "promotion_hash": "sha256:856f4986b47c83b91ecdbbd0f5e6224aaecadf2a1622e381fef4bf79d65b1b98", + "dry_run_ref": "docs/evaluations/ai_agent_report_runtime_fixture_readback_2026-06-12.json", + "writes_production": false, + "sends_telegram": false, + "reads_secret_value": false, + "live_shadow_run_count_24h": 0, + "blocked_reason": "週報 fixture 已可 replay,但尚未允許真實 queue write 或 Telegram delivery", + "next_no_write_step": "比對週報 summary、risk lane 與 zero-signal 缺口,產出只讀候選。" + }, + { + "candidate_id": "shadow_report_monthly_digest_candidate", + "display_name": "月報派送 shadow worker candidate", + "owner_agent": "hermes", + "source_fixture_id": "monthly_report_digest_readback", + "target_surface": "telegram_gateway.queue_preview", + "shadow_status": "needs_owner_review", + "promotion_hash": "sha256:03a1c192319cea2fe098d524514183a22ff83c26d26c881abf7ce3f6ef3ef376", + "dry_run_ref": "docs/evaluations/ai_agent_report_runtime_fixture_readback_2026-06-12.json", + "writes_production": false, + "sends_telegram": false, + "reads_secret_value": false, + "live_shadow_run_count_24h": 0, + "blocked_reason": "月報會影響較大範圍營運判讀,需 owner review 報表欄位與降噪策略", + "next_no_write_step": "先固定月報欄位、零訊號判讀與 SRE 戰情室接收摘要。" + }, + { + "candidate_id": "shadow_medium_low_noop_repair_candidate", + "display_name": "中低風險 no-op 修復 shadow candidate", + "owner_agent": "openclaw", + "source_fixture_id": "medium_low_noop_fixture", + "target_surface": "repair_candidate.noop_plan", + "shadow_status": "blocked_by_runtime_gate", + "promotion_hash": "sha256:5d18a0565fd98a5b6710ed37d3d3d696e53b925a2dae3c67e7dedc3be82713ba", + "dry_run_ref": "docs/evaluations/ai_agent_runtime_verifier_evidence_review_2026-06-12.json", + "writes_production": false, + "sends_telegram": false, + "reads_secret_value": false, + "live_shadow_run_count_24h": 0, + "blocked_reason": "尚未有 P2-101 操作權限模型、target inventory promotion 與 rollback/no-op evidence", + "next_no_write_step": "把 safe/no-op action candidate 分類成操作類別,等待 P2-101 權限模型。" + }, + { + "candidate_id": "shadow_post_action_verifier_candidate", + "display_name": "post-action verifier shadow candidate", + "owner_agent": "nemotron", + "source_fixture_id": "medium_low_noop_verifier_dry_run", + "target_surface": "post_action_verifier.fixture_only", + "shadow_status": "blocked_by_runtime_gate", + "promotion_hash": "sha256:02f75449799d1df3aa2cba8c004949187f717f879da53aa59b2ea8b576ec09dc", + "dry_run_ref": "docs/evaluations/ai_agent_report_runtime_fixture_readback_2026-06-12.json", + "writes_production": false, + "sends_telegram": false, + "reads_secret_value": false, + "live_shadow_run_count_24h": 0, + "blocked_reason": "verifier 仍只能 fixture-only,不可讀 canonical target 或寫入結果", + "next_no_write_step": "先建立 verifier input/output allow-list 與 no-write replay hash。" + } + ], + "no_write_execution_replays": [ + { + "replay_id": "daily_report_shadow_replay", + "display_name": "日報 shadow replay", + "owner_agent": "hermes", + "input_source": "daily_report_digest_readback", + "expected_action": "prepare_gateway_queue_candidate", + "simulated_outcome": "產生 redacted queue candidate diff,未寫 queue", + "replay_status": "passed_no_write", + "evidence_hash": "sha256:286ec7ff1e81fc4de63694e420b9e4e99c28630c9c30c0ec7b342e6a27633407", + "verifier_bound": true, + "writes_result": false, + "production_side_effect_count": 0 + }, + { + "replay_id": "weekly_report_shadow_replay", + "display_name": "週報 shadow replay", + "owner_agent": "hermes", + "input_source": "weekly_report_digest_readback", + "expected_action": "prepare_gateway_queue_candidate", + "simulated_outcome": "產生週報 summary candidate 與降噪標籤,未送 Telegram", + "replay_status": "passed_no_write", + "evidence_hash": "sha256:33502b098537c8db4544bda3d409fa7014e49a089e5877fd524a662c1c474ce6", + "verifier_bound": true, + "writes_result": false, + "production_side_effect_count": 0 + }, + { + "replay_id": "medium_low_noop_shadow_replay", + "display_name": "中低風險 no-op shadow replay", + "owner_agent": "openclaw", + "input_source": "medium_low_noop_fixture", + "expected_action": "classify_noop_repair_candidate", + "simulated_outcome": "只產生操作類別與人工可審核下一步,未執行修復", + "replay_status": "blocked_by_runtime_gate", + "evidence_hash": "sha256:7c7de152b1b7f396b649018d4754caf7670212a134180a885a826852bf5946a9", + "verifier_bound": true, + "writes_result": false, + "production_side_effect_count": 0 + }, + { + "replay_id": "verifier_shadow_replay", + "display_name": "verifier shadow replay", + "owner_agent": "nemotron", + "input_source": "medium_low_noop_verifier_dry_run", + "expected_action": "compare_expected_vs_observed_no_write", + "simulated_outcome": "只產生 verifier evidence hash,未讀 live target、未寫結果", + "replay_status": "blocked_by_runtime_gate", + "evidence_hash": "sha256:9915528dbbb3e6b637b85f4b83089fd2b5af08ecdc7aefb6f5192a00ac87cd1f", + "verifier_bound": true, + "writes_result": false, + "production_side_effect_count": 0 + } + ], + "verifier_shadow_cases": [ + { + "case_id": "shadow_promotion_verifier_case", + "display_name": "shadow promotion verifier case", + "owner_agent": "nemotron", + "expected_signal": "每個 shadow candidate 都要有 promotion hash、dry-run ref、blocked reason 與 next no-write step", + "observed_signal": "5 個 candidate 均具備 promotion hash 與 no-write 邊界", + "evidence_hash": "sha256:24f511e2808ed80d185ad685fa897b6a4d9132500a8b6f5cf0b11f6e31068d11", + "live_readback_enabled": false, + "writes_result": false, + "requires_secret_value": false + }, + { + "case_id": "queue_write_block_verifier_case", + "display_name": "Gateway queue write block verifier case", + "owner_agent": "hermes", + "expected_signal": "queue candidate 可讀,但 queue write count 必須維持 0", + "observed_signal": "Gateway queue write enabled=false 且 24h count=0", + "evidence_hash": "sha256:f87d3365f9c15a6954bf2fe270339ded0681700541463afb0bdbcdf515eead89", + "live_readback_enabled": false, + "writes_result": false, + "requires_secret_value": false + }, + { + "case_id": "telegram_send_block_verifier_case", + "display_name": "Telegram send block verifier case", + "owner_agent": "hermes", + "expected_signal": "SRE 戰情室路由只允許 metadata preview,不允許 Bot API send", + "observed_signal": "Telegram send enabled=false、Bot API enabled=false、send count=0", + "evidence_hash": "sha256:f0bc3dc2d4dcb17272abec4eb4643754f36a9775771837826ddb9713381cc2a6", + "live_readback_enabled": false, + "writes_result": false, + "requires_secret_value": false + }, + { + "case_id": "production_write_block_verifier_case", + "display_name": "production write block verifier case", + "owner_agent": "nemotron", + "expected_signal": "shadow replay 不得造成 DB、KM、PlayBook、timeline、repair 或 verifier result 寫入", + "observed_signal": "production_write_enabled=false 且 production side effect count=0", + "evidence_hash": "sha256:25c548f3eb5918478d7696f403bf758ff6f65e9c6eda760caab593b724f568ac", + "live_readback_enabled": false, + "writes_result": false, + "requires_secret_value": false + } + ], + "agent_shadow_roles": [ + { + "agent_id": "openclaw", + "display_name": "OpenClaw", + "shadow_responsibility": "把 fixture promotion 分類成可審核操作候選,先產生 no-write action plan,不直接執行修復。", + "observed_work": [ + "分類中低風險 no-op 修復候選", + "標記 P2-101 操作權限模型缺口", + "阻擋未附 rollback/no-op evidence 的 candidate" + ], + "blocked_now": [ + "runtime repair worker", + "production write", + "high risk execution" + ], + "live_action_count_24h": 0 + }, + { + "agent_id": "hermes", + "display_name": "Hermes", + "shadow_responsibility": "把日週月報與 SRE 戰情室 digest 轉成 redacted queue candidate preview,不寫 Gateway queue。", + "observed_work": [ + "產出日報與週報 shadow replay", + "確認 SRE_GROUP_CHAT_ID 只作 secret ref", + "維持 Telegram send count 0" + ], + "blocked_now": [ + "Gateway queue write", + "Telegram send", + "delivery receipt write" + ], + "live_action_count_24h": 0 + }, + { + "agent_id": "nemotron", + "display_name": "NemoTron", + "shadow_responsibility": "審查 shadow candidate 是否具備 no-write replay hash、verifier binding 與 failure lane。", + "observed_work": [ + "確認 4 個 verifier shadow case", + "標記 live readback 仍未授權", + "要求 P2-101 前不得讀 canonical target" + ], + "blocked_now": [ + "live verifier execution", + "canonical target readback", + "paid API call" + ], + "live_action_count_24h": 0 + } + ], + "operator_checkpoints": [ + { + "checkpoint_id": "shadow_candidate_hash_review", + "display_name": "shadow candidate hash review", + "owner_agent": "hermes", + "risk_tier": "low", + "approval_required": false, + "status": "passed_no_write", + "next_safe_step": "保留 5 個 promotion hash,下一步只能在 no-write shadow replay 讀取。" + }, + { + "checkpoint_id": "shadow_worker_toggle_review", + "display_name": "shadow worker toggle review", + "owner_agent": "openclaw", + "risk_tier": "high", + "approval_required": true, + "status": "blocked_by_runtime_gate", + "next_safe_step": "P2-101 操作權限模型完成前,不得啟動 live runtime worker 或 shadow worker schedule。" + }, + { + "checkpoint_id": "gateway_queue_write_block", + "display_name": "Gateway queue write block", + "owner_agent": "hermes", + "risk_tier": "medium", + "approval_required": true, + "status": "blocked_by_runtime_gate", + "next_safe_step": "只允許 queue candidate diff;不得 XADD / DB insert / Gateway queue write。" + }, + { + "checkpoint_id": "telegram_send_block", + "display_name": "Telegram send block", + "owner_agent": "hermes", + "risk_tier": "high", + "approval_required": true, + "status": "blocked_by_runtime_gate", + "next_safe_step": "SRE 戰情室仍只作 redacted preview;不得呼叫 Bot API sendMessage。" + }, + { + "checkpoint_id": "verifier_shadow_review", + "display_name": "verifier shadow review", + "owner_agent": "nemotron", + "risk_tier": "medium", + "approval_required": true, + "status": "needs_owner_review", + "next_safe_step": "先完成 verifier input/output allow-list,再進 P2-101 操作權限模型。" + }, + { + "checkpoint_id": "p2_101_permission_model_handoff", + "display_name": "P2-101 permission model handoff", + "owner_agent": "openclaw", + "risk_tier": "critical", + "approval_required": true, + "status": "blocked_by_runtime_gate", + "next_safe_step": "下一步定義操作類別權限模型,才可討論哪類 low / medium risk 能自動處理。" + } + ], + "display_redaction_contract": { + "redaction_required": true, + "raw_report_payload_display_allowed": false, + "raw_telegram_payload_display_allowed": false, + "raw_shadow_payload_display_allowed": false, + "private_reasoning_display_allowed": false, + "secret_value_display_allowed": false, + "work_window_transcript_display_allowed": false, + "allowed_display_fields": [ + "candidate_id", + "display_name", + "owner_agent", + "target_surface", + "shadow_status", + "promotion_hash", + "blocked_reason", + "next_no_write_step", + "evidence_hash" + ], + "blocked_display_fields": [ + "raw_prompt", + "chain_of_thought", + "telegram_chat_id", + "telegram_message_id", + "bot_token", + "authorization_header", + "secret_value", + "raw_shadow_payload", + "work_window_transcript" + ] + }, + "rollups": { + "shadow_candidate_count": 5, + "passed_no_write_candidate_count": 2, + "blocked_candidate_count": 2, + "needs_owner_review_candidate_count": 1, + "no_write_replay_count": 4, + "passed_no_write_replay_count": 2, + "verifier_shadow_case_count": 4, + "agent_role_count": 3, + "operator_checkpoint_count": 6, + "approval_required_checkpoint_ids": [ + "shadow_worker_toggle_review", + "gateway_queue_write_block", + "telegram_send_block", + "verifier_shadow_review", + "p2_101_permission_model_handoff" + ], + "shadow_worker_live_run_count": 0, + "gateway_queue_write_count": 0, + "telegram_send_count": 0, + "telegram_bot_api_call_count": 0, + "delivery_receipt_write_count": 0, + "ai_runtime_worker_run_count": 0, + "medium_low_auto_execution_count": 0, + "post_action_verifier_live_readback_count": 0, + "production_write_count": 0 + } +} diff --git a/docs/schemas/ai_agent_runtime_worker_shadow_gate_v1.schema.json b/docs/schemas/ai_agent_runtime_worker_shadow_gate_v1.schema.json new file mode 100644 index 000000000..7029b849a --- /dev/null +++ b/docs/schemas/ai_agent_runtime_worker_shadow_gate_v1.schema.json @@ -0,0 +1,370 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://awoooi.wooo.work/schemas/ai_agent_runtime_worker_shadow_gate_v1.schema.json", + "title": "AI Agent Runtime Worker Shadow Gate v1", + "type": "object", + "required": [ + "schema_version", + "generated_at", + "program_status", + "source_refs", + "shadow_gate_truth", + "shadow_worker_candidates", + "no_write_execution_replays", + "verifier_shadow_cases", + "agent_shadow_roles", + "operator_checkpoints", + "display_redaction_contract", + "rollups" + ], + "properties": { + "schema_version": { "const": "ai_agent_runtime_worker_shadow_gate_v1" }, + "generated_at": { "type": "string" }, + "program_status": { + "type": "object", + "required": [ + "overall_completion_percent", + "current_priority", + "current_task_id", + "next_task_id", + "read_only_mode", + "runtime_authority", + "status_note" + ], + "properties": { + "overall_completion_percent": { "type": "integer", "minimum": 0, "maximum": 100 }, + "current_priority": { "enum": ["P0", "P1", "P2", "P3"] }, + "current_task_id": { "const": "P2-404" }, + "next_task_id": { "const": "P2-101" }, + "read_only_mode": { "const": true }, + "runtime_authority": { + "const": "runtime_worker_shadow_no_write_execution_evidence_gate_only_no_live_send_or_write" + }, + "status_note": { "type": "string" } + }, + "additionalProperties": false + }, + "source_refs": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, + "shadow_gate_truth": { + "type": "object", + "required": [ + "shadow_worker_evidence_gate_ready", + "promotion_from_fixture_readback_ready", + "no_write_replay_plan_ready", + "action_candidate_selection_ready", + "mcp_evidence_reuse_ready", + "verifier_dry_run_binding_ready", + "failure_lane_ready", + "operator_review_packet_ready", + "production_delivery_enabled", + "gateway_queue_write_enabled", + "telegram_send_enabled", + "telegram_bot_api_call_enabled", + "delivery_receipt_write_enabled", + "shadow_worker_live_enabled", + "ai_runtime_worker_enabled", + "medium_low_auto_worker_enabled", + "post_action_verifier_live_readback_enabled", + "production_write_enabled", + "secret_value_read_enabled", + "work_window_transcript_display_allowed", + "shadow_worker_live_run_count_24h", + "gateway_queue_write_count_24h", + "telegram_send_count_24h", + "telegram_bot_api_call_count_24h", + "delivery_receipt_write_count_24h", + "ai_runtime_worker_run_count_24h", + "medium_low_auto_execution_count_24h", + "post_action_verifier_live_readback_count_24h", + "production_write_count_24h", + "truth_note" + ], + "properties": { + "shadow_worker_evidence_gate_ready": { "const": true }, + "promotion_from_fixture_readback_ready": { "const": true }, + "no_write_replay_plan_ready": { "const": true }, + "action_candidate_selection_ready": { "const": true }, + "mcp_evidence_reuse_ready": { "const": true }, + "verifier_dry_run_binding_ready": { "const": true }, + "failure_lane_ready": { "const": true }, + "operator_review_packet_ready": { "const": true }, + "production_delivery_enabled": { "const": false }, + "gateway_queue_write_enabled": { "const": false }, + "telegram_send_enabled": { "const": false }, + "telegram_bot_api_call_enabled": { "const": false }, + "delivery_receipt_write_enabled": { "const": false }, + "shadow_worker_live_enabled": { "const": false }, + "ai_runtime_worker_enabled": { "const": false }, + "medium_low_auto_worker_enabled": { "const": false }, + "post_action_verifier_live_readback_enabled": { "const": false }, + "production_write_enabled": { "const": false }, + "secret_value_read_enabled": { "const": false }, + "work_window_transcript_display_allowed": { "const": false }, + "shadow_worker_live_run_count_24h": { "const": 0 }, + "gateway_queue_write_count_24h": { "const": 0 }, + "telegram_send_count_24h": { "const": 0 }, + "telegram_bot_api_call_count_24h": { "const": 0 }, + "delivery_receipt_write_count_24h": { "const": 0 }, + "ai_runtime_worker_run_count_24h": { "const": 0 }, + "medium_low_auto_execution_count_24h": { "const": 0 }, + "post_action_verifier_live_readback_count_24h": { "const": 0 }, + "production_write_count_24h": { "const": 0 }, + "truth_note": { "type": "string" } + }, + "additionalProperties": false + }, + "shadow_worker_candidates": { + "type": "array", + "minItems": 5, + "items": { + "type": "object", + "required": [ + "candidate_id", + "display_name", + "owner_agent", + "source_fixture_id", + "target_surface", + "shadow_status", + "promotion_hash", + "dry_run_ref", + "writes_production", + "sends_telegram", + "reads_secret_value", + "live_shadow_run_count_24h", + "blocked_reason", + "next_no_write_step" + ], + "properties": { + "candidate_id": { + "enum": [ + "shadow_report_daily_digest_candidate", + "shadow_report_weekly_digest_candidate", + "shadow_report_monthly_digest_candidate", + "shadow_medium_low_noop_repair_candidate", + "shadow_post_action_verifier_candidate" + ] + }, + "display_name": { "type": "string" }, + "owner_agent": { "enum": ["openclaw", "hermes", "nemotron"] }, + "source_fixture_id": { "type": "string" }, + "target_surface": { "type": "string" }, + "shadow_status": { + "enum": ["passed_no_write_replay", "needs_owner_review", "blocked_by_runtime_gate"] + }, + "promotion_hash": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" }, + "dry_run_ref": { "type": "string" }, + "writes_production": { "const": false }, + "sends_telegram": { "const": false }, + "reads_secret_value": { "const": false }, + "live_shadow_run_count_24h": { "const": 0 }, + "blocked_reason": { "type": "string" }, + "next_no_write_step": { "type": "string" } + }, + "additionalProperties": false + } + }, + "no_write_execution_replays": { + "type": "array", + "minItems": 4, + "items": { + "type": "object", + "required": [ + "replay_id", + "display_name", + "owner_agent", + "input_source", + "expected_action", + "simulated_outcome", + "replay_status", + "evidence_hash", + "verifier_bound", + "writes_result", + "production_side_effect_count" + ], + "properties": { + "replay_id": { + "enum": [ + "daily_report_shadow_replay", + "weekly_report_shadow_replay", + "medium_low_noop_shadow_replay", + "verifier_shadow_replay" + ] + }, + "display_name": { "type": "string" }, + "owner_agent": { "enum": ["openclaw", "hermes", "nemotron"] }, + "input_source": { "type": "string" }, + "expected_action": { "type": "string" }, + "simulated_outcome": { "type": "string" }, + "replay_status": { "enum": ["passed_no_write", "blocked_by_runtime_gate"] }, + "evidence_hash": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" }, + "verifier_bound": { "const": true }, + "writes_result": { "const": false }, + "production_side_effect_count": { "const": 0 } + }, + "additionalProperties": false + } + }, + "verifier_shadow_cases": { + "type": "array", + "minItems": 4, + "items": { + "type": "object", + "required": [ + "case_id", + "display_name", + "owner_agent", + "expected_signal", + "observed_signal", + "evidence_hash", + "live_readback_enabled", + "writes_result", + "requires_secret_value" + ], + "properties": { + "case_id": { + "enum": [ + "shadow_promotion_verifier_case", + "queue_write_block_verifier_case", + "telegram_send_block_verifier_case", + "production_write_block_verifier_case" + ] + }, + "display_name": { "type": "string" }, + "owner_agent": { "enum": ["hermes", "nemotron"] }, + "expected_signal": { "type": "string" }, + "observed_signal": { "type": "string" }, + "evidence_hash": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" }, + "live_readback_enabled": { "const": false }, + "writes_result": { "const": false }, + "requires_secret_value": { "const": false } + }, + "additionalProperties": false + } + }, + "agent_shadow_roles": { + "type": "array", + "minItems": 3, + "items": { + "type": "object", + "required": [ + "agent_id", + "display_name", + "shadow_responsibility", + "observed_work", + "blocked_now", + "live_action_count_24h" + ], + "properties": { + "agent_id": { "enum": ["openclaw", "hermes", "nemotron"] }, + "display_name": { "type": "string" }, + "shadow_responsibility": { "type": "string" }, + "observed_work": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, + "blocked_now": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, + "live_action_count_24h": { "const": 0 } + }, + "additionalProperties": false + } + }, + "operator_checkpoints": { + "type": "array", + "minItems": 6, + "items": { + "type": "object", + "required": [ + "checkpoint_id", + "display_name", + "owner_agent", + "risk_tier", + "approval_required", + "status", + "next_safe_step" + ], + "properties": { + "checkpoint_id": { "type": "string" }, + "display_name": { "type": "string" }, + "owner_agent": { "enum": ["openclaw", "hermes", "nemotron"] }, + "risk_tier": { "enum": ["low", "medium", "high", "critical"] }, + "approval_required": { "type": "boolean" }, + "status": { + "enum": ["passed_no_write", "needs_owner_review", "blocked_by_runtime_gate"] + }, + "next_safe_step": { "type": "string" } + }, + "additionalProperties": false + } + }, + "display_redaction_contract": { + "type": "object", + "required": [ + "redaction_required", + "raw_report_payload_display_allowed", + "raw_telegram_payload_display_allowed", + "raw_shadow_payload_display_allowed", + "private_reasoning_display_allowed", + "secret_value_display_allowed", + "work_window_transcript_display_allowed", + "allowed_display_fields", + "blocked_display_fields" + ], + "properties": { + "redaction_required": { "const": true }, + "raw_report_payload_display_allowed": { "const": false }, + "raw_telegram_payload_display_allowed": { "const": false }, + "raw_shadow_payload_display_allowed": { "const": false }, + "private_reasoning_display_allowed": { "const": false }, + "secret_value_display_allowed": { "const": false }, + "work_window_transcript_display_allowed": { "const": false }, + "allowed_display_fields": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, + "blocked_display_fields": { "type": "array", "items": { "type": "string" }, "minItems": 1 } + }, + "additionalProperties": false + }, + "rollups": { + "type": "object", + "required": [ + "shadow_candidate_count", + "passed_no_write_candidate_count", + "blocked_candidate_count", + "needs_owner_review_candidate_count", + "no_write_replay_count", + "passed_no_write_replay_count", + "verifier_shadow_case_count", + "agent_role_count", + "operator_checkpoint_count", + "approval_required_checkpoint_ids", + "shadow_worker_live_run_count", + "gateway_queue_write_count", + "telegram_send_count", + "telegram_bot_api_call_count", + "delivery_receipt_write_count", + "ai_runtime_worker_run_count", + "medium_low_auto_execution_count", + "post_action_verifier_live_readback_count", + "production_write_count" + ], + "properties": { + "shadow_candidate_count": { "type": "integer" }, + "passed_no_write_candidate_count": { "type": "integer" }, + "blocked_candidate_count": { "type": "integer" }, + "needs_owner_review_candidate_count": { "type": "integer" }, + "no_write_replay_count": { "type": "integer" }, + "passed_no_write_replay_count": { "type": "integer" }, + "verifier_shadow_case_count": { "type": "integer" }, + "agent_role_count": { "type": "integer" }, + "operator_checkpoint_count": { "type": "integer" }, + "approval_required_checkpoint_ids": { "type": "array", "items": { "type": "string" } }, + "shadow_worker_live_run_count": { "const": 0 }, + "gateway_queue_write_count": { "const": 0 }, + "telegram_send_count": { "const": 0 }, + "telegram_bot_api_call_count": { "const": 0 }, + "delivery_receipt_write_count": { "const": 0 }, + "ai_runtime_worker_run_count": { "const": 0 }, + "medium_low_auto_execution_count": { "const": 0 }, + "post_action_verifier_live_readback_count": { "const": 0 }, + "production_write_count": { "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 921f1161a..ec354bdb0 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,9 +634,10 @@ Alert / Sentry / SigNoz / Gitea / Market Watch / Operator | `docs/evaluations/ai_agent_communication_learning_contract_2026-06-11.json` | 2026-06-11 committed snapshot;完成度 `35%`,runtime worker / DB migration / Telegram direct send 全部 false | | `apps/api/src/services/ai_agent_communication_learning_contract.py` | 只讀 loader;強制驗證 runtime / migration / Telegram / SDK / route 權限都未開 | | `GET /api/v1/agents/agent-communication-learning-contract` | 治理 API;只回傳 committed contract,不啟動 worker、不碰 DB/Redis、不呼叫外部服務 | -| `docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json` + `GET /api/v1/agents/agent-interaction-learning-proof` | P2-403A / P2-403B / P2-403C / P2-403D / P2-403E / P2-403F / P2-403G / P2-403H / P2-403I / P2-403J / P2-403L / P2-403M / P2-403N 互動、接手、學習、成長、read model gate、Redis dry-run gate、learning writeback approval package、Telegram receipt approval package、owner-approved learning dry-run、fixture dry-run、runtime write gate review、post-write verifier package、runtime verifier evidence review、報表真相、日週月報、Agent 工作量、圖表化報告、風險自動化政策、報表 runtime readiness、no-write dry-run 與 fixture/readback/verifier dry-run 證據面;目前 live session、message、handoff、learning write、Gateway queue、Telegram send、report delivery、auto optimization、verifier execution 全部 `0`,由 P2-404 runtime worker shadow gate 承接下一步 | +| `docs/evaluations/ai_agent_interaction_learning_proof_2026-06-11.json` + `GET /api/v1/agents/agent-interaction-learning-proof` | P2-403A / P2-403B / P2-403C / P2-403D / P2-403E / P2-403F / P2-403G / P2-403H / P2-403I / P2-403J / P2-403L / P2-403M / P2-403N / P2-404 互動、接手、學習、成長、read model gate、Redis dry-run gate、learning writeback approval package、Telegram receipt approval package、owner-approved learning dry-run、fixture dry-run、runtime write gate review、post-write verifier package、runtime verifier evidence review、報表真相、日週月報、Agent 工作量、圖表化報告、風險自動化政策、報表 runtime readiness、no-write dry-run、fixture/readback/verifier dry-run 與 shadow/no-write execution 證據面;目前 live session、message、handoff、learning write、Gateway queue、Telegram send、report delivery、auto optimization、shadow worker、verifier execution 全部 `0`,由 P2-101 操作類別權限模型承接下一步 | | `docs/evaluations/ai_agent_report_runtime_dry_run_2026-06-12.json` + `GET /api/v1/agents/agent-report-runtime-dry-run` | P2-403M 報表 runtime no-write dry-run 證據包;建立 5 個 dry-run artifact、3 個 SRE 戰情室 queue digest 草案、4 個 readback verifier case、3 個 Agent dry-run role 與 6 個 operator checkpoint;不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 delivery receipt、不啟動 worker、不跑 verifier live readback、不讀 secret,已由 P2-403N fixture readback 承接 | | `docs/evaluations/ai_agent_report_runtime_fixture_readback_2026-06-12.json` + `GET /api/v1/agents/agent-report-runtime-fixture-readback` | P2-403N fixture smoke / queue preview readback / verifier dry-run 證據包;建立 5 個 fixture smoke、3 個 SRE 戰情室 queue preview readback、4 個 verifier dry-run case、3 個 Agent fixture role 與 5 個 operator checkpoint;不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 delivery receipt、不啟動 worker、不跑 verifier live readback、不讀 secret,下一步 P2-404 | +| `docs/evaluations/ai_agent_runtime_worker_shadow_gate_2026-06-12.json` + `GET /api/v1/agents/agent-runtime-worker-shadow-gate` | P2-404 runtime worker shadow / no-write execution evidence gate;建立 5 個 shadow candidate、4 個 no-write replay、4 個 verifier shadow case、3 個 Agent shadow role 與 6 個 operator checkpoint;shadow live worker、Gateway queue write、Telegram send、Bot API、delivery receipt、auto worker、verifier live readback、production write 與 secret read 全部 `0 / false`,下一步 P2-101 | | `docs/evaluations/ai_agent_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 主動營運委派與版本生命週期契約 @@ -724,7 +725,8 @@ Repo / registry / release notes / K8s / host / observability / backup evidence 17. 建立報表真相、日報、週報、月報、Agent 工作量、圖表化報告、AI 分析建議與高 / 中 / 低風險自動化 policy review。✅ P2-403J 已完成;report delivery、Telegram queue、AI analysis runtime、中低風險 auto worker、生產優化與 route change 仍為 `0 / false`。 18. 建立報表派送、Telegram Gateway queue、讀報回執、AI 讀報後分析、中低風險自動處理、高風險審核與 post-action verifier 啟動前閘門。✅ P2-403L 已完成;live delivery、Gateway queue write、AI runtime worker、中低風險 auto worker、高風險自動執行與 production optimization 仍為 `0 / false`。 19. 建立報表 runtime no-write dry-run、SRE 戰情室 Gateway queue 草案與 readback verifier 草案。✅ P2-403M 已完成;Gateway queue write、Telegram send、Bot API、delivery receipt、AI runtime worker、中低風險 auto worker、verifier live readback、production write 與 secret value read 仍為 `0 / false`。 -20. 建立 fixture smoke、queue preview readback 與 verifier dry-run 證據包。✅ P2-403N 已完成;fixture smoke `5`、queue preview readback `3`、verifier dry-run case `4`,Gateway queue write、Telegram send、Bot API、delivery receipt、AI runtime worker、中低風險 auto worker、verifier live readback、production write 與 secret value read 仍為 `0 / false`。下一步 P2-404 runtime worker shadow / no-write execution evidence gate。 +20. 建立 fixture smoke、queue preview readback 與 verifier dry-run 證據包。✅ P2-403N 已完成;fixture smoke `5`、queue preview readback `3`、verifier dry-run case `4`,Gateway queue write、Telegram send、Bot API、delivery receipt、AI runtime worker、中低風險 auto worker、verifier live readback、production write 與 secret value read 仍為 `0 / false`。 +21. 建立 runtime worker shadow / no-write execution evidence gate。✅ P2-404 已完成;shadow candidate `5`、no-write replay `4`、verifier shadow case `4`、Agent shadow role `3`、operator checkpoint `6`,shadow live worker、Gateway queue write、Telegram send、Bot API、delivery receipt、AI runtime worker、中低風險 auto worker、verifier live readback、production write 與 secret value read 仍為 `0 / false`。下一步 P2-101 操作類別權限模型。 #### 3.2.1d 2026-06-11 Agent 互動、學習與成長證據面 @@ -753,6 +755,7 @@ Repo / registry / release notes / K8s / host / observability / backup evidence | `docs/evaluations/ai_agent_report_runtime_readiness_2026-06-12.json` + `GET /api/v1/agents/agent-report-runtime-readiness` | P2-403L 報表派送、Telegram Gateway queue、讀報回執、AI 讀報後分析、中低風險自動處理、高風險審核與 post-action verifier 啟動前閘門;不排程實發、不寫 Gateway queue、不啟動 runtime worker、不執行生產優化 | | `docs/evaluations/ai_agent_report_runtime_dry_run_2026-06-12.json` + `GET /api/v1/agents/agent-report-runtime-dry-run` | P2-403M 報表 runtime no-write dry-run 證據包;5 個 dry-run artifact、3 個 queue digest 草案、4 個 readback verifier case、3 個 Agent dry-run role、6 個 operator checkpoint;不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 delivery receipt、不啟動 worker、不跑 verifier live readback | | `docs/evaluations/ai_agent_report_runtime_fixture_readback_2026-06-12.json` + `GET /api/v1/agents/agent-report-runtime-fixture-readback` | P2-403N fixture smoke / queue preview readback / verifier dry-run 證據包;5 個 fixture smoke、3 個 queue preview readback、4 個 verifier dry-run case、3 個 Agent fixture role、5 個 operator checkpoint;不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 delivery receipt、不啟動 worker、不跑 verifier live readback | +| `docs/evaluations/ai_agent_runtime_worker_shadow_gate_2026-06-12.json` + `GET /api/v1/agents/agent-runtime-worker-shadow-gate` | P2-404 runtime worker shadow / no-write execution evidence gate;5 個 shadow candidate、4 個 no-write replay、4 個 verifier shadow case、3 個 Agent shadow role、6 個 operator checkpoint;不啟動 live worker、不寫 Gateway queue、不送 Telegram、不呼叫 Bot API、不寫 production target | | `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 仍需批准 | @@ -1899,6 +1902,13 @@ Phase 6 完成後 - 政策裁決:P2-403N 只允許 redacted hash、queue preview readback 與 verifier dry-run;任何 Gateway queue write、Telegram send、Bot API、delivery receipt、AI runtime worker、中低風險 auto worker、verifier live readback、production write 或 secret value read 都仍為 `0 / false`。 - 本波仍不送 Telegram、不寫 Gateway queue、不呼叫 Bot API、不寫 delivery receipt、不啟動 runtime worker、不跑 verifier live readback、不讀 secret、不回傳工作視窗對話內容;下一步 P2-404 才進 runtime worker shadow / no-write execution evidence gate。 +### 2026-06-12 14:10 (台北) — §3.2 / §5 — 完成 P2-404 runtime worker shadow gate — 把 fixture promotion 轉成 shadow/no-write 證據 + +- 新增 `ai_agent_runtime_worker_shadow_gate_v1` schema / committed snapshot / loader / API / 測試,定義 5 個 shadow candidate、4 個 no-write replay、4 個 verifier shadow case、3 個 Agent shadow role 與 6 個 operator checkpoint。 +- `apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx` 接入 `GET /api/v1/agents/agent-runtime-worker-shadow-gate`,治理頁顯示 shadow 候選、no-write replay、verifier shadow case、OpenClaw / Hermes / NemoTron 分工與 P2-101 handoff checkpoint。 +- 政策裁決:P2-404 只允許 redacted promotion hash、no-write replay hash、verifier shadow evidence 與 operator checkpoint;任何 shadow live worker、Gateway queue write、Telegram send、Bot API、delivery receipt、AI runtime worker、中低風險 auto worker、verifier live readback、production write 或 secret value read 都仍為 `0 / false`。 +- 本波仍不送 Telegram、不寫 Gateway queue、不呼叫 Bot API、不寫 delivery receipt、不啟動 live runtime worker、不跑 verifier live readback、不讀 secret、不回傳工作視窗對話內容;下一步 P2-101 才定義操作類別權限模型。 + ### 2026-06-12 11:55 (台北) — §3.2 / §5 — 完成 P2-403M 報表 runtime no-write dry-run 證據包 — 把 queue / verifier 草案固定成可審核證據 - 新增 `ai_agent_report_runtime_dry_run_v1` schema / committed snapshot / loader / API / 測試,定義 report_run snapshot preview、Telegram digest payload preview、AI post-report analysis packet、中低風險 no-op plan、post-action verifier readback plan。