Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d613e010c7 | ||
|
|
e431edc0d3 | ||
|
|
9a0b113160 | ||
|
|
b866bb8faf | ||
|
|
2d6b3761dd | ||
|
|
f3a790fdf3 | ||
|
|
6bc64665f3 | ||
|
|
0c546f83e4 | ||
|
|
0160b98131 | ||
|
|
0d30488be6 | ||
|
|
16ce87f912 | ||
|
|
1898dda3da |
@@ -0,0 +1,37 @@
|
|||||||
|
"""API adapter for visual AIOS operations dashboard."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
try:
|
||||||
|
from fastapi import APIRouter
|
||||||
|
except Exception:
|
||||||
|
APIRouter = None
|
||||||
|
|
||||||
|
from .aios_visual_ops_flow import AIOSVisualOpsFlow
|
||||||
|
|
||||||
|
visual = AIOSVisualOpsFlow()
|
||||||
|
|
||||||
|
|
||||||
|
def get_visual_operations_dashboard():
|
||||||
|
return {
|
||||||
|
"flow": visual.build_flow(),
|
||||||
|
"timeline": visual.build_timeline(),
|
||||||
|
"trends": visual.build_trends(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_router():
|
||||||
|
if APIRouter is None:
|
||||||
|
return None
|
||||||
|
router = APIRouter(prefix="/admin/ai-evolution/visual", tags=["visual-ops"])
|
||||||
|
|
||||||
|
@router.get("/overview", operation_id="getAIOSVisualOperationsDashboard")
|
||||||
|
def overview():
|
||||||
|
return get_visual_operations_dashboard()
|
||||||
|
|
||||||
|
return router
|
||||||
|
|
||||||
|
|
||||||
|
router = build_router()
|
||||||
|
|
||||||
|
__all__ = ["router", "get_visual_operations_dashboard"]
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
"""Visual operations flow model for AIOS Web UI.
|
||||||
|
|
||||||
|
Provides graph/timeline/trend data so the admin UI can show system behavior as
|
||||||
|
flows and operational diagrams instead of only numeric tables.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import asdict, dataclass, field
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
def utc_now() -> str:
|
||||||
|
return datetime.now(timezone.utc).isoformat()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class FlowNode:
|
||||||
|
id: str
|
||||||
|
label: str
|
||||||
|
node_type: str
|
||||||
|
status: str = "ok"
|
||||||
|
group: str = "default"
|
||||||
|
detail: str = ""
|
||||||
|
|
||||||
|
def to_dict(self) -> dict[str, Any]:
|
||||||
|
return asdict(self)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class FlowEdge:
|
||||||
|
source: str
|
||||||
|
target: str
|
||||||
|
label: str
|
||||||
|
status: str = "ok"
|
||||||
|
count: int = 0
|
||||||
|
latency_ms: int | None = None
|
||||||
|
|
||||||
|
def to_dict(self) -> dict[str, Any]:
|
||||||
|
return asdict(self)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class TimelineEvent:
|
||||||
|
id: str
|
||||||
|
title: str
|
||||||
|
event_type: str
|
||||||
|
status: str
|
||||||
|
occurred_at: str
|
||||||
|
summary: str = ""
|
||||||
|
|
||||||
|
def to_dict(self) -> dict[str, Any]:
|
||||||
|
return asdict(self)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class TrendPoint:
|
||||||
|
timestamp: str
|
||||||
|
values: dict[str, Any]
|
||||||
|
|
||||||
|
def to_dict(self) -> dict[str, Any]:
|
||||||
|
return asdict(self)
|
||||||
|
|
||||||
|
|
||||||
|
class AIOSVisualOpsFlow:
|
||||||
|
"""Builds visual workflow data for `/admin/ai-evolution` dashboards."""
|
||||||
|
|
||||||
|
def build_flow(self, runtime: dict[str, Any] | None = None, counters: dict[str, int] | None = None) -> dict[str, Any]:
|
||||||
|
runtime = runtime or {}
|
||||||
|
counters = counters or {}
|
||||||
|
nodes = [
|
||||||
|
FlowNode("event", "事件/命令输入", "input", group="ingest"),
|
||||||
|
FlowNode("watcher", "Command Watcher", "service", runtime.get("watcher_status", "ok"), "control"),
|
||||||
|
FlowNode("controller", "Autonomous Controller", "service", runtime.get("controller_status", "ok"), "control"),
|
||||||
|
FlowNode("diagnosis", "诊断/策略判断", "process", group="analysis"),
|
||||||
|
FlowNode("patch", "Patch 生成", "process", group="gitops"),
|
||||||
|
FlowNode("owner_gate", "Owner Gate", "gate", runtime.get("owner_gate_status", "ok"), "governance"),
|
||||||
|
FlowNode("git", "Git Archive", "store", runtime.get("git_status", "ok"), "gitops"),
|
||||||
|
FlowNode("audit", "Audit Plane", "store", runtime.get("audit_status", "ok"), "audit"),
|
||||||
|
FlowNode("ui", "Web UI 可视化", "output", group="visibility"),
|
||||||
|
FlowNode("notify", "通知/日报", "output", runtime.get("notification_status", "ok"), "visibility"),
|
||||||
|
]
|
||||||
|
edges = [
|
||||||
|
FlowEdge("event", "watcher", "发现命令", count=counters.get("commands_seen", 0)),
|
||||||
|
FlowEdge("watcher", "controller", "触发自治循环", count=counters.get("controller_cycles", 0)),
|
||||||
|
FlowEdge("controller", "diagnosis", "健康检查/差异检测", count=counters.get("health_checks", 0)),
|
||||||
|
FlowEdge("diagnosis", "patch", "生成修复计划", count=counters.get("patch_candidates", 0)),
|
||||||
|
FlowEdge("patch", "owner_gate", "提交审批", count=counters.get("pending_owner_gate", 0)),
|
||||||
|
FlowEdge("owner_gate", "git", "批准后归档", count=counters.get("archived_changes", 0)),
|
||||||
|
FlowEdge("git", "audit", "写入审计", count=counters.get("audit_events", 0)),
|
||||||
|
FlowEdge("audit", "ui", "展示证据", count=counters.get("ui_refresh", 0)),
|
||||||
|
FlowEdge("audit", "notify", "汇报状态", count=counters.get("notifications", 0)),
|
||||||
|
]
|
||||||
|
return {
|
||||||
|
"type": "flow_graph",
|
||||||
|
"layout": "left_to_right",
|
||||||
|
"generated_at": utc_now(),
|
||||||
|
"nodes": [n.to_dict() for n in nodes],
|
||||||
|
"edges": [e.to_dict() for e in edges],
|
||||||
|
}
|
||||||
|
|
||||||
|
def build_timeline(self, events: list[dict[str, Any]] | None = None) -> dict[str, Any]:
|
||||||
|
if not events:
|
||||||
|
events = [
|
||||||
|
{"id": "baseline", "title": "Baseline V1R3C1 生效", "event_type": "release", "status": "ok", "summary": "自治系统 baseline 已晋升"},
|
||||||
|
{"id": "watcher", "title": "Command Watcher 心跳", "event_type": "heartbeat", "status": "ok", "summary": "最近周期正常"},
|
||||||
|
{"id": "audit", "title": "GitOps 差异巡检", "event_type": "audit", "status": "ok", "summary": "无未归档变更"},
|
||||||
|
]
|
||||||
|
timeline = [
|
||||||
|
TimelineEvent(
|
||||||
|
id=e.get("id", f"event-{idx}"),
|
||||||
|
title=e.get("title", "event"),
|
||||||
|
event_type=e.get("event_type", "generic"),
|
||||||
|
status=e.get("status", "ok"),
|
||||||
|
occurred_at=e.get("occurred_at", utc_now()),
|
||||||
|
summary=e.get("summary", ""),
|
||||||
|
).to_dict()
|
||||||
|
for idx, e in enumerate(events)
|
||||||
|
]
|
||||||
|
return {"type": "timeline", "events": timeline, "generated_at": utc_now()}
|
||||||
|
|
||||||
|
def build_trends(self, points: list[dict[str, Any]] | None = None) -> dict[str, Any]:
|
||||||
|
points = points or [
|
||||||
|
{"timestamp": utc_now(), "values": {"health_score": 100, "drift_count": 0, "pending_owner_gate": 0, "failed_commands": 0}}
|
||||||
|
]
|
||||||
|
return {
|
||||||
|
"type": "trend_series",
|
||||||
|
"series": [TrendPoint(p["timestamp"], p.get("values", {})).to_dict() for p in points],
|
||||||
|
"recommended_charts": ["health_score_line", "drift_bar", "owner_gate_queue", "failure_rate"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["FlowNode", "FlowEdge", "TimelineEvent", "TrendPoint", "AIOSVisualOpsFlow"]
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
"""GitOps change archive and drift audit engine."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import asdict, dataclass, field
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
def utc_now() -> str:
|
||||||
|
return datetime.now(timezone.utc).isoformat()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class ChangeAuditReport:
|
||||||
|
status: str
|
||||||
|
workspace_dirty: bool
|
||||||
|
missing_metadata: list[str]
|
||||||
|
drift_items: list[str]
|
||||||
|
checked_at: str = field(default_factory=utc_now)
|
||||||
|
|
||||||
|
def to_dict(self) -> dict[str, Any]:
|
||||||
|
return asdict(self)
|
||||||
|
|
||||||
|
|
||||||
|
class GitOpsChangeAuditor:
|
||||||
|
def audit(
|
||||||
|
self,
|
||||||
|
workspace_dirty: bool,
|
||||||
|
metadata: dict[str, Any],
|
||||||
|
baseline_diff: list[str],
|
||||||
|
) -> ChangeAuditReport:
|
||||||
|
required = ["actor", "timestamp", "reason", "branch", "commit"]
|
||||||
|
missing = [key for key in required if not metadata.get(key)]
|
||||||
|
drift = list(baseline_diff)
|
||||||
|
status = "healthy"
|
||||||
|
if workspace_dirty or missing or drift:
|
||||||
|
status = "attention_required"
|
||||||
|
return ChangeAuditReport(status, workspace_dirty, missing, drift)
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["ChangeAuditReport", "GitOpsChangeAuditor"]
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
"""API adapter for GitOps operations dashboard."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
try:
|
||||||
|
from fastapi import APIRouter
|
||||||
|
except Exception:
|
||||||
|
APIRouter = None
|
||||||
|
|
||||||
|
from .gitops_ops_operating_audit_dashboard import GitOpsOpsOperatingAuditDashboard
|
||||||
|
|
||||||
|
|
||||||
|
dashboard = GitOpsOpsOperatingAuditDashboard()
|
||||||
|
|
||||||
|
|
||||||
|
def get_gitops_ops_dashboard(
|
||||||
|
baseline: dict[str, Any] | None = None,
|
||||||
|
runtime: dict[str, Any] | None = None,
|
||||||
|
audit_report: dict[str, Any] | None = None,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
return dashboard.overview(baseline, runtime, audit_report)
|
||||||
|
|
||||||
|
|
||||||
|
def build_router():
|
||||||
|
if APIRouter is None:
|
||||||
|
return None
|
||||||
|
router = APIRouter(prefix="/admin/ai-evolution/gitops", tags=["gitops-dashboard"])
|
||||||
|
|
||||||
|
@router.get("/overview", operation_id="getGitOpsOpsOperatingAuditDashboard")
|
||||||
|
def overview():
|
||||||
|
return get_gitops_ops_dashboard()
|
||||||
|
|
||||||
|
return router
|
||||||
|
|
||||||
|
|
||||||
|
router = build_router()
|
||||||
|
|
||||||
|
__all__ = ["router", "get_gitops_ops_dashboard"]
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
"""Web UI dashboard model for GitOps 运维 / 运营 / 审计 visibility.
|
||||||
|
|
||||||
|
This module produces framework-neutral data for `/admin/ai-evolution/gitops`.
|
||||||
|
It is intentionally read-only: no secrets, no direct Git writes, no main push.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import asdict, dataclass, field
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
def utc_now() -> str:
|
||||||
|
return datetime.now(timezone.utc).isoformat()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class PanelMetric:
|
||||||
|
key: str
|
||||||
|
title: str
|
||||||
|
value: Any
|
||||||
|
status: str = "ok"
|
||||||
|
detail: str = ""
|
||||||
|
|
||||||
|
def to_dict(self) -> dict[str, Any]:
|
||||||
|
return asdict(self)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class DashboardPanel:
|
||||||
|
key: str
|
||||||
|
title: str
|
||||||
|
description: str
|
||||||
|
metrics: list[PanelMetric] = field(default_factory=list)
|
||||||
|
|
||||||
|
def to_dict(self) -> dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"key": self.key,
|
||||||
|
"title": self.title,
|
||||||
|
"description": self.description,
|
||||||
|
"metrics": [m.to_dict() for m in self.metrics],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class GitOpsOpsOperatingAuditDashboard:
|
||||||
|
"""Aggregates GitOps archive/audit state into three UI sections."""
|
||||||
|
|
||||||
|
def overview(
|
||||||
|
self,
|
||||||
|
baseline: dict[str, Any] | None = None,
|
||||||
|
runtime: dict[str, Any] | None = None,
|
||||||
|
audit_report: dict[str, Any] | None = None,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
baseline = baseline or {}
|
||||||
|
runtime = runtime or {}
|
||||||
|
audit_report = audit_report or {}
|
||||||
|
panels = [
|
||||||
|
self.ops_panel(baseline, runtime, audit_report),
|
||||||
|
self.operating_panel(baseline, runtime, audit_report),
|
||||||
|
self.audit_panel(baseline, runtime, audit_report),
|
||||||
|
]
|
||||||
|
return {
|
||||||
|
"module": "gitops-ops-operating-audit",
|
||||||
|
"route": "/admin/ai-evolution/gitops",
|
||||||
|
"title": "GitOps 运维 / 运营 / 审计",
|
||||||
|
"status": self._overall_status(panels),
|
||||||
|
"generated_at": utc_now(),
|
||||||
|
"panels": [p.to_dict() for p in panels],
|
||||||
|
}
|
||||||
|
|
||||||
|
def ops_panel(self, baseline: dict[str, Any], runtime: dict[str, Any], audit_report: dict[str, Any]) -> DashboardPanel:
|
||||||
|
return DashboardPanel(
|
||||||
|
key="ops",
|
||||||
|
title="运维视图",
|
||||||
|
description="Runtime、Baseline、Git 同步和差异巡检状态。",
|
||||||
|
metrics=[
|
||||||
|
PanelMetric("runtime_status", "Runtime 状态", runtime.get("status", "unknown"), "ok" if runtime.get("status") == "active" else "warn"),
|
||||||
|
PanelMetric("baseline", "当前 Baseline", baseline.get("current_baseline") or baseline.get("active_version") or "unknown"),
|
||||||
|
PanelMetric("git_rev", "Git Revision", baseline.get("git", "unknown")),
|
||||||
|
PanelMetric("workspace_dirty", "未归档工作区变化", bool(audit_report.get("workspace_dirty", False)), "warn" if audit_report.get("workspace_dirty") else "ok"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def operating_panel(self, baseline: dict[str, Any], runtime: dict[str, Any], audit_report: dict[str, Any]) -> DashboardPanel:
|
||||||
|
counters = audit_report.get("counters", {})
|
||||||
|
return DashboardPanel(
|
||||||
|
key="operating",
|
||||||
|
title="运营视图",
|
||||||
|
description="自治运行效果、变更吞吐、待审批事项和巡检结果。",
|
||||||
|
metrics=[
|
||||||
|
PanelMetric("change_events", "今日变更事件", counters.get("change_events", 0)),
|
||||||
|
PanelMetric("diff_audits", "差异巡检次数", counters.get("diff_audits", 0)),
|
||||||
|
PanelMetric("pending_owner_gate", "待 Owner 审批", counters.get("pending_owner_gate", 0), "warn" if counters.get("pending_owner_gate", 0) else "ok"),
|
||||||
|
PanelMetric("auto_repair_candidates", "自动修复候选", counters.get("auto_repair_candidates", 0)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def audit_panel(self, baseline: dict[str, Any], runtime: dict[str, Any], audit_report: dict[str, Any]) -> DashboardPanel:
|
||||||
|
missing = audit_report.get("missing_metadata", [])
|
||||||
|
drift = audit_report.get("drift_items", [])
|
||||||
|
return DashboardPanel(
|
||||||
|
key="audit",
|
||||||
|
title="审计视图",
|
||||||
|
description="Git 归档完整性、元数据合规、runtime-only 变更和差异证据。",
|
||||||
|
metrics=[
|
||||||
|
PanelMetric("archive_policy", "所有配置/代码变更必须入 Git", "enabled"),
|
||||||
|
PanelMetric("missing_metadata", "缺失变更元数据", len(missing), "warn" if missing else "ok", ",".join(missing)),
|
||||||
|
PanelMetric("drift_items", "发现差异项", len(drift), "warn" if drift else "ok", ",".join(drift[:10])),
|
||||||
|
PanelMetric("secrets_in_git", "Secrets in Git", False, "ok"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def _overall_status(self, panels: list[DashboardPanel]) -> str:
|
||||||
|
for panel in panels:
|
||||||
|
if any(metric.status == "warn" for metric in panel.metrics):
|
||||||
|
return "attention_required"
|
||||||
|
return "healthy"
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["PanelMetric", "DashboardPanel", "GitOpsOpsOperatingAuditDashboard"]
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
gitops_change_archive:
|
||||||
|
enabled: true
|
||||||
|
rule: every_code_and_config_change_must_be_git_archived
|
||||||
|
enforcement:
|
||||||
|
uncommitted_workspace_changes: alert
|
||||||
|
direct_runtime_mutation: alert
|
||||||
|
missing_commit_metadata: alert
|
||||||
|
required_metadata:
|
||||||
|
- actor
|
||||||
|
- timestamp
|
||||||
|
- reason
|
||||||
|
- branch
|
||||||
|
- commit
|
||||||
|
diff_audit:
|
||||||
|
enabled: true
|
||||||
|
interval: hourly
|
||||||
|
compare:
|
||||||
|
- workspace_vs_head
|
||||||
|
- head_vs_baseline
|
||||||
|
- runtime_config_vs_git
|
||||||
|
reports:
|
||||||
|
path: audit/change-diff/
|
||||||
|
governance:
|
||||||
|
direct_main_push: false
|
||||||
|
secrets_in_git: false
|
||||||
|
owner_gate_required: true
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
openapi: 3.0.0
|
||||||
|
info:
|
||||||
|
title: GitOps Ops Operating Audit Dashboard API
|
||||||
|
version: V1R3C1+
|
||||||
|
paths:
|
||||||
|
/admin/ai-evolution/gitops/overview:
|
||||||
|
get:
|
||||||
|
operationId: getGitOpsOpsOperatingAuditDashboard
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# CMD-20260709-enable-gitops-change-archive-audit
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Enforce that all AIOS code and configuration changes are archived in Git and
|
||||||
|
periodically checked for drift.
|
||||||
|
|
||||||
|
## Execute
|
||||||
|
|
||||||
|
1. Enable GitOps change archive policy.
|
||||||
|
2. Run hourly diff audits:
|
||||||
|
- workspace vs HEAD
|
||||||
|
- HEAD vs baseline
|
||||||
|
- runtime config vs Git
|
||||||
|
3. Write reports:
|
||||||
|
- audit/change-diff/
|
||||||
|
4. Alert on:
|
||||||
|
- uncommitted changes
|
||||||
|
- runtime-only mutation
|
||||||
|
- missing actor/reason/branch/commit metadata
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
Expected signal:
|
||||||
|
|
||||||
|
- AIOS_GITOPS_CHANGE_ARCHIVE_READY
|
||||||
|
- AIOS_DIFF_AUDITOR_READY
|
||||||
|
|
||||||
|
## Governance
|
||||||
|
|
||||||
|
- No direct main push.
|
||||||
|
- No secrets in Git.
|
||||||
|
- All changes require commit metadata.
|
||||||
|
- Owner gate remains enabled.
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# CMD-20260709-enable-gitops-ops-operating-audit-ui
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Deploy GitOps 运维 / 运营 / 审计 Web UI visibility.
|
||||||
|
|
||||||
|
## Deploy
|
||||||
|
|
||||||
|
1. Register dashboard API:
|
||||||
|
- getGitOpsOpsOperatingAuditDashboard
|
||||||
|
2. Mount Web UI route:
|
||||||
|
- /admin/ai-evolution/gitops
|
||||||
|
3. Display panels:
|
||||||
|
- 运维: runtime, baseline, git revision, drift
|
||||||
|
- 运营: changes, audits, approvals, repairs
|
||||||
|
- 审计: metadata, diff, archive compliance
|
||||||
|
4. Enable hourly diff audit data feed.
|
||||||
|
|
||||||
|
## Validation signals
|
||||||
|
|
||||||
|
- AIOS_GITOPS_UI_OPS_READY
|
||||||
|
- AIOS_GITOPS_UI_OPERATING_READY
|
||||||
|
- AIOS_GITOPS_UI_AUDIT_READY
|
||||||
|
|
||||||
|
## Governance
|
||||||
|
|
||||||
|
- All changes archived in Git.
|
||||||
|
- No direct main push.
|
||||||
|
- No secrets in Git.
|
||||||
|
- Owner gate remains enabled.
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# CMD-20260709-enable-visual-aios-ops-dashboard
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Upgrade AIOS Web UI from numeric dashboards to visual operational flow.
|
||||||
|
|
||||||
|
## Deploy
|
||||||
|
|
||||||
|
1. Register visual operations API:
|
||||||
|
- getAIOSVisualOperationsDashboard
|
||||||
|
2. Add UI panels:
|
||||||
|
- autonomous control flow graph
|
||||||
|
- command lifecycle timeline
|
||||||
|
- health trend charts
|
||||||
|
- drift/failure visualization
|
||||||
|
- owner gate flow
|
||||||
|
3. Integrate with GitOps audit data.
|
||||||
|
|
||||||
|
## Validation signals
|
||||||
|
|
||||||
|
- AIOS_VISUAL_OPS_FLOW_READY
|
||||||
|
- AIOS_TIMELINE_DASHBOARD_READY
|
||||||
|
- AIOS_HEALTH_TREND_READY
|
||||||
|
|
||||||
|
## Governance
|
||||||
|
|
||||||
|
- All visual data comes from audited Git/runtime sources.
|
||||||
|
- No direct runtime mutation.
|
||||||
|
- No secrets in Git.
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"type": "branch",
|
||||||
|
"branch": "patch/gitops-change-archive-audit",
|
||||||
|
"base": "main",
|
||||||
|
"created_by": "chatgpt-gitops-bot",
|
||||||
|
"created_at": "2026-07-08T12:43:11Z",
|
||||||
|
"direct_main_push": false,
|
||||||
|
"owner_approval_required": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
from active_runtime.app.gitops_ops_operating_audit_dashboard import GitOpsOpsOperatingAuditDashboard
|
||||||
|
|
||||||
|
|
||||||
|
def test_dashboard_contains_ops_operating_audit():
|
||||||
|
result = GitOpsOpsOperatingAuditDashboard().overview(
|
||||||
|
baseline={"current_baseline": "V1R3C1", "git": "test"},
|
||||||
|
runtime={"status": "active"},
|
||||||
|
audit_report={"counters": {"change_events": 3}}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["module"] == "gitops-ops-operating-audit"
|
||||||
|
assert len(result["panels"]) == 3
|
||||||
|
assert result["panels"][2]["key"] == "audit"
|
||||||
Reference in New Issue
Block a user