"""Web UI dashboard model for Architect Governance Agent. Shows requirement changes, architecture review findings, document refresh status, deployment consistency, test case readiness, weekly research and V/R/C version recommendations. """ 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 ArchitectPanelMetric: 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 ArchitectPanel: key: str title: str description: str metrics: list[ArchitectPanelMetric] = 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 ArchitectGovernanceDashboard: def overview( self, requirement_changes: list[dict[str, Any]] | None = None, architecture_reviews: list[dict[str, Any]] | None = None, document_status: dict[str, Any] | None = None, research_status: dict[str, Any] | None = None, version_recommendations: list[dict[str, Any]] | None = None, ) -> dict[str, Any]: requirement_changes = requirement_changes or [] architecture_reviews = architecture_reviews or [] document_status = document_status or {} research_status = research_status or {} version_recommendations = version_recommendations or [] panels = [ self.requirement_panel(requirement_changes), self.architecture_panel(architecture_reviews), self.document_panel(document_status), self.research_panel(research_status), self.version_panel(version_recommendations), ] return { "module": "architect-governance", "route": "/admin/ai-evolution/architect", "title": "架构师 Agent 治理中心", "status": "attention_required" if any(self._panel_warn(panel) for panel in panels) else "healthy", "generated_at": utc_now(), "panels": [panel.to_dict() for panel in panels], "requirement_changes": requirement_changes, "architecture_reviews": architecture_reviews, "version_recommendations": version_recommendations, } def requirement_panel(self, changes: list[dict[str, Any]]) -> ArchitectPanel: return ArchitectPanel( key="requirements", title="需求变化记录", description="记录来自 Custom GPT、Codex、OpenClaw、Hermes 和用户反馈的需求变化。", metrics=[ ArchitectPanelMetric("total_requirement_changes", "需求变化数量", len(changes)), ArchitectPanelMetric( "undocumented_changes", "待刷新到用户需求文档", len([c for c in changes if not c.get("documented")]), "warn" if any(not c.get("documented") for c in changes) else "ok", ), ], ) def architecture_panel(self, reviews: list[dict[str, Any]]) -> ArchitectPanel: pending = [r for r in reviews if r.get("status") not in {"pass", "not_required"}] return ArchitectPanel( key="architecture_review", title="全量架构审视", description="展示架构一致性、扩展性、安全边界、可运维性和回滚策略审查。", metrics=[ ArchitectPanelMetric("review_count", "架构审查数量", len(reviews)), ArchitectPanelMetric("pending_reviews", "待处理架构审查", len(pending), "warn" if pending else "ok"), ], ) def document_panel(self, status: dict[str, Any]) -> ArchitectPanel: required_docs = ["requirements", "architecture", "deployment", "test_cases"] missing = [doc for doc in required_docs if status.get(doc) not in {"ready", "updated"}] return ArchitectPanel( key="documents", title="文档版本化状态", description="用户需求、架构设计、工程部署、测试例文档刷新状态。", metrics=[ ArchitectPanelMetric("requirements_doc", "用户需求文档", status.get("requirements", "unknown"), "warn" if "requirements" in missing else "ok"), ArchitectPanelMetric("architecture_doc", "架构设计文档", status.get("architecture", "unknown"), "warn" if "architecture" in missing else "ok"), ArchitectPanelMetric("deployment_doc", "工程部署文档", status.get("deployment", "unknown"), "warn" if "deployment" in missing else "ok"), ArchitectPanelMetric("test_case_doc", "测试例文档", status.get("test_cases", "unknown"), "warn" if "test_cases" in missing else "ok"), ], ) def research_panel(self, status: dict[str, Any]) -> ArchitectPanel: overdue = bool(status.get("overdue")) return ArchitectPanel( key="weekly_research", title="每周外部技术情报", description="联网搜索 Agent/模型版本、GitHub top 实现、潜在安全影响。", metrics=[ ArchitectPanelMetric("last_research_at", "最近调研时间", status.get("last_research_at", "never"), "warn" if overdue else "ok"), ArchitectPanelMetric("findings", "发现数量", status.get("findings", 0)), ArchitectPanelMetric("optimization_candidates", "可借鉴优化项", status.get("optimization_candidates", 0)), ], ) def version_panel(self, recommendations: list[dict[str, Any]]) -> ArchitectPanel: latest = recommendations[-1] if recommendations else {} return ArchitectPanel( key="version_decision", title="V/R/C 版本建议", description="由架构师 Agent 判断变更应进入 C、R 或 V。", metrics=[ ArchitectPanelMetric("recommendation_count", "版本建议数量", len(recommendations)), ArchitectPanelMetric("latest_recommendation", "最近建议", latest.get("version_bump", "none")), ArchitectPanelMetric("reason", "建议原因", latest.get("reason", "")), ], ) def _panel_warn(self, panel: ArchitectPanel) -> bool: return any(metric.status == "warn" for metric in panel.metrics) __all__ = ["ArchitectPanelMetric", "ArchitectPanel", "ArchitectGovernanceDashboard"]