style(obs): compact promotion exception workbench
Some checks failed
CD Pipeline / deploy (push) Has been cancelled

This commit is contained in:
ogt
2026-07-03 00:06:59 +08:00
parent 9014d1a290
commit eea707034b
5 changed files with 75 additions and 11 deletions

View File

@@ -105,6 +105,7 @@
- 2026-07-02 起 `/observability/business_intel` 必須採密集 AI 商業工作台:首屏使用 `data-density-guardrail="compact-business-workbench"`,以「戰果追蹤、閉環成效、競品訊號」短標籤承接 AI 商業狀態hero 說明、決策節奏註解、KPI 小註、panel 說明與頁尾資料來源不得佔用第一層視覺,畫面先保留高信心未跟進、平均信心分、有效率、競品監測、外部促銷活動監控、策略族群、最近建議與閉環學習紀錄。
- 2026-07-02 起 `/observability/host_health` 必須採密集 AI runtime 工作台:首屏使用 `data-density-guardrail="compact-runtime-workbench"`,以「主機級聯、自癒閉環、成本節流」短標籤承接 AI runtime 狀態hero 說明、KPI 小註與頁尾重複標題不得佔用第一層視覺畫面先保留建議服務離線、AIOps 未解、自癒成功率、節流供應商、AI 建議服務主機、健康趨勢、自癒閉環、工具層與事件紀錄。
- 2026-07-02 起 `/observability/rag_queries` 必須採密集 AI 知識工作台:首屏使用 `data-density-guardrail="compact-knowledge-workbench"`,以「知識命中、省模閉環、回饋學習」短標籤承接 RAG 召回狀態hero 說明、KPI 小註與頁尾重複標題不得佔用第一層視覺,畫面先保留查詢數、命中率、省模型、回饋分、查詢串流、使用情境品質與命中內容查閱。
- 2026-07-03 起 `/observability/promotion_review` 必須採密集 AI 晉升例外工作台:首屏使用 `data-density-guardrail="compact-promotion-workbench"`以「AI 例外、去重守門、防污染」短標籤承接知識晉升例外狀態hero 說明、KPI 小註與頁尾重複標題不得佔用第一層視覺畫面先保留待決策、知識庫、30 日採用、污染攔截、例外佇列、策略權重與最近知識;不得把人工審核呈現為 primary flow。
- 2026-07-02 起 `/ai_intelligence` 商品明細與單品作戰詳情的四格價格證據必須可測PChome 價格、MOMO 參考價、差距、可信度需以 `data-evidence` 固定,並以 `aria-label="價格證據"` 對應可掃描區塊;候選待確認或缺資料只能顯示「候選待確認 / 待補」,不得捏造價格或讓使用者打開 raw payload 才知道判斷依據。
- 2026-07-02 起 `/ai_intelligence` 必須是密集 AI 工作台不得退回大段文字說明頁首屏與明細可見內容只保留短狀態、數字、四格證據與下一步按鈕KPI note、benchmark detail、alert 副句、策略說明、decision copy、來源長句與單品 reason list 不得佔用第一層視覺。`tests/test_ai_intelligence_text_density_guardrails.py` 必須鎖住 `data-density-guardrail="compact-ai-workbench"`、短任務文案、detail meta 與 hidden explanatory copy。
- 2026-07-02 起 `/observability/overview` 也必須採密集 AI 觀測工作台:首屏以 `data-density-guardrail="compact-observability-workbench"``AI 觀測 / 風險優先 / 下一步` 與 golden signals 先呈現狀態、數字與操作入口hero lede、signal note、route desc、host meta 與資料來源長句不得佔用第一層視覺。`tests/test_observability_text_density_guardrails.py` 必須鎖住 compact marker 與 hidden explanatory copy。

View File

@@ -79,6 +79,7 @@ Baymard 的商品頁與比較 UX 研究強調:使用者需要清楚的 product
- AI business surface rollout: `/observability/business_intel` 已套用 compact AI business workbench guardrails`tests/test_business_intel_text_density_guardrails.py` 鎖住首屏短標籤、商業戰果/閉環/競品核心訊號與 hidden explanatory copy。
- AI runtime surface rollout: `/observability/host_health` 已套用 compact AI runtime workbench guardrails`tests/test_host_health_text_density_guardrails.py` 鎖住首屏短標籤、主機級聯/自癒/節流核心訊號與 hidden explanatory copy。
- AI knowledge surface rollout: `/observability/rag_queries` 已套用 compact AI knowledge workbench guardrails`tests/test_rag_queries_text_density_guardrails.py` 鎖住首屏短標籤、知識命中/省模閉環/回饋學習核心訊號與 hidden explanatory copy。
- AI promotion exception surface rollout: `/observability/promotion_review` 已套用 compact AI promotion workbench guardrails`tests/test_promotion_review_text_density_guardrails.py` 鎖住首屏短標籤、AI 例外/去重守門/防污染核心訊號與 non-manual wording。
## 下一步 TODO 候選
@@ -96,6 +97,7 @@ Baymard 的商品頁與比較 UX 研究強調:使用者需要清楚的 product
- 已完成: `/observability/business_intel` 首屏以「戰果追蹤 / 閉環成效 / 競品訊號」短標籤與四個核心數字呈現 AI 商業轉化狀態。
- 已完成: `/observability/host_health` 首屏以「主機級聯 / 自癒閉環 / 成本節流」短標籤與四個核心數字呈現 AI runtime 健康狀態。
- 已完成: `/observability/rag_queries` 首屏以「知識命中 / 省模閉環 / 回饋學習」短標籤與四個核心數字呈現 AI 知識召回狀態。
- 已完成: `/observability/promotion_review` 首屏以「AI 例外 / 去重守門 / 防污染」短標籤與四個核心數字呈現 AI 晉升例外狀態。
## 參考來源

View File

@@ -101,7 +101,7 @@
## P1 - Product Visibility And Professional Website Experience
狀態: 進行中,本輪已完成 `/ai_intelligence``/observability/overview``/ai_automation_smoke``/observability/agent_orchestration``/observability/ai_calls``/observability/quality_trend``/observability/budget``/observability/business_intel``/observability/host_health``/observability/rag_queries` 密集 AI 工作台文字密度守門。
狀態: 進行中,本輪已完成 `/ai_intelligence``/observability/overview``/ai_automation_smoke``/observability/agent_orchestration``/observability/ai_calls``/observability/quality_trend``/observability/budget``/observability/business_intel``/observability/host_health``/observability/rag_queries``/observability/promotion_review` 密集 AI 工作台文字密度守門。
目的: 讓 AI 自動化在產品裡可見,成為專業營運工作流,而不是只藏在後端。
@@ -160,6 +160,10 @@
- 首屏改成 `data-density-guardrail="compact-knowledge-workbench"`,以「知識命中 / 省模閉環 / 回饋學習」短標籤承接 RAG 召回狀態。
- hero 說明、KPI 小註與頁尾重複標題從可見 UI 退場,保留查詢數、命中率、省模型、回饋分、查詢串流、使用情境品質與命中內容查閱。
- `tests/test_rag_queries_text_density_guardrails.py` 已鎖住 compact marker、第一層知識訊號與 explanatory copy hidden contract。
- `/observability/promotion_review` 密集 AI 晉升例外工作台文字密度 guard 已完成:
- 首屏改成 `data-density-guardrail="compact-promotion-workbench"`以「AI 例外 / 去重守門 / 防污染」短標籤承接知識晉升例外狀態。
- hero 說明、KPI 小註與頁尾重複標題從可見 UI 退場保留待決策、知識庫、30 日採用、污染攔截、例外佇列、策略權重與最近知識。
- `tests/test_promotion_review_text_density_guardrails.py` 已鎖住 compact marker、第一層晉升例外訊號與 non-manual wording。
已完成 / 下一步,必須照順序:
@@ -285,6 +289,7 @@
| P1.7 | Agent orchestration compact workbench text-density guardrails | 已完成 | `/observability/agent_orchestration` first viewport hides explanatory copy; focused density guard test | Apply density guard to remaining high-visibility AI surfaces |
| P1.8 | AI calls compact workbench text-density guardrails | 已完成 | `/observability/ai_calls` first viewport hides explanatory copy; focused density guard test | Apply density guard to remaining high-visibility AI surfaces |
| P1.9 | Quality trend compact workbench text-density guardrails | 已完成 | `/observability/quality_trend` first viewport hides explanatory copy; focused density guard test | Apply density guard to remaining high-visibility AI surfaces |
| P1.10 | Promotion review compact AI exception workbench guardrails | 已完成 | `/observability/promotion_review` first viewport hides explanatory copy and avoids manual-primary wording; focused density guard test | Apply density guard to PPT audit surface |
| P2.1 | External benchmark encoded into requirements | 已完成 | benchmark guide + focused guard test + first-viewport status | P3.1 safe lane expansion |
| P3.1 | Extend receipt / replay / drift pattern to more lanes | 已完成 | direct mapping candidate decision lane closeout route + focused tests | P3.2 scheduled automation health summaries |
| P3.2 | Scheduled automation health summaries | 已完成 | `/api/ai-automation/scheduled-health-summary` + smoke service focused tests | P3.3 rollback evidence packages |

View File

@@ -9,6 +9,9 @@
.gate-kicker { color:var(--obs-accent); font-size:.76rem; letter-spacing:.13em; text-transform:uppercase; font-weight:850; }
.gate-title { margin:.45rem 0 .25rem; font-family: var(--momo-font-display, "Inter", "Noto Sans TC", system-ui, sans-serif); font-size:var(--obs-title-size); letter-spacing: 0; line-height:.98; }
.gate-subtitle { color:var(--obs-muted); max-width:880px; line-height:1.7; }
.gate-mode-row { display:flex; flex-wrap:wrap; gap:.5rem; margin-top:.75rem; }
.gate-mode { display:inline-flex; align-items:center; min-height:28px; padding:.32rem .65rem; border:1px solid var(--obs-line); border-radius:10px; background:rgba(255,255,255,.62); color:var(--obs-muted); font-size:.74rem; font-weight:850; white-space:nowrap; }
.gate-subtitle, .gate-signal small, .gate-review-copy, .gate-footer-copy { display:none; }
.gate-command { display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:.75rem; margin-top:1rem; }
.gate-signal { padding:.95rem; border:1px solid var(--obs-line); border-radius:20px; background:rgba(255,255,255,.62); }
.gate-label { color:var(--obs-muted); font-size:.72rem; letter-spacing:.1em; text-transform:uppercase; }
@@ -40,15 +43,16 @@
{% set approval_rate = (approved_30d / total_dist * 100) if total_dist > 0 else 0 %}
<div class="container-fluid mt-3">
<section class="gate-hero">
<div class="gate-kicker"><i class="fas fa-brain me-1"></i> 知識晉升審核 · 人工審核 / 去重 / 防污染</div>
<h1 class="gate-title">知識晉升審核</h1>
<section class="gate-hero" data-density-guardrail="compact-promotion-workbench">
<div class="gate-kicker"><i class="fas fa-brain me-1"></i> 知識晉升審核 · AI 例外決策 / 去重 / 防污染</div>
<h1 class="gate-title">AI 晉升例外台</h1>
<div class="gate-mode-row" aria-label="AI 晉升狀態模式"><span class="gate-mode">AI 例外</span><span class="gate-mode">去重守門</span><span class="gate-mode">防污染</span></div>
<p class="gate-subtitle">先審核高權重學習片段,避免錯誤知識污染業績建議。</p>
<div class="gate-command">
<div class="gate-signal"><div class="gate-label">審核</div><span class="gate-value {% if episodes|length > 0 %}status-warn{% else %}status-good{% endif %}">{{ episodes|length }}</span><small class="text-muted">高權重待審片段</small></div>
<div class="gate-signal"><div class="gate-label">決策</div><span class="gate-value {% if episodes|length > 0 %}status-warn{% else %}status-good{% endif %}">{{ episodes|length }}</span><small class="text-muted">高權重待審片段</small></div>
<div class="gate-signal"><div class="gate-label">知識庫</div><span class="gate-value">{{ kb_size or 0 }}</span><small class="text-muted">ai_insights 已晉升</small></div>
<div class="gate-signal"><div class="gate-label">30 日通過率</div><span class="gate-value status-blue">{{ "%.0f"|format(approval_rate) }}%</span><small class="text-muted">{{ approved_30d }}/{{ total_dist }} 個片段</small></div>
<div class="gate-signal"><div class="gate-label">30 日拒絕</div><span class="gate-value {% if rejected_30d.value > 0 %}status-bad{% else %}status-good{% endif %}">{{ rejected_30d.value }}</span><small class="text-muted">品質 / 幻覺 / 重複 / 人工拒</small></div>
<div class="gate-signal"><div class="gate-label">30 日採用</div><span class="gate-value status-blue">{{ "%.0f"|format(approval_rate) }}%</span><small class="text-muted">{{ approved_30d }}/{{ total_dist }} 個片段</small></div>
<div class="gate-signal"><div class="gate-label">污染攔截</div><span class="gate-value {% if rejected_30d.value > 0 %}status-bad{% else %}status-good{% endif %}">{{ rejected_30d.value }}</span><small class="text-muted">品質 / 幻覺 / 重複 / 例外否決</small></div>
</div>
</section>
@@ -57,9 +61,9 @@
<section class="gate-grid">
<div class="gate-stack">
<article class="gate-panel">
<div class="gate-panel-head"><div><div class="gate-label">審核佇列</div><h2 class="gate-panel-title">審核片段</h2></div><span class="badge {% if episodes %}bg-warning{% else %}bg-success{% endif %}">{{ episodes|length }} 筆</span></div>
<div class="gate-panel-head"><div><div class="gate-label">例外佇列</div><h2 class="gate-panel-title">決策片段</h2></div><span class="badge {% if episodes %}bg-warning{% else %}bg-success{% endif %}">{{ episodes|length }} 筆</span></div>
<div class="gate-panel-body">
<p class="text-muted small mb-0"><i class="fas fa-shield-halved me-1"></i>權重 ≥ 0.8 必經審核24 小時無回應自動降權。</p>
<p class="text-muted small mb-0 gate-review-copy"><i class="fas fa-shield-halved me-1"></i>權重 ≥ 0.8 必經 AI 例外檢查24 小時無回應自動降權。</p>
</div>
</article>
@@ -74,7 +78,7 @@
<div class="episode-text">{{ ep.distilled_text }}</div>
{% if ep.similar_insights %}<div class="similar-box"><small class="text-muted d-block mb-2"><i class="fas fa-search me-1"></i><strong>Top 3 相似已晉升知識</strong>(用來判斷是否重複)</small><ul class="list-unstyled mb-0 small">{% for sim in ep.similar_insights %}<li class="mb-2"><span class="badge bg-light text-dark me-1">#{{ sim.id }}</span><span class="badge bg-info me-1">{{ obs_label.insight(sim.insight_type) }}</span><span class="badge bg-secondary me-1">相似度 {{ "%.2f"|format(sim.similarity) }}</span><span>{{ sim.content }}{% if sim.content|length >= 180 %}…{% endif %}</span></li>{% endfor %}</ul></div>{% else %}<div class="similar-box"><small><i class="fas fa-seedling me-1"></i>知識庫無相似度 ≥ 0.7 的相似內容,可能是新領域知識。</small></div>{% endif %}
</div>
<div class="card-footer text-end"><button class="btn btn-success btn-sm me-2" onclick="approveEpisode({{ ep.id }}, this)"><i class="fas fa-check me-1"></i>通過晉升</button><button class="btn btn-outline-danger btn-sm" onclick="rejectEpisode({{ ep.id }}, this)"><i class="fas fa-times me-1"></i>拒絕</button></div>
<div class="card-footer text-end"><button class="btn btn-success btn-sm me-2" onclick="approveEpisode({{ ep.id }}, this)"><i class="fas fa-check me-1"></i>採用晉升</button><button class="btn btn-outline-danger btn-sm" onclick="rejectEpisode({{ ep.id }}, this)"><i class="fas fa-times me-1"></i>否決污染</button></div>
</article>
{% endfor %}
{% else %}
@@ -96,7 +100,7 @@
<section class="gate-table-shell"><div class="gate-table-title"><div><div class="gate-label">知識庫</div><h3>最近 10 筆 ai_insights</h3></div></div><div class="table-responsive"><table class="table table-sm mb-0"><thead class="table-light"><tr><th>#</th><th>類型</th><th>期間</th><th>SKU</th><th>建立時間</th><th>預覽</th></tr></thead><tbody>{% for i in latest_insights %}<tr><td><code>#{{ i.id }}</code></td><td><span class="badge bg-info">{{ i.insight_type }}</span></td><td><small>{{ i.period or '—' }}</small></td><td><small>{{ i.product_sku or '—' }}</small></td><td><small>{{ i.created_at }}</small></td><td><small class="text-muted">{{ i.preview }}{% if i.preview|length >= 160 %}…{% endif %}</small></td></tr>{% endfor %}</tbody></table></div></section>
{% endif %}
<p class="text-muted mt-3"><small><i class="fas fa-robot me-1"></i>知識晉升審核</small></p>
<p class="text-muted mt-3 gate-footer-copy"><small><i class="fas fa-robot me-1"></i>知識晉升審核</small></p>
</div>
<template id="obs-promotion-review-data">{{ episode_distribution_30d | default({}) | tojson }}</template>

View File

@@ -0,0 +1,52 @@
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def test_promotion_review_uses_compact_promotion_workbench_contract():
template = (ROOT / "templates/admin/promotion_review.html").read_text(encoding="utf-8")
assert 'data-density-guardrail="compact-promotion-workbench"' in template
assert 'aria-label="AI 晉升狀態模式"' in template
assert "AI 例外" in template
assert "去重守門" in template
assert "防污染" in template
def test_promotion_review_keeps_exception_signals_and_hides_explanatory_copy():
template = (ROOT / "templates/admin/promotion_review.html").read_text(encoding="utf-8")
for marker in ["待決策", "知識庫", "30 日採用", "污染攔截"]:
assert marker in template
assert ".gate-subtitle, .gate-signal small, .gate-review-copy, .gate-footer-copy { display:none; }" in template
assert 'class="gate-subtitle"' in template
assert "gate-review-copy" in template
assert "gate-footer-copy" in template
def test_promotion_review_preserves_ai_exception_workflow_and_non_manual_wording():
template = (ROOT / "templates/admin/promotion_review.html").read_text(encoding="utf-8")
for marker in [
"AI 晉升例外台",
"例外佇列",
"待決策片段",
"採用晉升",
"否決污染",
"30 日狀態分布",
"策略權重 Top",
"最近 10 筆 ai_insights",
]:
assert marker in template
for forbidden in [
"人工審核",
"人工拒",
"manual_required",
"raw payload",
"raw endpoint",
"資料表:",
]:
assert forbidden not in template