From 4452a006bfe31643fa69a34b9b00eb1efa8b2132 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 May 2026 20:38:29 +0800 Subject: [PATCH] feat(governance): show knowledge degradation ownership --- apps/api/src/services/failover_alerter.py | 47 +++++++++++++++++++ apps/api/src/services/governance_agent.py | 10 ++++ apps/api/tests/test_failover_alerter.py | 7 +++ apps/api/tests/test_governance_agent.py | 5 ++ docs/12-agent-game-rules.md | 4 ++ ...-04-15-MASTER-ai-autonomous-flywheel-v2.md | 2 +- 6 files changed, 74 insertions(+), 1 deletion(-) diff --git a/apps/api/src/services/failover_alerter.py b/apps/api/src/services/failover_alerter.py index 92c5b876..f2e2f58e 100644 --- a/apps/api/src/services/failover_alerter.py +++ b/apps/api/src/services/failover_alerter.py @@ -367,6 +367,7 @@ _TOP_LEVEL_FALLBACK_KEEP: dict[str, set[str]] = { "automatable_work", "next_action", "next_step", + "ownership", "ratio", "stale", "stale_count", @@ -543,6 +544,51 @@ def _governance_operator_context(event_type: str, impact: dict[str, Any]) -> lis ] +def _governance_ownership_lines(event_type: str, payload: dict[str, Any]) -> list[str]: + """Return explicit agent ownership for governance alerts.""" + ownership = _as_dict(payload.get("ownership")) + + if not ownership and event_type == "knowledge_degradation": + ownership = { + "lead_agent": "Hermes", + "lead_reason": "E7 自動 KM 主責:反查 Incident / Sentry / SigNoz / PlayBook,產生 KM 更新草稿與任務。", + "support_agents": [ + "OpenClaw:提供告警分類、規則匹配與 PlayBook 脈絡摘要,不直接批量改寫 KM。", + "ElephantAlpha:read-only 稽核高影響 KM 草稿與風險,不執行寫入或通知。", + ], + "human_owner": "KM owner / SRE owner", + "human_reason": "審核高影響 KM 後才允許寫入,避免 AI 自動固化錯誤知識。", + } + + if not ownership: + return [] + + rows: list[str] = [] + lead_agent = ownership.get("lead_agent") + lead_reason = ownership.get("lead_reason") + if lead_agent: + lead_text = f"主責:{lead_agent}" + if lead_reason: + lead_text += f" — {lead_reason}" + rows.append(lead_text) + + support_agents = ownership.get("support_agents") + if isinstance(support_agents, list): + rows.extend(str(item) for item in support_agents if item) + + human_owner = ownership.get("human_owner") + human_reason = ownership.get("human_reason") + if human_owner: + human_text = f"人工覆核:{human_owner}" + if human_reason: + human_text += f" — {human_reason}" + rows.append(human_text) + + if not rows: + return [] + return ["", "👥 *負責分工*", _tree_lines(rows)] + + def format_governance_alert_card(event_type: str, payload: dict[str, Any]) -> str: """格式化 AI 治理 Telegram 卡片。 @@ -571,6 +617,7 @@ def format_governance_alert_card(event_type: str, payload: dict[str, Any]) -> st ] sections.extend(_governance_operator_context(event_type, impact)) + sections.extend(_governance_ownership_lines(event_type, payload)) impact_lines = _governance_summary_lines(event_type, impact) if impact_lines: diff --git a/apps/api/src/services/governance_agent.py b/apps/api/src/services/governance_agent.py index fb4d7e75..aa87b6e7 100644 --- a/apps/api/src/services/governance_agent.py +++ b/apps/api/src/services/governance_agent.py @@ -224,6 +224,16 @@ class GovernanceAgent: ], "next_action": "run_kb_growth_healthcheck", }, + "ownership": { + "lead_agent": "Hermes", + "lead_reason": "E7 自動 KM 主責:反查 Incident / Sentry / SigNoz / PlayBook,產生 KM 更新草稿與任務。", + "support_agents": [ + "OpenClaw:提供告警分類、規則匹配與 PlayBook 脈絡摘要,不直接批量改寫 KM。", + "ElephantAlpha:read-only 稽核高影響 KM 草稿與風險,不執行寫入或通知。", + ], + "human_owner": "KM owner / SRE owner", + "human_reason": "審核高影響 KM 後才允許寫入,避免 AI 自動固化錯誤知識。", + }, "actionable": { "items": [ "每日檢查 ANTI_PATTERN 更新結果", diff --git a/apps/api/tests/test_failover_alerter.py b/apps/api/tests/test_failover_alerter.py index fb139aba..e8ec893b 100644 --- a/apps/api/tests/test_failover_alerter.py +++ b/apps/api/tests/test_failover_alerter.py @@ -283,6 +283,11 @@ def test_governance_alert_card_formats_knowledge_degradation() -> None: assert "*AI 治理警報|KM 需要更新" in card assert "💬 *白話說明*" in card assert "🧩 *AI 流程狀態*" in card + assert "👥 *負責分工*" in card + assert "主責:Hermes" in card + assert "OpenClaw:提供告警分類" in card + assert "ElephantAlpha:read\\-only 稽核" in card + assert "人工覆核:KM owner / SRE owner" in card assert "✅ *現在要做*" in card assert "queued\\_kb\\_healthcheck" in card assert "AwoooP Work Items" in card @@ -320,6 +325,8 @@ def test_governance_alert_card_accepts_legacy_knowledge_degradation_payload() -> assert "陳舊 KM:1425" in card assert "總 KM:1856" in card assert "陳舊比例:76\\.8%" in card + assert "主責:Hermes" in card + assert "人工覆核:KM owner / SRE owner" in card assert "▶️ 下一步:run\\_kb\\_growth\\_healthcheck" in card assert "每日檢查 ANTI\\_PATTERN 更新結果" in card assert "📎 *補充欄位*" not in card diff --git a/apps/api/tests/test_governance_agent.py b/apps/api/tests/test_governance_agent.py index 39461bc7..d0cb0219 100644 --- a/apps/api/tests/test_governance_agent.py +++ b/apps/api/tests/test_governance_agent.py @@ -251,6 +251,11 @@ class TestCheckKnowledgeDegradation: alerter.alert_governance.assert_called_once() call_args = alerter.alert_governance.call_args assert call_args[0][0] == "knowledge_degradation" + payload = call_args[0][1] + assert payload["ownership"]["lead_agent"] == "Hermes" + assert "OpenClaw" in payload["ownership"]["support_agents"][0] + assert "ElephantAlpha" in payload["ownership"]["support_agents"][1] + assert payload["ownership"]["human_owner"] == "KM owner / SRE owner" assert result["stale"] == 3 assert result["ratio"] == 0.3 diff --git a/docs/12-agent-game-rules.md b/docs/12-agent-game-rules.md index 494cf44d..c183d216 100644 --- a/docs/12-agent-game-rules.md +++ b/docs/12-agent-game-rules.md @@ -239,6 +239,10 @@ last_modified_by: Codex - 自動:`AUTO_DEPRECATED` 當日 30 天內未更新的 Playbook 自動降級 - 人工:人工覆核 playbook 風險,決定是否 rollback - `knowledge_degradation`: + - 主責:Hermes 反查 Incident / Sentry / SigNoz / PlayBook,產生 KM 更新草稿與任務 + - 輔責:OpenClaw 提供告警分類、規則匹配與 PlayBook 脈絡摘要 + - 稽核:ElephantAlpha read-only 檢查高影響草稿與風險,不執行寫入或通知 + - 人工:KM owner / SRE owner 審核高影響 KM 後才允許寫入 - 自動:觸發 `run_kb_growth_healthcheck` - 續接:`playbook_evidence` / `kb_rot_cleaner` 補齊缺口 - `governance_slo_data_gap`: diff --git a/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md b/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md index 26314007..51bb34bb 100644 --- a/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md +++ b/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md @@ -377,7 +377,7 @@ source_event_received **T15b inbound source envelope production verified(2026-05-13 台北)**:`awooop_conversation_event` 已補 `content_redacted`、`redaction_version`、`source_envelope`,Alertmanager / Sentry / SignOz inbound 皆會保存 redacted replay envelope 與 structured source refs。truth-chain 可由原始 alert id、Sentry issue id、SignOz alert fingerprint 回查;若尚未連到 incident / run,狀態會顯示 `inbound_received / observed`,不再誤顯 `not_found`。production DB-only smoke 證明三種來源皆 `found=true`、`schema_version=inbound_source_envelope_v1`、`leaked_token=false`。邊界:這是告警來源事實鏈,不是完整自動修復 live-fire;前端仍需 T15c 事件卷宗把 `source_envelope`、日誌引用、PlayBook/KM 命中、MCP/Ansible 證據、修復驗證與人工卡點轉成 Operator Console 產品介面。 -**OpenClaw / Hermes 主導權邊界(2026-05-13 台北)**:外部市場敘事確實正往 Hermes 這種 Agent runtime、MCP tool registry、多通道操作層靠攏;AWOOOI 產品命名與主入口可採「Hermes 主導」的體感。但內部責任不得混淆:OpenClaw(或等價 SRE cognitive core)主導診斷、分類、風險、PlayBook/KM/RAG/MCP 融合與修復可否自動化;Hermes 主導 channel delivery、Operator UI、Telegram / AwoooP / 前端階段呈現、callback 狀態與 delivery audit。Hermes 可 orchestrate OpenClaw decision envelope,但不得直接成為第二套黑盒修復決策引擎。 +**OpenClaw / Hermes 主導權邊界(2026-05-13 台北)**:外部市場敘事確實正往 Hermes 這種 Agent runtime、MCP tool registry、多通道操作層靠攏;AWOOOI 產品命名與主入口可採「Hermes 主導」的體感。但內部責任不得混淆:OpenClaw(或等價 SRE cognitive core)主導診斷、分類、風險、PlayBook/KM/RAG/MCP 融合與修復可否自動化;Hermes 主導 channel delivery、Operator UI、Telegram / AwoooP / 前端階段呈現、callback 狀態與 delivery audit。E7 自動 KM / `knowledge_degradation` 是治理維護流程,由 Hermes 主責反查 Incident / Sentry / SigNoz / PlayBook 並產生 KM 草稿,OpenClaw 提供 SRE 摘要與風險脈絡,ElephantAlpha 只做 read-only 稽核,人類 KM owner 審核後才寫入高影響知識。Hermes 可 orchestrate OpenClaw decision envelope,但不得直接成為第二套黑盒修復決策引擎。 ---