From 8b4bcdf277d98268fbb0f9582e650ba133c3d785 Mon Sep 17 00:00:00 2001 From: OoO Date: Sun, 24 May 2026 12:14:34 +0800 Subject: [PATCH] V10.399 demote named variant catalog alerts --- config.py | 2 +- docs/memory/history_logs.md | 1 + services/marketplace_product_matcher.py | 26 ++++++++++++++++++++++- tests/test_marketplace_product_matcher.py | 16 ++++++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/config.py b/config.py index b3ce577..4ac1018 100644 --- a/config.py +++ b/config.py @@ -325,7 +325,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '') # ========================================== # 系統版本與路徑 # ========================================== -SYSTEM_VERSION = "V10.398" +SYSTEM_VERSION = "V10.399" LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log') public_url = PUBLIC_URL # 用於模板顯示 diff --git a/docs/memory/history_logs.md b/docs/memory/history_logs.md index 0a478f2..de4c075 100644 --- a/docs/memory/history_logs.md +++ b/docs/memory/history_logs.md @@ -13,6 +13,7 @@ ## 📅 詳細更新日誌 (考古存檔) ### 2026-05-24:PChome 近門檻身份回收第二輪 +- **V10.399 多香味 catalog 價格告警降級**: marketplace matcher 新增 `variant_selection_review`,當一側是無明確選項的商品線、另一側列出多個具名香味/款式選項時,允許同款身份回收但只進 `identity_review`,不直接進 `price_alert_exact`。首個正式案例是 HH 女性私密衣物抗菌手洗精 200ml 對 PChome 白麝香/清新花園/寶貝粉香多香味 listing;此規則避免把多香味 catalog 價格誤當單一 variant 精準比價。 - **V10.398 true low confidence 保守回收**: marketplace matcher 針對正式前段 `true_low_confidence` 補一輪 focused exact identity lines,讓 Baan 嬰兒修護唇膏、植村秀 3D 極細防水眼線膠筆、YSL 恆久完美透膚煙染腮紅、HH 私密植萃美白緊緻凝露、Lab52 學習刷牙漱口水、Benefit 經典菲菲染唇液、Herb24 晨霧純精油擴香儀、Pavaruni 40 香味 10ml 精油與 GATSBY 爆水擦澡濕巾等近門檻真同款可被回收;未放寬 `MIN_MATCH_SCORE`。同版保留 peripera 多色任選對單一色號、LUNASOL 頰彩對眼彩組、MUJI 細軸棉棒對黑色棉棒的低信心保護,並讓多組件套組即使達強身份證據也停在 `identity_review`,避免總價被誤當精準價格告警。 ### 2026-05-21:瀏覽器測試守門與 PChome 熱路徑優化 diff --git a/services/marketplace_product_matcher.py b/services/marketplace_product_matcher.py index acb0139..b6bc1e9 100644 --- a/services/marketplace_product_matcher.py +++ b/services/marketplace_product_matcher.py @@ -503,6 +503,8 @@ VARIANT_OPTION_COLOR_WORDS = { "梔子花", "白麝香", "黑麝香", + "清新花園", + "寶貝粉香", "青檸羅勒", "炭木香", "無花果", @@ -1630,6 +1632,7 @@ def _build_evidence_flags( flags.append("catalog_count_omission") for reason in ( "unit_comparable", + "variant_selection_review", "variant_option_conflict", "variant_descriptor_conflict", "count_conflict", @@ -1682,7 +1685,7 @@ def _classify_match_quality( and (direct_spec_evidence or (shared_anchor and token_score >= 0.62 and sequence_score >= 0.58)) ) if strong_identity_evidence and not catalog_count_omission: - if multi_component_pair: + if multi_component_pair or "variant_selection_review" in reason_set: return "exact", "manual_review", "identity_review" return "exact", "total_price", "price_alert_exact" @@ -1760,6 +1763,9 @@ def score_marketplace_match( variant_option_conflict = _has_explicit_variant_option_conflict(left, right, shared_anchor) if variant_option_conflict: reasons.append("variant_option_conflict") + variant_selection_review = _has_named_variant_selection_review(left, right, shared_anchor) + if variant_selection_review: + reasons.append("variant_selection_review") hard_veto = brand_conflict or spec_conflict if bundle_offer_conflict: @@ -2936,6 +2942,24 @@ def _has_explicit_variant_option_conflict( return True +def _has_named_variant_selection_review( + left: ProductIdentity, + right: ProductIdentity, + shared_anchor: str, +) -> bool: + left_options = _explicit_variant_option_tokens(left) + right_options = _explicit_variant_option_tokens(right) + if bool(left_options) == bool(right_options): + return False + + option_identity = left if left_options else right + named_options = {option for option in (left_options or right_options) if not option.isdigit()} + if len(named_options) < 2: + return False + text = option_identity.searchable_name + return _is_multi_variant_catalog_listing(option_identity) or bool(re.search(r"[//、,&&]", text)) + + def _search_core_score(token: str, all_tokens: set[str]) -> tuple[int, int, str]: cleaned = _clean_search_phrase(token) if not cleaned: diff --git a/tests/test_marketplace_product_matcher.py b/tests/test_marketplace_product_matcher.py index d79300a..d68f736 100644 --- a/tests/test_marketplace_product_matcher.py +++ b/tests/test_marketplace_product_matcher.py @@ -843,6 +843,22 @@ def test_marketplace_matcher_ignores_quantity_plus_markers_inside_component_spec assert "multi_component_count_conflict" not in diagnostics.reasons +def test_marketplace_matcher_keeps_named_scent_catalog_in_identity_review(): + from services.marketplace_product_matcher import score_marketplace_match + + diagnostics = score_marketplace_match( + "【HH草本新淨界】女性私密衣物抗菌手洗精200ml(私密衣物手洗 衣物手洗精)", + "HH女性私密衣物抗菌手洗精 200ml (白麝香&清新花園&寶貝粉香)", + momo_price=399, + competitor_price=356, + ) + + assert diagnostics.score >= 0.76 + assert diagnostics.hard_veto is False + assert diagnostics.alert_tier == "identity_review" + assert "variant_selection_review" in diagnostics.reasons + + def test_marketplace_matcher_promotes_multi_variant_catalog_listings(): from services.marketplace_product_matcher import score_marketplace_match