V10.555 接線 focused reason 回刷窄門
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
================================================================================
|
||||
|
||||
【已完成】
|
||||
- V10.555 補 focused total-price reason-based 回刷:`_fetch_retryable_candidate_skus()` 新增一條結構化 reason 窄門,只要舊 attempt 已帶 `focused_exact_total_price_safe` 且命中 matcher 的 `FOCUSED_IDENTITY_TOTAL_PRICE_REASONS`,即可進近門檻重評;仍要求無 hard veto、`exact_identity`、分數下限,並排除 commercial / variant / count / bundle 等阻擋理由。這讓已經被 matcher 明確判為 total-price exact 的舊候選不再依賴手寫商品名 SQL 才能回刷,同時 rom&nd / Solone / Summer’s Eve 等 review-only 品線仍不會進自動價差線。
|
||||
- V10.554 接線香氛 / 精油 focused exact 回刷:Herb24 晨霧純精油擴香儀黑色、Pavaruni 40 香味 10ml 精油、Pavaruni 20 香味 450g 香氛蠟燭、Derma 大地有機植萃護膚油 150ml 現在明確標記 `focused_exact_total_price_safe`,並接進 `_fetch_retryable_candidate_skus()` 近門檻舊候選回刷。此入口只收 `low_score / refresh_low_score / true_low_confidence` 中命中精準名稱錨點、無 hard veto、`exact_identity` 且沒有變體 / 商業條件 / 件數衝突的候選;Laundrin、好物良品融蠟燈、Yuskin 等仍保留人工覆核,不為了拉覆蓋率強推自動價差。
|
||||
- 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 決策或覆核排除條件。
|
||||
|
||||
@@ -402,7 +402,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
|
||||
# ==========================================
|
||||
# 系統版本與路徑
|
||||
# ==========================================
|
||||
SYSTEM_VERSION = "V10.554"
|
||||
SYSTEM_VERSION = "V10.555"
|
||||
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
|
||||
public_url = PUBLIC_URL # 用於模板顯示
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
## 📅 詳細更新日誌 (考古存檔)
|
||||
|
||||
### 2026-06-01:PChome 比價新鮮度操作閉環
|
||||
- **V10.555 focused total-price reason-based 回刷窄門**: `_fetch_retryable_candidate_skus()` 新增結構化 diagnostics reason 回刷入口,舊 attempt 若已帶 `focused_exact_total_price_safe` 且命中 matcher 的 `FOCUSED_IDENTITY_TOTAL_PRICE_REASONS`,即可進近門檻重評,不再完全依賴手寫商品名 SQL。此路徑仍要求分數下限、無 hard veto、`exact_identity`,並套用 commercial / variant / count / bundle 等阻擋理由;rom&nd、Solone、Summer’s Eve 等 review-only focused line 不在 total-price reason set,仍不會被推入自動價差。
|
||||
- **V10.554 香氛 / 精油 focused exact 回刷接線**: Herb24 晨霧純精油擴香儀黑色、Pavaruni 40 香味 10ml 精油、Pavaruni 20 香味 450g 香氛蠟燭、Derma 大地有機植萃護膚油 150ml 已明確列入 matcher 的 `focused_exact_total_price_safe`,並接入 `_fetch_retryable_candidate_skus()` 的近門檻舊候選回刷入口。SQL 仍要求 `low_score / refresh_low_score / true_low_confidence`、分數下限、無 hard veto、`exact_identity`,且排除變體、商業條件與件數衝突;Laundrin、好物良品融蠟燈、Yuskin 等帶人工覆核訊號的品線不納入本輪自動回刷。
|
||||
- **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 決策或從覆核隊列中排除。
|
||||
|
||||
@@ -33,6 +33,8 @@ from datetime import datetime, timedelta, timezone
|
||||
from typing import Optional
|
||||
from urllib.parse import quote_plus
|
||||
|
||||
from services.marketplace_product_matcher import FOCUSED_IDENTITY_TOTAL_PRICE_REASONS
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# ── 比對參數 ─────────────────────────────────────────
|
||||
@@ -113,6 +115,16 @@ RECOVERABLE_DIAGNOSTIC_REASONS = {
|
||||
}
|
||||
|
||||
RECOVERABLE_SQL_REASON_LIST = ", ".join(f"'{reason}'" for reason in sorted(RECOVERABLE_DIAGNOSTIC_REASONS))
|
||||
FOCUSED_TOTAL_PRICE_SAFE_DIAGNOSTIC_REASONS = {
|
||||
"focused_exact_total_price_safe",
|
||||
*{
|
||||
f"focused_exact_identity_{reason}"
|
||||
for reason in FOCUSED_IDENTITY_TOTAL_PRICE_REASONS
|
||||
},
|
||||
}
|
||||
FOCUSED_TOTAL_PRICE_SAFE_SQL_REASON_LIST = ", ".join(
|
||||
f"'{reason}'" for reason in sorted(FOCUSED_TOTAL_PRICE_SAFE_DIAGNOSTIC_REASONS)
|
||||
)
|
||||
REVALIDATABLE_REVIEW_GATE_REASONS = {
|
||||
"strong_exact_spec_match",
|
||||
"spec_name_alignment",
|
||||
@@ -1379,6 +1391,23 @@ class CompetitorPriceFeeder:
|
||||
OR COALESCE(la.match_diagnostic_json->'reasons', '[]'::jsonb) ?| array[{RECOVERABLE_SQL_REASON_LIST}]
|
||||
)
|
||||
)
|
||||
OR (
|
||||
la.attempt_status IN (
|
||||
'low_score',
|
||||
'refresh_low_score',
|
||||
'true_low_confidence',
|
||||
'rescore_accepted_current'
|
||||
)
|
||||
AND COALESCE(la.best_match_score, 0) >= :min_score
|
||||
AND COALESCE(la.hard_veto, false) = false
|
||||
AND COALESCE(la.match_diagnostic_json->>'comparison_mode', 'exact_identity') = 'exact_identity'
|
||||
AND COALESCE(la.match_diagnostic_json->'reasons', '[]'::jsonb) ? 'focused_exact_total_price_safe'
|
||||
AND COALESCE(la.match_diagnostic_json->'reasons', '[]'::jsonb) ?| array[{FOCUSED_TOTAL_PRICE_SAFE_SQL_REASON_LIST}]
|
||||
AND NOT (
|
||||
COALESCE(la.match_diagnostic_json->'reasons', '[]'::jsonb)
|
||||
?| array[{REVALIDATABLE_REVIEW_BLOCK_SQL_REASON_LIST}]
|
||||
)
|
||||
)
|
||||
OR (
|
||||
la.attempt_status = 'true_low_confidence'
|
||||
AND COALESCE(la.best_match_score, 0) >= 0.95
|
||||
|
||||
@@ -110,6 +110,8 @@ def test_competitor_feeder_persists_all_match_attempt_outcomes():
|
||||
assert "preview_expired_identity_recovery" in source
|
||||
assert "_fetch_expired_identity_recovery_skus" in source
|
||||
assert "STALE_IDENTITY_RECOVERY_BLOCK_REASONS" in source
|
||||
assert "FOCUSED_IDENTITY_TOTAL_PRICE_REASONS" in source
|
||||
assert "FOCUSED_TOTAL_PRICE_SAFE_SQL_REASON_LIST" in source
|
||||
assert r"\+|[xX]\s*\d|[**]\s*\d" in source
|
||||
assert "湛藍|麋香|海洋|玫瑰|薰衣草" in source
|
||||
assert "read_only_no_crawl_no_llm_no_db_write" in source
|
||||
@@ -166,6 +168,10 @@ def test_competitor_feeder_persists_all_match_attempt_outcomes():
|
||||
assert "COALESCE(la.best_match_score, 0) >= 0.76" in retryable_source
|
||||
assert "COALESCE(la.best_match_score, 0) >= 0.95" in retryable_source
|
||||
assert "strong_exact_spec_match" in retryable_source
|
||||
assert "focused_exact_total_price_safe" in retryable_source
|
||||
assert "focused_exact_identity_romand_juicy_lip_tint_2_catalog" not in retryable_source
|
||||
assert "focused_exact_identity_solone_longlasting_eyeliner" not in retryable_source
|
||||
assert "focused_exact_identity_summer_eve_full_skin_wash_2pack" not in retryable_source
|
||||
assert "REVALIDATABLE_REVIEW_BLOCK_SQL_REASON_LIST" in retryable_source
|
||||
assert "commercial_condition_gap" in source
|
||||
assert "variant_selection_review" in source
|
||||
|
||||
Reference in New Issue
Block a user