feat(governance): 新增報表真相與告警有效性審查
This commit is contained in:
@@ -85,6 +85,9 @@ from src.services.ai_agent_proactive_operations_contract import (
|
||||
from src.services.ai_agent_redis_dry_run_gate import (
|
||||
load_latest_ai_agent_redis_dry_run_gate,
|
||||
)
|
||||
from src.services.ai_agent_report_truth_actionability_review import (
|
||||
load_latest_ai_agent_report_truth_actionability_review,
|
||||
)
|
||||
from src.services.ai_agent_runtime_write_gate_review import (
|
||||
load_latest_ai_agent_runtime_write_gate_review,
|
||||
)
|
||||
@@ -850,6 +853,34 @@ async def get_agent_runtime_verifier_evidence_review() -> dict[str, Any]:
|
||||
) from exc
|
||||
|
||||
|
||||
@router.get(
|
||||
"/agent-report-truth-actionability-review",
|
||||
response_model=dict[str, Any],
|
||||
summary="取得 AI Agent 報表真相與告警可處置性審查",
|
||||
description=(
|
||||
"讀取最新已提交的日報 / 週報 / 月報真相與告警可處置性審查;此端點只回傳 "
|
||||
"zero-signal findings、cadence contracts、actionability lanes 與人工操作選項,"
|
||||
"不發 Telegram、不修改 CronJob、不改 Prometheus / Alertmanager、不建立 work item、"
|
||||
"不寫 KM / PlayBook trust、不啟動 runtime worker。"
|
||||
),
|
||||
)
|
||||
async def get_agent_report_truth_actionability_review() -> dict[str, Any]:
|
||||
"""Return the latest read-only AI Agent report truth actionability review."""
|
||||
try:
|
||||
return await asyncio.to_thread(load_latest_ai_agent_report_truth_actionability_review)
|
||||
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_report_truth_actionability_review_invalid", error=str(exc))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="AI Agent 報表真相與告警可處置性審查無效",
|
||||
) from exc
|
||||
|
||||
|
||||
@router.get(
|
||||
"/agent-owner-approved-fixture-dry-run",
|
||||
response_model=dict[str, Any],
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
"""AI Agent report truth and alert actionability review snapshot."""
|
||||
|
||||
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_report_truth_actionability_review_*.json"
|
||||
_SCHEMA_VERSION = "ai_agent_report_truth_actionability_review_v1"
|
||||
|
||||
|
||||
def load_latest_ai_agent_report_truth_actionability_review(
|
||||
evaluations_dir: Path | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Load the newest committed report truth and actionability review."""
|
||||
directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR
|
||||
candidates = sorted(directory.glob(_SNAPSHOT_PATTERN))
|
||||
if not candidates:
|
||||
raise FileNotFoundError(
|
||||
f"no AI Agent report truth actionability review 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_runtime_boundaries(payload, str(latest))
|
||||
_require_findings(payload, str(latest))
|
||||
_require_telegram_routing(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") != "report_truth_actionability_review_only_no_report_send_or_runtime_fix":
|
||||
raise ValueError(f"{label}: runtime_authority must remain report-truth review only")
|
||||
if status.get("current_task_id") != "P2-403J" or status.get("next_task_id") != "P2-403K":
|
||||
raise ValueError(f"{label}: current/next task must remain P2-403J -> P2-403K")
|
||||
|
||||
|
||||
def _require_runtime_boundaries(payload: dict[str, Any], label: str) -> None:
|
||||
truth = payload.get("report_truth") or {}
|
||||
if truth.get("all_zero_weekly_report_is_actionable_anomaly") is not True:
|
||||
raise ValueError(f"{label}: all-zero weekly report must remain actionable anomaly")
|
||||
for flag in (
|
||||
"freshness_gate_implemented",
|
||||
"source_confidence_gate_implemented",
|
||||
"actionability_score_implemented",
|
||||
"ai_agent_runtime_control_allowed",
|
||||
"telegram_report_send_allowed",
|
||||
"cronjob_change_allowed",
|
||||
):
|
||||
if truth.get(flag) is not False:
|
||||
raise ValueError(f"{label}: {flag} must remain false until runtime gate")
|
||||
|
||||
boundaries = payload.get("approval_boundaries") or {}
|
||||
enabled = sorted(key for key, value in boundaries.items() if value is not False)
|
||||
if enabled:
|
||||
raise ValueError(f"{label}: approval boundaries must remain false: {enabled}")
|
||||
|
||||
|
||||
def _require_findings(payload: dict[str, Any], label: str) -> None:
|
||||
findings = payload.get("zero_signal_findings") or []
|
||||
finding_ids = {item.get("finding_id") for item in findings}
|
||||
required = {
|
||||
"weekly_stats_failure_becomes_zero",
|
||||
"weekly_k3s_uptime_hardcoded",
|
||||
"git_stats_failure_becomes_zero",
|
||||
"monthly_report_contract_missing",
|
||||
"heartbeat_noise_not_actionability_scored",
|
||||
}
|
||||
missing = sorted(required - finding_ids)
|
||||
if missing:
|
||||
raise ValueError(f"{label}: missing report truth findings: {missing}")
|
||||
|
||||
cadences = payload.get("report_cadence_contracts") or []
|
||||
cadence_ids = {item.get("cadence_id") for item in cadences}
|
||||
for cadence_id in ("daily_report", "weekly_report", "monthly_report"):
|
||||
if cadence_id not in cadence_ids:
|
||||
raise ValueError(f"{label}: missing cadence contract {cadence_id}")
|
||||
|
||||
lanes = payload.get("alert_actionability_lanes") or []
|
||||
lane_ids = {item.get("lane_id") for item in lanes}
|
||||
for lane_id in ("action_required_alert", "stale_source_alert", "heartbeat_noise", "report_truth_failure"):
|
||||
if lane_id not in lane_ids:
|
||||
raise ValueError(f"{label}: missing actionability lane {lane_id}")
|
||||
|
||||
|
||||
def _require_telegram_routing(payload: dict[str, Any], label: str) -> None:
|
||||
routing = payload.get("telegram_routing_consolidation") or {}
|
||||
if routing.get("canonical_room_name") != "AwoooI SRE 戰情室":
|
||||
raise ValueError(f"{label}: canonical Telegram room must remain AwoooI SRE 戰情室")
|
||||
if routing.get("canonical_room_env") != "SRE_GROUP_CHAT_ID":
|
||||
raise ValueError(f"{label}: canonical Telegram room env must remain SRE_GROUP_CHAT_ID")
|
||||
required_false = (
|
||||
"other_bot_or_group_alerts_allowed",
|
||||
"direct_telegram_api_send_allowed",
|
||||
"secret_value_read_allowed",
|
||||
"route_change_allowed",
|
||||
)
|
||||
for flag in required_false:
|
||||
if routing.get(flag) is not False:
|
||||
raise ValueError(f"{label}: telegram routing flag {flag} must remain false until approved migration")
|
||||
if routing.get("product_alerts_must_route_to_canonical_room") is not True:
|
||||
raise ValueError(f"{label}: product alerts must target canonical SRE war room")
|
||||
|
||||
routes = payload.get("telegram_route_findings") or []
|
||||
route_ids = {item.get("route_id") for item in routes}
|
||||
required_routes = {
|
||||
"gitea_cd_direct_telegram",
|
||||
"gitea_code_review_direct_telegram",
|
||||
"multi_bot_secret_injection",
|
||||
"legacy_alert_chat_env",
|
||||
}
|
||||
missing = sorted(required_routes - route_ids)
|
||||
if missing:
|
||||
raise ValueError(f"{label}: missing Telegram route findings: {missing}")
|
||||
|
||||
|
||||
def _require_rollup_consistency(payload: dict[str, Any], label: str) -> None:
|
||||
rollups = payload.get("rollups") or {}
|
||||
findings = payload.get("zero_signal_findings") or []
|
||||
cadences = payload.get("report_cadence_contracts") or []
|
||||
lanes = payload.get("alert_actionability_lanes") or []
|
||||
routes = payload.get("telegram_route_findings") or []
|
||||
actions = payload.get("operator_actions") or []
|
||||
blocked = {
|
||||
*(item.get("blocked_runtime_action") for item in findings),
|
||||
*(item.get("blocked_runtime_action") for item in routes),
|
||||
*(item.get("blocked_runtime_action") for item in actions),
|
||||
*(payload.get("approval_boundaries") or {}).keys(),
|
||||
}
|
||||
blocked.discard(None)
|
||||
expected_counts = {
|
||||
"zero_signal_finding_count": len(findings),
|
||||
"critical_finding_count": sum(1 for item in findings if item.get("severity") == "critical"),
|
||||
"high_finding_count": sum(1 for item in findings if item.get("severity") == "high"),
|
||||
"cadence_contract_count": len(cadences),
|
||||
"missing_cadence_contract_count": sum(1 for item in cadences if item.get("status") == "missing_contract"),
|
||||
"actionability_lane_count": len(lanes),
|
||||
"telegram_route_finding_count": len(routes),
|
||||
"legacy_or_direct_route_count": sum(
|
||||
1
|
||||
for item in routes
|
||||
if item.get("current_state") in {"direct_send_path_present", "legacy_chat_env_referenced", "multiple_bot_tokens_present"}
|
||||
),
|
||||
"operator_action_count": len(actions),
|
||||
"blocked_runtime_action_count": len(blocked),
|
||||
}
|
||||
mismatched = {
|
||||
key: {"expected": expected, "actual": rollups.get(key)}
|
||||
for key, expected in expected_counts.items()
|
||||
if rollups.get(key) != expected
|
||||
}
|
||||
if mismatched:
|
||||
raise ValueError(f"{label}: rollup counts must match payload sections: {mismatched}")
|
||||
|
||||
approval_required = sorted(
|
||||
action.get("action_id")
|
||||
for action in actions
|
||||
if action.get("status") == "approval_required"
|
||||
)
|
||||
if sorted(rollups.get("approval_required_action_ids") or []) != approval_required:
|
||||
raise ValueError(f"{label}: approval_required_action_ids mismatch")
|
||||
if rollups.get("all_zero_weekly_report_confidence") != "low_trust_actionable_anomaly":
|
||||
raise ValueError(f"{label}: all-zero weekly report confidence must stay low trust")
|
||||
@@ -14,8 +14,8 @@ def test_load_latest_ai_agent_interaction_learning_proof_reads_committed_snapsho
|
||||
|
||||
assert data["schema_version"] == "ai_agent_interaction_learning_proof_v1"
|
||||
assert data["program_status"]["overall_completion_percent"] == 99
|
||||
assert data["program_status"]["current_task_id"] == "P2-403I"
|
||||
assert data["program_status"]["next_task_id"] == "P2-403J"
|
||||
assert data["program_status"]["current_task_id"] == "P2-403J"
|
||||
assert data["program_status"]["next_task_id"] == "P2-403K"
|
||||
assert data["program_status"]["read_only_mode"] is True
|
||||
assert data["program_status"]["runtime_authority"] == "proof_surface_only_no_live_worker"
|
||||
assert data["live_truth"]["runtime_loop_enabled"] is False
|
||||
|
||||
@@ -17,8 +17,8 @@ def test_ai_agent_interaction_learning_proof_endpoint_returns_committed_snapshot
|
||||
data = response.json()
|
||||
assert data["schema_version"] == "ai_agent_interaction_learning_proof_v1"
|
||||
assert data["program_status"]["overall_completion_percent"] == 99
|
||||
assert data["program_status"]["current_task_id"] == "P2-403I"
|
||||
assert data["program_status"]["next_task_id"] == "P2-403J"
|
||||
assert data["program_status"]["current_task_id"] == "P2-403J"
|
||||
assert data["program_status"]["next_task_id"] == "P2-403K"
|
||||
assert data["program_status"]["read_only_mode"] is True
|
||||
assert data["live_truth"]["runtime_loop_enabled"] is False
|
||||
assert data["live_truth"]["active_live_agent_sessions"] == 0
|
||||
|
||||
@@ -14,8 +14,8 @@ def test_load_latest_ai_agent_proactive_operations_contract_reads_committed_snap
|
||||
|
||||
assert data["schema_version"] == "ai_agent_proactive_operations_contract_v1"
|
||||
assert data["program_status"]["overall_completion_percent"] == 100
|
||||
assert data["program_status"]["current_task_id"] == "P2-403I"
|
||||
assert data["program_status"]["next_task_id"] == "P2-403J"
|
||||
assert data["program_status"]["current_task_id"] == "P2-403J"
|
||||
assert data["program_status"]["next_task_id"] == "P2-403K"
|
||||
assert data["program_status"]["read_only_mode"] is True
|
||||
assert data["program_status"]["runtime_authority"] == "contract_only_no_version_or_runtime_update"
|
||||
assert data["approval_boundaries"]["runtime_version_update_allowed"] is False
|
||||
@@ -25,7 +25,7 @@ def test_load_latest_ai_agent_proactive_operations_contract_reads_committed_snap
|
||||
assert data["approval_boundaries"]["telegram_direct_send_allowed"] is False
|
||||
assert data["rollups"]["version_domain_count"] == len(data["version_lifecycle_domains"]) == 12
|
||||
assert data["rollups"]["delegable_capability_count"] == len(data["delegable_capabilities"]) == 24
|
||||
assert data["rollups"]["rollout_task_count"] == len(data["rollout_tasks"]) == 16
|
||||
assert data["rollups"]["rollout_task_count"] == len(data["rollout_tasks"]) == 17
|
||||
assert data["rollups"]["auto_execute_allowed_count"] == 0
|
||||
assert any(domain["domain_id"] == "ai_agents_models" for domain in data["version_lifecycle_domains"])
|
||||
assert any(
|
||||
|
||||
@@ -17,8 +17,8 @@ def test_ai_agent_proactive_operations_contract_endpoint_returns_committed_snaps
|
||||
data = response.json()
|
||||
assert data["schema_version"] == "ai_agent_proactive_operations_contract_v1"
|
||||
assert data["program_status"]["overall_completion_percent"] == 100
|
||||
assert data["program_status"]["current_task_id"] == "P2-403I"
|
||||
assert data["program_status"]["next_task_id"] == "P2-403J"
|
||||
assert data["program_status"]["current_task_id"] == "P2-403J"
|
||||
assert data["program_status"]["next_task_id"] == "P2-403K"
|
||||
assert data["program_status"]["read_only_mode"] is True
|
||||
assert data["approval_boundaries"]["runtime_version_update_allowed"] is False
|
||||
assert data["approval_boundaries"]["package_upgrade_allowed"] is False
|
||||
@@ -26,7 +26,7 @@ def test_ai_agent_proactive_operations_contract_endpoint_returns_committed_snaps
|
||||
assert data["approval_boundaries"]["telegram_direct_send_allowed"] is False
|
||||
assert data["rollups"]["version_domain_count"] == 12
|
||||
assert data["rollups"]["delegable_capability_count"] == 24
|
||||
assert data["rollups"]["rollout_task_count"] == 16
|
||||
assert data["rollups"]["rollout_task_count"] == 17
|
||||
assert data["rollups"]["auto_execute_allowed_count"] == 0
|
||||
assert any(domain["domain_id"] == "host_os_packages" for domain in data["version_lifecycle_domains"])
|
||||
assert any(
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import copy
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from src.services.ai_agent_report_truth_actionability_review import (
|
||||
load_latest_ai_agent_report_truth_actionability_review,
|
||||
)
|
||||
|
||||
|
||||
def _write_snapshot(tmp_path, payload):
|
||||
path = tmp_path / "ai_agent_report_truth_actionability_review_2026-06-12.json"
|
||||
path.write_text(json.dumps(payload), encoding="utf-8")
|
||||
return path
|
||||
|
||||
|
||||
def test_load_latest_ai_agent_report_truth_actionability_review():
|
||||
data = load_latest_ai_agent_report_truth_actionability_review()
|
||||
|
||||
assert data["schema_version"] == "ai_agent_report_truth_actionability_review_v1"
|
||||
assert data["program_status"]["current_task_id"] == "P2-403J"
|
||||
assert data["program_status"]["next_task_id"] == "P2-403K"
|
||||
assert data["report_truth"]["all_zero_weekly_report_is_actionable_anomaly"] is True
|
||||
assert data["report_truth"]["freshness_gate_implemented"] is False
|
||||
assert data["report_truth"]["telegram_report_send_allowed"] is False
|
||||
assert data["rollups"]["zero_signal_finding_count"] == len(data["zero_signal_findings"])
|
||||
assert data["rollups"]["missing_cadence_contract_count"] == 1
|
||||
assert data["telegram_routing_consolidation"]["canonical_room_name"] == "AwoooI SRE 戰情室"
|
||||
assert data["telegram_routing_consolidation"]["canonical_room_env"] == "SRE_GROUP_CHAT_ID"
|
||||
assert data["telegram_routing_consolidation"]["direct_telegram_api_send_allowed"] is False
|
||||
assert data["rollups"]["telegram_route_finding_count"] == len(data["telegram_route_findings"])
|
||||
assert data["rollups"]["all_zero_weekly_report_confidence"] == "low_trust_actionable_anomaly"
|
||||
|
||||
|
||||
def test_rejects_all_zero_weekly_report_as_green(tmp_path):
|
||||
data = load_latest_ai_agent_report_truth_actionability_review()
|
||||
bad = copy.deepcopy(data)
|
||||
bad["report_truth"]["all_zero_weekly_report_is_actionable_anomaly"] = False
|
||||
_write_snapshot(tmp_path, bad)
|
||||
|
||||
with pytest.raises(ValueError, match="all-zero weekly report"):
|
||||
load_latest_ai_agent_report_truth_actionability_review(tmp_path)
|
||||
|
||||
|
||||
def test_rejects_runtime_report_send_allowed(tmp_path):
|
||||
data = load_latest_ai_agent_report_truth_actionability_review()
|
||||
bad = copy.deepcopy(data)
|
||||
bad["report_truth"]["telegram_report_send_allowed"] = True
|
||||
_write_snapshot(tmp_path, bad)
|
||||
|
||||
with pytest.raises(ValueError, match="telegram_report_send_allowed"):
|
||||
load_latest_ai_agent_report_truth_actionability_review(tmp_path)
|
||||
|
||||
|
||||
def test_rejects_missing_heartbeat_noise_lane(tmp_path):
|
||||
data = load_latest_ai_agent_report_truth_actionability_review()
|
||||
bad = copy.deepcopy(data)
|
||||
bad["alert_actionability_lanes"] = [
|
||||
lane for lane in bad["alert_actionability_lanes"] if lane["lane_id"] != "heartbeat_noise"
|
||||
]
|
||||
bad["rollups"]["actionability_lane_count"] = len(bad["alert_actionability_lanes"])
|
||||
_write_snapshot(tmp_path, bad)
|
||||
|
||||
with pytest.raises(ValueError, match="heartbeat_noise"):
|
||||
load_latest_ai_agent_report_truth_actionability_review(tmp_path)
|
||||
|
||||
|
||||
def test_rejects_non_canonical_telegram_room(tmp_path):
|
||||
data = load_latest_ai_agent_report_truth_actionability_review()
|
||||
bad = copy.deepcopy(data)
|
||||
bad["telegram_routing_consolidation"]["canonical_room_name"] = "Legacy Ops Group"
|
||||
_write_snapshot(tmp_path, bad)
|
||||
|
||||
with pytest.raises(ValueError, match="canonical Telegram room"):
|
||||
load_latest_ai_agent_report_truth_actionability_review(tmp_path)
|
||||
|
||||
|
||||
def test_rejects_direct_telegram_api_send_allowed(tmp_path):
|
||||
data = load_latest_ai_agent_report_truth_actionability_review()
|
||||
bad = copy.deepcopy(data)
|
||||
bad["telegram_routing_consolidation"]["direct_telegram_api_send_allowed"] = True
|
||||
_write_snapshot(tmp_path, bad)
|
||||
|
||||
with pytest.raises(ValueError, match="direct_telegram_api_send_allowed"):
|
||||
load_latest_ai_agent_report_truth_actionability_review(tmp_path)
|
||||
|
||||
|
||||
def test_rejects_rollup_mismatch(tmp_path):
|
||||
data = load_latest_ai_agent_report_truth_actionability_review()
|
||||
bad = copy.deepcopy(data)
|
||||
bad["rollups"]["zero_signal_finding_count"] = 999
|
||||
_write_snapshot(tmp_path, bad)
|
||||
|
||||
with pytest.raises(ValueError, match="rollup counts"):
|
||||
load_latest_ai_agent_report_truth_actionability_review(tmp_path)
|
||||
@@ -0,0 +1,30 @@
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from src.main import app
|
||||
|
||||
|
||||
def test_get_ai_agent_report_truth_actionability_review_api():
|
||||
client = TestClient(app)
|
||||
response = client.get("/api/v1/agents/agent-report-truth-actionability-review")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["schema_version"] == "ai_agent_report_truth_actionability_review_v1"
|
||||
assert data["program_status"]["current_task_id"] == "P2-403J"
|
||||
assert data["program_status"]["next_task_id"] == "P2-403K"
|
||||
assert data["report_truth"]["all_zero_weekly_report_is_actionable_anomaly"] is True
|
||||
assert data["report_truth"]["freshness_gate_implemented"] is False
|
||||
assert data["report_truth"]["telegram_report_send_allowed"] is False
|
||||
assert data["rollups"]["zero_signal_finding_count"] == 5
|
||||
assert data["rollups"]["critical_finding_count"] == 1
|
||||
assert data["rollups"]["high_finding_count"] == 3
|
||||
assert data["rollups"]["cadence_contract_count"] == 3
|
||||
assert data["rollups"]["missing_cadence_contract_count"] == 1
|
||||
assert data["rollups"]["actionability_lane_count"] == 4
|
||||
assert data["telegram_routing_consolidation"]["canonical_room_name"] == "AwoooI SRE 戰情室"
|
||||
assert data["telegram_routing_consolidation"]["canonical_room_env"] == "SRE_GROUP_CHAT_ID"
|
||||
assert data["telegram_routing_consolidation"]["other_bot_or_group_alerts_allowed"] is False
|
||||
assert data["telegram_routing_consolidation"]["direct_telegram_api_send_allowed"] is False
|
||||
assert data["rollups"]["telegram_route_finding_count"] == 4
|
||||
assert data["rollups"]["legacy_or_direct_route_count"] == 4
|
||||
assert data["rollups"]["operator_action_count"] == 5
|
||||
@@ -3994,6 +3994,37 @@
|
||||
"forbiddenEvidence": "禁止證據 {count}",
|
||||
"reviewMode": "只讀 review"
|
||||
}
|
||||
},
|
||||
"reportTruthActionabilityReview": {
|
||||
"title": "P2-403J 報表真相與告警有效性",
|
||||
"source": "{generated} · {current} → {next}",
|
||||
"truthTitle": "報表真相",
|
||||
"telegramTitle": "AwoooI SRE 戰情室路由",
|
||||
"policyTitle": "收斂與批准邊界",
|
||||
"metrics": {
|
||||
"overall": "P2-403J 進度",
|
||||
"findings": "真相缺口",
|
||||
"critical": "Critical",
|
||||
"cadences": "日週月",
|
||||
"missingCadence": "缺契約",
|
||||
"telegramRoutes": "TG 旁路",
|
||||
"legacyRoutes": "待收斂路徑",
|
||||
"actions": "人工選項",
|
||||
"approval": "需批准",
|
||||
"blocked": "阻擋動作 {count}"
|
||||
},
|
||||
"flags": {
|
||||
"allZero": "全 0 週報異常: {value}",
|
||||
"freshness": "freshness gate: {value}",
|
||||
"confidence": "confidence gate: {value}",
|
||||
"actionability": "actionability score: {value}",
|
||||
"otherRoutes": "其他群組允許: {value}",
|
||||
"routeChange": "路由變更允許: {value}"
|
||||
},
|
||||
"labels": {
|
||||
"canonicalRoom": "唯一戰情室: {room}",
|
||||
"legacyRoutesDetail": "direct send / legacy chat / multi bot 必須收斂"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -3994,6 +3994,37 @@
|
||||
"forbiddenEvidence": "禁止證據 {count}",
|
||||
"reviewMode": "只讀 review"
|
||||
}
|
||||
},
|
||||
"reportTruthActionabilityReview": {
|
||||
"title": "P2-403J 報表真相與告警有效性",
|
||||
"source": "{generated} · {current} → {next}",
|
||||
"truthTitle": "報表真相",
|
||||
"telegramTitle": "AwoooI SRE 戰情室路由",
|
||||
"policyTitle": "收斂與批准邊界",
|
||||
"metrics": {
|
||||
"overall": "P2-403J 進度",
|
||||
"findings": "真相缺口",
|
||||
"critical": "Critical",
|
||||
"cadences": "日週月",
|
||||
"missingCadence": "缺契約",
|
||||
"telegramRoutes": "TG 旁路",
|
||||
"legacyRoutes": "待收斂路徑",
|
||||
"actions": "人工選項",
|
||||
"approval": "需批准",
|
||||
"blocked": "阻擋動作 {count}"
|
||||
},
|
||||
"flags": {
|
||||
"allZero": "全 0 週報異常: {value}",
|
||||
"freshness": "freshness gate: {value}",
|
||||
"confidence": "confidence gate: {value}",
|
||||
"actionability": "actionability score: {value}",
|
||||
"otherRoutes": "其他群組允許: {value}",
|
||||
"routeChange": "路由變更允許: {value}"
|
||||
},
|
||||
"labels": {
|
||||
"canonicalRoom": "唯一戰情室: {room}",
|
||||
"legacyRoutesDetail": "direct send / legacy chat / multi bot 必須收斂"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -45,6 +45,7 @@ import {
|
||||
type AiAgentPostWriteVerifierPackageSnapshot,
|
||||
type AiAgentProactiveOperationsContractSnapshot,
|
||||
type AiAgentRedisDryRunGateSnapshot,
|
||||
type AiAgentReportTruthActionabilityReviewSnapshot,
|
||||
type AiAgentRuntimeVerifierEvidenceReviewSnapshot,
|
||||
type AiAgentRuntimeWriteGateReviewSnapshot,
|
||||
type AiAgentTelegramReceiptApprovalPackageSnapshot,
|
||||
@@ -335,6 +336,7 @@ export function AutomationInventoryTab() {
|
||||
const [runtimeWriteGateReview, setRuntimeWriteGateReview] = useState<AiAgentRuntimeWriteGateReviewSnapshot | null>(null)
|
||||
const [postWriteVerifierPackage, setPostWriteVerifierPackage] = useState<AiAgentPostWriteVerifierPackageSnapshot | null>(null)
|
||||
const [runtimeVerifierEvidenceReview, setRuntimeVerifierEvidenceReview] = useState<AiAgentRuntimeVerifierEvidenceReviewSnapshot | null>(null)
|
||||
const [reportTruthActionabilityReview, setReportTruthActionabilityReview] = useState<AiAgentReportTruthActionabilityReviewSnapshot | null>(null)
|
||||
const [ownerDryRunPackage, setOwnerDryRunPackage] = useState<AiAgentOwnerApprovedFixtureDryRunSnapshot | null>(null)
|
||||
const [hostStatefulInventory, setHostStatefulInventory] = useState<AiAgentHostStatefulVersionInventorySnapshot | null>(null)
|
||||
const [serviceHealthGapMatrix, setServiceHealthGapMatrix] = useState<ServiceHealthGapMatrixSnapshot | null>(null)
|
||||
@@ -366,6 +368,7 @@ export function AutomationInventoryTab() {
|
||||
apiClient.getAiAgentRuntimeWriteGateReview(),
|
||||
apiClient.getAiAgentPostWriteVerifierPackage(),
|
||||
apiClient.getAiAgentRuntimeVerifierEvidenceReview(),
|
||||
apiClient.getAiAgentReportTruthActionabilityReview(),
|
||||
apiClient.getAiAgentOwnerApprovedFixtureDryRun(),
|
||||
apiClient.getAiAgentHostStatefulVersionInventory(),
|
||||
apiClient.getServiceHealthGapMatrix(),
|
||||
@@ -396,6 +399,7 @@ export function AutomationInventoryTab() {
|
||||
runtimeWriteGateReviewResult,
|
||||
postWriteVerifierPackageResult,
|
||||
runtimeVerifierEvidenceReviewResult,
|
||||
reportTruthActionabilityReviewResult,
|
||||
ownerDryRunPackageResult,
|
||||
hostStatefulInventoryResult,
|
||||
serviceHealthGapMatrixResult,
|
||||
@@ -423,6 +427,7 @@ export function AutomationInventoryTab() {
|
||||
setRuntimeWriteGateReview(runtimeWriteGateReviewResult.status === 'fulfilled' ? runtimeWriteGateReviewResult.value : null)
|
||||
setPostWriteVerifierPackage(postWriteVerifierPackageResult.status === 'fulfilled' ? postWriteVerifierPackageResult.value : null)
|
||||
setRuntimeVerifierEvidenceReview(runtimeVerifierEvidenceReviewResult.status === 'fulfilled' ? runtimeVerifierEvidenceReviewResult.value : null)
|
||||
setReportTruthActionabilityReview(reportTruthActionabilityReviewResult.status === 'fulfilled' ? reportTruthActionabilityReviewResult.value : null)
|
||||
setOwnerDryRunPackage(ownerDryRunPackageResult.status === 'fulfilled' ? ownerDryRunPackageResult.value : null)
|
||||
setHostStatefulInventory(hostStatefulInventoryResult.status === 'fulfilled' ? hostStatefulInventoryResult.value : null)
|
||||
setServiceHealthGapMatrix(serviceHealthGapMatrixResult.status === 'fulfilled' ? serviceHealthGapMatrixResult.value : null)
|
||||
@@ -448,6 +453,7 @@ export function AutomationInventoryTab() {
|
||||
runtimeWriteGateReviewResult,
|
||||
postWriteVerifierPackageResult,
|
||||
runtimeVerifierEvidenceReviewResult,
|
||||
reportTruthActionabilityReviewResult,
|
||||
ownerDryRunPackageResult,
|
||||
hostStatefulInventoryResult,
|
||||
serviceHealthGapMatrixResult,
|
||||
@@ -834,6 +840,46 @@ export function AutomationInventoryTab() {
|
||||
})
|
||||
}, [runtimeVerifierEvidenceReview])
|
||||
|
||||
const visibleReportTruthFindings = useMemo(() => {
|
||||
if (!reportTruthActionabilityReview) return []
|
||||
const priority = { critical: 0, high: 1, medium: 2, low: 3 } as Record<string, number>
|
||||
return [...reportTruthActionabilityReview.zero_signal_findings]
|
||||
.sort((a, b) => {
|
||||
const left = priority[a.severity] ?? 4
|
||||
const right = priority[b.severity] ?? 4
|
||||
if (left !== right) return left - right
|
||||
return a.finding_id.localeCompare(b.finding_id)
|
||||
})
|
||||
}, [reportTruthActionabilityReview])
|
||||
|
||||
const visibleTelegramRouteFindings = useMemo(() => {
|
||||
if (!reportTruthActionabilityReview) return []
|
||||
const priority = {
|
||||
direct_send_path_present: 0,
|
||||
legacy_chat_env_referenced: 1,
|
||||
multiple_bot_tokens_present: 2,
|
||||
} as Record<string, number>
|
||||
return [...reportTruthActionabilityReview.telegram_route_findings]
|
||||
.sort((a, b) => {
|
||||
const left = priority[a.current_state] ?? 3
|
||||
const right = priority[b.current_state] ?? 3
|
||||
if (left !== right) return left - right
|
||||
return a.route_id.localeCompare(b.route_id)
|
||||
})
|
||||
}, [reportTruthActionabilityReview])
|
||||
|
||||
const visibleReportTruthActions = useMemo(() => {
|
||||
if (!reportTruthActionabilityReview) return []
|
||||
const priority = { approval_required: 0, ready_for_owner: 1, blocked_by_runtime_gate: 2 } as Record<string, number>
|
||||
return [...reportTruthActionabilityReview.operator_actions]
|
||||
.sort((a, b) => {
|
||||
const left = priority[a.status] ?? 3
|
||||
const right = priority[b.status] ?? 3
|
||||
if (left !== right) return left - right
|
||||
return a.action_id.localeCompare(b.action_id)
|
||||
})
|
||||
}, [reportTruthActionabilityReview])
|
||||
|
||||
const visibleOwnerDryRunGates = useMemo(() => {
|
||||
if (!ownerDryRunPackage) return []
|
||||
const priority = { approval_required: 0, approved_for_fixture_only: 1, fixture_only: 2, ready: 3 } as Record<string, number>
|
||||
@@ -1013,7 +1059,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 || !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 || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) {
|
||||
return (
|
||||
<div style={{ padding: 20 }}>
|
||||
<GlassCard variant="subtle" padding="lg">
|
||||
@@ -1152,6 +1198,16 @@ export function AutomationInventoryTab() {
|
||||
const runtimeVerifierApprovals = runtimeVerifierEvidenceReview.rollups.approval_required_action_ids.length
|
||||
const runtimeVerifierBlockedActions = runtimeVerifierEvidenceReview.rollups.blocked_runtime_action_count
|
||||
const runtimeVerifierLiveTotal = runtimeVerifierEvidenceReview.rollups.live_verifier_execution_count
|
||||
const reportTruthOverall = reportTruthActionabilityReview.program_status.overall_completion_percent
|
||||
const reportTruthFindings = reportTruthActionabilityReview.rollups.zero_signal_finding_count
|
||||
const reportTruthCritical = reportTruthActionabilityReview.rollups.critical_finding_count
|
||||
const reportTruthCadences = reportTruthActionabilityReview.rollups.cadence_contract_count
|
||||
const reportTruthMissingCadence = reportTruthActionabilityReview.rollups.missing_cadence_contract_count
|
||||
const reportTruthRouteFindings = reportTruthActionabilityReview.rollups.telegram_route_finding_count
|
||||
const reportTruthLegacyRoutes = reportTruthActionabilityReview.rollups.legacy_or_direct_route_count
|
||||
const reportTruthActions = reportTruthActionabilityReview.rollups.operator_action_count
|
||||
const reportTruthApprovals = reportTruthActionabilityReview.rollups.approval_required_action_ids.length
|
||||
const reportTruthBlockedActions = reportTruthActionabilityReview.rollups.blocked_runtime_action_count
|
||||
const ownerDryRunOverall = ownerDryRunPackage.program_status.overall_completion_percent
|
||||
const ownerDryRunFixtures = ownerDryRunPackage.rollups.fixture_set_count
|
||||
const ownerDryRunGates = ownerDryRunPackage.rollups.dry_run_gate_count
|
||||
@@ -1737,6 +1793,125 @@ export function AutomationInventoryTab() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 12, border: '0.5px solid #d8c6a6', borderRadius: 7, background: '#fffdf7', display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, flexWrap: 'wrap' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 7, minWidth: 0 }}>
|
||||
<BellRing size={14} style={{ color: '#d97757' }} />
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 13, fontWeight: 700, color: '#141413' }}>
|
||||
{t('reportTruthActionabilityReview.title')}
|
||||
</span>
|
||||
</div>
|
||||
<Chip
|
||||
value={t('reportTruthActionabilityReview.source', {
|
||||
generated: formatDateTime(reportTruthActionabilityReview.generated_at),
|
||||
current: reportTruthActionabilityReview.program_status.current_task_id,
|
||||
next: reportTruthActionabilityReview.program_status.next_task_id,
|
||||
})}
|
||||
muted
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(128px, 1fr))', gap: 10 }} className="automation-inventory-live-read-kpi-grid">
|
||||
<MetricCard label={t('reportTruthActionabilityReview.metrics.overall')} value={`${reportTruthOverall}%`} tone="warn" icon={<Gauge size={16} />} />
|
||||
<MetricCard label={t('reportTruthActionabilityReview.metrics.findings')} value={reportTruthFindings} tone="danger" icon={<AlertTriangle size={16} />} />
|
||||
<MetricCard label={t('reportTruthActionabilityReview.metrics.critical')} value={reportTruthCritical} tone="danger" icon={<ShieldAlert size={16} />} />
|
||||
<MetricCard label={t('reportTruthActionabilityReview.metrics.cadences')} value={reportTruthCadences} tone="warn" icon={<FileText size={16} />} />
|
||||
<MetricCard label={t('reportTruthActionabilityReview.metrics.missingCadence')} value={reportTruthMissingCadence} tone="danger" icon={<Lock size={16} />} />
|
||||
<MetricCard label={t('reportTruthActionabilityReview.metrics.telegramRoutes')} value={reportTruthRouteFindings} tone="danger" icon={<BellOff size={16} />} />
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 0.85fr) minmax(0, 1.15fr)', gap: 12 }} className="automation-inventory-live-read-grid">
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 10, minWidth: 0 }}>
|
||||
<div style={{ padding: 11, border: '0.5px solid #eee9dd', borderRadius: 7, background: '#faf9f3', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
|
||||
<SmallLabel>{t('reportTruthActionabilityReview.truthTitle')}</SmallLabel>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
|
||||
{reportTruthActionabilityReview.report_truth.truth_note}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={t('reportTruthActionabilityReview.flags.allZero', { value: String(reportTruthActionabilityReview.report_truth.all_zero_weekly_report_is_actionable_anomaly) })} />
|
||||
<Chip value={t('reportTruthActionabilityReview.flags.freshness', { value: String(reportTruthActionabilityReview.report_truth.freshness_gate_implemented) })} muted />
|
||||
<Chip value={t('reportTruthActionabilityReview.flags.confidence', { value: String(reportTruthActionabilityReview.report_truth.source_confidence_gate_implemented) })} muted />
|
||||
<Chip value={t('reportTruthActionabilityReview.flags.actionability', { value: String(reportTruthActionabilityReview.report_truth.actionability_score_implemented) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 11, border: '0.5px solid #eee9dd', borderRadius: 7, background: '#faf9f3', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
|
||||
<SmallLabel>{t('reportTruthActionabilityReview.telegramTitle')}</SmallLabel>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
|
||||
{reportTruthActionabilityReview.telegram_routing_consolidation.routing_note}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={t('reportTruthActionabilityReview.labels.canonicalRoom', { room: reportTruthActionabilityReview.telegram_routing_consolidation.canonical_room_name })} />
|
||||
<Chip value={reportTruthActionabilityReview.telegram_routing_consolidation.canonical_room_env} muted />
|
||||
<Chip value={t('reportTruthActionabilityReview.flags.otherRoutes', { value: String(reportTruthActionabilityReview.telegram_routing_consolidation.other_bot_or_group_alerts_allowed) })} muted />
|
||||
<Chip value={t('reportTruthActionabilityReview.flags.routeChange', { value: String(reportTruthActionabilityReview.telegram_routing_consolidation.route_change_allowed) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 11, border: '0.5px solid #eee9dd', borderRadius: 7, background: '#faf9f3', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
|
||||
<SmallLabel>{t('reportTruthActionabilityReview.policyTitle')}</SmallLabel>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 8 }}>
|
||||
<SummaryTile label={t('reportTruthActionabilityReview.metrics.legacyRoutes')} value={`${reportTruthLegacyRoutes}`} detail={t('reportTruthActionabilityReview.labels.legacyRoutesDetail')} tone="danger" icon={<BellOff size={16} />} />
|
||||
<SummaryTile label={t('reportTruthActionabilityReview.metrics.approval')} value={`${reportTruthApprovals}`} detail={t('reportTruthActionabilityReview.metrics.blocked', { count: reportTruthBlockedActions })} tone="warn" icon={<Lock size={16} />} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 10, minWidth: 0 }}>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{visibleReportTruthFindings.map(finding => (
|
||||
<div key={finding.finding_id} style={{ padding: 10, border: '0.5px solid #eee9dd', borderRadius: 7, background: '#faf9f3', display: 'flex', flexDirection: 'column', gap: 7, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, minWidth: 0 }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 12, fontWeight: 700, color: '#141413', lineHeight: 1.35, overflowWrap: 'anywhere' }}>
|
||||
{finding.display_name}
|
||||
</span>
|
||||
<Chip value={finding.severity} muted={finding.severity !== 'critical'} />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{finding.operator_meaning}
|
||||
</span>
|
||||
<Chip value={finding.blocked_runtime_action} muted />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{visibleTelegramRouteFindings.map(routeFinding => (
|
||||
<div key={routeFinding.route_id} style={{ padding: 10, border: '0.5px solid #eee9dd', borderRadius: 7, background: '#faf9f3', display: 'flex', flexDirection: 'column', gap: 7, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, minWidth: 0 }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 12, fontWeight: 700, color: '#141413', lineHeight: 1.35, overflowWrap: 'anywhere' }}>
|
||||
{routeFinding.display_name}
|
||||
</span>
|
||||
<Chip value={routeFinding.current_state} />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{routeFinding.risk}
|
||||
</span>
|
||||
<Chip value={routeFinding.target_state} muted />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(190px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{visibleReportTruthActions.map(action => (
|
||||
<div key={action.action_id} style={{ padding: 10, border: '0.5px solid #eee9dd', borderRadius: 7, background: '#faf9f3', display: 'flex', flexDirection: 'column', gap: 7, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, alignItems: 'center', minWidth: 0 }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 12, fontWeight: 700, color: '#141413', overflowWrap: 'anywhere' }}>
|
||||
{action.display_name}
|
||||
</span>
|
||||
<Chip value={redisDryRunValueLabel('statuses', action.status)} muted={action.status !== 'approval_required'} />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{action.operator_instruction}
|
||||
</span>
|
||||
<Chip value={action.blocked_runtime_action} muted />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 12, border: '0.5px solid #d8c6a6', borderRadius: 7, background: '#fffdf7', display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, flexWrap: 'wrap' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 7, minWidth: 0 }}>
|
||||
|
||||
@@ -317,6 +317,11 @@ export const apiClient = {
|
||||
return handleResponse<AiAgentRuntimeVerifierEvidenceReviewSnapshot>(res)
|
||||
},
|
||||
|
||||
async getAiAgentReportTruthActionabilityReview() {
|
||||
const res = await fetch(`${API_BASE_URL}/agents/agent-report-truth-actionability-review`)
|
||||
return handleResponse<AiAgentReportTruthActionabilityReviewSnapshot>(res)
|
||||
},
|
||||
|
||||
async getAiAgentOwnerApprovedFixtureDryRun() {
|
||||
const res = await fetch(`${API_BASE_URL}/agents/agent-owner-approved-fixture-dry-run`)
|
||||
return handleResponse<AiAgentOwnerApprovedFixtureDryRunSnapshot>(res)
|
||||
@@ -1843,6 +1848,106 @@ export interface AiAgentRuntimeVerifierEvidenceReviewSnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
export interface AiAgentReportTruthActionabilityReviewSnapshot {
|
||||
schema_version: 'ai_agent_report_truth_actionability_review_v1'
|
||||
generated_at: string
|
||||
program_status: {
|
||||
overall_completion_percent: number
|
||||
current_priority: 'P0' | 'P1' | 'P2' | 'P3'
|
||||
current_task_id: string
|
||||
next_task_id: string
|
||||
read_only_mode: true
|
||||
runtime_authority: 'report_truth_actionability_review_only_no_report_send_or_runtime_fix'
|
||||
status_note: string
|
||||
}
|
||||
source_refs: string[]
|
||||
report_truth: {
|
||||
report_truth_packet_ready: true
|
||||
all_zero_weekly_report_is_actionable_anomaly: true
|
||||
daily_report_contract_present: boolean
|
||||
weekly_report_contract_present: boolean
|
||||
monthly_report_contract_present: false
|
||||
freshness_gate_implemented: false
|
||||
source_confidence_gate_implemented: false
|
||||
actionability_score_implemented: false
|
||||
ai_agent_runtime_control_allowed: false
|
||||
telegram_report_send_allowed: false
|
||||
cronjob_change_allowed: false
|
||||
truth_note: string
|
||||
}
|
||||
zero_signal_findings: Array<{
|
||||
finding_id: string
|
||||
display_name: string
|
||||
severity: string
|
||||
source: string
|
||||
evidence: string
|
||||
operator_meaning: string
|
||||
required_fix: string
|
||||
owner_agent: 'openclaw' | 'hermes' | 'nemotron'
|
||||
blocked_runtime_action: string
|
||||
}>
|
||||
report_cadence_contracts: Array<{
|
||||
cadence_id: string
|
||||
display_name: string
|
||||
status: string
|
||||
source: string
|
||||
required_truth: string
|
||||
next_action: string
|
||||
owner_agent: 'openclaw' | 'hermes' | 'nemotron'
|
||||
}>
|
||||
alert_actionability_lanes: Array<{
|
||||
lane_id: string
|
||||
display_name: string
|
||||
routing_policy: string
|
||||
ai_agent_role: string
|
||||
notification_policy: string
|
||||
}>
|
||||
telegram_routing_consolidation: {
|
||||
canonical_room_name: 'AwoooI SRE 戰情室'
|
||||
canonical_room_env: 'SRE_GROUP_CHAT_ID'
|
||||
product_alerts_must_route_to_canonical_room: true
|
||||
other_bot_or_group_alerts_allowed: false
|
||||
direct_telegram_api_send_allowed: false
|
||||
secret_value_read_allowed: false
|
||||
route_change_allowed: false
|
||||
routing_note: string
|
||||
}
|
||||
telegram_route_findings: Array<{
|
||||
route_id: string
|
||||
display_name: string
|
||||
source: string
|
||||
current_state: string
|
||||
target_state: string
|
||||
risk: string
|
||||
required_fix: string
|
||||
blocked_runtime_action: string
|
||||
}>
|
||||
operator_actions: Array<{
|
||||
action_id: string
|
||||
display_name: string
|
||||
action_type: string
|
||||
status: string
|
||||
owner_agent: 'openclaw' | 'hermes' | 'nemotron'
|
||||
operator_instruction: string
|
||||
blocked_runtime_action: string
|
||||
}>
|
||||
approval_boundaries: Record<string, false>
|
||||
rollups: {
|
||||
zero_signal_finding_count: number
|
||||
critical_finding_count: number
|
||||
high_finding_count: number
|
||||
cadence_contract_count: number
|
||||
missing_cadence_contract_count: number
|
||||
actionability_lane_count: number
|
||||
telegram_route_finding_count: number
|
||||
legacy_or_direct_route_count: number
|
||||
operator_action_count: number
|
||||
approval_required_action_ids: string[]
|
||||
blocked_runtime_action_count: number
|
||||
all_zero_weekly_report_confidence: 'low_trust_actionable_anomaly'
|
||||
}
|
||||
}
|
||||
|
||||
export interface AiAgentOwnerApprovedFixtureDryRunSnapshot {
|
||||
schema_version: 'ai_agent_owner_approved_fixture_dry_run_v1'
|
||||
generated_at: string
|
||||
|
||||
@@ -1,3 +1,32 @@
|
||||
## 2026-06-12|P2-403J 報表真相與告警有效性審查
|
||||
|
||||
**背景**:統帥指出 AWOOOI 週報告警、AI 效能、K3s、開發活動與 AI 成本全為 `0`,這種報表沒有營運價值,也可能代表資料來源失效而非系統健康;同時本產品所有告警必須集中到 **AwoooI SRE 戰情室**,不得散到其他 TG Bot 或群組。
|
||||
|
||||
**完成**:
|
||||
|
||||
- 盤點 `weekly_report_service.py`、`report_generation_service.py`、`heartbeat_report_service.py`、`telegram_gateway.py`、`constants.py` 與 Gitea workflow notification path,確認全 0 週報目前存在「資料源失敗後靜默降級成 0 / 硬編健康值 / Git 統計失敗回 0 / 月報 truth contract 缺口 / 心跳未做可處置性評分」等結構性問題。
|
||||
- 新增 `ai_agent_report_truth_actionability_review_v1` schema、committed snapshot、只讀 loader、API route 與測試。
|
||||
- 新增 `GET /api/v1/agents/agent-report-truth-actionability-review`:只回傳報表真相、全 0 缺口、日 / 週 / 月報契約、告警 actionability lane、TG route finding 與人工操作選項;不發 Telegram、不改 CronJob、不改 Prometheus / Alertmanager、不改 route / receiver、不讀 secret、不寫 work item / KM / PlayBook trust、不開 runtime worker。
|
||||
- Snapshot 固定 `5` 個 zero-signal finding、`3` 個報表週期契約、`4` 個 actionability lane、`4` 條 TG 旁路風險、`5` 個 operator action、`28` 個 blocked runtime action;全 0 週報 confidence 固定為 `low_trust_actionable_anomaly`。
|
||||
- Telegram 路由契約固定 canonical room:`AwoooI SRE 戰情室`,canonical env:`SRE_GROUP_CHAT_ID`;其他 TG Bot / 群組、direct Telegram API send、舊 `TELEGRAM_ALERT_CHAT_ID` 與多 bot token direct route 目前全部列為待收斂風險,不得解讀為已授權 route change。
|
||||
- Governance automation inventory 頁新增 P2-403J 區塊,顯示全 0 週報異常、freshness / confidence / actionability gate、日週月契約、TG 旁路、AwoooI SRE 戰情室與 operator action;仍不提供任何執行按鈕。
|
||||
- `agent-interaction-learning-proof` 與 `agent-proactive-operations-contract` 已同步 current / next:`P2-403J -> P2-403K`;主動營運 rollout task count `16 -> 17`。
|
||||
|
||||
**本地驗證**:
|
||||
|
||||
- JSON parse:P2-403J schema / snapshot、P2-403 interaction snapshot、P2-403 proactive snapshot、`zh-TW.json`、`en.json` 通過。
|
||||
- `cmp -s apps/web/messages/zh-TW.json apps/web/messages/en.json`:通過。
|
||||
- `python3 -m py_compile apps/api/src/services/ai_agent_report_truth_actionability_review.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_report_truth_actionability_review.py apps/api/tests/test_ai_agent_report_truth_actionability_review_api.py`:`8 passed`。
|
||||
|
||||
**完成度同步**:
|
||||
|
||||
- P2-403J 報表真相與告警有效性審查:本地契約 / API / UI 接線進行中。
|
||||
- 三 Agent 主動溝通、學習與成長證據:仍維持 `99%`,不因只讀審查完成而宣稱 runtime loop 已打通。
|
||||
- IwoooS 整體仍維持 `64%`;active runtime gate 仍 `0`。
|
||||
|
||||
**邊界**:本段尚未發 Telegram、未改任何 TG secret / chat id、未改 CronJob、未改 Prometheus / Alertmanager、未改 route / receiver、未建立 silence、未讀 secret value、未寫 work item / KM / PlayBook trust、未啟動 runtime worker、未 SSH、未 active scan。
|
||||
|
||||
## 2026-06-12|IwoooS P0 Public Gateway / Nginx Preflight 只讀清冊
|
||||
|
||||
**背景**:統帥要求所有重要配置都要納入資安控管,尤其 Nginx / public gateway / reverse proxy / TLS / route 常被變動,必須先有資安機制管住變更前置條件。本段延續「先建立框架、只讀證據、低摩擦流程,再階段性收攏」原則,只做 repo-only preflight 清冊與前台可視化,不讀 live 主機、不執行 `nginx -t`、不 reload、不改 DNS / TLS / ACME。
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
| Nemotron 實際整合應用 | 30% | 完整回放前仍被關卡擋下 | `blocked_needs_evidence`,下一關是 `refresh_source_evidence_then_5_record_smoke_only` |
|
||||
| 工具 / 服務 / 套件 AI 自動化 | 92% | P0 已完成;P1 服務 / runtime / 監控 / provider / service health / 備份 / DR / 套件與供應鏈只讀基線已完成;P1-007 失敗限定通知合約與前端 redaction 合約已完成;下一主線是 P2-004 依賴 / 供應鏈漂移監控 | 狀態分類、盤點 schema、權限矩陣、靜態盤點種子、只讀 API、UI 骨架、驗證、自動化待辦 schema / 快照 / API / 分組 UI、Backup / DR 目標盤點、準備度矩陣、備份通知政策、Backup / DR 證據 UI、復原演練批准包模板、異地 / escrow 準備度狀態、任務批准邊界、確定性進度彙總、Python 套件 / 供應鏈只讀基線、JS pnpm/npm 只讀基線、Docker build surface 只讀基線、CVE / license / drift 嚴重度政策、定期依賴漂移與外部資料來源檢查設計、依賴升級批准包模板、runtime_surface_inventory_v1 schema / snapshot / API / UI、gitea_workflow_runner_health_v1 schema / snapshot / API / UI、observability_contract_matrix_v1 schema / snapshot / API / UI、ai_provider_route_matrix_v1 schema / snapshot / API / UI、service_health_gap_matrix_v1 schema / snapshot / API / UI、service health evidence cards UI、service_health_failure_notification_policy_v1 schema / snapshot / API / UI 已完成 |
|
||||
| OpenClaw / Hermes / NemoTron 佈建布局 | 45% | P1-401 / P1-402 已完成;仍是只讀 layout 與治理頁顯示,不是 runtime deploy | `ai_agent_deployment_layout_v1` schema、`ai_agent_deployment_layout_2026-06-11.json`、`GET /api/v1/agents/agent-deployment-layout`、治理頁自動化盤點 UI、`AI_AGENT_DEPLOYMENT_LAYOUT_2026-06-11.md` |
|
||||
| OpenClaw / Hermes / NemoTron 主動溝通、學習與成長證據 | 99% | P2-401A 已完成只讀 contract;P2-403A 已完成互動 / 接手 / 學習 / 成長證據面板;P2-403B 已完成 AgentSession / Redis Streams live read model gate;P2-403C 已完成 Redis Streams consumer group dry-run、handoff envelope、ack / dead-letter / replay gate;P2-403D 已完成 learning writeback approval package;P2-403E 已完成 Telegram receipt approval package;P2-403F 已完成 owner-approved learning dry-run preview、人工操作選項與 fixture-only dry-run 總包;P2-403G 已完成 runtime write gate review,固定雙重批准、dry-run hash、post-write verifier 與 redaction 欄位;P2-403H 已完成 post-write verifier implementation package、rollback lane、failure lane 與人工操作選項;P2-403I 已完成 runtime verifier evidence implementation review、redaction review、rollback / failure receipt gate 與人工操作選項。runtime worker、DB migration、production Redis consumer group、Telegram 實發、KM / PlayBook trust / timeline / replay score 寫入、SDK / 付費服務仍未開 gate | `ai_agent_communication_learning_contract_v1`、`ai_agent_interaction_learning_proof_v1`、`ai_agent_live_read_model_gate_v1`、`ai_agent_redis_dry_run_gate_v1`、`ai_agent_learning_writeback_approval_package_v1`、`ai_agent_telegram_receipt_approval_package_v1`、`ai_agent_owner_approved_learning_dry_run_v1`、`ai_agent_owner_approved_fixture_dry_run_v1`、`GET /api/v1/agents/agent-communication-learning-contract`、`GET /api/v1/agents/agent-interaction-learning-proof`、`GET /api/v1/agents/agent-live-read-model-gate`、`GET /api/v1/agents/agent-redis-dry-run-gate`、`GET /api/v1/agents/agent-learning-writeback-approval-package`、`GET /api/v1/agents/agent-telegram-receipt-approval-package`、`GET /api/v1/agents/agent-owner-approved-learning-dry-run`、`GET /api/v1/agents/agent-owner-approved-fixture-dry-run`、`ai_agent_runtime_write_gate_review_v1`、`GET /api/v1/agents/agent-runtime-write-gate-review`、`ai_agent_post_write_verifier_package_v1`、`GET /api/v1/agents/agent-post-write-verifier-package`、`ai_agent_runtime_verifier_evidence_review_v1`、`GET /api/v1/agents/agent-runtime-verifier-evidence-review`、`/zh-TW/governance?tab=automation-inventory`、MASTER §3.2.1b / §3.2.1d / §3.4.3 |
|
||||
| OpenClaw / Hermes / NemoTron 主動溝通、學習與成長證據 | 99% | P2-401A 已完成只讀 contract;P2-403A 已完成互動 / 接手 / 學習 / 成長證據面板;P2-403B 已完成 AgentSession / Redis Streams live read model gate;P2-403C 已完成 Redis Streams consumer group dry-run、handoff envelope、ack / dead-letter / replay gate;P2-403D 已完成 learning writeback approval package;P2-403E 已完成 Telegram receipt approval package;P2-403F 已完成 owner-approved learning dry-run preview、人工操作選項與 fixture-only dry-run 總包;P2-403G 已完成 runtime write gate review,固定雙重批准、dry-run hash、post-write verifier 與 redaction 欄位;P2-403H 已完成 post-write verifier implementation package、rollback lane、failure lane 與人工操作選項;P2-403I 已完成 runtime verifier evidence implementation review;P2-403J 已完成報表真相與告警有效性審查,將全 0 週報視為低可信可處置異常,並要求本產品正式 TG 告警收斂到 AwoooI SRE 戰情室。runtime worker、DB migration、production Redis consumer group、Telegram 實發、Telegram route change、KM / PlayBook trust / timeline / replay score 寫入、SDK / 付費服務仍未開 gate | `ai_agent_communication_learning_contract_v1`、`ai_agent_interaction_learning_proof_v1`、`ai_agent_live_read_model_gate_v1`、`ai_agent_redis_dry_run_gate_v1`、`ai_agent_learning_writeback_approval_package_v1`、`ai_agent_telegram_receipt_approval_package_v1`、`ai_agent_owner_approved_learning_dry_run_v1`、`ai_agent_owner_approved_fixture_dry_run_v1`、`GET /api/v1/agents/agent-communication-learning-contract`、`GET /api/v1/agents/agent-interaction-learning-proof`、`GET /api/v1/agents/agent-live-read-model-gate`、`GET /api/v1/agents/agent-redis-dry-run-gate`、`GET /api/v1/agents/agent-learning-writeback-approval-package`、`GET /api/v1/agents/agent-telegram-receipt-approval-package`、`GET /api/v1/agents/agent-owner-approved-learning-dry-run`、`GET /api/v1/agents/agent-owner-approved-fixture-dry-run`、`ai_agent_runtime_write_gate_review_v1`、`GET /api/v1/agents/agent-runtime-write-gate-review`、`ai_agent_post_write_verifier_package_v1`、`GET /api/v1/agents/agent-post-write-verifier-package`、`ai_agent_runtime_verifier_evidence_review_v1`、`GET /api/v1/agents/agent-runtime-verifier-evidence-review`、`ai_agent_report_truth_actionability_review_v1`、`GET /api/v1/agents/agent-report-truth-actionability-review`、`/zh-TW/governance?tab=automation-inventory`、MASTER §3.2.1b / §3.2.1d / §3.4.3 |
|
||||
| AI Agent 主動營運委派與版本生命週期 | 100% | P2-402A / P2-402B / P2-402C / P2-402D / P2-402E / P2-402F / P2-402G 已完成;已建立 repo-only 版本新鮮度快照、工具採用批准包、Telegram action-required digest policy、Gitea PR 草案 lane、host / K3s / stateful 版本只讀盤點、API 與 governance UI。定期排程、外部版本查詢、工具安裝、CI 變更、套件升級、主機更新、container pull、實際 PR creation、auto merge、Telegram 實發、SSH、kubectl、重啟仍未開 gate | `ai_agent_proactive_operations_contract_v1`、`ai_agent_version_freshness_snapshot_v1`、`ai_agent_tool_adoption_approval_package_v1`、`ai_agent_telegram_action_required_digest_policy_v1`、`ai_agent_gitea_pr_draft_lane_v1`、`ai_agent_host_stateful_version_inventory_v1`、`GET /api/v1/agents/agent-proactive-operations-contract`、`GET /api/v1/agents/agent-version-freshness-snapshot`、`GET /api/v1/agents/agent-tool-adoption-approval-package`、`GET /api/v1/agents/agent-telegram-action-required-digest-policy`、`GET /api/v1/agents/agent-gitea-pr-draft-lane`、`GET /api/v1/agents/agent-host-stateful-version-inventory`、`/zh-TW/governance?tab=automation-inventory`、MASTER §3.2.1c |
|
||||
| 本工作清單與分析報告 | 100% | 已完成 | 本 MD 文件 |
|
||||
|
||||
@@ -20,9 +20,9 @@ AI Agent 自動化工作包目前完成度:**92%**。本工作清單文件本
|
||||
|
||||
三 Agent 佈建布局目前完成度:**45%**。第一波已完成只讀 schema / snapshot / API / 測試 / 報告,第二波已接入治理頁自動化盤點 UI;正式 runtime 佈署、Telegram E2E 發送與 AgentSession 工作流仍需逐項 gate。
|
||||
|
||||
三 Agent 主動溝通、學習與成長證據目前完成度:**99%**。已完成只讀契約、互動 / 接手 / 學習 / 成長證據面板、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、API、治理頁顯示、測試與 MASTER 同步;目前 live AgentSession、Agent message、handoff、learning write、Telegram receipt、Gateway queue write、runtime verifier execution 與 Telegram send 仍全部為 `0`,下一步依優先順序推 `P2-403J` 成長趨勢週報與 operator feedback applied 指標,但在批准前仍不得啟動 runtime loop。
|
||||
三 Agent 主動溝通、學習與成長證據目前完成度:**99%**。已完成只讀契約、互動 / 接手 / 學習 / 成長證據面板、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 報表真相與告警有效性審查、API、治理頁顯示、測試與 MASTER 同步;目前 live AgentSession、Agent message、handoff、learning write、Telegram receipt、Gateway queue write、runtime verifier execution、Telegram route change 與 Telegram send 仍全部為 `0`,下一步依優先順序推 `P2-403K` unified report truth service / SRE 戰情室路由遷移批准包,但在批准前仍不得啟動 runtime loop。
|
||||
|
||||
AI Agent 主動營運委派與版本生命週期目前完成度:**100%**。已完成 12 類版本 domain、24 類可委派能力、5 種 cadence、8 類 MCP、4 類 RAG memory、只讀 API、`P2-402B` repo-only daily version freshness snapshot、`P2-402C` Renovate / OSV-Scanner / Trivy / Syft / Grype 工具採用批准包、`P2-402D` Telegram action-required digest policy、`P2-402E` Gitea PR 草案 lane、`P2-402F` host OS / K3s / stateful services 版本只讀盤點,以及 `P2-402G` governance UI 顯示可委派能力;`P2-403A`、`P2-403B`、`P2-403C`、`P2-403D`、`P2-403E`、`P2-403F` 、`P2-403G`、`P2-403H` 與 `P2-403I` 已先補互動、學習證據面、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。下一步是 `P2-403J` 成長趨勢週報與 operator feedback applied 指標,外部 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-403B`、`P2-403C`、`P2-403D`、`P2-403E`、`P2-403F` 、`P2-403G`、`P2-403H`、`P2-403I` 與 `P2-403J` 已先補互動、學習證據面、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 戰情室收斂審查。下一步是 `P2-403K` unified report truth service / SRE 戰情室路由遷移批准包,外部 registry / package source / host probe / SSH / kubectl / 工具安裝 / CI 變更 / 實際 PR creation / Telegram 實發與 learning write 仍需 gate。
|
||||
|
||||
完成度計算模型:
|
||||
|
||||
@@ -967,6 +967,7 @@ UI:
|
||||
| P2-403F | 完成 | 100 | Hermes + OpenClaw | Owner-approved learning dry-run preview、人工操作選項與驗證 / rollback gate | `ai_agent_owner_approved_learning_dry_run_v1` / snapshot / 只讀 API / governance UI;dry-run preview 欄位、operator actions、evidence gate、rollback / verification contract | 不產生 live preview、不寫 KM、不更新 PlayBook trust、不寫 timeline / replay score、不發 Telegram |
|
||||
| P2-403G | 完成 | 100 | OpenClaw | Runtime write gate review、雙重批准、dry-run hash、post-write verifier 與 redaction gate | `ai_agent_runtime_write_gate_review_v1` / snapshot / 只讀 API / governance UI;4 個 write target、4 個 approval gate、9 個必填欄位與 live write total `0` | 不寫 KM、不更新 PlayBook trust、不寫 timeline / replay score、不發 Telegram;runtime write 仍未授權 |
|
||||
| P2-403H | 完成 | 100 | OpenClaw | Post-write verifier implementation package、rollback lane、failure lane 與人工操作選項 | `ai_agent_post_write_verifier_package_v1` / snapshot / 只讀 API / governance UI;4 個 verification target、3 個 failure lane、4 個 operator action 與 live verifier execution `0` | 不讀 canonical target、不寫 rollback work item、不發 Telegram、不寫 KM / PlayBook trust / timeline / replay score;runtime verifier 仍未授權 |
|
||||
| P2-403J | 完成 | 100 | OpenClaw | 報表真相與告警有效性審查;全 0 週報判為異常;本產品所有 TG 告警收斂至 AwoooI SRE 戰情室 | `ai_agent_report_truth_actionability_review_v1` / snapshot / 只讀 API / governance UI;5 個真相缺口、3 個日週月契約、4 個 actionability lane、4 條 TG 旁路風險、5 個 operator action | 不發 Telegram、不改 CronJob、不改 Prometheus / Alertmanager、不改 route / receiver、不讀 secret、不寫 work item / KM / PlayBook trust、不開 runtime worker |
|
||||
| P2-101 | 待辦 | 0 | OpenClaw | 定義操作類別權限模型 | 操作政策 schema | HITL 關卡 |
|
||||
| P2-102 | 待辦 | 0 | OpenClaw | 所有候選操作都要有 dry-run 證據 | dry-run 合約 | 不直接 apply |
|
||||
| P2-103 | 待辦 | 0 | Hermes | 把任務結果接回 KM / LOGBOOK / 稽核軌跡 | 證據寫入器 | 不洩漏 secret |
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
> 文件定位: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、API 與治理頁 UI。
|
||||
> 事實邊界:本波只建立可見證據面與 read model gate,不啟動 runtime worker、不建立 DB migration、不開 Redis consumer group、不發 Telegram、不顯示工作視窗對話內容。
|
||||
|
||||
## 0. P2-403J 補記:報表真相與 AwoooI SRE 戰情室收斂
|
||||
|
||||
2026-06-12 已新增 P2-403J:`ai_agent_report_truth_actionability_review_v1`、`docs/evaluations/ai_agent_report_truth_actionability_review_2026-06-12.json`、`GET /api/v1/agents/agent-report-truth-actionability-review` 與治理頁區塊。
|
||||
|
||||
本段把週報全 0 固定為「低可信可處置異常」,不是健康訊號;同時把本產品正式 Telegram 告警目標固定為 **AwoooI SRE 戰情室**(`SRE_GROUP_CHAT_ID`),其他 TG Bot / 群組 / direct Telegram API 路徑都列為待收斂旁路風險。此段仍只讀,不發 Telegram、不改 CronJob、不改 Alertmanager / Prometheus、不改 route / receiver、不讀 secret、不寫 work item / KM / PlayBook trust、不開 runtime worker。
|
||||
|
||||
## 1. 結論
|
||||
|
||||
已完成 P2-403A、P2-403B、P2-403C、P2-403D、P2-403E、P2-403F、P2-403G、P2-403H 與 P2-403I:讓統帥能在治理頁看到 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 下一步要通過哪些 gate。
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
> 日期:2026-06-11(台北時間)
|
||||
> 文件定位:P2-402A / P2-402B / P2-402C / P2-402D / P2-402E / P2-402F / P2-402G / P2-403A / P2-403B / P2-403C / P2-403D / P2-403E / P2-403F / P2-403G / P2-403H / P2-403I 只讀契約與治理 UI 摘要。權威細節以 MASTER §3.2.1c / §3.2.1d、`ai_agent_proactive_operations_contract_v1`、`ai_agent_interaction_learning_proof_v1`、`ai_agent_live_read_model_gate_v1`、`ai_agent_redis_dry_run_gate_v1`、`ai_agent_learning_writeback_approval_package_v1`、`ai_agent_telegram_receipt_approval_package_v1`、`ai_agent_owner_approved_learning_dry_run_v1`、`ai_agent_owner_approved_fixture_dry_run_v1`、`ai_agent_runtime_write_gate_review_v1`、`ai_agent_post_write_verifier_package_v1`、`ai_agent_runtime_verifier_evidence_review_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` 為準。
|
||||
|
||||
## 0. P2-403J 補記:報表與告警接管真相
|
||||
|
||||
2026-06-12 已新增 `ai_agent_report_truth_actionability_review_v1`:全 0 週報不再可被解讀為健康,而是 report truth / source freshness / confidence 缺口;日報、週報、月報需共用 truth gate;Watchdog / NoAlertsReceived 等心跳需進 actionability lane;本產品正式 Telegram 告警需收斂至 **AwoooI SRE 戰情室**(`SRE_GROUP_CHAT_ID`)。其他 TG Bot、舊 `TELEGRAM_ALERT_CHAT_ID`、direct Telegram API send 與多 bot token route 目前只列為待收斂風險,不代表已改 secret 或已切 route。
|
||||
|
||||
## 1. 本波完成度
|
||||
|
||||
| 範圍 | 完成度 | 狀態 |
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
"program_status": {
|
||||
"overall_completion_percent": 99,
|
||||
"current_priority": "P2",
|
||||
"current_task_id": "P2-403I",
|
||||
"next_task_id": "P2-403J",
|
||||
"current_task_id": "P2-403J",
|
||||
"next_task_id": "P2-403K",
|
||||
"read_only_mode": true,
|
||||
"runtime_authority": "proof_surface_only_no_live_worker",
|
||||
"status_note": "P2-403I 已把 runtime verifier evidence implementation review 接入;review checks、implementation lanes、rollback / failure receipt redaction 與人工操作選項齊備,但 live AgentSession、message、handoff、learning write、Telegram receipt 與 verifier execution 仍全部為 0。"
|
||||
"status_note": "P2-403J 已把報表真相、全 0 週報可處置異常、日週月契約、心跳降噪與 Telegram 收斂到 AwoooI SRE 戰情室的只讀審查接入;live AgentSession、message、handoff、learning write、Telegram receipt、verifier execution 與 route change 仍全部為 0。"
|
||||
},
|
||||
"live_truth": {
|
||||
"runtime_loop_enabled": false,
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
"program_status": {
|
||||
"overall_completion_percent": 100,
|
||||
"current_priority": "P2",
|
||||
"current_task_id": "P2-403I",
|
||||
"next_task_id": "P2-403J",
|
||||
"current_task_id": "P2-403J",
|
||||
"next_task_id": "P2-403K",
|
||||
"read_only_mode": true,
|
||||
"runtime_authority": "contract_only_no_version_or_runtime_update",
|
||||
"status_note": "P2-403I 已把 runtime verifier evidence implementation review 接入治理證據;live AgentSession / Redis consumer / runtime worker / learning write / Telegram receipt / verifier execution 目前全為 0,下一步是 P2-403J 成長趨勢週報與 operator feedback applied 指標。"
|
||||
"status_note": "P2-403J 已把報表真相與告警可處置性審查接入治理證據;全 0 週報視為低可信可處置異常,Telegram 正式告警必須收斂到 AwoooI SRE 戰情室。live AgentSession / Redis consumer / runtime worker / learning write / Telegram receipt / verifier execution / route change 目前全為 0。"
|
||||
},
|
||||
"external_source_evidence": [
|
||||
{
|
||||
@@ -938,6 +938,23 @@
|
||||
"runtime_learning_write",
|
||||
"agent_replay_score_write"
|
||||
]
|
||||
},
|
||||
{
|
||||
"task_id": "P2-403J",
|
||||
"sequence": 13,
|
||||
"display_name": "Report truth and alert actionability review",
|
||||
"status": "done",
|
||||
"owner_agent": "openclaw",
|
||||
"completion_percent": 100,
|
||||
"runtime_authority": "report_truth_actionability_review_only_no_report_send_or_runtime_fix",
|
||||
"blocked_runtime_actions": [
|
||||
"telegram_weekly_report_send_as_normal",
|
||||
"telegram_route_change",
|
||||
"direct_telegram_send_to_legacy_chat",
|
||||
"report_truth_runtime_write",
|
||||
"work_item_write",
|
||||
"heartbeat_to_auto_repair"
|
||||
]
|
||||
}
|
||||
],
|
||||
"approval_boundaries": {
|
||||
@@ -958,7 +975,7 @@
|
||||
"cadence_count": 5,
|
||||
"mcp_tool_count": 8,
|
||||
"rag_memory_count": 4,
|
||||
"rollout_task_count": 16,
|
||||
"rollout_task_count": 17,
|
||||
"auto_execute_allowed_count": 0,
|
||||
"approval_required_capability_count": 23,
|
||||
"blocked_update_domain_ids": [
|
||||
|
||||
@@ -0,0 +1,289 @@
|
||||
{
|
||||
"schema_version": "ai_agent_report_truth_actionability_review_v1",
|
||||
"generated_at": "2026-06-12T10:48:00+08:00",
|
||||
"program_status": {
|
||||
"overall_completion_percent": 99,
|
||||
"current_priority": "P2",
|
||||
"current_task_id": "P2-403J",
|
||||
"next_task_id": "P2-403K",
|
||||
"read_only_mode": true,
|
||||
"runtime_authority": "report_truth_actionability_review_only_no_report_send_or_runtime_fix",
|
||||
"status_note": "P2-403J 將日報、週報、月報、心跳與告警可處置性固定成真相審查契約;目前只揭露資料可信度與下一步接管缺口,不發 Telegram、不修改 CronJob、不啟動修復。"
|
||||
},
|
||||
"source_refs": [
|
||||
"apps/api/src/services/weekly_report_service.py",
|
||||
"apps/api/src/services/report_generation_service.py",
|
||||
"apps/api/src/services/heartbeat_report_service.py",
|
||||
"apps/api/src/services/telegram_gateway.py",
|
||||
"apps/api/src/core/constants.py",
|
||||
".gitea/workflows/cd.yaml",
|
||||
".gitea/workflows/code-review.yaml",
|
||||
"k8s/awoooi-prod/14-cronjob-weekly-report.yaml",
|
||||
"docs/adr/ADR-041-periodic-reporting-architecture.md",
|
||||
"docs/adr/ADR-109-telegram-gateway-unified-dedup.md",
|
||||
"docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md"
|
||||
],
|
||||
"report_truth": {
|
||||
"report_truth_packet_ready": true,
|
||||
"all_zero_weekly_report_is_actionable_anomaly": true,
|
||||
"daily_report_contract_present": true,
|
||||
"weekly_report_contract_present": true,
|
||||
"monthly_report_contract_present": false,
|
||||
"freshness_gate_implemented": false,
|
||||
"source_confidence_gate_implemented": false,
|
||||
"actionability_score_implemented": false,
|
||||
"ai_agent_runtime_control_allowed": false,
|
||||
"telegram_report_send_allowed": false,
|
||||
"cronjob_change_allowed": false,
|
||||
"truth_note": "目前已確認週報全 0 不能視為正常;weekly report 有多個資料源失敗後降級成 0 / 硬編值的路徑,必須先建立 freshness、source confidence 與 actionability gate。"
|
||||
},
|
||||
"zero_signal_findings": [
|
||||
{
|
||||
"finding_id": "weekly_stats_failure_becomes_zero",
|
||||
"display_name": "Stats 失敗被包成 0",
|
||||
"severity": "critical",
|
||||
"source": "apps/api/src/services/weekly_report_service.py",
|
||||
"evidence": "get_incident_summary / get_resolution_stats / get_ai_performance 失敗時改用空 dict,最後 alert / AI 指標成為 0。",
|
||||
"operator_meaning": "週報顯示 0 可能代表資料源失敗,不代表沒有告警或沒有 AI 活動。",
|
||||
"required_fix": "報表必須顯示 source freshness、last_success_at、query_error 與 confidence,不得靜默降級成 0。",
|
||||
"owner_agent": "openclaw",
|
||||
"blocked_runtime_action": "telegram_weekly_report_as_green_status"
|
||||
},
|
||||
{
|
||||
"finding_id": "weekly_k3s_uptime_hardcoded",
|
||||
"display_name": "K3s uptime 硬編 99.9",
|
||||
"severity": "high",
|
||||
"source": "apps/api/src/services/weekly_report_service.py",
|
||||
"evidence": "k3s_uptime = 99.9,HPA events = 0,成本與 token 也固定為 0。",
|
||||
"operator_meaning": "週報裡的健康、HPA、成本欄位不是完整真實讀回,會誤導 operator。",
|
||||
"required_fix": "接 Prometheus / K8s / AI cost ledger 或標為 data_missing;禁止用固定值裝成健康。",
|
||||
"owner_agent": "hermes",
|
||||
"blocked_runtime_action": "weekly_report_kpi_green_badge"
|
||||
},
|
||||
{
|
||||
"finding_id": "git_stats_failure_becomes_zero",
|
||||
"display_name": "Git 統計失敗被包成 0",
|
||||
"severity": "high",
|
||||
"source": "apps/api/src/services/weekly_report_service.py",
|
||||
"evidence": "git log 在 /app 執行失敗時直接 return 0,0。",
|
||||
"operator_meaning": "Commits / 部署為 0 可能只是容器內沒有 git history 或路徑不對。",
|
||||
"required_fix": "改用 Gitea API / committed deploy marker / workflow run readback;失敗時顯示 source_unavailable。",
|
||||
"owner_agent": "openclaw",
|
||||
"blocked_runtime_action": "weekly_dev_activity_green_badge"
|
||||
},
|
||||
{
|
||||
"finding_id": "monthly_report_contract_missing",
|
||||
"display_name": "月報缺少獨立 truth contract",
|
||||
"severity": "medium",
|
||||
"source": "apps/api/src/api/v1/stats.py",
|
||||
"evidence": "stats API 有 daily / weekly / monthly period,但日報與週報各自實作,月報沒有獨立 freshness / confidence / actionability contract。",
|
||||
"operator_meaning": "日報、週報、月報不能保證同一套資料真相與異常判讀。",
|
||||
"required_fix": "建立 unified report truth service,日 / 週 / 月共用資料源、freshness、confidence、actionability 與 failure lane。",
|
||||
"owner_agent": "hermes",
|
||||
"blocked_runtime_action": "monthly_report_send"
|
||||
},
|
||||
{
|
||||
"finding_id": "heartbeat_noise_not_actionability_scored",
|
||||
"display_name": "心跳告警未做可處置性評分",
|
||||
"severity": "high",
|
||||
"source": "apps/api/src/core/constants.py",
|
||||
"evidence": "Watchdog / NoAlertsReceived / DeadMansSwitch 會被排除自動修復,但尚未分成 useful heartbeat、stale source、noise-only 與 report-only。",
|
||||
"operator_meaning": "心跳不該觸發修復,但也不能完全無腦報平安;它應該只在 freshness 失效、來源斷線、回報異常時升級。",
|
||||
"required_fix": "新增 heartbeat actionability gate:正常心跳沉默,stale source 進 failure-only 通知,無事故心跳只進摘要。",
|
||||
"owner_agent": "nemotron",
|
||||
"blocked_runtime_action": "heartbeat_to_repair_flywheel"
|
||||
}
|
||||
],
|
||||
"report_cadence_contracts": [
|
||||
{
|
||||
"cadence_id": "daily_report",
|
||||
"display_name": "日報",
|
||||
"status": "contract_present_needs_truth_gate",
|
||||
"source": "apps/api/src/services/report_generation_service.py",
|
||||
"required_truth": "24h incidents、repair execution、KM、PlayBook、source freshness、query error、last_success_at。",
|
||||
"next_action": "接 unified report truth service;若資料缺失,日報必須顯示 DATA MISSING 並建立 work item。",
|
||||
"owner_agent": "hermes"
|
||||
},
|
||||
{
|
||||
"cadence_id": "weekly_report",
|
||||
"display_name": "週報",
|
||||
"status": "critical_zero_signal_gap",
|
||||
"source": "apps/api/src/services/weekly_report_service.py",
|
||||
"required_truth": "7d incidents、AI proposals/executions、K3s metrics、Gitea commits/deploys、cost ledger、confidence。",
|
||||
"next_action": "把全 0 判為 actionable anomaly;先阻擋 green weekly report,再補 source readback。",
|
||||
"owner_agent": "openclaw"
|
||||
},
|
||||
{
|
||||
"cadence_id": "monthly_report",
|
||||
"display_name": "月報",
|
||||
"status": "missing_contract",
|
||||
"source": "apps/api/src/api/v1/stats.py",
|
||||
"required_truth": "30d trend、SLO breach、automation learning delta、cost trend、noise reduction、operator feedback applied。",
|
||||
"next_action": "建立月報契約,不再只靠 stats period 參數。",
|
||||
"owner_agent": "hermes"
|
||||
}
|
||||
],
|
||||
"alert_actionability_lanes": [
|
||||
{
|
||||
"lane_id": "action_required_alert",
|
||||
"display_name": "需處置告警",
|
||||
"routing_policy": "有影響、有 owner、有 next action、有 evidence,才推 Telegram action-required。",
|
||||
"ai_agent_role": "OpenClaw 分類與 PlayBook context,Hermes 取 KM,NemoTron 做 regression / critic。",
|
||||
"notification_policy": "failure-only / action-required 即時通知;成功只進摘要。"
|
||||
},
|
||||
{
|
||||
"lane_id": "stale_source_alert",
|
||||
"display_name": "資料來源過期",
|
||||
"routing_policy": "告警數為 0 但 source freshness 失效時,升級為資料鏈路異常,不得當健康。",
|
||||
"ai_agent_role": "OpenClaw 建立資料鏈路 work item,Hermes 補來源證據,NemoTron 評估是否為趨勢異常。",
|
||||
"notification_policy": "只在超過 TTL 或連續失敗時推 failure-only 通知。"
|
||||
},
|
||||
{
|
||||
"lane_id": "heartbeat_noise",
|
||||
"display_name": "心跳噪音",
|
||||
"routing_policy": "正常 Watchdog / DeadMansSwitch 不進修復飛輪;只做 dedupe 與摘要。",
|
||||
"ai_agent_role": "OpenClaw 抑制噪音,Hermes 寫入治理摘要,NemoTron 監看是否有長期盲區。",
|
||||
"notification_policy": "平穩成功不即時通知;狀態變更或 freshness 失效才通知。"
|
||||
},
|
||||
{
|
||||
"lane_id": "report_truth_failure",
|
||||
"display_name": "報表真相失敗",
|
||||
"routing_policy": "日 / 週 / 月報任一來源 query_error、last_success_at 過期或全 0 不可信,建立 work item。",
|
||||
"ai_agent_role": "OpenClaw 產出修復候選,Hermes 補資料源與 runbook,NemoTron review false-green 風險。",
|
||||
"notification_policy": "報表發送時附 DATA QUALITY 區塊;高風險才 Telegram action-required。"
|
||||
}
|
||||
],
|
||||
"telegram_routing_consolidation": {
|
||||
"canonical_room_name": "AwoooI SRE 戰情室",
|
||||
"canonical_room_env": "SRE_GROUP_CHAT_ID",
|
||||
"product_alerts_must_route_to_canonical_room": true,
|
||||
"other_bot_or_group_alerts_allowed": false,
|
||||
"direct_telegram_api_send_allowed": false,
|
||||
"secret_value_read_allowed": false,
|
||||
"route_change_allowed": false,
|
||||
"routing_note": "本產品所有 action-required / failure-only / report truth failure 告警都必須收斂到 AwoooI SRE 戰情室;其他 TG Bot 或群組只能保留為待遷移清冊,不得作為正式告警出口。"
|
||||
},
|
||||
"telegram_route_findings": [
|
||||
{
|
||||
"route_id": "gitea_cd_direct_telegram",
|
||||
"display_name": "Gitea CD 直接 Telegram 發送",
|
||||
"source": ".gitea/workflows/cd.yaml",
|
||||
"current_state": "direct_send_path_present",
|
||||
"target_state": "awoooi_sre_war_room_only",
|
||||
"risk": "CD 成功 / 失敗通知可能繞過 gateway 與統一 dedupe / routing contract。",
|
||||
"required_fix": "改成 AWOOI API / Telegram gateway 單一路由,並以 SRE_GROUP_CHAT_ID 作唯一正式收件群組。",
|
||||
"blocked_runtime_action": "direct_telegram_send_to_legacy_chat"
|
||||
},
|
||||
{
|
||||
"route_id": "gitea_code_review_direct_telegram",
|
||||
"display_name": "Gitea Code Review 直接 Telegram 發送",
|
||||
"source": ".gitea/workflows/code-review.yaml",
|
||||
"current_state": "direct_send_path_present",
|
||||
"target_state": "awoooi_sre_war_room_only",
|
||||
"risk": "code-review start / completion 可能打到 TELEGRAM_ALERT_CHAT_ID,與 SRE 戰情室不一致。",
|
||||
"required_fix": "統一 code-review 通知出口,只允許 AwoooI SRE 戰情室接收 action-required 與 failure-only 訊息。",
|
||||
"blocked_runtime_action": "code_review_direct_send_to_legacy_chat"
|
||||
},
|
||||
{
|
||||
"route_id": "multi_bot_secret_injection",
|
||||
"display_name": "多 Bot token 注入路徑",
|
||||
"source": ".gitea/workflows/cd.yaml",
|
||||
"current_state": "multiple_bot_tokens_present",
|
||||
"target_state": "single_gateway_sender_contract",
|
||||
"risk": "NEMOTRON_BOT_TOKEN、OPENCLAW_BOT_TOKEN、TELEGRAM_BOT_TOKEN 並存時,告警責任與收件地點會分散。",
|
||||
"required_fix": "保留 agent identity 作 metadata,不讓 agent 直接持 token 發送;由 gateway 依 canonical room contract 統一發送。",
|
||||
"blocked_runtime_action": "agent_bot_direct_alert_send"
|
||||
},
|
||||
{
|
||||
"route_id": "legacy_alert_chat_env",
|
||||
"display_name": "舊 TELEGRAM_ALERT_CHAT_ID 路由",
|
||||
"source": ".gitea/workflows/*.yaml",
|
||||
"current_state": "legacy_chat_env_referenced",
|
||||
"target_state": "sre_group_chat_id_only",
|
||||
"risk": "部分 workflow 使用 TELEGRAM_ALERT_CHAT_ID,部分 runtime 使用 SRE_GROUP_CHAT_ID,造成告警消失或散到不同群組。",
|
||||
"required_fix": "建立 route inventory 與 migration gate;正式告警只允許 SRE_GROUP_CHAT_ID,舊 chat id 只能做稽核對照。",
|
||||
"blocked_runtime_action": "legacy_alert_chat_delivery"
|
||||
}
|
||||
],
|
||||
"operator_actions": [
|
||||
{
|
||||
"action_id": "block_green_all_zero_weekly_report",
|
||||
"display_name": "阻擋全 0 週報綠燈",
|
||||
"action_type": "report_quality_gate",
|
||||
"status": "ready_for_owner",
|
||||
"owner_agent": "openclaw",
|
||||
"operator_instruction": "週報全 0 時先顯示資料可信度紅燈,要求 source freshness / confidence 證據。",
|
||||
"blocked_runtime_action": "telegram_weekly_report_send_as_normal"
|
||||
},
|
||||
{
|
||||
"action_id": "build_unified_report_truth_service",
|
||||
"display_name": "建立日週月報真相服務",
|
||||
"action_type": "implementation_review",
|
||||
"status": "approval_required",
|
||||
"owner_agent": "hermes",
|
||||
"operator_instruction": "統一日報、週報、月報資料來源、freshness、confidence、query_error 與 actionability score。",
|
||||
"blocked_runtime_action": "report_truth_runtime_write"
|
||||
},
|
||||
{
|
||||
"action_id": "score_heartbeat_actionability",
|
||||
"display_name": "心跳可處置性評分",
|
||||
"action_type": "noise_reduction",
|
||||
"status": "ready_for_owner",
|
||||
"owner_agent": "nemotron",
|
||||
"operator_instruction": "把 Watchdog / NoAlertsReceived / provider heartbeat 分成 report-only、stale source、action-required。",
|
||||
"blocked_runtime_action": "heartbeat_to_auto_repair"
|
||||
},
|
||||
{
|
||||
"action_id": "create_report_truth_work_items",
|
||||
"display_name": "建立報表資料鏈路工作項",
|
||||
"action_type": "work_item_draft",
|
||||
"status": "approval_required",
|
||||
"owner_agent": "openclaw",
|
||||
"operator_instruction": "對 stats、git、k3s、cost、Telegram delivery 每個 source 建立 owner、TTL、next action 與 verifier。",
|
||||
"blocked_runtime_action": "work_item_write"
|
||||
},
|
||||
{
|
||||
"action_id": "consolidate_telegram_routes_to_sre_war_room",
|
||||
"display_name": "收斂 TG 告警到 AwoooI SRE 戰情室",
|
||||
"action_type": "route_change_review",
|
||||
"status": "approval_required",
|
||||
"owner_agent": "openclaw",
|
||||
"operator_instruction": "盤點所有 TELEGRAM_ALERT_CHAT_ID / OPENCLAW_TG_CHAT_ID / SRE_GROUP_CHAT_ID / direct Telegram API send;正式告警只保留 AwoooI SRE 戰情室。",
|
||||
"blocked_runtime_action": "telegram_route_change"
|
||||
}
|
||||
],
|
||||
"approval_boundaries": {
|
||||
"telegram_report_send_allowed": false,
|
||||
"telegram_heartbeat_send_allowed": false,
|
||||
"telegram_route_change_allowed": false,
|
||||
"telegram_direct_send_allowed": false,
|
||||
"telegram_legacy_chat_delivery_allowed": false,
|
||||
"cronjob_change_allowed": false,
|
||||
"prometheus_rule_change_allowed": false,
|
||||
"alertmanager_route_change_allowed": false,
|
||||
"report_truth_runtime_write_allowed": false,
|
||||
"work_item_write_allowed": false,
|
||||
"km_write_allowed": false,
|
||||
"playbook_trust_write_allowed": false,
|
||||
"runtime_worker_allowed": false,
|
||||
"secret_plaintext_allowed": false
|
||||
},
|
||||
"rollups": {
|
||||
"zero_signal_finding_count": 5,
|
||||
"critical_finding_count": 1,
|
||||
"high_finding_count": 3,
|
||||
"cadence_contract_count": 3,
|
||||
"missing_cadence_contract_count": 1,
|
||||
"actionability_lane_count": 4,
|
||||
"telegram_route_finding_count": 4,
|
||||
"legacy_or_direct_route_count": 4,
|
||||
"operator_action_count": 5,
|
||||
"approval_required_action_ids": [
|
||||
"build_unified_report_truth_service",
|
||||
"consolidate_telegram_routes_to_sre_war_room",
|
||||
"create_report_truth_work_items"
|
||||
],
|
||||
"blocked_runtime_action_count": 28,
|
||||
"all_zero_weekly_report_confidence": "low_trust_actionable_anomaly"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://awoooi.local/schemas/ai_agent_report_truth_actionability_review_v1.schema.json",
|
||||
"title": "AI Agent Report Truth Actionability Review",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema_version",
|
||||
"generated_at",
|
||||
"program_status",
|
||||
"source_refs",
|
||||
"report_truth",
|
||||
"zero_signal_findings",
|
||||
"report_cadence_contracts",
|
||||
"alert_actionability_lanes",
|
||||
"telegram_routing_consolidation",
|
||||
"telegram_route_findings",
|
||||
"operator_actions",
|
||||
"approval_boundaries",
|
||||
"rollups"
|
||||
],
|
||||
"properties": {
|
||||
"schema_version": { "const": "ai_agent_report_truth_actionability_review_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": { "const": 99 },
|
||||
"current_priority": { "enum": ["P0", "P1", "P2", "P3"] },
|
||||
"current_task_id": { "const": "P2-403J" },
|
||||
"next_task_id": { "const": "P2-403K" },
|
||||
"read_only_mode": { "const": true },
|
||||
"runtime_authority": { "const": "report_truth_actionability_review_only_no_report_send_or_runtime_fix" },
|
||||
"status_note": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"source_refs": { "type": "array", "items": { "type": "string" }, "minItems": 1 },
|
||||
"report_truth": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"report_truth_packet_ready",
|
||||
"all_zero_weekly_report_is_actionable_anomaly",
|
||||
"daily_report_contract_present",
|
||||
"weekly_report_contract_present",
|
||||
"monthly_report_contract_present",
|
||||
"freshness_gate_implemented",
|
||||
"source_confidence_gate_implemented",
|
||||
"actionability_score_implemented",
|
||||
"ai_agent_runtime_control_allowed",
|
||||
"telegram_report_send_allowed",
|
||||
"cronjob_change_allowed",
|
||||
"truth_note"
|
||||
],
|
||||
"properties": {
|
||||
"report_truth_packet_ready": { "const": true },
|
||||
"all_zero_weekly_report_is_actionable_anomaly": { "const": true },
|
||||
"daily_report_contract_present": { "type": "boolean" },
|
||||
"weekly_report_contract_present": { "type": "boolean" },
|
||||
"monthly_report_contract_present": { "const": false },
|
||||
"freshness_gate_implemented": { "const": false },
|
||||
"source_confidence_gate_implemented": { "const": false },
|
||||
"actionability_score_implemented": { "const": false },
|
||||
"ai_agent_runtime_control_allowed": { "const": false },
|
||||
"telegram_report_send_allowed": { "const": false },
|
||||
"cronjob_change_allowed": { "const": false },
|
||||
"truth_note": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"zero_signal_findings": { "type": "array", "minItems": 1 },
|
||||
"report_cadence_contracts": { "type": "array", "minItems": 3 },
|
||||
"alert_actionability_lanes": { "type": "array", "minItems": 1 },
|
||||
"telegram_routing_consolidation": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"canonical_room_name",
|
||||
"canonical_room_env",
|
||||
"product_alerts_must_route_to_canonical_room",
|
||||
"other_bot_or_group_alerts_allowed",
|
||||
"direct_telegram_api_send_allowed",
|
||||
"secret_value_read_allowed",
|
||||
"route_change_allowed",
|
||||
"routing_note"
|
||||
],
|
||||
"properties": {
|
||||
"canonical_room_name": { "const": "AwoooI SRE 戰情室" },
|
||||
"canonical_room_env": { "const": "SRE_GROUP_CHAT_ID" },
|
||||
"product_alerts_must_route_to_canonical_room": { "const": true },
|
||||
"other_bot_or_group_alerts_allowed": { "const": false },
|
||||
"direct_telegram_api_send_allowed": { "const": false },
|
||||
"secret_value_read_allowed": { "const": false },
|
||||
"route_change_allowed": { "const": false },
|
||||
"routing_note": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"telegram_route_findings": { "type": "array", "minItems": 1 },
|
||||
"operator_actions": { "type": "array", "minItems": 1 },
|
||||
"approval_boundaries": { "type": "object", "additionalProperties": { "const": false } },
|
||||
"rollups": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"zero_signal_finding_count",
|
||||
"critical_finding_count",
|
||||
"high_finding_count",
|
||||
"cadence_contract_count",
|
||||
"missing_cadence_contract_count",
|
||||
"actionability_lane_count",
|
||||
"telegram_route_finding_count",
|
||||
"legacy_or_direct_route_count",
|
||||
"operator_action_count",
|
||||
"approval_required_action_ids",
|
||||
"blocked_runtime_action_count",
|
||||
"all_zero_weekly_report_confidence"
|
||||
],
|
||||
"properties": {
|
||||
"zero_signal_finding_count": { "type": "integer", "minimum": 1 },
|
||||
"critical_finding_count": { "type": "integer", "minimum": 1 },
|
||||
"high_finding_count": { "type": "integer", "minimum": 1 },
|
||||
"cadence_contract_count": { "type": "integer", "minimum": 3 },
|
||||
"missing_cadence_contract_count": { "type": "integer", "minimum": 1 },
|
||||
"actionability_lane_count": { "type": "integer", "minimum": 1 },
|
||||
"telegram_route_finding_count": { "type": "integer", "minimum": 1 },
|
||||
"legacy_or_direct_route_count": { "type": "integer", "minimum": 1 },
|
||||
"operator_action_count": { "type": "integer", "minimum": 1 },
|
||||
"approval_required_action_ids": { "type": "array", "items": { "type": "string" } },
|
||||
"blocked_runtime_action_count": { "type": "integer", "minimum": 1 },
|
||||
"all_zero_weekly_report_confidence": { "const": "low_trust_actionable_anomaly" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
Reference in New Issue
Block a user