From b69d173f18dfa42a02396b459dd20ada9daddcf5 Mon Sep 17 00:00:00 2001 From: ogt Date: Thu, 2 Jul 2026 18:29:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A5=97=E7=94=A8=20AI=20surface=20benchmark?= =?UTF-8?q?=20golden=20signals?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/AI_INTELLIGENCE_MODULE_SOT.md | 1 + .../guides/external_professional_benchmark.md | 3 +- .../pchome_ai_automation_priority_backlog.md | 4 + templates/admin/observability_overview.html | 32 ++++- templates/ai_intelligence.html | 111 +++++++++++++++++- tests/test_ai_surface_benchmark_guardrails.py | 75 ++++++++++++ 6 files changed, 222 insertions(+), 4 deletions(-) create mode 100644 tests/test_ai_surface_benchmark_guardrails.py diff --git a/docs/AI_INTELLIGENCE_MODULE_SOT.md b/docs/AI_INTELLIGENCE_MODULE_SOT.md index ee24f55..d59a7cb 100644 --- a/docs/AI_INTELLIGENCE_MODULE_SOT.md +++ b/docs/AI_INTELLIGENCE_MODULE_SOT.md @@ -96,6 +96,7 @@ - 2026-07-02 起 PChome controlled apply rollback evidence 必須提供聚合 endpoint;`/api/ai/pchome-growth/mapping-backlog/direct-mapping-retry-candidate-exception-controlled-apply-rollback-evidence-package` 會聚合 receipt replay、drift verifier、drift recovery、compact readback、artifact retention 五類 evidence,輸出 rollback required / ready actions / protected chain / next machine action。此 endpoint 不執行 rollback、不執行 re-apply、不執行 SQL、不寫 DB;0 drift 時必須輸出 no-op evidence,drift detected 時才輸出 check-mode reapply action。 - 2026-07-02 起 `/metrics` 必須匯出 AI automation scheduled health summary gauges:`momo_ai_automation_scheduled_health_summary_total`、`momo_ai_automation_scheduled_health_family_status`、`momo_ai_automation_scheduled_health_primary_human_gate_count`、`momo_ai_automation_scheduled_health_writes_database_count`。Prometheus scrape 不得寄 Telegram、不寫 DB、不執行 current smoke,只讀 scheduled health summary history。 - 2026-07-02 起 P4 source / deployment governance 必須提供 machine-readable report:`scripts/ops/report_source_deploy_runtime_truth.py` 會分層輸出 Gitea / origin / local HEAD source truth、部署檔案 SHA256 readback、正式 `/health` runtime truth、optional container readback 與 GitHub freeze / `momo-db` protected / no DB write / no secret read 安全紅線。此 report 是推 Gitea 與正式部署後的 P4 收斂證據,不得把 source-control success 直接等同 deployment success 或 production runtime success。 +- 2026-07-02 起 `/ai_intelligence` 與 `/observability/overview` 必須同樣套用 AI automation benchmark golden signals:首屏需有 `AI 自動化狀態` 區塊,直接顯示「已自動落地、已驗證、異動狀態、下一步」。`/ai_intelligence` 需以 `/api/ai/pchome-growth/ai-automation-readiness` 只讀更新狀態;`/observability/overview` 需用正式觀測資料分層呈現風險與下一步。raw endpoint、artifact、DB table、manual/human gate 文字不得進首屏訊號。 - V10.644 起 `/ai_intelligence` 的商品明細列不得只用句子描述比價;每列必須顯示 PChome 價格、MOMO 參考價、差距、可信度四格價格證據,並保留下一步按鈕。單位價候選需顯示單位價與單位,候選待確認或缺資料則以「待補 / 候選待確認」呈現,不得捏造價格。 - V10.645 起 `/ai_intelligence` 的商品明細分流切換後,必須顯示「這類商品怎麼處理」的行動摘要,包含件數、近 7 天業績、平均可信度、最大價差、代表商品與主按鈕;使用者不得只能看到商品列表而不知道下一步。 - V10.646 起 `/ai_intelligence` 的商品明細必須提供搜尋與排序;搜尋至少涵蓋商品、分類、商品編號與 MOMO 候選資訊,排序至少支援優先級、近 7 天業績、價差、下滑幅度與可信度。搜尋/排序後的行動摘要與明細列表必須使用同一批結果。 diff --git a/docs/guides/external_professional_benchmark.md b/docs/guides/external_professional_benchmark.md index 1c2b489..1999ec1 100644 --- a/docs/guides/external_professional_benchmark.md +++ b/docs/guides/external_professional_benchmark.md @@ -71,6 +71,7 @@ Baymard 的商品頁與比較 UX 研究強調:使用者需要清楚的 product - 證據按需: 產品畫面顯示「回讀、異動、留存、資料寫入」等營運語;receipt、hash、artifact、DB table 名稱只留在 detailed readback 與 tests。 - Golden signals: AI automation 第一視窗至少要有四個核心訊號:已自動落地、已驗證、異動狀態、下一步。 - Dashboard-as-code: benchmark 結論必須進 tests;`tests/test_pchome_dashboard_benchmark_guardrails.py` 是 PChome AI dashboard benchmark guard。 +- Surface rollout: `/ai_intelligence` 與 `/observability/overview` 已套用相同 golden-signal guardrails;`tests/test_ai_surface_benchmark_guardrails.py` 鎖住兩頁首屏的狀態分層、下一步優先與 evidence-on-demand 語言。 ## 下一步 TODO 候選 @@ -78,7 +79,7 @@ Baymard 的商品頁與比較 UX 研究強調:使用者需要清楚的 product 2. 在覆核頁新增差異高亮:色號、香味、容量、入數、任選、效期、來源新鮮度。 3. 將 PPT / AI payload 的比價項目拆成 identity evidence 與 offer evidence。 4. 每週 benchmark 結果若命中上述 TODO,回寫 `TODO_NEXT_STEPS.txt` 或新增 ADR / memory。 -5. 將 PChome AI automation benchmark guardrails 套到 `/ai_intelligence`、`/observability/overview` 與後續 AI Agent surfaces。 +5. 將 PChome AI automation benchmark guardrails 套到後續 AI Agent surfaces 與每條 safe automation lane 的 first-viewport summary。 ## 參考來源 diff --git a/docs/guides/pchome_ai_automation_priority_backlog.md b/docs/guides/pchome_ai_automation_priority_backlog.md index 2536afc..10860bb 100644 --- a/docs/guides/pchome_ai_automation_priority_backlog.md +++ b/docs/guides/pchome_ai_automation_priority_backlog.md @@ -159,6 +159,9 @@ 下一步: 1. 將同一套 benchmark guardrails 套到 `/ai_intelligence` 與 `/observability/overview`。 + - 已完成: `/ai_intelligence` 與 `/observability/overview` 首屏都有 `AI 自動化狀態` golden-signal strip。 + - 已完成: 兩頁都明確呈現「已自動落地、已驗證、異動狀態、下一步」。 + - 已完成: `tests/test_ai_surface_benchmark_guardrails.py` 鎖住 DOM、下一步優先與 evidence-on-demand wording。 2. 為後續 safe automation lanes 建立同樣的 first-viewport summary。 完成標準: @@ -235,6 +238,7 @@ | P3.3 | Rollback evidence packages | 已完成 | controlled apply rollback evidence route + focused tests | P3.4 observability metrics integration | | P3.4 | Observability metrics integration | 已完成 | `/metrics` exports scheduled health summary gauges + focused tests | P4 source / deployment governance ongoing | | P4.1 | Source / deployment / runtime truth package | 已完成 | `scripts/ops/report_source_deploy_runtime_truth.py` + focused tests | 每次 Gitea push / production deploy 後執行 P4 report | +| P2.2 | Benchmark guardrails applied to core AI surfaces | 已完成 | `/ai_intelligence` + `/observability/overview` golden-signal strips + focused tests | 後續 safe automation lanes 套同樣 first-viewport summary | ## 後續回報格式 diff --git a/templates/admin/observability_overview.html b/templates/admin/observability_overview.html index 22108d9..16cae02 100644 --- a/templates/admin/observability_overview.html +++ b/templates/admin/observability_overview.html @@ -82,7 +82,8 @@ line-height: 1.75; } - .obs-command-strip { + .obs-command-strip, + .obs-automation-strip { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.75rem; @@ -384,6 +385,7 @@ @media (max-width: 1180px) { .obs-command-strip, + .obs-automation-strip, .obs-route-map { grid-template-columns: repeat(2, minmax(0, 1fr)); } @@ -395,6 +397,7 @@ @media (max-width: 720px) { .obs-command-strip, + .obs-automation-strip, .obs-route-map, .obs-metric-grid { grid-template-columns: 1fr; @@ -425,6 +428,31 @@ 私有 AI 中樞的第一入口:模型主機、AI 呼叫、知識學習、工具編排、自癒、預算與 PPT 視覺審核收斂到同一張工作台。所有數字只讀正式資料來源;缺資料時呈現可診斷空狀態。

+
+
+
已自動落地
+
已接入
+
主機探測、AI 呼叫、自癒、預算與品質訊號已進總覽。
+
+
+
已驗證
+
+ {% if host_bad.value == 0 and (not ai or ai.error_rate < 15) %}正常{% else %}需追蹤{% endif %} +
+
以正式資料回讀主機健康、錯誤率、成本與知識命中。
+
+
+
異動狀態
+
{{ risk_count }}
+
即時風險分層;詳細事件保留在各子頁。
+
+
+
下一步
+
{% if risk_count == 0 %}維持監控{% else %}先處理風險{% endif %}
+
{% if risk_count == 0 %}持續觀察健康、成本與自癒訊號。{% else %}依風險數進入主機、預算、呼叫或知識頁。{% endif %}
+
+
+
即時風險
@@ -609,7 +637,7 @@
知識品質

知識與品質

- 知識晉升審核晉升守門與人工審核。07 + 知識晉升審核晉升守門與 AI 例外決策。07 知識召回詳情查詢命中、節省呼叫、反饋追蹤。08 反饋趨勢呼叫端品質、蒸餾池、根因建議。09 PPT 視覺審核PPT 審核、修法建議、修復流程。10 diff --git a/templates/ai_intelligence.html b/templates/ai_intelligence.html index b7ea9dd..01b9b29 100644 --- a/templates/ai_intelligence.html +++ b/templates/ai_intelligence.html @@ -455,6 +455,45 @@ color: #fff !important; } + .ai-benchmark-strip { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 10px; + } + + .ai-benchmark-signal { + min-height: 102px; + border: 1px solid var(--momo-border-subtle); + border-radius: 8px; + background: rgba(255, 255, 255, 0.92); + box-shadow: var(--momo-shadow-soft); + padding: 12px; + } + + .ai-benchmark-label { + color: var(--momo-text-muted); + font-size: 0.72rem; + font-weight: 950; + } + + .ai-benchmark-value { + display: block; + margin-top: 8px; + color: var(--momo-text-strong); + font-size: 0.98rem; + font-weight: 950; + line-height: 1.25; + } + + .ai-benchmark-detail { + display: block; + margin-top: 7px; + color: var(--momo-text-muted); + font-size: 0.72rem; + font-weight: 780; + line-height: 1.35; + } + .ai-intel-hero { position: relative; overflow: hidden; @@ -2500,7 +2539,8 @@ } .growth-command-kpi-grid, - .growth-command-focus { + .growth-command-focus, + .ai-benchmark-strip { grid-template-columns: 1fr; } @@ -2914,6 +2954,29 @@
+
+
+
已自動落地
+ 讀取中 + 確認受控落地與回讀狀態。 +
+
+
已驗證
+ 等待回讀 + 確認收據、漂移與證據狀態。 +
+
+
異動狀態
+ 整理中 + 只顯示營運可讀異動,不暴露底層資料表。 +
+
+
下一步
+ 整理下一個自動動作 + 優先給出可自動執行或可回讀的下一步。 +
+
+
@@ -3548,6 +3611,7 @@ let activeGrowthCategoryFilter = ''; // ── 頁面載入 ──────────────────────────────────────── document.addEventListener('DOMContentLoaded', () => { loadDashboard(); + loadAutomationBenchmarkStrip(); loadGrowthOps(); bindActionDelegation(); }); @@ -3636,6 +3700,51 @@ async function loadDashboard() { } } +async function loadAutomationBenchmarkStrip() { + try { + const response = await fetch('/api/ai/pchome-growth/ai-automation-readiness?include_receipt_replay=true&include_drift_verifier=true&limit=20'); + const payload = await readJsonResponse(response); + const summary = payload.summary || {}; + const receiptSummary = (payload.receipt_replay || {}).summary || {}; + const driftSummary = (payload.drift_verifier || {}).summary || {}; + const primaryGateCount = Number(summary.primary_human_gate_count || 0); + const selectorCount = Number(receiptSummary.selector_count || receiptSummary.target_selector_count || 0); + const replayPassCount = Number(receiptSummary.receipt_replay_pass_count || receiptSummary.post_apply_readback_pass_count || 0); + const driftCount = Number(driftSummary.drift_count || 0); + const nextAction = payload.next_machine_action || summary.next_machine_action || '持續回讀與漂移監控'; + + setText('aiBenchmarkLanded', selectorCount ? `${formatCount(selectorCount)} 筆已落地` : '閉環已接入'); + setText('aiBenchmarkLandedDetail', primaryGateCount === 0 ? '主流程無人工阻斷,持續由 AI 受控回讀。' : `仍有 ${formatCount(primaryGateCount)} 個例外需 AI 收斂。`); + setText('aiBenchmarkVerified', replayPassCount ? `${formatCount(replayPassCount)} 筆已回讀` : '收據回讀就緒'); + setText('aiBenchmarkVerifiedDetail', driftCount === 0 ? '目前沒有漂移,證據可追蹤。' : `${formatCount(driftCount)} 筆漂移,進入自動恢復建議。`); + setText('aiBenchmarkChange', driftCount === 0 ? '無異動待修復' : `${formatCount(driftCount)} 筆待修復`); + setText('aiBenchmarkChangeDetail', '異動只呈現營運狀態,詳細收據留在證據層。'); + setText('aiBenchmarkNextAction', humanizeMachineAction(nextAction)); + setText('aiBenchmarkNextActionDetail', '下一步優先顯示可自動執行、可回讀、可回滾的動作。'); + } catch (error) { + setText('aiBenchmarkLanded', '等待回讀'); + setText('aiBenchmarkVerified', '暫無狀態'); + setText('aiBenchmarkChange', '讀取延遲'); + setText('aiBenchmarkNextAction', '重新整理狀態'); + setText('aiBenchmarkNextActionDetail', '目前未取得 AI 自動化摘要,頁面其餘作戰資料仍可使用。'); + console.warn('AI automation benchmark strip failed', error); + } +} + +function humanizeMachineAction(value) { + const text = String(value || '').trim(); + if (!text) return '持續回讀與漂移監控'; + return text + .replace(/_/g, ' ') + .replace(/\bNO OP\b/i, '維持監控') + .replace(/\bMONITOR\b/i, '持續監控') + .replace(/\bREPLAY\b/i, '重新回讀') + .replace(/\bDRIFT\b/i, '檢查異動') + .replace(/\bROLLBACK\b/i, '準備回滾證據') + .replace(/\bCONTROLLED APPLY\b/i, '受控落地') + .slice(0, 42); +} + // ── KPI(high_risk_count 來自後端全量 CTE)───────── function renderKPIs(stats) { document.getElementById('kpiSkus').textContent = (stats.total_skus || 0).toLocaleString(); diff --git a/tests/test_ai_surface_benchmark_guardrails.py b/tests/test_ai_surface_benchmark_guardrails.py new file mode 100644 index 0000000..32f0abb --- /dev/null +++ b/tests/test_ai_surface_benchmark_guardrails.py @@ -0,0 +1,75 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +def _read(path: str) -> str: + return (ROOT / path).read_text(encoding="utf-8") + + +def test_ai_intelligence_first_viewport_has_benchmark_golden_signals(): + template = _read("templates/ai_intelligence.html") + strip = template.split('aria-label="AI 自動化狀態"', 1)[1].split( + '
', + 1, + )[0] + + assert 'data-benchmark-guardrail="golden-signals"' in strip + assert 'data-signal="automated-landing"' in strip + assert 'data-signal="verified"' in strip + assert 'data-signal="change-state"' in strip + assert 'data-signal="next-machine-action"' in strip + assert "已自動落地" in strip + assert "已驗證" in strip + assert "異動狀態" in strip + assert "下一步" in strip + assert "維持監控" in strip + assert "先處理風險" in strip + + +def test_benchmark_guardrail_surfaces_keep_evidence_on_demand_language(): + combined = "\n".join( + [ + _read("templates/ai_intelligence.html").split('aria-label="AI 自動化狀態"', 1)[1].split( + '
', + 1, + )[0], + ] + ) + + forbidden_visible_terms = [ + "DB writes", + "Artifact", + "endpoint", + "JSON", + "table", + "manual review", + "human gate", + ] + for term in forbidden_visible_terms: + assert term not in combined