V10.553 瘦身 current 比價結果查詢

This commit is contained in:
OoO
2026-06-01 13:17:06 +08:00
parent e0ed5cc732
commit 47d5c8043b
5 changed files with 21 additions and 7 deletions

View File

@@ -4,6 +4,7 @@
================================================================================
【已完成】
- V10.553 優化 current PPT/AI 比價結果查詢:`fetch_competitor_comparison_results()` 的 current/latest MOMO 價格改用 `JOIN LATERAL` 取單品最新價,移除 `ROW_NUMBER() OVER (PARTITION BY p.id ...)` window scan歷史報表的 `end_date` cutoff 仍保留在 lateral 子查詢內,維持「指定期間截止日前最新 MOMO 價」語意不變。這能降低簡報、OpenClaw/AI payload 與比價匯出在大量 price_records 下的查詢成本。
- V10.552 收斂決策查詢的新鮮度口徑:`fetch_top_competitor_risks()`、PChome review queue、review sample 與 current PPT/AI 比價結果都不再把 `expires_at IS NULL` 當成有效現價,只接受 `expires_at > CURRENT_TIMESTAMP` 的 PChome identity_v2 價格。未知新鮮度只留在 coverage 的診斷欄位與 V10.551 刷新入口不再進入價格風險、簡報、AI 決策或覆核排除條件。
- V10.551 收斂未知新鮮度刷新與補抓排序:`_fetch_expired_identity_skus()` / `_fetch_expired_identity_recovery_skus()` 將 `expires_at IS NULL` 視為必須刷新或可搜尋救援的未知新鮮度 identity和 V10.549「未知新鮮度不算可決策覆蓋率」口徑對齊;兩條路徑改用 `JOIN LATERAL` 取最新 MOMO 價,移除 product-wide window scan。`_fetch_unmatched_priority_skus()` 也改用 lateral 最新價,並優先重搜低風險 `no_result / refresh_no_result`,讓 V10.550 的安全召回詞先用在最可能被救回的商品。
- V10.550 補安全搜尋召回詞:`_build_variant_recall_search_plan()` 對低風險穩定品類新增 `品牌 + 品類` 的補搜尋詞,讓 `no_result / refresh_no_result` 更有機會找到 PChome 候選後再交給 matcher 安全判斷;美甲片、指甲油、唇彩、香氛/精油、粉底、防曬、任選/色號/款式等高 variant 風險商品不走通用召回DASHING DIVA 仍只走既有 line-specific recall + sort fallback。此變更不改 `MIN_MATCH_SCORE`、hard veto、fresh-search write safety 或 stronger existing match 覆寫保護。

View File

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

View File

@@ -13,6 +13,7 @@
## 📅 詳細更新日誌 (考古存檔)
### 2026-06-01PChome 比價新鮮度操作閉環
- **V10.553 current PPT/AI 比價結果查詢瘦身**: `fetch_competitor_comparison_results()` 不再用 `ROW_NUMBER() OVER (PARTITION BY p.id ...)``price_records` 取得 current/latest MOMO 價格,改為 `JOIN LATERAL` 逐商品取最新價;有指定 `end_date` 的歷史報表仍把 `pr.timestamp < DATE(:end_date) + INTERVAL '1 day'` 放在 lateral 子查詢中,保留「截止日前最新 MOMO 價」語意。這降低簡報、OpenClaw/AI payload 與比價匯出在大量價格紀錄下的查詢成本。
- **V10.552 決策查詢新鮮度口徑收斂**: Top competitor risks、PChome review queue、review sample 與 current PPT/AI 比價結果全部改成只吃 `cp.expires_at > CURRENT_TIMESTAMP` 的有效 PChome identity_v2 價格,不再把 `expires_at IS NULL` 當作有效現價。未知新鮮度現在只作 coverage 診斷與刷新入口不會被用來產生價格風險、簡報、AI 決策或從覆核隊列中排除。
- **V10.551 未知新鮮度刷新與補抓排序收斂**: `expires_at IS NULL` 的 identity_v2 價格現在會被 `_fetch_expired_identity_skus()``_fetch_expired_identity_recovery_skus()` 視為需要刷新 / 可搜尋救援的未知新鮮度資料,避免 V10.549 已排除出可決策覆蓋率後卻沒有刷新入口;兩條路徑都改用 `JOIN LATERAL` 取最新 MOMO 價,不再做 product-wide window scan。`_fetch_unmatched_priority_skus()` 同步改為 lateral latest price且把低風險 `no_result / refresh_no_result` 排到補抓前段,讓安全召回詞優先投入最可能回收的 SKU。
- **V10.550 安全搜尋召回詞補強**: `competitor_price_feeder` 在既有精準搜尋詞之外,對低風險穩定品類補上一組 `品牌 + 品類` recall keyword提升 `no_result / refresh_no_result` 找到候選的機率;高 variant 風險商品如美甲片、指甲油、唇彩、香氛/精油、粉底、防曬與含任選/色號/款式/香味的商品不走通用召回。DASHING DIVA 仍保留既有 line-specific recall 與 PChome sort fallback本次不更動 `MIN_MATCH_SCORE`、hard veto、auto write safety 或 stronger existing match 保護。

View File

@@ -1717,12 +1717,17 @@ def fetch_competitor_comparison_results(
p.id AS product_id,
p.i_code AS sku,
p.name,
pr.price AS momo_price,
ROW_NUMBER() OVER (PARTITION BY p.id ORDER BY pr.timestamp DESC, pr.id DESC) AS rn
latest_price.price AS momo_price
FROM products p
JOIN price_records pr ON pr.product_id = p.id
JOIN LATERAL (
SELECT pr.price
FROM price_records pr
WHERE pr.product_id = p.id
{momo_price_cutoff}
ORDER BY pr.timestamp DESC, pr.id DESC
LIMIT 1
) latest_price ON TRUE
WHERE p.status = 'ACTIVE'
{momo_price_cutoff}
),
{valid_competitor_cte},
{attempt_cte}
@@ -1756,8 +1761,7 @@ def fetch_competitor_comparison_results(
LEFT JOIN valid_competitor vc ON vc.sku = lm.sku
LEFT JOIN latest_attempt la ON la.sku = lm.sku
{sales_join}
WHERE lm.rn = 1
AND lm.momo_price > 0
WHERE lm.momo_price > 0
ORDER BY {order_expr}
LIMIT :limit
""")

View File

@@ -56,6 +56,9 @@ def test_competitor_ppt_results_keep_pending_diagnostics_in_export():
def test_competitor_ppt_results_use_history_for_dated_reports():
source = (ROOT / "services" / "competitor_intel_repository.py").read_text(encoding="utf-8")
route_source = (ROOT / "routes" / "openclaw_bot_routes.py").read_text(encoding="utf-8")
comparison_source = source.split("def fetch_competitor_comparison_results", 1)[1].split(
"def build_competitor_intel_payload", 1
)[0]
assert "requested_historical_prices" in source
assert "use_history_prices" in source
@@ -63,6 +66,11 @@ def test_competitor_ppt_results_use_history_for_dated_reports():
assert "cph.crawled_at >= DATE(:start_date)" in source
assert "cph.crawled_at < DATE(:end_date) + INTERVAL '1 day'" in source
assert "pr.timestamp < DATE(:end_date) + INTERVAL '1 day'" in source
assert "FROM products p\n JOIN LATERAL" in comparison_source
assert "WHERE pr.product_id = p.id" in comparison_source
assert "ORDER BY pr.timestamp DESC, pr.id DESC" in comparison_source
assert "ROW_NUMBER() OVER (PARTITION BY p.id" not in comparison_source
assert "WHERE lm.rn = 1" not in comparison_source
assert "'competitor_price_history' AS competitor_source" in source
assert "\"competitor_source\"" in source
assert "\"pc_crawled_at\"" in source