From b297b013acaf5fe83828d80465d3d327232385a2 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 25 Jun 2026 21:10:22 +0800 Subject: [PATCH] feat(web): split Runs dry-run and apply ledger --- apps/web/messages/en.json | 10 ++++- apps/web/messages/zh-TW.json | 10 ++++- .../awooop/automation-asset-ledger.tsx | 40 ++++++++++++++----- .../src/components/awooop/status-chain.tsx | 1 + docs/LOGBOOK.md | 23 +++++++++++ ...6-25-awoooi-navigation-ia-consolidation.md | 13 +++++- ...026-06-25-awoooi-product-uiux-inventory.md | 19 ++++++++- 7 files changed, 100 insertions(+), 16 deletions(-) diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index dc69a9f03..2cb04b965 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -10469,13 +10469,16 @@ "km": "KM", "playbook": "PlayBook", "script": "腳本", + "dryRun": "乾跑", + "apply": "套用", "schedule": "排程", "verifier": "Verifier" }, "values": { "ready": "ready", "pending": "pending", - "blocked": "blocked" + "blocked": "blocked", + "notApplied": "未套用" } }, "runs": { @@ -10863,13 +10866,16 @@ "km": "KM", "playbook": "PlayBook", "script": "腳本", + "dryRun": "乾跑", + "apply": "套用", "schedule": "排程", "verifier": "Verifier" }, "values": { "ready": "ready", "pending": "pending", - "blocked": "blocked" + "blocked": "blocked", + "notApplied": "未套用" } }, "columns": { diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index dc69a9f03..2cb04b965 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -10469,13 +10469,16 @@ "km": "KM", "playbook": "PlayBook", "script": "腳本", + "dryRun": "乾跑", + "apply": "套用", "schedule": "排程", "verifier": "Verifier" }, "values": { "ready": "ready", "pending": "pending", - "blocked": "blocked" + "blocked": "blocked", + "notApplied": "未套用" } }, "runs": { @@ -10863,13 +10866,16 @@ "km": "KM", "playbook": "PlayBook", "script": "腳本", + "dryRun": "乾跑", + "apply": "套用", "schedule": "排程", "verifier": "Verifier" }, "values": { "ready": "ready", "pending": "pending", - "blocked": "blocked" + "blocked": "blocked", + "notApplied": "未套用" } }, "columns": { diff --git a/apps/web/src/components/awooop/automation-asset-ledger.tsx b/apps/web/src/components/awooop/automation-asset-ledger.tsx index e58402958..de2e2ab75 100644 --- a/apps/web/src/components/awooop/automation-asset-ledger.tsx +++ b/apps/web/src/components/awooop/automation-asset-ledger.tsx @@ -22,6 +22,10 @@ function countLabel(value: number) { return value > 0 ? String(value) : "--"; } +function valueLabel(value: number, fallback: string) { + return value > 0 ? String(value) : fallback; +} + export function AwoooPAutomationAssetLedger({ chain, remediationSummary, @@ -36,9 +40,16 @@ export function AwoooPAutomationAssetLedger({ const playbookCount = (chain?.execution?.playbook_ids?.length ?? 0) + (chain?.execution?.playbook_paths?.length ?? 0); const ansible = chain?.execution?.ansible; - const scriptCount = (ansible?.candidate_count ?? 0) - + (ansible?.check_mode_total ?? 0) - + (ansible?.apply_total ?? 0); + const ansibleCandidates = ansible?.candidate_count ?? 0; + const dryRunCount = (ansible?.check_mode_total ?? 0) + (ansible?.pending_check_mode_total ?? 0); + const applyCount = ansible?.apply_total ?? 0; + const ansibleDryRunOnly = Boolean(chain?.evidence?.ansible_dry_run_only) + || ( + dryRunCount > 0 + && applyCount === 0 + && ansible?.applied !== true + && ansible?.controlled_apply !== true + ); const correlation = chain?.source_refs?.correlation; const scheduleCount = (correlation?.provider_event_total ?? 0) + (correlation?.direct_ref_total ?? 0) @@ -64,13 +75,24 @@ export function AwoooPAutomationAssetLedger({ value: countLabel(playbookCount), }, { - key: "script", - tone: scriptCount > 0 + key: "dryRun", + tone: dryRunCount > 0 ? "ready" - : remediationSummary?.has_mcp_investigation || (chain?.mcp?.gateway?.total ?? 0) > 0 + : ansibleCandidates > 0 ? "pending" : "blocked", - value: countLabel(scriptCount), + value: valueLabel(dryRunCount, ansibleCandidates > 0 ? t("values.pending") : "--"), + }, + { + key: "apply", + tone: applyCount > 0 || ansible?.applied === true + ? "ready" + : ansibleDryRunOnly || chain?.needs_human + ? "blocked" + : dryRunCount > 0 || ansibleCandidates > 0 + ? "pending" + : "blocked", + value: applyCount > 0 ? String(applyCount) : ansible?.applied === true ? t("values.ready") : t("values.notApplied"), }, { key: "schedule", @@ -79,8 +101,8 @@ export function AwoooPAutomationAssetLedger({ }, { key: "verifier", - tone: verifierReady ? "ready" : verifierBlocked ? "blocked" : "pending", - value: verifierReady ? t("values.ready") : verifierBlocked ? t("values.blocked") : t("values.pending"), + tone: verifierReady ? "ready" : verifierBlocked || ansibleDryRunOnly ? "blocked" : "pending", + value: verifierReady ? t("values.ready") : verifierBlocked || ansibleDryRunOnly ? t("values.blocked") : t("values.pending"), }, ] satisfies Array<{ key: string; tone: AutomationAssetTone; value: string }>; const readyCount = items.filter((item) => item.tone === "ready").length; diff --git a/apps/web/src/components/awooop/status-chain.tsx b/apps/web/src/components/awooop/status-chain.tsx index d8a6ed0f1..efd10d814 100644 --- a/apps/web/src/components/awooop/status-chain.tsx +++ b/apps/web/src/components/awooop/status-chain.tsx @@ -55,6 +55,7 @@ export interface AwoooPStatusChain { latest_mode?: string | null; latest_at?: string | null; latest_preview?: string | null; + ansible_dry_run_only?: boolean | null; }; writes?: { incident?: boolean | null; diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 9ae7eed5c..dc0010417 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,26 @@ +## 2026-06-25|Runs 資產沉澱拆出乾跑 / 套用狀態 + +**背景**:`INC-20260625-977E5F` 已在後端修正為 `ansible_check_mode_only`,但 Runs 頁既有 `資產沉澱` ledger 仍把 Ansible candidate、check-mode 與 apply 混在「腳本」一格,容易讓「只有乾跑」看起來像已具備可執行資產。這會延續使用者指出的核心問題:AI 看起來有動作,但 operator 仍不知道到底做到哪一步。 + +**完成**: +- `AwoooPAutomationAssetLedger` 將原本單一 `腳本` 判讀拆成 `乾跑` 與 `套用`。 +- 前端型別補上 `evidence.ansible_dry_run_only`。 +- `ansible_dry_run_only=true` 或 `check_mode_total>0 / apply_total=0` 時,`乾跑` 顯示 ready、`套用` 顯示 blocked / `未套用`,`Verifier` 也不再以 pending 淡化卡點。 +- `zh-TW` / `en` messages 同步新增 `dryRun`、`apply`、`notApplied`。 + +**驗證**: +- `python3 -m json.tool apps/web/messages/zh-TW.json` / `apps/web/messages/en.json` 通過。 +- i18n leaf diff:`missing_en=0 extra_en=0`。 +- `pnpm --filter @awoooi/web typecheck` 通過。 +- `git diff --check` 通過。 + +**完成度同步**: +- Runs 資產沉澱可判讀性:`65% -> 68%`。 +- AwoooP 操作台產品化:`66% -> 67%`。 +- 真正 AI 自動化 verified repair 成功率不提高;本段仍是視覺 / 語意分層,不是 apply 或 verifier。 + +**邊界**:本段只改前端顯示與 i18n;不執行 Ansible apply、不新增操作按鈕、不發 Telegram、不開 runtime gate、不把 dry-run 當修復完成。 + ## 2026-06-25|Ansible check-mode 乾跑不再誤標為已修復 **背景**:使用者貼出的 `node-exporter-188` Telegram 告警顯示已批准後仍像「沒有自動化」。正式 API 讀回 `INC-20260625-977E5F` 時發現更精準的真相:系統有 Ansible `check_mode` 證據,`check_mode_total=1`、`apply_total=0`、`auto_repair_execution_records=0`,但 AwoooP status chain 仍把它標成 `execution_succeeded / executed_pending_verification`。這會讓 operator 誤以為 AI 已執行修復,只缺 verifier;實際上它只是乾跑成功,尚未進入 apply / verifier。 diff --git a/docs/workplans/2026-06-25-awoooi-navigation-ia-consolidation.md b/docs/workplans/2026-06-25-awoooi-navigation-ia-consolidation.md index 0189afc90..8e9fc7cf9 100644 --- a/docs/workplans/2026-06-25-awoooi-navigation-ia-consolidation.md +++ b/docs/workplans/2026-06-25-awoooi-navigation-ia-consolidation.md @@ -165,11 +165,22 @@ | 正式站 | code `d7b3997b`、deploy marker `420b0b18`;`INC-20260625-977E5F` production API 讀回 `ansible_check_mode_only`、`dry_run_completed_no_apply`、`repair_status=not_executed`、`ansible_dry_run_only=true` | | 邊界 | 不執行 Ansible apply、不新增主機命令、不發 Telegram、不開 runtime gate;本段只修 truth-chain 與 operator outcome 語意 | +## 4.9 2026-06-25 Runs 資產 ledger 拆出乾跑 / 套用 + +| 項目 | 結果 | +|---|---| +| 核心修正 | `資產沉澱` 不再把 Ansible candidate、check-mode、apply 混成單一「腳本」完成數 | +| 新顯示 | `乾跑`、`套用`、`Verifier` 分開呈現 | +| 判讀 | `ansible_dry_run_only=true` 或 `check_mode_total>0 / apply_total=0` 時,乾跑 ready、套用 blocked / `未套用`、Verifier 顯示卡點 | +| IA 含義 | AwoooP 後續 Runs / Work Items / Approvals 必須共享 dry-run -> owner apply gate -> verifier -> KM / PlayBook writeback 的分層語意 | +| 驗證 | JSON parse、i18n leaf diff `0`、web typecheck、diff check 通過 | +| 邊界 | 不新增 action button、不觸發執行、不套用 PlayBook、不開 runtime gate;只是把狀態從長文字拆成可掃描的資產格 | + ## 5. 下一輪必做 | 優先級 | 工作 | 驗收 | |---|---|---| -| P0 | AwoooP Runs 共用 Situation Strip / Agent Flow / Action Rail | Recurrence Work Item status chip 與 Ansible dry-run truth-chain 已完成;下一步補首屏 Situation Strip,讓 Runs 一眼看懂卡點、owner、dry-run、apply、verifier 與下一步 | +| P0 | AwoooP Runs 共用 Situation Strip / Agent Flow / Action Rail | Recurrence Work Item status chip、Ansible dry-run truth-chain 與資產 ledger 分層已完成;下一步補首屏 Situation Strip,讓 Runs 一眼看懂卡點、owner、dry-run、apply、verifier 與下一步 | | P0 | Repair candidate draft readback 串接 | 後端已拆出 `draft_ready_for_owner_review` 與 `ansible_check_mode_only`;下一步 Work Items / KB 顯示草案 ID、owner、rollback、verifier、KM / PlayBook / script / schedule 資產狀態 | | P0 | Tenants 舊表格 responsive 化 | route / source 已完成卡片化;下一步處理租戶資料表 drawer 與產品 topology drilldown | | P0 | Observability topology | 主機 / 服務 / 網站 / 告警 / SLO 關聯可視化 | diff --git a/docs/workplans/2026-06-25-awoooi-product-uiux-inventory.md b/docs/workplans/2026-06-25-awoooi-product-uiux-inventory.md index aee28ec53..0b613aec4 100644 --- a/docs/workplans/2026-06-25-awoooi-product-uiux-inventory.md +++ b/docs/workplans/2026-06-25-awoooi-product-uiux-inventory.md @@ -218,6 +218,21 @@ Tenants 目前已讀到: 完成度同步:AwoooP status-chain 真相語意 `64% -> 67%`;Telegram / AwoooP 乾跑誤導修正 source-side / production readback `100%`;真正 AI 自動化 verified repair 成功率不提高,仍需以 apply + verifier + KM / PlayBook writeback 計算。 +### 2.5.7 Runs 資產沉澱拆出乾跑 / 套用狀態 + +2026-06-25 已完成 `/zh-TW/awooop/runs` 前端語意小切片:`資產沉澱` ledger 不再把 Ansible candidate、check-mode、apply 全部混在「腳本」一格,而是拆成 `乾跑` 與 `套用`。 + +| 項目 | 完成 | +|---|---| +| UI | `AwoooPAutomationAssetLedger` 新增 `dryRun` / `apply` 兩格 | +| 判讀 | `ansible_dry_run_only=true` 或 `check_mode_total>0 / apply_total=0` 時,乾跑 ready、套用 blocked / `未套用` | +| Verifier | dry-run only 時 Verifier 不再淡化為 pending,改顯示卡點 | +| i18n | `zh-TW` / `en` messages 新增 `dryRun`、`apply`、`notApplied`;leaf diff `0` | +| 驗證 | JSON parse、i18n leaf diff、`pnpm --filter @awoooi/web typecheck`、`git diff --check` 通過 | +| 邊界 | 只改前端顯示;不新增執行、重啟、Telegram send、PlayBook apply、Ansible apply 或 runtime gate | + +完成度同步:AwoooP Runs 可判讀性 `65% -> 68%`;AwoooP 操作台產品化 `66% -> 67%`;真正 AI 自動化 verified repair 成功率不提高。 + ## 3. 頁面 UI/UX 現況盤點 2026-06-25 對正式站桌機 / mobile 抽查: @@ -225,7 +240,7 @@ Tenants 目前已讀到: | 頁面 | 現況 | 主要問題 | 優先級 | |---|---|---|---| | `/zh-TW/awooop` | Google Ads 式 shell 已存在,AwoooP 概覽與 AI 自動化真相帶可見 | 仍需把 Runs / Work Items / Approvals 的卡點與 owner SOP rail 串回同一首屏;後續要減少下方長文字卡 | P0 | -| `/zh-TW/awooop/runs` | Runs 狀態鏈、provider evidence、recurrence Work Item 草案狀態 chip 可見;後端已能分辨 Ansible check-mode 乾跑與真正修復執行 | mobile 有長字串、內部 provider URL / key 類資訊外露風險;仍需補 Situation Strip / Agent Flow / Action Rail 才能一眼分辨「乾跑、已套用、待 verifier、需 owner apply gate」 | P0 | +| `/zh-TW/awooop/runs` | Runs 狀態鏈、provider evidence、recurrence Work Item 草案狀態 chip 可見;後端與資產 ledger 已能分辨 Ansible check-mode 乾跑、套用與 verifier 卡點 | mobile 有長字串、內部 provider URL / key 類資訊外露風險;仍需補 Situation Strip / Agent Flow / Action Rail 才能一眼分辨「乾跑、已套用、待 verifier、需 owner apply gate」 | P0 | | `/zh-TW/awooop/work-items` | 工作項目、repair candidate 與 operator SOP rail 可見;已能一眼看到人工卡點、候選品質、沉澱資產與負責人接手 | 底部長表格仍需 responsive data grid / drawer 化;每筆 item 還要補更細的 owner、rollback、verifier receipt 與狀態回寫 | P0 | | `/zh-TW/awooop/approvals` | approval 狀態鏈、AI evidence 與審批決策 handoff rail 可見;已能一眼看到阻塞、證據、接手包與安全閘門;後端已能把 prefilled host-service 草案標成 owner-review-ready | 表格仍需 drawer 化;Runs / Work Items 仍要讀回 draft-ready 狀態、owner、rollback、verifier receipt 與資產 ID | P0 | | `/zh-TW/awooop/tenants` | 16 產品、31 路由、10 repo 資產可讀;作戰圖與 route/source 手機卡片已上線 | 下一步補產品拓樸 drilldown 與租戶資料表 drawer | P0 | @@ -413,7 +428,7 @@ AWOOOI 缺的是: |---|---:| | 全站 UI/UX 專業化 | `56%` | | 導航 / IA 整合 | `64%` | -| AwoooP 操作台產品化 | `66%` | +| AwoooP 操作台產品化 | `67%` | | Tenants 全產品資產中心 | `68%` | | Observability 專業拓樸 / 告警中心 | `38%` | | Knowledge / PlayBook 沉澱可視化 | `34%` |