V10.569 串接 Webcrumbs 比價信封摘要
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s

This commit is contained in:
OoO
2026-06-02 10:56:01 +08:00
parent 97e7e2843b
commit a32982395e
9 changed files with 152 additions and 3 deletions

View File

@@ -141,6 +141,7 @@
- AI 自動化 Session SOP: `docs/guides/ai_automation_session_sop.md`
- Browse.sh 爬蟲診斷手冊: `docs/guides/browse_sh_crawler_playbook.md`
- Webcrumbs 共用 UI Runtime: `docs/guides/webcrumbs_shared_runtime.md`
- 外部專業 Benchmark: `docs/guides/external_professional_benchmark.md`
- AI 競價情報 SOT: `docs/AI_INTELLIGENCE_MODULE_SOT.md`
- Agent 角色矩陣: `docs/guides/codex_agent_roles.md`
- ADR 索引: `docs/adr/README.md`

View File

@@ -4,6 +4,7 @@
================================================================================
【已完成】
- 外部專業 benchmark 固定節奏:已建立每週一 09:30 自動檢視,並新增 `docs/guides/external_professional_benchmark.md`,把 Google Merchant Center、Google Product structured data、Schema.org Product/Offer/AggregateOffer 與 Baymard 電商 UX 做法轉成可落地準則identity evidence、fresh offer、review 差異高亮、PPT/AI evidence 分層。
- V10.565 補 PChome 覆蓋率操作建議:`/api/ai/pchome-match/backfill/status` 會把低覆蓋率拆成 `operation_backlog`,分別列出刷新舊 identity、重評近門檻、補抓未配對、人工覆核、單位價覆核與過期搜尋救援預覽同時回傳 `recommended_next_action`Dashboard 狀態摘要會顯示「建議執行比價補強 / 刷新過期 identity / 處理覆核」等下一步,讓覆蓋率 KPI 直接連到可執行行動。
- V10.563 收斂正式 preview 假可救候選M.A.C 超持妝輕透濾鏡蜜粉若只有 PChome 端出現明確色號(例如 `#絕絕紫`),會標成 `variant_selection_review` 並維持 `true_low_confidence`,不再佔 recoverable 池SAUGELLA 賽吉兒菁萃潔浴凝露新增潤澤 / 日用型 / 加強 / 黃金女郎型變體互斥,避免同品線不同私密清潔款式被誤救成 matched。
- V10.566 新增市場情報 Professional Source Governance把 robots/REP、sitemap/lastmod、JSON-LD / schema.org structured data、canonical URL、rate limit、公開資料邊界、provenance、snapshot hash 與 idempotency key 變成可審核 source contract。新增 `/api/market_intel/mcp_professional_source_governance` 與市場情報頁卡片、deployment readiness smoke targetAPI/UI 只審核操作員貼回的治理摘要,不抓外站、不讀 robots/sitemap、不開 DB、不寫檔、不掛 scheduler後續 fetch target review 才能引用通過治理的來源。

View File

@@ -402,7 +402,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
# ==========================================
# 系統版本與路徑
# ==========================================
SYSTEM_VERSION = "V10.568"
SYSTEM_VERSION = "V10.569"
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
public_url = PUBLIC_URL # 用於模板顯示

View File

@@ -58,6 +58,7 @@
- PChome 覆核隊列本身也必須輸出 `decision_envelope``fetch_competitor_review_queue()``fetch_competitor_review_queue_page()``/api/pchome-review/queue` 的每筆候選需帶相同的 `subject``evidence``recommended_action``expected_impact``guardrails`,供 Dashboard、Agent、Telegram 與 PPT 共用;任何下游不得另寫一套比價狀態翻譯或繞過 HITL guardrails。
- Dashboard 覆核卡與 `/api/export/excel/pchome-review` 也必須顯示/匯出 `decision_envelope` 的等級、資料品質、建議代碼、HITL、trace 與 `can_auto_execute=false` 邊界;操作員離開系統畫面或下載 Excel 後,仍要看得到「不可自動寫正式價差」的 guardrails。
- OpenClaw 週報/日報/月報與 competitor PPT 不得再各自重算或翻譯 PChome 覆核狀態;必須透過 `competitor_intel_repository.summarize_review_decision_envelopes()` 讀取同一份 `decision_envelope` 摘要,並在 prompt / data_summary / KPI slide 保留 HITL 與 `can_auto_execute=false` 邊界。
- Webcrumbs / Shared UI host data 也必須透過 `summarize_review_decision_envelopes()` 輸出 `reviewDecisionBrief`,並在 metadata 保留 review queue、HITL 與 auto-execute-blocked 數量;不得另寫一套 PChome 覆核摘要或在前端 runtime 重新推論價格行動。
- ElephantAlpha 的 `resource_optimization` 與低信心 `ea_escalation` 也必須輸出 `decision_envelope`:資源壓力信封只能使用 `action_plans`、CPU 實測、hygiene 結果與 insight/action trace不得加入 LLM 預測效益;`triaged_alert()``ea_escalation` 亦需渲染信封並以 `decision_id` 作為 callback 追蹤 ID。
## 一、四 AI Agent 路由架構
@@ -445,6 +446,7 @@ python3 -m services.competitor_identity_revalidator --limit 500 --apply
4. **底部運算足跡** — FinOps + Observability用分隔線隔開主訊息
5. **EA HITL 專業 brief**`ea_escalation` 必須分成決策狀態、背景摘要、風險摘要、TOP 待審 SKU 與建議處置;價格類行動不得用長 bullet 串接,必須拆出 MOMO/PChome 價格、價差、人工處置與 PChome ID。
6. **價格類決策信封專業 brief**`price_alert``pchome_match_review``competitor_price_review` 等含 PChome / 價格證據的 `decision_envelope`EventRouter 必須直送 evidence template不得進 L1/L2 重摘要Telegram 內容必須拆成「標的、價格證據、比對證據、人工下一步」,並從信封讀取 `momo_price``competitor_price``candidate_gap_pct``match_score``unit_price_insight``existing_match_conflict`
7. **Shared UI 信封摘要共用** — Webcrumbs host data 與其他共用 UI runtime 必須讀 `reviewDecisionBrief` / `decision_envelope` 的結構化證據,不在瀏覽器端重組比價判斷;這些 payload 只能讀 DB 既有覆核資料,不呼叫 LLM、不抓外站、不寫資料。
### 5.2 語意化 Emoji 字典

View File

@@ -0,0 +1,71 @@
# 外部專業做法 Benchmark
> 用途:定期把外部電商、商品資料與 UX 專業做法轉成 EwoooC / MOMO Pro 的可執行產品準則。
## 固定節奏
- 每週一 09:30 執行外部 benchmark自動輸出可落地建議。
- 只採用能改善核心價值的做法:商品身份比對準確率、可用比價覆蓋率、價格新鮮度、人工覆核效率、競品情報決策品質。
- 外部資料必須保留來源、讀取日期、觀察結論與不採用原因。
## 2026-06-02 初始觀察
### 1. 商品 identity 必須優先吃結構化 identifiers
Google Merchant Center 的商品資料規格把 `id``brand``gtin``mpn``price``availability` 視為商品資料核心Schema.org / Google Product structured data 也把 `Product``Offer``AggregateOffer``sku``gtin``brand``price``availability` 放在商品與報價語意中心。
落地到本產品:
- 比對引擎不能只靠商品名稱 token應逐步建立 `identity_evidence` 欄位分層保存品牌、SKU、GTIN/條碼、MPN/型號、容量、入數、色號、香味、款式。
- 若雙方有 GTIN / MPN / 明確型號,應優先作為 strong evidence。
- 若缺 GTIN / MPN不得自動推定同款要清楚標示 `identifier_missing``identifier_weak`
### 2. 價格可用性必須和 freshness 綁在一起
Google Merchant Center 要求價格與庫存狀態要和 landing page / checkout 保持一致Schema.org Offer 也有 `price``priceCurrency``availability` 等報價欄位。
落地到本產品:
- `decision_ready` 只能計入明確未過期價格,不應把未知 freshness 當可決策。
- Dashboard 必須拆開 identity coverage、fresh price coverage、pending identity、stale identity。
- 目前 V10.549-V10.565 的方向正確:未知新鮮度不得灌高覆蓋率,並要進刷新/救援流程。
### 3. 多 offer / 多平台比價應該呈現為 offer evidence不只是單一低價
Schema.org `AggregateOffer` 用於同一商品對應多個商家 offer。這個概念適合我們把 MOMO / PChome 的同款證據與價格證據分開保存。
落地到本產品:
- `competitor_prices` 應逐步從單一 match row演進成「identity pair + offer snapshot」兩層。
- PPT / AI 決策不只顯示價差,也要顯示 identity confidence、freshness、offer source、last crawled、manual review state。
### 4. Product comparison UX 要讓使用者比較規格差異
Baymard 的商品頁與比較 UX 研究強調:使用者需要清楚的 product comparison尤其是規格驅動品類。
落地到本產品:
- 人工覆核頁不能只列 MOMO/PChome 名稱與價格;要突出「不一致欄位」:色號、香味、容量、入數、套組、任選、效期、航空版。
-`identity_veto` / `true_low_confidence` 要顯示人可以理解的原因,不只顯示 `待審`
- Dashboard 建議下一步要直接連到對應操作:刷新、補抓、重評、單位價覆核、人工覆核。
## 目前不採用
- 不採用「只靠低價/高相似度自動配對」:價格相近不是 identity evidence。
- 不採用「大量放寬 threshold 來拉覆蓋率」:會污染核心比價資料。
- 不採用「把外部網站 UI 風格直接照搬」:只吸收資訊架構、證據呈現與工作流做法。
## 下一步 TODO 候選
1. 建立 `identity_evidence` 正規化 payload讓 matcher 回傳 identifier/spec/variant evidence。
2. 在覆核頁新增差異高亮:色號、香味、容量、入數、任選、效期、來源新鮮度。
3. 將 PPT / AI payload 的比價項目拆成 identity evidence 與 offer evidence。
4. 每週 benchmark 結果若命中上述 TODO回寫 `TODO_NEXT_STEPS.txt` 或新增 ADR / memory。
## 參考來源
- Google Merchant Center Product data specification: https://support.google.com/merchants/answer/7052112
- Google Search Central Product structured data: https://developers.google.com/search/docs/appearance/structured-data/product
- Schema.org Product / Offer / AggregateOffer: https://schema.org/Product, https://schema.org/Offer, https://schema.org/AggregateOffer
- Baymard Product Page UX Best Practices: https://baymard.com/blog/current-state-ecommerce-product-page-ux
- Baymard Product Comparison UX: https://baymard.com/blog/provide-comparison-features

View File

@@ -106,6 +106,7 @@
- 2026-06-01 起,`V10.566` 新增市場情報 Professional Source Governance gate將 robots/REP、sitemap/lastmod、JSON-LD / schema.org structured data、canonical URL、rate limit、公開資料邊界、provenance、snapshot hash 與 idempotency key 納入 source contract並接上 `/api/market_intel/mcp_professional_source_governance`、UI preview panel、deployment readiness check 與 production smoke target仍不抓外站、不讀 robots/sitemap、不開 DB、不寫檔、不掛 scheduler。
- 2026-06-02 起,`V10.567` 將 MCP 市場洞察 fallback 收斂為 GCP-A / GCP-B only不再讓 111 承接非即時市場分析長任務;預設 timeout 25 秒、`num_predict` 500GCP 不可用時直接保守降級,避免 Elephant Alpha 60 秒 timeout 與 111 負載尖峰。
- 2026-06-02 起,`V10.568` 將價格類 `decision_envelope` 的 Telegram 直送訊息改為專業 brief標的、價格證據、比對證據、人工下一步四段式review queue 信封 subject 同步帶 `momo_price` / `competitor_price`,讓 Telegram、PPT、Webcrumbs 與 AI 摘要共用價格證據。
- 2026-06-02 起,`V10.569` 將 Webcrumbs host data 串到 `summarize_review_decision_envelopes()`payload 新增 `reviewDecisionBrief` 與 review queue / HITL / auto-execute-blocked metadata共用 UI runtime 讀同一份 PChome 覆核信封摘要,仍只讀 DB、不呼叫 LLM、不抓外站、不寫資料。
## 3. 12 Agent 決策信封整合

View File

@@ -13,6 +13,7 @@
## 📅 詳細更新日誌 (考古存檔)
### 2026-06-01PChome 比價新鮮度操作閉環
- **V10.569 Webcrumbs 比價信封摘要串接**: `build_webcrumbs_marketplace_host_data()` 讀取 `fetch_competitor_review_queue()` 後統一走 `summarize_review_decision_envelopes()`,在 host data payload 輸出 `reviewDecisionBrief`,並於 metadata 增加 `review_queue_count``hitl_count``auto_execute_blocked_count``decision_envelope_source`。Webcrumbs / Shared UI 現在和 Telegram、OpenClaw、PPT 共用同一份 PChome 覆核信封摘要,仍維持只讀、不呼叫 LLM、不抓外站、不寫 DB同版收錄 `docs/guides/external_professional_benchmark.md` 作為外部專業做法週巡檢落地準則入口。
- **V10.568 價格類決策信封專業 brief**: `decision_envelope` 的價格 / PChome 覆核事件在 Telegram EventRouter 直送時,改以「標的、價格證據、比對證據、人工下一步」四段式排版呈現,保留 `momo:eig:` 忽略按鈕且不進 L1/L2 AI 重摘要。`competitor_intel_repository` 同步在 review queue 信封 subject 補上 `momo_price` / `competitor_price`,讓 Telegram、PPT、Webcrumbs 與 AI 摘要可共用同一份價格證據,不再各自補查或重組。
- **V10.567 MCP 市場洞察 GCP-only fallback**: `MCPCollectorService._ollama_topic_fallback()` 改成只使用 GCP-A / GCP-B Ollama失敗後保守回本地 fallback不再把市場洞察長分析轉嫁到 111。預設 timeout 收斂為 25 秒、`num_predict` 收斂為 500避免 Elephant Alpha 在 GCP-A/GCP-B 短暫不可用時撞 60 秒總上限或造成 111 負載尖峰Gemini 仍維持 `GEMINI_API_HARD_DISABLED=true` 預設硬封鎖。
- **V10.565 PChome 覆蓋率操作建議**: 補強 `/api/ai/pchome-match/backfill/status`,將低覆蓋率拆成 `operation_backlog`:刷新舊 identity、重評近門檻、補抓未配對、人工覆核、單位價覆核與過期搜尋救援預覽並新增 `recommended_next_action`Dashboard 狀態摘要會直接顯示建議下一步,避免使用者只看到低覆蓋率卻不知道該按哪條產線。

View File

@@ -14,7 +14,9 @@ from typing import Any
from services.competitor_intel_repository import (
fetch_competitor_coverage,
fetch_competitor_review_queue,
fetch_top_competitor_risks,
summarize_review_decision_envelopes,
)
@@ -99,6 +101,27 @@ def _coverage_metadata(coverage: dict, row_count: int) -> dict:
}
def _review_decision_brief(engine, limit: int) -> dict:
"""Read the shared review decision brief without blocking host-data preview."""
try:
review_queue = fetch_competitor_review_queue(engine, limit=min(max(limit, 1), 8))
return summarize_review_decision_envelopes(review_queue, limit=min(max(limit, 1), 5))
except Exception:
return summarize_review_decision_envelopes([], limit=min(max(limit, 1), 5))
def _attach_review_brief(payload: dict, review_brief: dict) -> dict:
payload["reviewDecisionBrief"] = review_brief
metadata = payload.setdefault("metadata", {})
metadata["review_queue_count"] = len(review_brief.get("items") or [])
metadata["hitl_count"] = int(review_brief.get("hitl_count") or 0)
metadata["auto_execute_blocked_count"] = int(
review_brief.get("auto_execute_blocked_count") or 0
)
metadata["decision_envelope_source"] = "competitor_intel_repository"
return payload
def build_webcrumbs_marketplace_host_data(engine=None, limit: int = 5) -> dict:
"""Build read-only host data for the Webcrumbs diagnostic page.
@@ -117,11 +140,12 @@ def build_webcrumbs_marketplace_host_data(engine=None, limit: int = 5) -> dict:
raw_risks = fetch_top_competitor_risks(engine, limit=max(limit * 4, 20)) or []
risks = [item for item in raw_risks if _is_direct_price_alert(item)][:limit]
coverage = fetch_competitor_coverage(engine) or {}
review_brief = _review_decision_brief(engine, limit=limit)
if not risks:
payload = _empty_payload("no_current_exact_risk")
payload["metadata"] = _coverage_metadata(coverage, row_count=0)
return payload
return _attach_review_brief(payload, review_brief)
rows = []
for item in risks[:limit]:
@@ -146,7 +170,7 @@ def build_webcrumbs_marketplace_host_data(engine=None, limit: int = 5) -> dict:
sku = str(top.get("sku") or "-")
evidence_refs = ["competitor_prices", "price_records", "exact", "total_price", "price_alert_exact"]
return {
payload = {
"marketSnapshot": rows,
"aiCandidate": {
"ticker": sku,
@@ -165,3 +189,4 @@ def build_webcrumbs_marketplace_host_data(engine=None, limit: int = 5) -> dict:
},
"metadata": _coverage_metadata(coverage, row_count=len(rows)),
}
return _attach_review_brief(payload, review_brief)

View File

@@ -49,6 +49,43 @@ def test_webcrumbs_host_data_maps_price_alert_exact_rows(monkeypatch):
"pending": 612,
},
)
monkeypatch.setattr(
svc,
"fetch_competitor_review_queue",
lambda passed_engine, limit: [
{
"sku": "SKU-REVIEW",
"name": "人工覆核精華液",
"decision_envelope": {
"decision_id": "review_queue:SKU-REVIEW",
"severity": "P2",
"subject": {
"sku": "SKU-REVIEW",
"name": "人工覆核精華液",
"momo_price": 399,
"competitor_price": 329,
"competitor_product_id": "PCH-REVIEW",
},
"recommended_action": {
"action": "review_accept_identity",
"requires_hitl": True,
},
"expected_impact": {"candidate_gap_pct": 21.3},
"guardrails": {
"data_quality": "complete",
"can_auto_execute": False,
},
"evidence": [
{
"metric": "match_score",
"value": 0.91,
"basis": "exact/total_price/identity_review",
}
],
},
}
],
)
payload = svc.build_webcrumbs_marketplace_host_data(engine=engine, limit=5)
@@ -71,11 +108,19 @@ def test_webcrumbs_host_data_maps_price_alert_exact_rows(monkeypatch):
assert payload["metadata"]["fresh_match_rate"] == 79.5
assert payload["metadata"]["stale_match_count"] == 18
assert payload["metadata"]["pending_match_count"] == 612
assert payload["metadata"]["review_queue_count"] == 1
assert payload["metadata"]["hitl_count"] == 1
assert payload["metadata"]["auto_execute_blocked_count"] == 1
assert payload["metadata"]["decision_envelope_source"] == "competitor_intel_repository"
assert payload["reviewDecisionBrief"]["items"][0]["sku"] == "SKU-REVIEW"
assert payload["reviewDecisionBrief"]["items"][0]["can_auto_execute"] is False
assert "review_accept_identity" in payload["reviewDecisionBrief"]["items"][0]["action"]
assert all(row["freshness_status"] == "price_alert_exact" for row in payload["marketSnapshot"])
def test_webcrumbs_host_data_uses_empty_state_without_risks(monkeypatch):
monkeypatch.setattr(svc, "fetch_top_competitor_risks", lambda engine, limit: [])
monkeypatch.setattr(svc, "fetch_competitor_review_queue", lambda engine, limit: [])
monkeypatch.setattr(
svc,
"fetch_competitor_coverage",
@@ -91,6 +136,8 @@ def test_webcrumbs_host_data_uses_empty_state_without_risks(monkeypatch):
assert payload["metadata"]["fresh_match_count"] == 1
assert payload["metadata"]["stale_match_count"] == 2
assert payload["metadata"]["pending_match_count"] == 9
assert payload["metadata"]["review_queue_count"] == 0
assert payload["reviewDecisionBrief"]["text"] == "(目前沒有待覆核決策信封)"
assert "非同款、單位價或變體候選" in payload["aiCandidate"]["thesis"]