From 09538932dfe6fe6165e2d48b2dd5bb2088094ff6 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 29 Jun 2026 19:06:18 +0800 Subject: [PATCH] fix(awooop): route alert handoff through controlled review --- apps/web/messages/en.json | 22 +++++++++---------- apps/web/messages/zh-TW.json | 22 +++++++++---------- apps/web/src/app/[locale]/alerts/page.tsx | 20 +++++++++-------- .../src/components/panels/MonitoringPanel.tsx | 2 +- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index a543b725..9b469e43 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -1870,11 +1870,11 @@ "telegramValue": "{channel} / {status}", "telegramDetail": "類型 {type};出站 {outbound};最新 {latest}", "aiTitle": "AI 處置判定", - "aiDetail": "狀態 {state};下一步 {nextStep};人工 {needsHuman}", + "aiDetail": "狀態 {state};下一步 {nextStep};受控分流 {controlledReview}", "sourceTitle": "Sentry / SigNoz 匹配", "sourceDetail": "直連 {direct} / 候選 {candidate} / 已套用 {applied};原因 {reason}", - "needsHumanYes": "需要", - "needsHumanNo": "不需要", + "controlledReviewYes": "AI 受控覆核 / critical evidence", + "controlledReviewNo": "AI 受控鏈路", "stateLabels": { "verificationDegradedManualRequired": "驗證退化,AI 進入 verifier / rollback", "verificationDegradedAiVerifierRequired": "驗證退化,AI 進入 verifier / rollback", @@ -1895,21 +1895,21 @@ }, "handoff": { "eyebrow": "現在要做", - "titleManual": "需要 break-glass 確認", + "titleControlledReview": "AI 受控覆核,critical 才 break-glass", "titleAutomated": "自動鏈路已完成,持續觀察", "titleUnknown": "等待 truth-chain 資料", - "actionManualVerifyOrRepair": "到 AwoooP Work Items / Runs 確認執行證據;若服務仍異常,排入 AI 受控重試或 rollback,不要直接靜默關閉。", + "actionControlledVerifyOrRepair": "到 AwoooP Work Items / Runs 確認執行證據;若服務仍異常,排入 AI 受控重試、verifier 或 rollback。", "actionNoManual": "目前由 AI 受控鏈路處理;保留真相鏈與Run history 供稽核追蹤。", "actionUnknown": "尚未拿到完整狀態,先等 status-chain 載入完成。", "ownerLabel": "主責", - "ownerSre": "SRE owner / AwoooP operator", + "ownerControlledReview": "AI controlled queue / SRE break-glass only", "ownerAutomation": "AI 自動化鏈路", "entryLabel": "處理入口", - "entryManual": "Work Items / Approvals / Runs", + "entryControlledReview": "Work Items / Runs / verifier", "entryReadOnly": "Runs / History", "reasonLabel": "原因", "boundaryLabel": "邊界", - "boundary": "只讀追蹤,不觸發修復" + "boundary": "低 / 中 / 高走 AI controlled;critical 才 break-glass" }, "repeatStates": { "duplicate": "最新入站重複", @@ -2291,8 +2291,8 @@ "loadFailed": "焦點 Incident 資料讀取失敗:{error}", "boundary": "此區塊只讀取監控證據,不會自動標記 Sentry/SigNoz 已匹配,也不會觸發修復或靜音告警。最新 PlayBook:{playbook};executor:{executor}。", "human": { - "yes": "需要人工", - "no": "未要求人工" + "yes": "AI 受控覆核", + "no": "AI 受控鏈路" }, "links": { "workItems": "工作項", @@ -2329,7 +2329,7 @@ "ansibleDetail": "模式 {mode}、回傳碼 {rc}、套用 {apply}", "km": "KM", "kmDetail": "驗證 {verification};下一步 {next}", - "handoff": "交接狀態" + "handoff": "受控分流" }, "providerEvidence": { "title": "供應者匹配狀態", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index ac8c8c02..f80a30c1 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -1870,11 +1870,11 @@ "telegramValue": "{channel} / {status}", "telegramDetail": "類型 {type};出站 {outbound};最新 {latest}", "aiTitle": "AI 處置判定", - "aiDetail": "狀態 {state};下一步 {nextStep};人工 {needsHuman}", + "aiDetail": "狀態 {state};下一步 {nextStep};受控分流 {controlledReview}", "sourceTitle": "Sentry / SigNoz 匹配", "sourceDetail": "直連 {direct} / 候選 {candidate} / 已套用 {applied};原因 {reason}", - "needsHumanYes": "需要", - "needsHumanNo": "不需要", + "controlledReviewYes": "AI 受控覆核 / critical evidence", + "controlledReviewNo": "AI 受控鏈路", "stateLabels": { "verificationDegradedManualRequired": "驗證退化,AI 進入 verifier / rollback", "verificationDegradedAiVerifierRequired": "驗證退化,AI 進入 verifier / rollback", @@ -1895,21 +1895,21 @@ }, "handoff": { "eyebrow": "現在要做", - "titleManual": "需要 break-glass 確認", + "titleControlledReview": "AI 受控覆核,critical 才 break-glass", "titleAutomated": "自動鏈路已完成,持續觀察", "titleUnknown": "等待 truth-chain 資料", - "actionManualVerifyOrRepair": "到 AwoooP Work Items / Runs 確認執行證據;若服務仍異常,排入 AI 受控重試或 rollback,不要直接靜默關閉。", + "actionControlledVerifyOrRepair": "到 AwoooP Work Items / Runs 確認執行證據;若服務仍異常,排入 AI 受控重試、verifier 或 rollback。", "actionNoManual": "目前由 AI 受控鏈路處理;保留真相鏈與Run history 供稽核追蹤。", "actionUnknown": "尚未拿到完整狀態,先等 status-chain 載入完成。", "ownerLabel": "主責", - "ownerSre": "SRE owner / AwoooP operator", + "ownerControlledReview": "AI controlled queue / SRE break-glass only", "ownerAutomation": "AI 自動化鏈路", "entryLabel": "處理入口", - "entryManual": "Work Items / Approvals / Runs", + "entryControlledReview": "Work Items / Runs / verifier", "entryReadOnly": "Runs / History", "reasonLabel": "原因", "boundaryLabel": "邊界", - "boundary": "只讀追蹤,不觸發修復" + "boundary": "低 / 中 / 高走 AI controlled;critical 才 break-glass" }, "repeatStates": { "duplicate": "最新入站重複", @@ -2291,8 +2291,8 @@ "loadFailed": "焦點 Incident 資料讀取失敗:{error}", "boundary": "此區塊只讀取監控證據,不會自動標記 Sentry/SigNoz 已匹配,也不會觸發修復或靜音告警。最新 PlayBook:{playbook};executor:{executor}。", "human": { - "yes": "需要人工", - "no": "未要求人工" + "yes": "AI 受控覆核", + "no": "AI 受控鏈路" }, "links": { "workItems": "工作項", @@ -2329,7 +2329,7 @@ "ansibleDetail": "模式 {mode}、回傳碼 {rc}、套用 {apply}", "km": "KM", "kmDetail": "驗證 {verification};下一步 {next}", - "handoff": "交接狀態" + "handoff": "受控分流" }, "providerEvidence": { "title": "供應者匹配狀態", diff --git a/apps/web/src/app/[locale]/alerts/page.tsx b/apps/web/src/app/[locale]/alerts/page.tsx index 2f65a5a3..7070006d 100644 --- a/apps/web/src/app/[locale]/alerts/page.tsx +++ b/apps/web/src/app/[locale]/alerts/page.tsx @@ -245,25 +245,27 @@ function FocusIncidentEvidencePanel({ const latestOutboundLabel = latestOutbound?.sent_at ? formatTimestamp(latestOutbound.sent_at, locale, emptyLabel) : emptyLabel - const needsHumanLabel = chain?.needs_human ? t('operatorFlow.needsHumanYes') : t('operatorFlow.needsHumanNo') - const handoffTone = !chain ? 'gray' : chain.needs_human ? 'red' : 'green' + const controlledReviewLabel = chain?.needs_human + ? t('operatorFlow.controlledReviewYes') + : t('operatorFlow.controlledReviewNo') + const handoffTone = !chain ? 'gray' : chain.needs_human ? 'amber' : 'green' const handoffTitle = chain?.needs_human - ? t('operatorFlow.handoff.titleManual') + ? t('operatorFlow.handoff.titleControlledReview') : chain ? t('operatorFlow.handoff.titleAutomated') : t('operatorFlow.handoff.titleUnknown') const handoffAction = !chain ? t('operatorFlow.handoff.actionUnknown') : chain.needs_human - ? t('operatorFlow.handoff.actionManualVerifyOrRepair') + ? t('operatorFlow.handoff.actionControlledVerifyOrRepair') : t('operatorFlow.handoff.actionNoManual') const handoffOwner = chain?.needs_human - ? t('operatorFlow.handoff.ownerSre') + ? t('operatorFlow.handoff.ownerControlledReview') : chain ? t('operatorFlow.handoff.ownerAutomation') : emptyLabel const handoffEntry = chain?.needs_human - ? t('operatorFlow.handoff.entryManual') + ? t('operatorFlow.handoff.entryControlledReview') : chain ? t('operatorFlow.handoff.entryReadOnly') : emptyLabel @@ -328,9 +330,9 @@ function FocusIncidentEvidencePanel({ detail: t('operatorFlow.aiDetail', { state: outcomeStateLabel, nextStep: nextActionLabel, - needsHuman: needsHumanLabel, + controlledReview: controlledReviewLabel, }), - tone: chain?.needs_human ? 'red' : chain ? 'green' : 'gray', + tone: chain?.needs_human ? 'amber' : chain ? 'green' : 'gray', testId: 'alerts-ai-state', }, { @@ -467,7 +469,7 @@ function FocusIncidentEvidencePanel({ className={cn( 'mb-3 border px-3 py-3', handoffTone === 'green' && 'border-[#9bc7a4] bg-[#f0faf2]', - handoffTone === 'red' && 'border-[#e2a29b] bg-[#fff0ef]', + handoffTone === 'amber' && 'border-[#d9b36f] bg-[#fff7e8]', handoffTone === 'gray' && 'border-[#d8d3c7] bg-[#faf9f3]', )} > diff --git a/apps/web/src/components/panels/MonitoringPanel.tsx b/apps/web/src/components/panels/MonitoringPanel.tsx index 684a0c4c..1250b5df 100644 --- a/apps/web/src/components/panels/MonitoringPanel.tsx +++ b/apps/web/src/components/panels/MonitoringPanel.tsx @@ -247,7 +247,7 @@ function IncidentObservabilityFocus({ const ansibleTone: EvidenceTone = ansible?.applied || (ansible?.apply_total ?? 0) > 0 ? 'success' : (ansible?.considered || (ansible?.record_total ?? 0) > 0 ? 'warning' : 'neutral') - const handoffTone: EvidenceTone = chain?.needs_human ? 'blocked' : (chain ? 'success' : 'neutral') + const handoffTone: EvidenceTone = chain?.needs_human ? 'warning' : (chain ? 'success' : 'neutral') const navItems = [ {