feat(governance): 新增 Agent host stateful 版本盤點
All checks were successful
CD Pipeline / tests (push) Successful in 1m27s
Code Review / ai-code-review (push) Successful in 13s
CD Pipeline / build-and-deploy (push) Successful in 6m0s
CD Pipeline / post-deploy-checks (push) Successful in 1m54s

This commit is contained in:
Your Name
2026-06-11 15:42:06 +08:00
parent cc6140230d
commit 2d00fa1f1e
17 changed files with 1422 additions and 30 deletions

View File

@@ -58,6 +58,9 @@ from src.services.ai_agent_deployment_layout import (
from src.services.ai_agent_gitea_pr_draft_lane import (
load_latest_ai_agent_gitea_pr_draft_lane,
)
from src.services.ai_agent_host_stateful_version_inventory import (
load_latest_ai_agent_host_stateful_version_inventory,
)
from src.services.ai_agent_proactive_operations_contract import (
load_latest_ai_agent_proactive_operations_contract,
)
@@ -709,6 +712,35 @@ async def get_agent_gitea_pr_draft_lane() -> dict[str, Any]:
) from exc
@router.get(
"/agent-host-stateful-version-inventory",
response_model=dict[str, Any],
summary="取得 AI Agent host / K3s / stateful 版本只讀盤點",
description=(
"讀取最新已提交的 AI Agent host OS / K3s / stateful services 版本只讀盤點與 "
"maintenance window 批准包;此端點不 SSH、不執行 host command、不執行 kubectl、"
"不 apt upgrade、不升級 kernel/K3s、不 drain node、不 reboot、不 restart stateful service、"
"不做 DB migration、不刪備份、不 restore、不 pull image、不安裝套件、不查外部版本來源、"
"不 active scan、不發 Telegram、不讀取 secret、不回傳工作視窗對話內容。"
),
)
async def get_agent_host_stateful_version_inventory() -> dict[str, Any]:
"""Return the latest read-only host / K3s / stateful version inventory."""
try:
return await asyncio.to_thread(load_latest_ai_agent_host_stateful_version_inventory)
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_host_stateful_version_inventory_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="AI Agent host / K3s / stateful 版本只讀盤點無效",
) from exc
@router.get(
"/runtime-surface-inventory",
response_model=dict[str, Any],

View File

@@ -0,0 +1,286 @@
"""
AI Agent host and stateful version inventory snapshot.
Loads the latest committed, read-only host OS, K3s, and stateful services
inventory contract. This module never runs SSH, kubectl, package upgrades,
node drains, reboots, stateful restarts, live scans, Telegram sends, or exposes
work-window transcripts.
"""
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_host_stateful_version_inventory_*.json"
_SCHEMA_VERSION = "ai_agent_host_stateful_version_inventory_v1"
_RUNTIME_AUTHORITY = "host_stateful_readonly_inventory_no_upgrade_or_restart"
_TRANSCRIPT_MARKERS = {
"# In app browser",
"My request for Codex",
"Current URL:",
"AGENTS.md instructions",
"<environment_context>",
"批准!繼續",
}
def load_latest_ai_agent_host_stateful_version_inventory(
evaluations_dir: Path | None = None,
) -> dict[str, Any]:
"""Load the newest committed host / K3s / stateful version inventory."""
directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR
candidates = sorted(directory.glob(_SNAPSHOT_PATTERN))
if not candidates:
raise FileNotFoundError(
f"no AI Agent host stateful version inventory snapshots found in {directory}"
)
latest = candidates[-1]
with latest.open(encoding="utf-8") as handle:
payload = json.load(handle)
if not isinstance(payload, dict):
raise ValueError(f"{latest}: expected JSON object")
_require_schema(payload, _SCHEMA_VERSION, str(latest))
_require_read_only_boundaries(payload, str(latest))
_require_rollup_consistency(payload, str(latest))
_require_inventory_safety(payload, str(latest))
_require_maintenance_approval_contract(payload, str(latest))
_require_display_redaction(payload, str(latest))
_require_no_plaintext_secret_payload_keys(payload, str(latest))
_require_no_conversation_transcript_content(payload, str(latest))
return payload
def _require_schema(payload: dict[str, Any], expected: str, label: str) -> None:
actual = payload.get("schema_version")
if actual != expected:
raise ValueError(f"{label}: expected schema_version={expected}, got {actual!r}")
def _require_read_only_boundaries(payload: dict[str, Any], label: str) -> None:
program_status = payload.get("program_status") or {}
if program_status.get("read_only_mode") is not True:
raise ValueError(f"{label}: program_status.read_only_mode must be true")
if program_status.get("runtime_authority") != _RUNTIME_AUTHORITY:
raise ValueError(f"{label}: runtime_authority must stay {_RUNTIME_AUTHORITY}")
operation_boundaries = payload.get("operation_boundaries") or {}
if operation_boundaries.get("read_only_inventory_allowed") is not True:
raise ValueError(f"{label}: read_only_inventory_allowed must be true")
blocked_operation_flags = {
"ssh_login_allowed",
"host_command_execution_allowed",
"kubectl_command_execution_allowed",
"apt_upgrade_allowed",
"os_release_upgrade_allowed",
"kernel_upgrade_allowed",
"k3s_upgrade_allowed",
"kubelet_restart_allowed",
"node_drain_allowed",
"reboot_allowed",
"stateful_service_restart_allowed",
"database_migration_allowed",
"backup_delete_allowed",
"restore_execution_allowed",
"image_pull_allowed",
"package_install_allowed",
"external_version_lookup_allowed",
"active_network_scan_allowed",
"telegram_direct_send_allowed",
"telegram_gateway_queue_write_allowed",
"secret_plaintext_allowed",
"conversation_transcript_allowed",
}
allowed_operation_flags = sorted(
flag
for flag in blocked_operation_flags
if operation_boundaries.get(flag) is not False
)
if allowed_operation_flags:
raise ValueError(
f"{label}: operation boundaries must remain false: {allowed_operation_flags}"
)
approval_boundaries = payload.get("approval_boundaries") or {}
allowed_approval_flags = sorted(
flag for flag, value in approval_boundaries.items() if value is not False
)
if allowed_approval_flags:
raise ValueError(
f"{label}: approval boundaries must remain false: {allowed_approval_flags}"
)
def _require_rollup_consistency(payload: dict[str, Any], label: str) -> None:
host_inventory = payload.get("host_inventory") or []
k3s_inventory = payload.get("k3s_inventory") or {}
stateful_services = payload.get("stateful_services") or []
readonly_probe_plan = payload.get("readonly_probe_plan") or []
maintenance_requirements = payload.get("maintenance_window_approval_package") or {}
rollups = payload.get("rollups") or {}
expected_counts = {
"host_count": len(host_inventory),
"k3s_node_count": len(k3s_inventory.get("nodes") or []),
"stateful_service_count": len(stateful_services),
"readonly_probe_step_count": len(readonly_probe_plan),
"maintenance_required_field_count": len(maintenance_requirements.get("required_fields") or []),
}
mismatched = {
key: {"expected": expected, "actual": rollups.get(key)}
for key, expected in expected_counts.items()
if rollups.get(key) != expected
}
if mismatched:
raise ValueError(f"{label}: rollup counts must match payload sections: {mismatched}")
expected_host_ids = sorted(host.get("host_id") for host in host_inventory)
if sorted(rollups.get("host_ids") or []) != expected_host_ids:
raise ValueError(f"{label}: rollups.host_ids mismatch")
expected_service_ids = sorted(service.get("service_id") for service in stateful_services)
if sorted(rollups.get("stateful_service_ids") or []) != expected_service_ids:
raise ValueError(f"{label}: rollups.stateful_service_ids mismatch")
zero_rollups = {
"ssh_login_allowed_count",
"kubectl_command_execution_allowed_count",
"apt_upgrade_allowed_count",
"k3s_upgrade_allowed_count",
"node_drain_allowed_count",
"reboot_allowed_count",
"stateful_service_restart_allowed_count",
"telegram_direct_send_allowed_count",
"conversation_transcript_allowed_count",
}
nonzero = sorted(key for key in zero_rollups if rollups.get(key) != 0)
if nonzero:
raise ValueError(f"{label}: safety counters must remain 0: {nonzero}")
def _require_inventory_safety(payload: dict[str, Any], label: str) -> None:
unsafe_hosts = [
host.get("host_id")
for host in payload.get("host_inventory") or []
if host.get("readonly_only") is not True
or host.get("host_update_authorized") is not False
or host.get("reboot_authorized") is not False
or host.get("maintenance_window_required") is not True
or not host.get("version_observation_status")
]
if unsafe_hosts:
raise ValueError(f"{label}: host inventory must remain read-only and gated: {unsafe_hosts}")
k3s = payload.get("k3s_inventory") or {}
if k3s.get("skew_policy_required") is not True:
raise ValueError(f"{label}: K3s skew policy must be required")
if k3s.get("upgrade_authorized") is not False:
raise ValueError(f"{label}: K3s upgrade must remain unauthorized")
unsafe_nodes = [
node.get("node_id")
for node in k3s.get("nodes") or []
if node.get("drain_authorized") is not False
or node.get("kubelet_restart_authorized") is not False
or node.get("readonly_only") is not True
]
if unsafe_nodes:
raise ValueError(f"{label}: K3s nodes must remain read-only: {unsafe_nodes}")
unsafe_services = [
service.get("service_id")
for service in payload.get("stateful_services") or []
if service.get("readonly_only") is not True
or service.get("restart_authorized") is not False
or service.get("upgrade_authorized") is not False
or service.get("backup_required_before_change") is not True
or not service.get("version_observation_status")
]
if unsafe_services:
raise ValueError(
f"{label}: stateful services must remain read-only and backup-gated: {unsafe_services}"
)
unsafe_probe_steps = [
step.get("step_id")
for step in payload.get("readonly_probe_plan") or []
if step.get("run_now_allowed") is not False
or step.get("mutation_allowed") is not False
or not step.get("planned_output")
]
if unsafe_probe_steps:
raise ValueError(f"{label}: readonly probe steps must stay planned-only: {unsafe_probe_steps}")
def _require_maintenance_approval_contract(payload: dict[str, Any], label: str) -> None:
required_fields = {
"owner",
"decision",
"maintenance_window",
"affected_hosts",
"affected_services",
"backup_snapshot_ref",
"rollback_owner",
"rollback_plan",
"smoke_plan",
"communication_plan",
"risk_acceptance",
}
package = payload.get("maintenance_window_approval_package") or {}
actual_fields = set(package.get("required_fields") or [])
if not required_fields.issubset(actual_fields):
raise ValueError(f"{label}: maintenance window approval package missing required fields")
if package.get("approval_required_before_probe") is not True:
raise ValueError(f"{label}: approval must be required before live probe")
if package.get("approval_required_before_change") is not True:
raise ValueError(f"{label}: approval must be required before changes")
if package.get("break_glass_record_required") is not True:
raise ValueError(f"{label}: break-glass record must be required")
def _require_display_redaction(payload: dict[str, Any], label: str) -> None:
display = payload.get("display_redaction_contract") or {}
if display.get("conversation_transcript_display_allowed") is not False:
raise ValueError(f"{label}: conversation transcript display must remain false")
if display.get("redaction_required") is not True:
raise ValueError(f"{label}: display redaction must be required")
def _require_no_plaintext_secret_payload_keys(value: Any, label: str, path: str = "$") -> None:
if isinstance(value, dict):
forbidden_key_fragments = {
"secret_value",
"token_plaintext",
"authorization_header",
"private_key",
"credential_value",
}
for key, nested in value.items():
normalized_key = str(key).lower()
if any(fragment in normalized_key for fragment in forbidden_key_fragments):
raise ValueError(f"{label}: forbidden plaintext secret key at {path}.{key}")
_require_no_plaintext_secret_payload_keys(nested, label, f"{path}.{key}")
elif isinstance(value, list):
for index, nested in enumerate(value):
_require_no_plaintext_secret_payload_keys(nested, label, f"{path}[{index}]")
def _require_no_conversation_transcript_content(value: Any, label: str, path: str = "$") -> None:
if isinstance(value, str):
for marker in _TRANSCRIPT_MARKERS:
if marker in value:
raise ValueError(
f"{label}: forbidden work-window conversation content at {path}: {marker}"
)
elif isinstance(value, dict):
for key, nested in value.items():
_require_no_conversation_transcript_content(nested, label, f"{path}.{key}")
elif isinstance(value, list):
for index, nested in enumerate(value):
_require_no_conversation_transcript_content(nested, label, f"{path}[{index}]")

View File

@@ -0,0 +1,122 @@
from __future__ import annotations
import json
import pytest
from src.services.ai_agent_host_stateful_version_inventory import (
load_latest_ai_agent_host_stateful_version_inventory,
)
def test_load_latest_ai_agent_host_stateful_version_inventory_reads_committed_snapshot():
data = load_latest_ai_agent_host_stateful_version_inventory()
assert data["schema_version"] == "ai_agent_host_stateful_version_inventory_v1"
assert data["program_status"]["overall_completion_percent"] == 86
assert data["program_status"]["current_task_id"] == "P2-402F"
assert data["program_status"]["next_task_id"] == "P2-402G"
assert data["program_status"]["read_only_mode"] is True
assert data["program_status"]["runtime_authority"] == (
"host_stateful_readonly_inventory_no_upgrade_or_restart"
)
assert data["operation_boundaries"]["read_only_inventory_allowed"] is True
assert data["operation_boundaries"]["ssh_login_allowed"] is False
assert data["operation_boundaries"]["kubectl_command_execution_allowed"] is False
assert data["operation_boundaries"]["apt_upgrade_allowed"] is False
assert data["operation_boundaries"]["k3s_upgrade_allowed"] is False
assert data["operation_boundaries"]["node_drain_allowed"] is False
assert data["operation_boundaries"]["reboot_allowed"] is False
assert data["operation_boundaries"]["stateful_service_restart_allowed"] is False
assert data["operation_boundaries"]["telegram_direct_send_allowed"] is False
assert data["operation_boundaries"]["conversation_transcript_allowed"] is False
assert data["rollups"]["host_count"] == len(data["host_inventory"]) == 5
assert data["rollups"]["k3s_node_count"] == len(data["k3s_inventory"]["nodes"]) == 2
assert data["rollups"]["stateful_service_count"] == len(data["stateful_services"]) == 12
assert data["rollups"]["readonly_probe_step_count"] == len(data["readonly_probe_plan"]) == 6
assert data["rollups"]["ssh_login_allowed_count"] == 0
assert data["rollups"]["kubectl_command_execution_allowed_count"] == 0
assert data["rollups"]["apt_upgrade_allowed_count"] == 0
assert data["rollups"]["k3s_upgrade_allowed_count"] == 0
assert data["rollups"]["node_drain_allowed_count"] == 0
assert data["rollups"]["reboot_allowed_count"] == 0
assert data["rollups"]["stateful_service_restart_allowed_count"] == 0
assert data["rollups"]["telegram_direct_send_allowed_count"] == 0
assert data["rollups"]["conversation_transcript_allowed_count"] == 0
assert all(host["readonly_only"] is True for host in data["host_inventory"])
assert all(service["restart_authorized"] is False for service in data["stateful_services"])
def test_ai_agent_host_stateful_version_inventory_blocks_ssh(tmp_path):
snapshot = _snapshot()
snapshot["operation_boundaries"]["ssh_login_allowed"] = True
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="operation boundaries"):
load_latest_ai_agent_host_stateful_version_inventory(tmp_path)
def test_ai_agent_host_stateful_version_inventory_rejects_rollup_mismatch(tmp_path):
snapshot = _snapshot()
snapshot["rollups"]["host_count"] = 99
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="rollup counts"):
load_latest_ai_agent_host_stateful_version_inventory(tmp_path)
def test_ai_agent_host_stateful_version_inventory_rejects_host_reboot(tmp_path):
snapshot = _snapshot()
snapshot["host_inventory"][0]["reboot_authorized"] = True
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="host inventory"):
load_latest_ai_agent_host_stateful_version_inventory(tmp_path)
def test_ai_agent_host_stateful_version_inventory_rejects_k3s_drain(tmp_path):
snapshot = _snapshot()
snapshot["k3s_inventory"]["nodes"][0]["drain_authorized"] = True
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="K3s nodes"):
load_latest_ai_agent_host_stateful_version_inventory(tmp_path)
def test_ai_agent_host_stateful_version_inventory_rejects_stateful_restart(tmp_path):
snapshot = _snapshot()
snapshot["stateful_services"][0]["restart_authorized"] = True
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="stateful services"):
load_latest_ai_agent_host_stateful_version_inventory(tmp_path)
def test_ai_agent_host_stateful_version_inventory_requires_maintenance_fields(tmp_path):
snapshot = _snapshot()
snapshot["maintenance_window_approval_package"]["required_fields"] = ["owner"]
snapshot["rollups"]["maintenance_required_field_count"] = 1
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="maintenance window approval package"):
load_latest_ai_agent_host_stateful_version_inventory(tmp_path)
def test_ai_agent_host_stateful_version_inventory_rejects_transcript_markers(tmp_path):
snapshot = _snapshot()
snapshot["program_status"]["status_note"] = "禁止放入 My request for Codex"
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="forbidden work-window conversation content"):
load_latest_ai_agent_host_stateful_version_inventory(tmp_path)
def _write_snapshot(tmp_path, snapshot: dict) -> None:
(tmp_path / "ai_agent_host_stateful_version_inventory_2026-06-11.json").write_text(
json.dumps(snapshot),
encoding="utf-8",
)
def _snapshot() -> dict:
return json.loads(json.dumps(load_latest_ai_agent_host_stateful_version_inventory()))

View File

@@ -0,0 +1,58 @@
from __future__ import annotations
import json
from fastapi import FastAPI
from fastapi.testclient import TestClient
from src.api.v1.agents import router
def test_agent_host_stateful_version_inventory_endpoint_returns_committed_snapshot():
app = FastAPI()
app.include_router(router, prefix="/api/v1")
client = TestClient(app)
response = client.get("/api/v1/agents/agent-host-stateful-version-inventory")
assert response.status_code == 200
data = response.json()
assert data["schema_version"] == "ai_agent_host_stateful_version_inventory_v1"
assert data["program_status"]["overall_completion_percent"] == 86
assert data["program_status"]["current_task_id"] == "P2-402F"
assert data["program_status"]["next_task_id"] == "P2-402G"
assert data["program_status"]["read_only_mode"] is True
assert data["operation_boundaries"]["read_only_inventory_allowed"] is True
assert data["operation_boundaries"]["ssh_login_allowed"] is False
assert data["operation_boundaries"]["kubectl_command_execution_allowed"] is False
assert data["operation_boundaries"]["apt_upgrade_allowed"] is False
assert data["operation_boundaries"]["k3s_upgrade_allowed"] is False
assert data["operation_boundaries"]["node_drain_allowed"] is False
assert data["operation_boundaries"]["reboot_allowed"] is False
assert data["operation_boundaries"]["stateful_service_restart_allowed"] is False
assert data["operation_boundaries"]["telegram_direct_send_allowed"] is False
assert data["operation_boundaries"]["conversation_transcript_allowed"] is False
assert data["rollups"]["host_count"] == 5
assert data["rollups"]["k3s_node_count"] == 2
assert data["rollups"]["stateful_service_count"] == 12
assert data["rollups"]["readonly_probe_step_count"] == 6
assert data["rollups"]["maintenance_required_field_count"] == 11
assert data["rollups"]["ssh_login_allowed_count"] == 0
assert data["rollups"]["kubectl_command_execution_allowed_count"] == 0
assert data["rollups"]["apt_upgrade_allowed_count"] == 0
assert data["rollups"]["k3s_upgrade_allowed_count"] == 0
assert data["rollups"]["node_drain_allowed_count"] == 0
assert data["rollups"]["reboot_allowed_count"] == 0
assert data["rollups"]["stateful_service_restart_allowed_count"] == 0
assert data["rollups"]["telegram_direct_send_allowed_count"] == 0
assert data["rollups"]["conversation_transcript_allowed_count"] == 0
serialized = json.dumps(data, ensure_ascii=False)
for marker in [
"批准!繼續",
"My request for Codex",
"Current URL:",
"# In app browser",
"AGENTS.md instructions",
]:
assert marker not in serialized

View File

@@ -13,9 +13,9 @@ def test_load_latest_ai_agent_proactive_operations_contract_reads_committed_snap
data = load_latest_ai_agent_proactive_operations_contract()
assert data["schema_version"] == "ai_agent_proactive_operations_contract_v1"
assert data["program_status"]["overall_completion_percent"] == 78
assert data["program_status"]["current_task_id"] == "P2-402E"
assert data["program_status"]["next_task_id"] == "P2-402F"
assert data["program_status"]["overall_completion_percent"] == 86
assert data["program_status"]["current_task_id"] == "P2-402F"
assert data["program_status"]["next_task_id"] == "P2-402G"
assert data["program_status"]["read_only_mode"] is True
assert data["program_status"]["runtime_authority"] == "contract_only_no_version_or_runtime_update"
assert data["approval_boundaries"]["runtime_version_update_allowed"] is False

View File

@@ -16,9 +16,9 @@ def test_ai_agent_proactive_operations_contract_endpoint_returns_committed_snaps
assert response.status_code == 200
data = response.json()
assert data["schema_version"] == "ai_agent_proactive_operations_contract_v1"
assert data["program_status"]["overall_completion_percent"] == 78
assert data["program_status"]["current_task_id"] == "P2-402E"
assert data["program_status"]["next_task_id"] == "P2-402F"
assert data["program_status"]["overall_completion_percent"] == 86
assert data["program_status"]["current_task_id"] == "P2-402F"
assert data["program_status"]["next_task_id"] == "P2-402G"
assert data["program_status"]["read_only_mode"] is True
assert data["approval_boundaries"]["runtime_version_update_allowed"] is False
assert data["approval_boundaries"]["package_upgrade_allowed"] is False

View File

@@ -1,3 +1,28 @@
## 2026-06-11P2-402F AI Agent host / K3s / stateful 版本只讀盤點
**背景**P2-402E 已建立 Gitea PR 草案 lane但 host OS、K3s、PostgreSQL、Redis、MinIO、Harbor、Gitea 與監控 / DevOps stateful 服務仍缺少統一版本盤點與 maintenance window 批准包。本階段先建立 committed read-only inventory讓 OpenClaw / Hermes / NemoTron 可以整理版本與維護證據,但不得執行 SSH、kubectl、升級、重啟或 Telegram 實發。
**本輪完成**
- 新增 `docs/schemas/ai_agent_host_stateful_version_inventory_v1.schema.json`
- 新增 `docs/evaluations/ai_agent_host_stateful_version_inventory_2026-06-11.json`5 台主機、2 個 K3s 節點、12 個 stateful / ops 服務、6 個只讀 probe step、11 個 maintenance window 必填欄位。
- 新增 `apps/api/src/services/ai_agent_host_stateful_version_inventory.py`,強制驗證 SSH / kubectl / apt upgrade / K3s upgrade / node drain / reboot / stateful restart / Telegram direct send / conversation transcript 全部 false。
- 新增 `GET /api/v1/agents/agent-host-stateful-version-inventory`
- 新增 loader / API 測試,覆蓋 SSH boundary、rollup consistency、host reboot、K3s drain、stateful restart、maintenance package 欄位與工作視窗內容 redaction。
- 更新 `ai_agent_proactive_operations_contract_2026-06-11.json`:整體完成度 `86%`current task `P2-402F`next task `P2-402G`
- 同步 `AI_AGENT_AUTOMATION_WORKLIST_2026-06-04.md``AI_AGENT_PROACTIVE_OPERATIONS_2026-06-11.md`、P2-402C/D/E 報告與 MASTER §3.2.1c / §5 / changelog。
**完成度同步**
- P2-402F`100%`
- AI Agent 主動營運委派與版本生命週期:`86%`
- Current task`P2-402F`
- Next task`P2-402G` governance UI 顯示可委派能力。
**邊界**
- 本波仍不 SSH、不執行 host command、不執行 kubectl、不 apt / kernel / K3s upgrade、不 node drain、不 kubelet restart、不 reboot、不 stateful restart、不 DB migration、不 restore、不 pull image、不發 Telegram、不讀取或輸出 secret、不回傳工作視窗對話內容。
## 2026-06-11P0 Telegram no-action 人工處置包
**背景**:使用者再次指出 Telegram 告警即使已改成 `NO_ACTION - REPAIR_CANDIDATE_MISSING`卡片仍只說「AI 選擇不執行修復,需要人工判斷」,但沒有產出可操作的人工處置選項、證據補齊清單、修復候選建立方式或後續驗證說明。這代表前一輪只止住 fake execution尚未把 no-action / 需人工路徑變成可接手的處置包。

View File

@@ -13,7 +13,7 @@
| 工具 / 服務 / 套件 AI 自動化 | 92% | P0 已完成P1 服務 / runtime / 監控 / provider / service health / 備份 / DR / 套件與供應鏈只讀基線已完成P1-007 失敗限定通知合約與前端 redaction 合約已完成;下一主線是 P2-004 依賴 / 供應鏈漂移監控 | 狀態分類、盤點 schema、權限矩陣、靜態盤點種子、只讀 API、UI 骨架、驗證、自動化待辦 schema / 快照 / API / 分組 UI、Backup / DR 目標盤點、準備度矩陣、備份通知政策、Backup / DR 證據 UI、復原演練批准包模板、異地 / escrow 準備度狀態、任務批准邊界、確定性進度彙總、Python 套件 / 供應鏈只讀基線、JS pnpm/npm 只讀基線、Docker build surface 只讀基線、CVE / license / drift 嚴重度政策、定期依賴漂移與外部資料來源檢查設計、依賴升級批准包模板、runtime_surface_inventory_v1 schema / snapshot / API / UI、gitea_workflow_runner_health_v1 schema / snapshot / API / UI、observability_contract_matrix_v1 schema / snapshot / API / UI、ai_provider_route_matrix_v1 schema / snapshot / API / UI、service_health_gap_matrix_v1 schema / snapshot / API / UI、service health evidence cards UI、service_health_failure_notification_policy_v1 schema / snapshot / API / UI 已完成 |
| OpenClaw / Hermes / NemoTron 佈建布局 | 45% | P1-401 / P1-402 已完成;仍是只讀 layout 與治理頁顯示,不是 runtime deploy | `ai_agent_deployment_layout_v1` schema、`ai_agent_deployment_layout_2026-06-11.json``GET /api/v1/agents/agent-deployment-layout`、治理頁自動化盤點 UI、`AI_AGENT_DEPLOYMENT_LAYOUT_2026-06-11.md` |
| OpenClaw / Hermes / NemoTron 主動溝通與學習契約 | 35% | P2-401A 已完成只讀 contractruntime worker、DB migration、Telegram 實發、SDK / 付費服務仍未開 gate | `ai_agent_communication_learning_contract_v1` schema、`ai_agent_communication_learning_contract_2026-06-11.json``GET /api/v1/agents/agent-communication-learning-contract`、MASTER §3.2.1b / §3.4.3 |
| AI Agent 主動營運委派與版本生命週期 | 78% | P2-402A / P2-402B / P2-402C / P2-402D / P2-402E 已完成;已建立 repo-only 版本新鮮度快照、工具採用批准包、Telegram action-required digest policy、Gitea PR 草案 lane 與 API。定期排程、外部版本查詢、工具安裝、CI 變更、套件升級、主機更新、container pull、實際 PR creation、auto merge、Telegram 實發仍未開 gate | `ai_agent_proactive_operations_contract_v1``ai_agent_version_freshness_snapshot_v1``ai_agent_tool_adoption_approval_package_v1``ai_agent_telegram_action_required_digest_policy_v1``ai_agent_gitea_pr_draft_lane_v1``GET /api/v1/agents/agent-proactive-operations-contract``GET /api/v1/agents/agent-version-freshness-snapshot``GET /api/v1/agents/agent-tool-adoption-approval-package``GET /api/v1/agents/agent-telegram-action-required-digest-policy``GET /api/v1/agents/agent-gitea-pr-draft-lane`、MASTER §3.2.1c |
| AI Agent 主動營運委派與版本生命週期 | 86% | P2-402A / P2-402B / P2-402C / P2-402D / P2-402E / P2-402F 已完成;已建立 repo-only 版本新鮮度快照、工具採用批准包、Telegram action-required digest policy、Gitea PR 草案 lane、host / K3s / stateful 版本只讀盤點與 API。定期排程、外部版本查詢、工具安裝、CI 變更、套件升級、主機更新、container pull、實際 PR creation、auto merge、Telegram 實發、SSH、kubectl、重啟仍未開 gate | `ai_agent_proactive_operations_contract_v1``ai_agent_version_freshness_snapshot_v1``ai_agent_tool_adoption_approval_package_v1``ai_agent_telegram_action_required_digest_policy_v1``ai_agent_gitea_pr_draft_lane_v1``ai_agent_host_stateful_version_inventory_v1``GET /api/v1/agents/agent-proactive-operations-contract``GET /api/v1/agents/agent-version-freshness-snapshot``GET /api/v1/agents/agent-tool-adoption-approval-package``GET /api/v1/agents/agent-telegram-action-required-digest-policy``GET /api/v1/agents/agent-gitea-pr-draft-lane``GET /api/v1/agents/agent-host-stateful-version-inventory`MASTER §3.2.1c |
| 本工作清單與分析報告 | 100% | 已完成 | 本 MD 文件 |
AI Agent 自動化工作包目前完成度:**92%**。本工作清單文件本身完成度:**100%**。
@@ -22,7 +22,7 @@ AI Agent 自動化工作包目前完成度:**92%**。本工作清單文件本
三 Agent 主動溝通與學習契約目前完成度:**35%**。已完成只讀 schema / snapshot / API / 測試與 MASTER 同步;下一步依優先順序推 `P2-401B` AgentSession / Redis Streams migration 與 worker gate但在批准前仍不得啟動 runtime loop。
AI Agent 主動營運委派與版本生命週期目前完成度:**78%**。已完成 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 版本只讀盤點,外部 registry / package source / host probe / 工具安裝 / CI 變更 / 實際 PR creation / Telegram 實發仍需 gate。
AI Agent 主動營運委派與版本生命週期目前完成度:**86%**。已完成 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 顯示可委派能力,外部 registry / package source / host probe / SSH / kubectl / 工具安裝 / CI 變更 / 實際 PR creation / Telegram 實發仍需 gate。
完成度計算模型:
@@ -956,7 +956,7 @@ UI
| P2-402C | 完成 | 100 | OpenClaw | 建立 Renovate / OSV-Scanner / Trivy / Syft / Grype 工具採用批准包 | `ai_agent_tool_adoption_approval_package_v1` / snapshot / 只讀 API / 測試5 工具、5 官方來源、4 採用 lane、6 批准欄位 | 只讀tool install、CI change、external lookup、vulnerability DB、PR、Telegram 全部未啟用 |
| P2-402D | 完成 | 100 | OpenClaw | 建立 Telegram action-required digest policy | `ai_agent_telegram_action_required_digest_policy_v1` / snapshot / 只讀 API / 測試8 條 digest rule、3 個 channel 草案、5 類 trigger category、成功降噪與 redaction policy | 只讀Telegram send、Gateway queue write、route / receiver change、workflow、runtime 全部未啟用 |
| P2-402E | 完成 | 100 | Hermes | 設計 Gitea PR 草案 lane | `ai_agent_gitea_pr_draft_lane_v1` / snapshot / 只讀 API / 測試6 條 grouping rule、7 個 lane step、9 個 required check、6 條 rollback requirement、4 個 draft template | 只讀branch push、PR creation、workflow trigger、lockfile、package upgrade、auto merge、Telegram 全部未啟用 |
| P2-402F | 待辦 | 0 | OpenClaw | 建立 host OS / K3s / stateful services 版本只讀盤點 | host / K3s / DB / Redis / MinIO / Gitea 版本矩陣 | host readonly probe + maintenance window approval |
| P2-402F | 完成 | 100 | OpenClaw | 建立 host OS / K3s / stateful services 版本只讀盤點 | `ai_agent_host_stateful_version_inventory_v1` / snapshot / 只讀 API / 測試5 台主機、2 個 K3s 節點、12 個 stateful / ops 服務、6 個只讀 probe step、maintenance window approval package | 只讀SSH、kubectl、apt / K3s upgrade、node drain、reboot、stateful restart、Telegram 全部未啟用 |
| P2-402G | 待辦 | 0 | Hermes | 接入 governance UI 顯示可委派能力 | 自主等級、gate、owner、Telegram policy | frontend UI change approval |
| P2-101 | 待辦 | 0 | OpenClaw | 定義操作類別權限模型 | 操作政策 schema | HITL 關卡 |
| P2-102 | 待辦 | 0 | OpenClaw | 所有候選操作都要有 dry-run 證據 | dry-run 合約 | 不直接 apply |

View File

@@ -1,7 +1,7 @@
# AI Agent Gitea PR 草案 Lane 工作報告
> 日期2026-06-11台北時間
> 狀態P2-402E 已完成;整體 AI Agent 主動營運與版本生命週期完成度 78%。
> 狀態P2-402E 已完成;P2-402F 已接續完成;整體 AI Agent 主動營運與版本生命週期完成度 86%。
> 邊界:本文件與對應 API 只提供 Gitea PR 草案 lane不 push branch、不建立或更新 Gitea PR、不留言、不 auto merge、不觸發 workflow、不改 CI、不寫 lockfile、不升級套件、不 build / pull image、不發 Telegram、不顯示工作視窗對話內容。
## 1. 本波完成項目
@@ -13,7 +13,7 @@
| API loader | 完成 | `apps/api/src/services/ai_agent_gitea_pr_draft_lane.py` |
| 只讀 API | 完成 | `GET /api/v1/agents/agent-gitea-pr-draft-lane` |
| 測試 | 完成 | loader / API / PR creation boundary / automerge boundary / blocking checks / owner response / transcript redaction |
| 主契約同步 | 完成 | `ai_agent_proactive_operations_contract_v1` 完成度 78%current `P2-402E`next `P2-402F` |
| 主契約同步 | 完成 | `ai_agent_proactive_operations_contract_v1` 已由 P2-402F 推進到完成度 86%current `P2-402F`next `P2-402G` |
## 2. Grouping 規則摘要
@@ -66,7 +66,7 @@
| 優先 | ID | 工作 | 完成標準 |
|---:|---|---|---|
| 1 | P2-402F | host OS / K3s / stateful services 版本只讀盤點 | 主機、K3s、PostgreSQL、Redis、MinIO、Harbor、Gitea 版本矩陣;只讀 probe / maintenance approval |
| 1 | P2-402F | host OS / K3s / stateful services 版本只讀盤點 | 已完成;只讀 schema / snapshot / API / 測試SSH / kubectl / upgrade / reboot 未啟用 |
| 2 | P2-402G | Governance UI 顯示可委派能力 | 前端顯示 autonomy level、gate、owner、Telegram policy無執行按鈕 |
| 3 | 候選池 | Gitea bot / branch policy approval package | bot account、branch naming、PR permission、rollback、audit trail |
| 4 | 候選池 | Draft PR packet renderer | 把 grouping / test / rollback / owner response 轉為可審核 PR 草案,不呼叫 Gitea API |

View File

@@ -0,0 +1,66 @@
# AI Agent Host / K3s / Stateful 版本只讀盤點
> 日期2026-06-11台北時間
> 狀態P2-402F 已完成;整體 AI Agent 主動營運與版本生命週期完成度 86%。
> 事實來源:`ai_agent_host_stateful_version_inventory_v1`、`ai_agent_proactive_operations_contract_v1`、MASTER §3.2.1c。
## 1. 本波完成
| 項目 | 狀態 | 說明 |
|---|---|---|
| Schema | 完成 | `docs/schemas/ai_agent_host_stateful_version_inventory_v1.schema.json` |
| Snapshot | 完成 | `docs/evaluations/ai_agent_host_stateful_version_inventory_2026-06-11.json` |
| 只讀 loader | 完成 | 強制 SSH / kubectl / upgrade / drain / reboot / restart / Telegram / transcript gate 全為 false |
| API | 完成 | `GET /api/v1/agents/agent-host-stateful-version-inventory` |
| 測試 | 完成 | loader / API / rollup / reboot / drain / stateful restart / redaction boundary |
| 主契約同步 | 完成 | `ai_agent_proactive_operations_contract_v1` 完成度 86%current `P2-402F`next `P2-402G` |
## 2. 盤點範圍
| 類別 | 數量 | 內容 |
|---|---:|---|
| Host | 5 | 188 AI / DB / monitoring / backup110 DevOps / registry112 Kali read-only120 K3s blocked121 K3s peer / VIP evidence |
| K3s node | 2 | 120 server、121 server需要 skew policy、node readiness、ArgoCD sync / health 與 rollback ref |
| Stateful / ops service | 12 | PostgreSQL、Redis、MinIO、ClickHouse、SignOz、Prometheus、Alertmanager、Gitea、Harbor、Sentry、Langfuse、ArgoCD |
| Readonly probe step | 6 | endpoint map、CD banner evidence、host probe packet、K3s skew packet、stateful packet、maintenance packet |
| Maintenance required fields | 11 | owner、decision、maintenance window、affected scope、backup snapshot、rollback、smoke、communication、risk acceptance |
## 3. 仍維持 false
| Gate | 值 |
|---|---|
| SSH login | false |
| Host command execution | false |
| Kubectl command execution | false |
| Apt / kernel / K3s upgrade | false |
| Node drain / kubelet restart | false |
| Reboot | false |
| Stateful service restart / upgrade | false |
| DB migration / restore / backup delete | false |
| Image pull / package install | false |
| External version lookup / active scan | false |
| Telegram direct send / queue write | false |
| Secret plaintext / 工作視窗對話內容 | false |
## 4. Maintenance Window 批准包
任何從「只讀盤點」進到「live probe」或「變更」前都必須補齊
| 欄位 | 用途 |
|---|---|
| owner / decision | 明確責任人與是否接受風險 |
| maintenance_window | 維護時間窗,不可由 Agent 自行假設 |
| affected_hosts / affected_services | 爆炸半徑與服務清單 |
| backup_snapshot_ref | 變更前備份證據 |
| rollback_owner / rollback_plan | 回滾責任人與步驟 |
| smoke_plan | public / NodePort / stateful / backup / rollback readback |
| communication_plan | Telegram / AwoooP / owner 溝通草案 |
| risk_acceptance | 人工接受風險,不可由 AI 自動批准 |
## 5. 下一步
| 優先 | 任務 | 關卡 |
|---:|---|---|
| 1 | P2-402G Governance UI 顯示可委派能力 | frontend UI change approval |
| 2 | Host readonly probe owner request | 需 owner approval不得直接 SSH / kubectl |
| 3 | Stateful backup freshness packet | 需備份 evidence不得 restore / prune |

View File

@@ -1,7 +1,7 @@
# AI Agent 主動營運委派與版本生命週期分析報告
> 日期2026-06-11台北時間
> 文件定位P2-402A / P2-402B / P2-402C / P2-402D / P2-402E 只讀契約摘要。權威細節以 MASTER §3.2.1c、`ai_agent_proactive_operations_contract_v1`、`ai_agent_version_freshness_snapshot_v1`、`ai_agent_tool_adoption_approval_package_v1`、`ai_agent_telegram_action_required_digest_policy_v1``ai_agent_gitea_pr_draft_lane_v1` 為準。
> 文件定位P2-402A / P2-402B / P2-402C / P2-402D / P2-402E / P2-402F 只讀契約摘要。權威細節以 MASTER §3.2.1c、`ai_agent_proactive_operations_contract_v1`、`ai_agent_version_freshness_snapshot_v1`、`ai_agent_tool_adoption_approval_package_v1`、`ai_agent_telegram_action_required_digest_policy_v1``ai_agent_gitea_pr_draft_lane_v1` 與 `ai_agent_host_stateful_version_inventory_v1` 為準。
## 1. 本波完成度
@@ -12,7 +12,8 @@
| 工具採用批准包 | 100% | P2-402C 已完成 Renovate / OSV-Scanner / Trivy / Syft / Grype schema / committed snapshot / API / 測試 |
| Telegram action-required digest policy | 100% | P2-402D 已完成 critical / action-required / failure-only digest schema / committed snapshot / API / 測試 |
| Gitea PR 草案 lane | 100% | P2-402E 已完成 grouping、automerge=false、測試證據、rollback、owner response schema / committed snapshot / API / 測試 |
| 整體主動營運與版本生命週期 | 78% | 已完成架構、repo-only freshness、工具採用批准包、Telegram digest policy 與 Gitea PR 草案 laneruntime 排程、工具安裝、CI 變更、實際 PR 建立與更新仍未開 gate |
| Host / K3s / stateful 版本只讀盤點 | 100% | P2-402F 已完成 5 台主機、2 個 K3s 節點、12 個 stateful / ops 服務與 maintenance window 批准包 schema / committed snapshot / API / 測試 |
| 整體主動營運與版本生命週期 | 86% | 已完成架構、repo-only freshness、工具採用批准包、Telegram digest policy、Gitea PR 草案 lane 與 host / K3s / stateful 版本只讀盤點runtime 排程、工具安裝、CI 變更、實際 PR 建立與更新、host probe、升級、重啟仍未開 gate |
## 2. 可交給 AI Agent 的工作分類
@@ -46,6 +47,9 @@
| `docs/schemas/ai_agent_gitea_pr_draft_lane_v1.schema.json` | Gitea PR 草案 lane schemabranch push、PR creation、workflow trigger、lockfile、automerge、Telegram 全部預設 false |
| `docs/evaluations/ai_agent_gitea_pr_draft_lane_2026-06-11.json` | 6 條 grouping rule、7 個 lane step、9 個 required check、6 條 rollback requirement、4 個 draft template |
| `GET /api/v1/agents/agent-gitea-pr-draft-lane` | 只讀 API不 push branch、不建立 PR、不觸發 workflow、不改 CI、不升級套件、不發 Telegram |
| `docs/schemas/ai_agent_host_stateful_version_inventory_v1.schema.json` | Host / K3s / stateful 版本只讀盤點 schemaSSH、kubectl、upgrade、drain、reboot、restart、Telegram 全部預設 false |
| `docs/evaluations/ai_agent_host_stateful_version_inventory_2026-06-11.json` | 5 台主機、2 個 K3s 節點、12 個 stateful / ops 服務、6 個只讀 probe 步驟、maintenance window approval package |
| `GET /api/v1/agents/agent-host-stateful-version-inventory` | 只讀 API不 SSH、不 kubectl、不升級、不 drain、不 reboot、不重啟 stateful、不發 Telegram |
## 4. P2-402B Repo-only 版本新鮮度快照
@@ -94,16 +98,28 @@ P2-402C 的重點是把「哪些工具可被採用、採用前要填哪些批准
P2-402E 的重點是先把「PR 草案要長什麼樣、要有哪些證據、誰要回覆、怎麼 rollback」固定成契約。它不是 Gitea bot 啟用bot account、branch policy、實際 PR creation、workflow trigger、lockfile write、package upgrade、Telegram 實發全部維持 blocked。
## 8. 下一步優先順序
## 8. P2-402F Host / K3s / Stateful 版本只讀盤點
| 類別 | 本波定義 | 仍禁止 |
|---|---|---|
| Host inventory | 5 台主機188 AI / DB / monitoring / backup、110 DevOps / registry、112 Kali read-only、120 K3s blocked、121 K3s peer / VIP evidence | 不 SSH、不跑 host command、不 apt upgrade、不 reboot |
| K3s inventory | 2 個 K3s server 節點與 VIP API endpoint要求 version skew policy、node readiness、ArgoCD sync / health、rollback ref | 不 kubectl、不 K3s upgrade、不 node drain、不 kubelet restart |
| Stateful services | 12 個服務PostgreSQL、Redis、MinIO、ClickHouse、SignOz、Prometheus、Alertmanager、Gitea、Harbor、Sentry、Langfuse、ArgoCD | 不 restart、不 upgrade、不 migration、不 restore、不刪 backup |
| Readonly probe packet | 6 個 planned-only steprepo endpoint map、CD banner evidence、host probe packet、K3s skew packet、stateful packet、maintenance window packet | 不把 planned probe 當已執行,不開 runtime gate |
| Maintenance window | owner、decision、maintenance window、affected scope、backup snapshot、rollback owner、smoke plan、communication plan、risk acceptance | 不用 Agent 自我批准取代 owner gate |
P2-402F 的重點是把「要盤哪些主機與 stateful 服務、盤點前要誰批准、升級前要哪些備份與 rollback 證據」固定成資料契約。它不是主機探測或升級SSH、kubectl、apt upgrade、K3s upgrade、node drain、reboot、stateful restart、Telegram 實發全部維持 blocked。
## 9. 下一步優先順序
| ID | 優先 | 任務 | 關卡 |
|---|---|---|---|
| P2-402D | 0 | Telegram action-required digest policy | 已完成只讀Telegram send / queue write 未啟用 |
| P2-402E | 1 | Gitea PR 草案 lane | 已完成只讀branch push / PR creation / workflow trigger 未啟用 |
| P2-402F | 2 | host OS / K3s / stateful services 版本只讀盤點 | host probe / maintenance approval |
| P2-402F | 2 | host OS / K3s / stateful services 版本只讀盤點 | 已完成只讀SSH / kubectl / upgrade / reboot 未啟用 |
| P2-402G | 3 | governance UI 顯示可委派能力 | frontend UI approval |
## 8. 仍維持 false 的安全邊界
## 10. 仍維持 false 的安全邊界
- `runtime_version_update_allowed=false`
- `package_upgrade_allowed=false`
@@ -119,3 +135,10 @@ P2-402E 的重點是先把「PR 草案要長什麼樣、要有哪些證據、誰
- `external_registry_lookup_allowed=false`
- `daily_schedule_enabled=false`
- `gitea_pr_creation_allowed=false`
- `ssh_login_allowed=false`
- `kubectl_command_execution_allowed=false`
- `apt_upgrade_allowed=false`
- `k3s_upgrade_allowed=false`
- `node_drain_allowed=false`
- `reboot_allowed=false`
- `stateful_service_restart_allowed=false`

View File

@@ -50,6 +50,6 @@
| 優先 | ID | 工作 | 完成標準 |
|---:|---|---|---|
| 1 | P2-402E | Gitea PR 草案 lane | 已完成Renovate grouping、automerge=false、測試要求、rollback、owner responsebot / branch policy 仍未批准 |
| 2 | P2-402F | host OS / K3s / stateful services 版本只讀盤點 | 主機、K3s、PostgreSQL、Redis、MinIO、Harbor、Gitea 只讀版本矩陣 |
| 2 | P2-402F | host OS / K3s / stateful services 版本只讀盤點 | 已完成;主機、K3s、PostgreSQL、Redis、MinIO、Harbor、Gitea 只讀版本矩陣 |
| 3 | P2-402G | Governance UI 顯示可委派能力 | 前端顯示 autonomy level、gate、owner、Telegram policy無執行按鈕 |
| 4 | 候選池 | Telegram Gateway E2E 批准包 | queue write / send / callback / fallback path 的測試與 rollout gate |

View File

@@ -39,7 +39,7 @@
|---:|---|---|---|---|
| 1 | P2-402D | Telegram action-required digest policy | 定義 critical / action-required / failure-only禁止成功洗版接 Telegram Gateway E2E gate | 完成 |
| 2 | P2-402E | Gitea PR 草案 lane | Renovate grouping、automerge=false、測試要求、rollback、owner response | 完成 |
| 3 | P2-402F | host OS / K3s / stateful services 版本只讀盤點 | 主機、K3s、PostgreSQL、Redis、MinIO、Harbor、Gitea 只讀版本矩陣 | 待辦 |
| 3 | P2-402F | host OS / K3s / stateful services 版本只讀盤點 | 主機、K3s、PostgreSQL、Redis、MinIO、Harbor、Gitea 只讀版本矩陣 | 完成 |
| 4 | P2-402G | Governance UI 顯示可委派能力 | 前端顯示 autonomy level、gate、owner、Telegram policy無執行按鈕 | 待辦 |
| 5 | 候選池 | SBOM artifact policy | Syft / Trivy artifact 格式、保存、redaction、消費者規則 | 未排正式編號 |
| 6 | 候選池 | Scanner false-positive policy | OSV / Trivy / Grype 差異、suppression、severity mapping、owner SLA | 未排正式編號 |

View File

@@ -0,0 +1,586 @@
{
"schema_version": "ai_agent_host_stateful_version_inventory_v1",
"generated_at": "2026-06-11T15:31:00+08:00",
"program_status": {
"overall_completion_percent": 86,
"current_task_id": "P2-402F",
"next_task_id": "P2-402G",
"read_only_mode": true,
"runtime_authority": "host_stateful_readonly_inventory_no_upgrade_or_restart",
"status_note": "已建立 host OS / K3s / stateful services 版本只讀盤點與 maintenance window 批准包;仍不執行 SSH、kubectl、升級、重啟、drain、restore、Telegram 實發或外部版本查詢。"
},
"source_refs": [
{
"ref_id": "service_endpoints",
"path": "docs/reference/SERVICE-ENDPOINTS.md",
"usage": "主機、K3s VIP、AI、資料庫、監控、DevOps、備份與安全端點來源。"
},
{
"ref_id": "deployment_layout",
"path": "docs/evaluations/ai_agent_deployment_layout_2026-06-11.json",
"usage": "AI Agent 在 188 / 110 / 112 / 120 / 121 的只讀佈建與 gate 來源。"
},
{
"ref_id": "version_freshness",
"path": "docs/evaluations/ai_agent_version_freshness_snapshot_2026-06-11.json",
"usage": "P2-402B 已明確把 host / K3s live version probe 留給 P2-402F gate。"
},
{
"ref_id": "latest_cd_evidence",
"path": "Gitea cd.yaml run 2667 log",
"usage": "部署過程只讀看到 121/125 login banner 與 rollout evidence未使用 SSH 手動命令,未收 secret value。"
},
{
"ref_id": "hard_rules_high_value_config",
"path": "docs/HARD_RULES.md#high-value-config-control",
"usage": "主機、K3s、workflow、secret、backup、AI provider 與 runtime config 變更必須 source-of-truth、owner gate、diff、rollback 與驗證。"
}
],
"operation_boundaries": {
"read_only_inventory_allowed": true,
"ssh_login_allowed": false,
"host_command_execution_allowed": false,
"kubectl_command_execution_allowed": false,
"apt_upgrade_allowed": false,
"os_release_upgrade_allowed": false,
"kernel_upgrade_allowed": false,
"k3s_upgrade_allowed": false,
"kubelet_restart_allowed": false,
"node_drain_allowed": false,
"reboot_allowed": false,
"stateful_service_restart_allowed": false,
"database_migration_allowed": false,
"backup_delete_allowed": false,
"restore_execution_allowed": false,
"image_pull_allowed": false,
"package_install_allowed": false,
"external_version_lookup_allowed": false,
"active_network_scan_allowed": false,
"telegram_direct_send_allowed": false,
"telegram_gateway_queue_write_allowed": false,
"secret_plaintext_allowed": false,
"conversation_transcript_allowed": false
},
"approval_boundaries": {
"host_readonly_probe_approved": false,
"ssh_probe_approved": false,
"kubectl_probe_approved": false,
"maintenance_window_approved": false,
"apt_upgrade_approved": false,
"kernel_upgrade_approved": false,
"k3s_upgrade_approved": false,
"node_drain_approved": false,
"reboot_approved": false,
"stateful_restart_approved": false,
"stateful_upgrade_approved": false,
"backup_restore_drill_approved": false,
"telegram_send_approved": false
},
"agent_roles": [
{
"agent": "OpenClaw",
"role": "仲裁者",
"responsibility": "判斷 host / K3s / stateful 版本盤點是否可進 owner gate禁止在證據不足時推升級或重啟。"
},
{
"agent": "Hermes",
"role": "執行規劃者",
"responsibility": "整理 repo evidence、probe 草案、maintenance window packet 與 rollback checklist不執行命令。"
},
{
"agent": "NemoTron",
"role": "研究助理",
"responsibility": "在 dry-run / human-review 邊界內協助摘要版本 skew 與相依性風險,不做生產建議最終裁決。"
}
],
"host_inventory": [
{
"host_id": "host_188_ai_db_monitoring_backup",
"display_name": "188 AI / DB / monitoring / backup host",
"known_addresses": [
"192.168.0.188"
],
"primary_surfaces": [
"Ollama",
"OpenClaw",
"PostgreSQL",
"Redis",
"SignOz",
"ClickHouse",
"Prometheus",
"Alertmanager",
"MinIO"
],
"version_observation_status": "repo_reference_only_live_probe_not_run",
"readonly_only": true,
"host_update_authorized": false,
"reboot_authorized": false,
"maintenance_window_required": true,
"next_evidence_needed": [
"os-release",
"kernel version",
"docker / container runtime version",
"stateful service versions",
"backup freshness"
],
"blocked_actions": [
"apt upgrade",
"kernel upgrade",
"reboot",
"stateful restart",
"backup delete",
"restore execution"
]
},
{
"host_id": "host_110_devops_registry",
"display_name": "110 DevOps / registry host",
"known_addresses": [
"192.168.0.110"
],
"primary_surfaces": [
"Gitea",
"Harbor registry",
"Sentry",
"Langfuse",
"Prometheus blackbox exporter"
],
"version_observation_status": "repo_reference_only_live_probe_not_run",
"readonly_only": true,
"host_update_authorized": false,
"reboot_authorized": false,
"maintenance_window_required": true,
"next_evidence_needed": [
"os-release",
"Gitea version",
"registry version",
"Sentry / Langfuse version",
"runner health"
],
"blocked_actions": [
"workflow change",
"runner restart",
"registry image delete",
"host package upgrade",
"reboot"
]
},
{
"host_id": "host_112_kali_readonly",
"display_name": "112 Kali scanner read-only host",
"known_addresses": [
"192.168.0.112"
],
"primary_surfaces": [
"Kali scanner API",
"security evidence collector"
],
"version_observation_status": "repo_reference_only_live_probe_not_run",
"readonly_only": true,
"host_update_authorized": false,
"reboot_authorized": false,
"maintenance_window_required": true,
"next_evidence_needed": [
"scanner service version",
"tool package baseline",
"active scan gate state"
],
"blocked_actions": [
"active scan",
"credentialed scan",
"tool upgrade",
"reboot"
]
},
{
"host_id": "host_120_k3s_master_blocked",
"display_name": "120 K3s master / blocked recovery host",
"known_addresses": [
"192.168.0.120"
],
"primary_surfaces": [
"K3s server",
"control-plane recovery context"
],
"version_observation_status": "blocked_host_live_probe_not_run",
"readonly_only": true,
"host_update_authorized": false,
"reboot_authorized": false,
"maintenance_window_required": true,
"next_evidence_needed": [
"reachability evidence",
"K3s version",
"node readiness",
"kubelet status"
],
"blocked_actions": [
"ssh probe",
"node drain",
"K3s upgrade",
"kubelet restart",
"reboot"
]
},
{
"host_id": "host_121_k3s_peer",
"display_name": "121 K3s peer host",
"known_addresses": [
"192.168.0.121",
"192.168.0.125"
],
"primary_surfaces": [
"K3s server",
"VIP endpoint",
"AWOOOI API/Web/Worker rollout evidence"
],
"version_observation_status": "cd_login_banner_observed_os_only",
"observed_evidence_summary": "Gitea CD run 2667 login banner observed Ubuntu 22.04.5 LTS and kernel 5.15.0-179-generic on the deploy target; this is deployment evidence only, not a full host version inventory.",
"readonly_only": true,
"host_update_authorized": false,
"reboot_authorized": false,
"maintenance_window_required": true,
"next_evidence_needed": [
"K3s version",
"kubectl version",
"container runtime version",
"node readiness",
"pending package updates with owner gate"
],
"blocked_actions": [
"apt upgrade",
"do-release-upgrade",
"node drain",
"K3s upgrade",
"reboot"
]
}
],
"k3s_inventory": {
"cluster_id": "awoooi_prod_k3s",
"api_endpoint": "192.168.0.125:6443",
"version_observation_status": "repo_reference_only_kubectl_probe_not_run",
"skew_policy_required": true,
"upgrade_authorized": false,
"nodes": [
{
"node_id": "k3s_120",
"host_id": "host_120_k3s_master_blocked",
"role": "server",
"readonly_only": true,
"drain_authorized": false,
"kubelet_restart_authorized": false,
"version_observation_status": "blocked_host_live_probe_not_run"
},
{
"node_id": "k3s_121",
"host_id": "host_121_k3s_peer",
"role": "server",
"readonly_only": true,
"drain_authorized": false,
"kubelet_restart_authorized": false,
"version_observation_status": "rollout_evidence_only_version_probe_not_run"
}
],
"required_pre_change_evidence": [
"kubectl version --client/output redacted",
"K3s server version",
"node readiness",
"current ArgoCD sync / health",
"version skew policy assessment",
"rollback ref"
]
},
"stateful_services": [
{
"service_id": "postgresql",
"display_name": "PostgreSQL",
"host_id": "host_188_ai_db_monitoring_backup",
"endpoint_ref": "docs/reference/SERVICE-ENDPOINTS.md#資料庫-1921680188",
"version_observation_status": "repo_reference_only_live_probe_not_run",
"readonly_only": true,
"restart_authorized": false,
"upgrade_authorized": false,
"backup_required_before_change": true
},
{
"service_id": "redis",
"display_name": "Redis",
"host_id": "host_188_ai_db_monitoring_backup",
"endpoint_ref": "docs/reference/SERVICE-ENDPOINTS.md#資料庫-1921680188",
"version_observation_status": "repo_reference_only_live_probe_not_run",
"readonly_only": true,
"restart_authorized": false,
"upgrade_authorized": false,
"backup_required_before_change": true
},
{
"service_id": "minio",
"display_name": "MinIO",
"host_id": "host_188_ai_db_monitoring_backup",
"endpoint_ref": "docs/reference/SERVICE-ENDPOINTS.md#備份-1921680188",
"version_observation_status": "repo_reference_only_live_probe_not_run",
"readonly_only": true,
"restart_authorized": false,
"upgrade_authorized": false,
"backup_required_before_change": true
},
{
"service_id": "clickhouse",
"display_name": "ClickHouse",
"host_id": "host_188_ai_db_monitoring_backup",
"endpoint_ref": "docs/reference/SERVICE-ENDPOINTS.md#監控-1921680188--1921680110",
"version_observation_status": "repo_reference_only_live_probe_not_run",
"readonly_only": true,
"restart_authorized": false,
"upgrade_authorized": false,
"backup_required_before_change": true
},
{
"service_id": "signoz",
"display_name": "SignOz",
"host_id": "host_188_ai_db_monitoring_backup",
"endpoint_ref": "docs/reference/SERVICE-ENDPOINTS.md#監控-1921680188--1921680110",
"version_observation_status": "repo_reference_only_live_probe_not_run",
"readonly_only": true,
"restart_authorized": false,
"upgrade_authorized": false,
"backup_required_before_change": true
},
{
"service_id": "prometheus",
"display_name": "Prometheus",
"host_id": "host_188_ai_db_monitoring_backup",
"endpoint_ref": "docs/reference/SERVICE-ENDPOINTS.md#監控-1921680188--1921680110",
"version_observation_status": "repo_reference_only_live_probe_not_run",
"readonly_only": true,
"restart_authorized": false,
"upgrade_authorized": false,
"backup_required_before_change": true
},
{
"service_id": "alertmanager",
"display_name": "Alertmanager",
"host_id": "host_188_ai_db_monitoring_backup",
"endpoint_ref": "docs/reference/SERVICE-ENDPOINTS.md#監控-1921680188--1921680110",
"version_observation_status": "repo_reference_only_live_probe_not_run",
"readonly_only": true,
"restart_authorized": false,
"upgrade_authorized": false,
"backup_required_before_change": true
},
{
"service_id": "gitea",
"display_name": "Gitea",
"host_id": "host_110_devops_registry",
"endpoint_ref": "docs/reference/SERVICE-ENDPOINTS.md#devops-1921680110",
"version_observation_status": "repo_reference_only_live_probe_not_run",
"readonly_only": true,
"restart_authorized": false,
"upgrade_authorized": false,
"backup_required_before_change": true
},
{
"service_id": "harbor_registry",
"display_name": "Harbor / registry",
"host_id": "host_110_devops_registry",
"endpoint_ref": "docs/reference/SERVICE-ENDPOINTS.md#devops-1921680110",
"version_observation_status": "repo_reference_only_live_probe_not_run",
"readonly_only": true,
"restart_authorized": false,
"upgrade_authorized": false,
"backup_required_before_change": true
},
{
"service_id": "sentry",
"display_name": "Sentry",
"host_id": "host_110_devops_registry",
"endpoint_ref": "docs/reference/SERVICE-ENDPOINTS.md#監控-1921680188--1921680110",
"version_observation_status": "repo_reference_only_live_probe_not_run",
"readonly_only": true,
"restart_authorized": false,
"upgrade_authorized": false,
"backup_required_before_change": true
},
{
"service_id": "langfuse",
"display_name": "Langfuse",
"host_id": "host_110_devops_registry",
"endpoint_ref": "docs/reference/SERVICE-ENDPOINTS.md#監控-1921680188--1921680110",
"version_observation_status": "repo_reference_only_live_probe_not_run",
"readonly_only": true,
"restart_authorized": false,
"upgrade_authorized": false,
"backup_required_before_change": true
},
{
"service_id": "argocd",
"display_name": "ArgoCD",
"host_id": "host_121_k3s_peer",
"endpoint_ref": "docs/reference/SERVICE-ENDPOINTS.md#k3s-叢集管理",
"version_observation_status": "repo_reference_only_live_probe_not_run",
"readonly_only": true,
"restart_authorized": false,
"upgrade_authorized": false,
"backup_required_before_change": true
}
],
"readonly_probe_plan": [
{
"step_id": "repo_endpoint_map",
"display_name": "Repo endpoint map 對齊",
"planned_output": "整理 SERVICE-ENDPOINTS、runtime surface、deployment layout 的主機與服務 mapping。",
"run_now_allowed": false,
"mutation_allowed": false
},
{
"step_id": "cd_banner_evidence_extract",
"display_name": "CD banner evidence 摘要",
"planned_output": "只讀引用最新 CD login banner / rollout log標註其侷限不當成完整版本盤點。",
"run_now_allowed": false,
"mutation_allowed": false
},
{
"step_id": "host_readonly_probe_packet",
"display_name": "Host readonly probe packet",
"planned_output": "準備 os-release、kernel、container runtime、package pending summary 的 owner approval request。",
"run_now_allowed": false,
"mutation_allowed": false
},
{
"step_id": "k3s_version_skew_packet",
"display_name": "K3s version skew packet",
"planned_output": "準備 K3s / kubectl / node readiness / skew policy 的只讀證據欄位。",
"run_now_allowed": false,
"mutation_allowed": false
},
{
"step_id": "stateful_service_version_packet",
"display_name": "Stateful service version packet",
"planned_output": "準備 PostgreSQL、Redis、MinIO、Gitea、Harbor、監控服務的版本與備份前置欄位。",
"run_now_allowed": false,
"mutation_allowed": false
},
{
"step_id": "maintenance_window_packet",
"display_name": "Maintenance window approval packet",
"planned_output": "產出 owner、affected scope、backup、rollback、smoke、communication 與 risk acceptance 欄位。",
"run_now_allowed": false,
"mutation_allowed": false
}
],
"maintenance_window_approval_package": {
"package_id": "host_stateful_maintenance_window_packet_v1",
"approval_required_before_probe": true,
"approval_required_before_change": true,
"break_glass_record_required": true,
"required_fields": [
"owner",
"decision",
"maintenance_window",
"affected_hosts",
"affected_services",
"backup_snapshot_ref",
"rollback_owner",
"rollback_plan",
"smoke_plan",
"communication_plan",
"risk_acceptance"
],
"forbidden_fields": [
"secret value",
"private key",
"authorization header",
"cookie",
"session payload",
"work-window transcript",
"chain-of-thought"
],
"minimum_smoke_plan": [
"public health",
"internal NodePort health when applicable",
"stateful service ready check",
"backup freshness readback",
"rollback ref readback"
]
},
"telegram_policy": {
"status": "draft_only",
"direct_send_allowed": false,
"gateway_queue_write_allowed": false,
"allowed_digest_types_after_gate": [
"action_required_missing_evidence",
"critical_version_skew",
"maintenance_window_owner_response_needed",
"rollout_failure"
],
"success_noise_suppression": true
},
"display_redaction_contract": {
"conversation_transcript_display_allowed": false,
"redaction_required": true,
"allowed_frontend_fields": [
"整體完成度",
"目前任務",
"下一任務",
"主機版本盤點摘要",
"K3s skew gate",
"stateful services 摘要",
"maintenance window approval package"
],
"forbidden_frontend_content": [
"工作視窗對話內容",
"secret 明文",
"private key",
"authorization header",
"cookie",
"prompt 全文",
"chain-of-thought",
"browser session context"
]
},
"rollups": {
"host_count": 5,
"k3s_node_count": 2,
"stateful_service_count": 12,
"readonly_probe_step_count": 6,
"maintenance_required_field_count": 11,
"host_ids": [
"host_110_devops_registry",
"host_112_kali_readonly",
"host_120_k3s_master_blocked",
"host_121_k3s_peer",
"host_188_ai_db_monitoring_backup"
],
"stateful_service_ids": [
"alertmanager",
"argocd",
"clickhouse",
"gitea",
"harbor_registry",
"langfuse",
"minio",
"postgresql",
"prometheus",
"redis",
"sentry",
"signoz"
],
"ssh_login_allowed_count": 0,
"kubectl_command_execution_allowed_count": 0,
"apt_upgrade_allowed_count": 0,
"k3s_upgrade_allowed_count": 0,
"node_drain_allowed_count": 0,
"reboot_allowed_count": 0,
"stateful_service_restart_allowed_count": 0,
"telegram_direct_send_allowed_count": 0,
"conversation_transcript_allowed_count": 0
},
"next_actions": [
{
"task_id": "P2-402G",
"priority": "P2",
"summary": "把可委派能力接入 governance UI顯示 autonomy level、gate、owner、Telegram policy。",
"gate": "frontend_ui_change_approval_required"
}
]
}

View File

@@ -2,13 +2,13 @@
"schema_version": "ai_agent_proactive_operations_contract_v1",
"generated_at": "2026-06-11T21:30:00+08:00",
"program_status": {
"overall_completion_percent": 78,
"overall_completion_percent": 86,
"current_priority": "P2",
"current_task_id": "P2-402E",
"next_task_id": "P2-402F",
"current_task_id": "P2-402F",
"next_task_id": "P2-402G",
"read_only_mode": true,
"runtime_authority": "contract_only_no_version_or_runtime_update",
"status_note": "P2-402E 已建立 Gitea PR 草案 lane、schema、snapshot、只讀 API 與測試;本波仍不 push branch、不建立或更新 Gitea PR、不觸發 workflow、不改 CI、不寫 lockfile、不升級套件、不發 Telegram。"
"status_note": "P2-402F 已建立 host OS / K3s / stateful services 版本只讀盤點與 maintenance window 批准包;本波仍不 SSH、不執行 kubectl、不升級主機 / K3s / stateful service、不 drain、不 reboot、不發 Telegram。"
},
"external_source_evidence": [
{
@@ -646,16 +646,16 @@
"completion_percent": 100,
"owner_agent": "Hermes",
"summary": "建立 Gitea PR 草案 lane、schema、snapshot、只讀 API 與測試;定義 grouping、automerge=false、測試證據、rollback、owner response 與 redaction policy。",
"next_gate": "P2-402F_host_stateful_version_inventory"
"next_gate": "P2-402F_completed"
},
{
"task_id": "P2-402F",
"priority": "P2",
"status": "planned",
"completion_percent": 0,
"status": "done",
"completion_percent": 100,
"owner_agent": "OpenClaw",
"summary": "建立 host OS / K3s / stateful services 版本只讀盤點maintenance window 批准包。",
"next_gate": "host_readonly_probe_and_maintenance_window_approval_required"
"summary": "建立 host OS / K3s / stateful services 版本只讀盤點maintenance window 批准包、schema、snapshot、只讀 API 與測試;所有 SSH / kubectl / upgrade / drain / reboot / restart gate 維持 false。",
"next_gate": "P2-402G_governance_ui_capability_display"
},
{
"task_id": "P2-402G",

View File

@@ -0,0 +1,184 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://awoooi.wooo.work/schemas/ai_agent_host_stateful_version_inventory_v1.schema.json",
"title": "AI Agent Host Stateful Version Inventory v1",
"type": "object",
"required": [
"schema_version",
"generated_at",
"program_status",
"operation_boundaries",
"approval_boundaries",
"host_inventory",
"k3s_inventory",
"stateful_services",
"readonly_probe_plan",
"maintenance_window_approval_package",
"display_redaction_contract",
"rollups"
],
"additionalProperties": true,
"properties": {
"schema_version": {
"const": "ai_agent_host_stateful_version_inventory_v1"
},
"generated_at": {
"type": "string"
},
"program_status": {
"type": "object",
"required": [
"overall_completion_percent",
"current_task_id",
"next_task_id",
"read_only_mode",
"runtime_authority"
],
"properties": {
"overall_completion_percent": {
"const": 86
},
"current_task_id": {
"const": "P2-402F"
},
"next_task_id": {
"const": "P2-402G"
},
"read_only_mode": {
"const": true
},
"runtime_authority": {
"const": "host_stateful_readonly_inventory_no_upgrade_or_restart"
}
}
},
"operation_boundaries": {
"type": "object",
"required": [
"read_only_inventory_allowed",
"ssh_login_allowed",
"host_command_execution_allowed",
"kubectl_command_execution_allowed",
"apt_upgrade_allowed",
"k3s_upgrade_allowed",
"node_drain_allowed",
"reboot_allowed",
"stateful_service_restart_allowed",
"telegram_direct_send_allowed",
"secret_plaintext_allowed",
"conversation_transcript_allowed"
],
"properties": {
"read_only_inventory_allowed": {
"const": true
},
"ssh_login_allowed": {
"const": false
},
"host_command_execution_allowed": {
"const": false
},
"kubectl_command_execution_allowed": {
"const": false
},
"apt_upgrade_allowed": {
"const": false
},
"k3s_upgrade_allowed": {
"const": false
},
"node_drain_allowed": {
"const": false
},
"reboot_allowed": {
"const": false
},
"stateful_service_restart_allowed": {
"const": false
},
"telegram_direct_send_allowed": {
"const": false
},
"secret_plaintext_allowed": {
"const": false
},
"conversation_transcript_allowed": {
"const": false
}
}
},
"host_inventory": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": [
"host_id",
"readonly_only",
"version_observation_status",
"host_update_authorized",
"reboot_authorized",
"maintenance_window_required"
],
"properties": {
"readonly_only": {
"const": true
},
"host_update_authorized": {
"const": false
},
"reboot_authorized": {
"const": false
},
"maintenance_window_required": {
"const": true
}
}
}
},
"stateful_services": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": [
"service_id",
"readonly_only",
"version_observation_status",
"restart_authorized",
"upgrade_authorized",
"backup_required_before_change"
],
"properties": {
"readonly_only": {
"const": true
},
"restart_authorized": {
"const": false
},
"upgrade_authorized": {
"const": false
},
"backup_required_before_change": {
"const": true
}
}
}
},
"display_redaction_contract": {
"type": "object",
"required": [
"conversation_transcript_display_allowed",
"redaction_required"
],
"properties": {
"conversation_transcript_display_allowed": {
"const": false
},
"redaction_required": {
"const": true
}
}
}
}
}

View File

@@ -670,7 +670,7 @@ Repo / registry / release notes / K8s / host / observability / backup evidence
| 檔案 / API | 用途 |
|---|---|
| `docs/schemas/ai_agent_proactive_operations_contract_v1.schema.json` | 主動營運委派、版本生命週期、MCP、RAG、Telegram policy、approval boundary 契約 |
| `docs/evaluations/ai_agent_proactive_operations_contract_2026-06-11.json` | 12 類版本 domain、24 類可委派能力、5 種 cadence、8 類 MCP、4 類 RAG memory完成度 `78%` |
| `docs/evaluations/ai_agent_proactive_operations_contract_2026-06-11.json` | 12 類版本 domain、24 類可委派能力、5 種 cadence、8 類 MCP、4 類 RAG memory完成度 `86%` |
| `apps/api/src/services/ai_agent_proactive_operations_contract.py` | 只讀 loader強制 runtime update / package upgrade / host upgrade / workflow schedule / auto merge / Telegram direct send 全部 false |
| `GET /api/v1/agents/agent-proactive-operations-contract` | 治理 API只回傳 committed snapshot不啟用排程、不升級、不呼叫付費服務 |
| `docs/schemas/ai_agent_version_freshness_snapshot_v1.schema.json` | P2-402B repo-only 版本新鮮度 schema鎖定 schedule / external lookup / upgrade / Telegram / PR / host probe 全部 false |
@@ -685,6 +685,9 @@ Repo / registry / release notes / K8s / host / observability / backup evidence
| `docs/schemas/ai_agent_gitea_pr_draft_lane_v1.schema.json` | P2-402E Gitea PR 草案 lane schema鎖定 branch push / PR creation / workflow trigger / lockfile / automerge / Telegram 全部 false |
| `docs/evaluations/ai_agent_gitea_pr_draft_lane_2026-06-11.json` | P2-402E committed snapshot6 條 grouping rule、7 個 lane step、9 個 required check、6 條 rollback requirement、4 個 draft template |
| `GET /api/v1/agents/agent-gitea-pr-draft-lane` | 只讀 API只回傳 PR 草案 lane不 push branch、不建立 PR、不觸發 workflow、不改 CI、不升級套件、不發 Telegram |
| `docs/schemas/ai_agent_host_stateful_version_inventory_v1.schema.json` | P2-402F host / K3s / stateful 版本只讀盤點 schema鎖定 SSH / kubectl / upgrade / drain / reboot / restart / Telegram 全部 false |
| `docs/evaluations/ai_agent_host_stateful_version_inventory_2026-06-11.json` | P2-402F committed snapshot5 台主機、2 個 K3s 節點、12 個 stateful / ops 服務、6 個只讀 probe step、maintenance window approval package |
| `GET /api/v1/agents/agent-host-stateful-version-inventory` | 只讀 API只回傳 host / K3s / stateful 版本盤點,不 SSH、不 kubectl、不升級、不重啟、不發 Telegram |
**採用順序:**
@@ -692,7 +695,8 @@ Repo / registry / release notes / K8s / host / observability / backup evidence
2. 再評估 external primary source weekly watchRenovate、OSV-Scanner、Trivy、Syft、Grype、Kubernetes skew policy、Docker Scout。✅ P2-402C 已建立工具採用批准包工具安裝、CI 變更、外部查詢仍未授權。
3. 建立 Telegram action-required digest policy先定義 critical / action-required / failure-only 通知門檻,禁止成功洗版。✅ P2-402D 已建立 policy snapshot/APITelegram 實發與 queue write 仍未授權。
4. 再進 Gitea PR 草案 lanegrouping、automerge=false、tests、rollback、owner response。✅ P2-402E 已建立 draft lane snapshot/APIbranch push、PR creation、workflow trigger、lockfile、package upgrade、auto merge 仍未授權。
5. 最後才進人工批准後的 dry-run / smoke / canary / production rollout。下一步 P2-402F host OS / K3s / stateful services 版本只讀盤點
5. 建立 host OS / K3s / stateful services 版本只讀盤點先固定維護窗口、備份、rollback 與 smoke gate。✅ P2-402F 已建立 snapshot/APISSH、kubectl、upgrade、drain、reboot、stateful restart 仍未授權
6. 最後才進人工批准後的 dry-run / smoke / canary / production rollout。下一步 P2-402G governance UI 顯示可委派能力。
#### 3.2.2 核心缺口與災難場景
@@ -1726,6 +1730,12 @@ Phase 6 完成後
- 更新 `ai_agent_proactive_operations_contract_2026-06-11.json`:整體完成度 `78%`current task `P2-402E`next task `P2-402F`
- 本波仍不 push branch、不建立或更新 Gitea PR、不留言、不 auto merge、不觸發 workflow、不改 CI、不寫 lockfile、不升級套件、不 build / pull image、不發 Telegram、不讀取或輸出 secret、不回傳工作視窗對話內容P2-402F 才建立 host OS / K3s / stateful services 版本只讀盤點。
### 2026-06-11 23:59 (台北) — §3.2 / §5 — 完成 P2-402F host / K3s / stateful 版本只讀盤點 — 回應統帥要求讓 Agent 定期管理主機、套件、服務與維護窗口
- 新增 `ai_agent_host_stateful_version_inventory_v1` schema / committed snapshot / loader / API / 測試,定義 5 台主機、2 個 K3s 節點、12 個 stateful / ops 服務、6 個只讀 probe step、maintenance window approval package 與 redaction policy。
- 更新 `ai_agent_proactive_operations_contract_2026-06-11.json`:整體完成度 `86%`current task `P2-402F`next task `P2-402G`
- 本波仍不 SSH、不執行 host command、不執行 kubectl、不 apt / kernel / K3s upgrade、不 node drain、不 kubelet restart、不 reboot、不 stateful restart、不 DB migration、不 restore、不 pull image、不發 Telegram、不讀取或輸出 secret、不回傳工作視窗對話內容P2-402G 才接治理 UI 顯示可委派能力。
### 2026-04-15 (台北) — 全檔 — 建立 v2 骨架§0/§1 完成 — 統帥批准「單 MASTER + 4 道閘門」結構
- 從 v1plans/2026-04-15-MASTER-ai-autonomous-flywheel.md繼承核心發現