- {(remediationQueue.items ?? []).slice(0, 4).map(item => (
+ {(remediationQueue.items ?? []).slice(0, 4).map(item => {
+ const historySummary = historyByWorkItem.get(item.work_item_id)
+ return (
)}
+ {historySummary && (
+
+ {t('dryRunHistorySummary', {
+ count: historySummary.count,
+ time: formatShortDateTime(historySummary.latest_at),
+ route: historyRouteLabel(historySummary),
+ })}
+
+ )}
{actionState[item.work_item_id]?.status === 'error' && (
{t('dryRunError')}
@@ -535,7 +624,8 @@ function VerificationCoveragePanel({ coverage }: { coverage?: Adr100Verification
)}
- ))}
+ )
+ })}
)}
diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md
index 0c52c63a..241e1d5c 100644
--- a/docs/LOGBOOK.md
+++ b/docs/LOGBOOK.md
@@ -1,3 +1,30 @@
+## 2026-05-14 | T27 Remediation history read model,前端與 Telegram 可看見試跑重複次數與 MCP 路徑
+
+**背景**:T26 已讓 ADR-100 remediation dry-run 寫入 `alert_operation_log` 與 `timeline_events`,但 governance 頁重新整理後仍看不到某筆補救工作過去試跑幾次、上次跑到哪個 preview、是否有用 MCP、是否仍只讀。Telegram 詳情 / 歷史也還沒有把這段 dry-run history 明確帶出。
+
+**修正**:
+- `Adr100RemediationService.history()` 新增 `adr100_remediation_history_v1` read model,從既有 `alert_operation_log` 讀 `adr100_remediation_dry_run_history_v1` context,不新增資料表。
+- 新增 `GET /api/v1/ai/slo/remediation/history`,支援 `limit / incident_id / work_item_id`,回傳 `items` 與 `by_work_item` 聚合,包含 count、latest preview、agent、tool、scope、writes flags。
+- `/governance` 補救工作佇列會讀 history endpoint;每筆工作顯示「歷史 N 次;上次時間;agent/tool」,點試跑成功後會重新整理 history,不只依賴當次 UI state。
+- Telegram `detail:{incident_id}` 與 `history:{incident_id}` 會補上 `ADR-100 補救試跑` 摘要,包含歷史次數、上次 mode/preview、MCP agent/tool/scope、是否寫 incident/auto-repair 狀態。
+
+**本地驗證**:
+- `python -m py_compile apps/api/src/services/adr100_remediation_service.py apps/api/src/api/v1/ai_slo.py apps/api/src/services/telegram_gateway.py apps/api/tests/test_adr100_remediation_service.py`:pass。
+- `ruff check --select F,E9 src/services/adr100_remediation_service.py src/api/v1/ai_slo.py src/services/telegram_gateway.py tests/test_adr100_remediation_service.py`:pass。
+- `DATABASE_URL=postgresql+asyncpg://test:test@localhost:5432/test python -m pytest tests/test_adr100_remediation_service.py tests/test_adr100_slo_status_service.py tests/test_ai_governance_endpoints.py -q`:36 passed。
+- i18n JSON parse / `git diff --check`:pass。
+- `pnpm --filter @awoooi/web typecheck`:pass。
+- `pnpm --dir apps/web exec next lint --file src/app/[locale]/governance/tabs/slo-tab.tsx`:pass。
+- `NEXT_PUBLIC_API_URL=https://awoooi.wooo.work pnpm --filter @awoooi/web build`:pass。
+
+**推版與 production 驗證**:
+- 待 T27 commit 推 Gitea main 後驗證。
+
+**目前整體進度**:
+- Alertmanager 低風險自動修復主線:約 98%。
+- 完整 AI 自動化管理產品化:約 92%。
+- T27 補上「試跑歷史」read model 與 UI/Telegram 可讀摘要。下一段應把 Incident 詳情頁的 stage event 展開成更完整的工作鏈路,而不是只顯示壓縮 ascii timeline。
+
## 2026-05-14 | T26 Remediation dry-run 寫入 history,試跑結果不再只停在前端暫存
**背景**:T25 已讓 Operator 能在 `/governance` 補救佇列點「試跑」,但結果只存在當次 UI state。這仍無法完全回答「這次 dry-run 是否真的發生、跑到哪個流程、MCP 有沒有用到、後續是否能從 Incident history 回看」。