From 383a29a1393d457eb7bcfe3f59bc937a47ea848f Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 25 May 2026 08:46:21 +0800 Subject: [PATCH] feat(governance): show callback owner review triage --- .../src/services/platform_operator_service.py | 20 +++++++++ .../test_awooop_operator_timeline_labels.py | 20 +++++++++ apps/web/messages/en.json | 8 ++++ apps/web/messages/zh-TW.json | 8 ++++ .../web/src/app/[locale]/awooop/runs/page.tsx | 42 +++++++++++++++++++ .../app/[locale]/awooop/work-items/page.tsx | 30 +++++++++++++ 6 files changed, 128 insertions(+) diff --git a/apps/api/src/services/platform_operator_service.py b/apps/api/src/services/platform_operator_service.py index 5c9744b6..ef951ab6 100644 --- a/apps/api/src/services/platform_operator_service.py +++ b/apps/api/src/services/platform_operator_service.py @@ -1215,6 +1215,26 @@ def _km_stale_callback_owner_review_work_item( "target_surface": "awooop_runs_callback_evidence", "target_href": f"/awooop/runs?{target_query}", "work_item_href": f"/awooop/work-items?{work_item_query}", + "triage": { + "schema_version": "km_stale_callback_owner_review_triage_v1", + "flow_stage": "callback_observed_owner_review_link_missing", + "ai_lead_agent": "Hermes", + "supporting_agents": ["OpenClaw", "ElephantAlpha"], + "automation_state": "manual_owner_review_required", + "safe_to_auto_repair": False, + "blocking_reason": reason or "no_matching_completion_item", + "matching_strategy": "related_incident_id_exact_match", + "already_done": [ + "callback_reply_persisted", + "completion_queue_checked", + "generated_read_only_work_item", + ], + "next_actions": [ + "review_runs_callback_evidence", + "queue_matching_km_stale_candidate", + "complete_owner_review_after_owner_approval", + ], + }, "writes_on_read": False, "manual_review_required": True, "batch_writes_allowed": False, diff --git a/apps/api/tests/test_awooop_operator_timeline_labels.py b/apps/api/tests/test_awooop_operator_timeline_labels.py index 1c7bd91c..5c89d055 100644 --- a/apps/api/tests/test_awooop_operator_timeline_labels.py +++ b/apps/api/tests/test_awooop_operator_timeline_labels.py @@ -578,6 +578,26 @@ def test_km_stale_completion_summary_generates_owner_review_work_item() -> None: "&work_item_id=km-callback-owner-review%3Aawoooi%3AINC-20260524-16109D" "&incident_id=INC-20260524-16109D" ), + "triage": { + "schema_version": "km_stale_callback_owner_review_triage_v1", + "flow_stage": "callback_observed_owner_review_link_missing", + "ai_lead_agent": "Hermes", + "supporting_agents": ["OpenClaw", "ElephantAlpha"], + "automation_state": "manual_owner_review_required", + "safe_to_auto_repair": False, + "blocking_reason": "no_matching_completion_item", + "matching_strategy": "related_incident_id_exact_match", + "already_done": [ + "callback_reply_persisted", + "completion_queue_checked", + "generated_read_only_work_item", + ], + "next_actions": [ + "review_runs_callback_evidence", + "queue_matching_km_stale_candidate", + "complete_owner_review_after_owner_approval", + ], + }, "writes_on_read": False, "manual_review_required": True, "batch_writes_allowed": False, diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index abd28ddb..1f7b94d5 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -2021,6 +2021,10 @@ "callbackOwnerReviewLatest": "Latest: {incident} / {action}", "callbackOwnerReviewQueue": "Completion queue: ready {ready}; blocked {blocked}; completed {completed}; failed {failed}", "callbackOwnerReviewNext": "Next: {next}", + "callbackOwnerReviewFlow": "Flow: {stage}; match: {strategy}", + "callbackOwnerReviewAgents": "Lead: {lead}; support: {support}", + "callbackOwnerReviewAutomation": "Automation: {state}; safe auto-repair={safe}", + "callbackOwnerReviewBlocker": "Blocker: {reason}", "callbackOwnerReviewEmpty": "Recent callback evidence is matched or no data is available yet", "ciSecretHygiene": "Repo-controlled step env / action input exposure is guarded; key rotation and log retention remain", "governance": "Unresolved governance alerts: {unresolved}; pending dispatch: {queued}", @@ -2801,6 +2805,10 @@ "noRelated": "This incident has no matching owner-review completion item yet.", "fetchFailed": "KM owner-review summary failed to load: {reason}", "openWorkItem": "Open work item", + "triageFlow": "Flow: {stage}; match: {strategy}", + "triageAgents": "Lead: {lead}; support: {support}", + "triageAutomation": "Automation: {state}; safe auto-repair={safe}", + "triageBlocker": "Blocker: {reason}", "statuses": { "matched_owner_review": "Matched owner review", "no_related_owner_review": "No matched owner review", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index a72160aa..4e57d7ff 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -2022,6 +2022,10 @@ "callbackOwnerReviewLatest": "最新:{incident} / {action}", "callbackOwnerReviewQueue": "Completion queue:可處理 {ready};卡住 {blocked};完成 {completed};失敗 {failed}", "callbackOwnerReviewNext": "下一步:{next}", + "callbackOwnerReviewFlow": "流程:{stage};匹配:{strategy}", + "callbackOwnerReviewAgents": "主責:{lead};協作:{support}", + "callbackOwnerReviewAutomation": "自動化:{state};可安全自動修復={safe}", + "callbackOwnerReviewBlocker": "卡點:{reason}", "callbackOwnerReviewEmpty": "近期 callback evidence 均已匹配或尚無資料", "ciSecretHygiene": "repo 可控 step env / action input 泄漏面已加 guard;仍需 key rotation 與 log retention 收斂", "governance": "未解治理告警:{unresolved};pending dispatch:{queued}", @@ -2802,6 +2806,10 @@ "noRelated": "本 Incident 尚未對到 owner-review completion item。", "fetchFailed": "KM owner-review 摘要讀取失敗:{reason}", "openWorkItem": "開啟工作項", + "triageFlow": "流程:{stage};匹配:{strategy}", + "triageAgents": "主責:{lead};協作:{support}", + "triageAutomation": "自動化:{state};可安全自動修復={safe}", + "triageBlocker": "卡點:{reason}", "statuses": { "matched_owner_review": "已匹配 owner review", "no_related_owner_review": "未匹配 owner review", diff --git a/apps/web/src/app/[locale]/awooop/runs/page.tsx b/apps/web/src/app/[locale]/awooop/runs/page.tsx index eed95017..8c021b44 100644 --- a/apps/web/src/app/[locale]/awooop/runs/page.tsx +++ b/apps/web/src/app/[locale]/awooop/runs/page.tsx @@ -307,11 +307,25 @@ interface KmStaleCallbackOwnerReviewWorkItem { target_surface?: string | null; target_href?: string | null; work_item_href?: string | null; + triage?: KmStaleCallbackOwnerReviewTriage | null; writes_on_read?: boolean | null; manual_review_required?: boolean | null; batch_writes_allowed?: boolean | null; } +interface KmStaleCallbackOwnerReviewTriage { + schema_version?: string; + flow_stage?: string | null; + ai_lead_agent?: string | null; + supporting_agents?: string[]; + automation_state?: string | null; + safe_to_auto_repair?: boolean | null; + blocking_reason?: string | null; + matching_strategy?: string | null; + already_done?: string[]; + next_actions?: string[]; +} + interface KmStaleCompletionSummary { schema_version?: string; project_id?: string | null; @@ -1488,6 +1502,7 @@ function CallbackKmCompletionSummary({ ? summary.related_items[0] : null; const workItem = summary.work_item?.status === "open" ? summary.work_item : null; + const triage = workItem?.triage ?? null; return (
@@ -1540,6 +1555,33 @@ function CallbackKmCompletionSummary({ {t("openWorkItem")} ) : null} + {triage ? ( +
+

+ {t("triageFlow", { + stage: triage.flow_stage ?? "--", + strategy: triage.matching_strategy ?? "--", + })} +

+

+ {t("triageAgents", { + lead: triage.ai_lead_agent ?? "--", + support: triage.supporting_agents?.join(" / ") || "--", + })} +

+

+ {t("triageAutomation", { + state: triage.automation_state ?? "--", + safe: String(triage.safe_to_auto_repair ?? false), + })} +

+

+ {t("triageBlocker", { + reason: triage.blocking_reason ?? "--", + })} +

+
+ ) : null}
); diff --git a/apps/web/src/app/[locale]/awooop/work-items/page.tsx b/apps/web/src/app/[locale]/awooop/work-items/page.tsx index 2cda2ceb..de158959 100644 --- a/apps/web/src/app/[locale]/awooop/work-items/page.tsx +++ b/apps/web/src/app/[locale]/awooop/work-items/page.tsx @@ -784,11 +784,25 @@ type KmStaleCallbackOwnerReviewWorkItem = { target_surface?: string | null; target_href?: string | null; work_item_href?: string | null; + triage?: KmStaleCallbackOwnerReviewTriage | null; writes_on_read?: boolean | null; manual_review_required?: boolean | null; batch_writes_allowed?: boolean | null; }; +type KmStaleCallbackOwnerReviewTriage = { + schema_version?: string; + flow_stage?: string | null; + ai_lead_agent?: string | null; + supporting_agents?: string[]; + automation_state?: string | null; + safe_to_auto_repair?: boolean | null; + blocking_reason?: string | null; + matching_strategy?: string | null; + already_done?: string[]; + next_actions?: string[]; +}; + type KmStaleCallbackCompletionSummary = { schema_version?: string; status?: string | null; @@ -1584,6 +1598,7 @@ function buildWorkItems( const latestCallbackSummary = latestCallbackOwnerReview?.km_stale_completion_summary ?? null; const latestCallbackWorkItem = latestCallbackSummary?.work_item ?? null; + const latestCallbackTriage = latestCallbackWorkItem?.triage ?? null; const remediationQueue = telemetry.slo?.adr100?.verification_coverage?.remediation_queue; const remediationTotal = remediationQueue?.total ?? 0; const remediationReadyForAi = remediationQueue?.ready_for_ai ?? 0; @@ -1803,6 +1818,21 @@ function buildWorkItems( t("evidence.callbackOwnerReviewNext", { next: latestCallbackWorkItem?.next_step ?? "--", }), + t("evidence.callbackOwnerReviewFlow", { + stage: latestCallbackTriage?.flow_stage ?? "--", + strategy: latestCallbackTriage?.matching_strategy ?? "--", + }), + t("evidence.callbackOwnerReviewAgents", { + lead: latestCallbackTriage?.ai_lead_agent ?? "--", + support: latestCallbackTriage?.supporting_agents?.join(" / ") || "--", + }), + t("evidence.callbackOwnerReviewAutomation", { + state: latestCallbackTriage?.automation_state ?? "--", + safe: String(latestCallbackTriage?.safe_to_auto_repair ?? false), + }), + t("evidence.callbackOwnerReviewBlocker", { + reason: latestCallbackTriage?.blocking_reason ?? "--", + }), ] : [t("evidence.callbackOwnerReviewEmpty")], href: latestCallbackWorkItem?.target_href ?? "/awooop/runs",