From 6e70a6eb4731bcb1c1d991a9ef216e99bdca3676 Mon Sep 17 00:00:00 2001 From: OoO Date: Mon, 1 Jun 2026 02:28:21 +0800 Subject: [PATCH] =?UTF-8?q?V10.537=20=E6=8E=A5=E9=80=9A=20focused=20true?= =?UTF-8?q?=5Flow=20revalidation=20queue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TODO_NEXT_STEPS.txt | 1 + config.py | 2 +- docs/AI_INTELLIGENCE_MODULE_SOT.md | 1 + docs/memory/history_logs.md | 1 + services/competitor_price_feeder.py | 70 +++++++++++++++++++ ...t_competitor_match_attempts_persistence.py | 7 ++ 6 files changed, 81 insertions(+), 1 deletion(-) diff --git a/TODO_NEXT_STEPS.txt b/TODO_NEXT_STEPS.txt index f52e061..318fa3c 100644 --- a/TODO_NEXT_STEPS.txt +++ b/TODO_NEXT_STEPS.txt @@ -4,6 +4,7 @@ ================================================================================ 【已完成】 + - V10.537 將 V10.536 focused exact 線接進 `run_retryable_candidate_revalidation()` 窄門:既有 `true_low_confidence` 舊候選若命中新品線且無 hard veto / 型別、款式、香味、件數、組合阻擋,就可重新走 matcher 寫入正式價差;有色號/香味/即期等阻擋仍不進回刷。 - V10.536 補 PChome 高分 `true_low_confidence` 安全救回線:新增花美水 Relax 薰衣草潤滑凝膠 1.7g x3、St.Clare 私密呼呼慕斯 x2 / 慕斯+噴霧組、BIOPEUTIC 果酸煥膚水凝乳 20% 150ml、台塑生醫嬰兒沐浴洗髮 3 件組、Elizabeth Arden 八小時護唇膏 SPF15 3.7g x3、理膚寶水全面修復潤唇膏 7.5ml focused total-price 規則;這些都要求同品牌、同品線與同規格/同組合,仍保留色號、香味、款式敏感品的 `variant_selection_review` 防線。 - V10.535 修 ElephantAlpha 價格 trigger statement timeout:`price_drop_alert` / `market_opportunity` / DB evidence prefetch 改為先篩最近有效 PChome identity_v2,再用 `JOIN LATERAL` 查單一 SKU 最新 MOMO 價格;保留 match_score/tags/diagnostic evidence,避免 scheduler 週期性重查整張 `price_records`。 - V10.534 收緊 PChome rescore accepted gate:`no_match / price_basis=none / alert_tier=suppress` 不得再進 `rescore_accepted_current`,並新增 `--retract-unsafe-accepted` 退回舊的 unsafe accepted rows;Dashboard / daily / growth / OpenClaw 文案改為「重算待人工覆核」,避免操作員把人工覆核隊列誤解為可直接採用或可自動寫價。 diff --git a/config.py b/config.py index a07fb9b..1d943e5 100644 --- a/config.py +++ b/config.py @@ -402,7 +402,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '') # ========================================== # 系統版本與路徑 # ========================================== -SYSTEM_VERSION = "V10.536" +SYSTEM_VERSION = "V10.537" LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log') public_url = PUBLIC_URL # 用於模板顯示 diff --git a/docs/AI_INTELLIGENCE_MODULE_SOT.md b/docs/AI_INTELLIGENCE_MODULE_SOT.md index fb19b49..baa2853 100644 --- a/docs/AI_INTELLIGENCE_MODULE_SOT.md +++ b/docs/AI_INTELLIGENCE_MODULE_SOT.md @@ -100,6 +100,7 @@ SQL漏斗(~300筆) - PChome coverage 的 `attempt_status` / `rescore_accepted_count` / `actionable_review_count` 口徑必須與 review queue 對齊:統計「沒有新鮮有效 identity」的商品,而不是只統計「完全沒有 identity」的商品;已過期但可重算採用的 stale identity 仍應出現在待審數字中,避免 API 與 Dashboard 漏報。 - `run_retryable_candidate_revalidation()` 的自動回刷主戰場仍限 `low_score` / `refresh_low_score` / `recoverable_low_score`;`true_low_confidence` 只有在已補 focused exact 規則的窄範圍品線、舊分數 >= 0.95、`comparison_mode='exact_identity'`、含 `strong_exact_spec_match` 且不含 commercial / variant / count / bundle / refill 等阻擋理由時,才可進入重評,不得全面打開人工審核池。 - 高分 `true_low_confidence` 的自動救回只能用具名 focused exact 線逐批擴充;同品牌、同品線、同規格/同組合的花美水 Relax、St.Clare 私密呼呼、BIOPEUTIC 果酸、台塑生醫嬰兒沐浴洗髮、Elizabeth Arden 八小時護唇膏與理膚寶水全面修復潤唇膏可走 total-price,色號、香味、款式、即期品與 catalog selection 仍維持 review / veto。 +- `true_low_confidence` focused exact 線必須同步接入 `run_retryable_candidate_revalidation()` 的 SQL 窄門,讓舊候選可被批次回收;該窄門只允許具名品線豁免 `variant_selection_review`,其他 hard veto / 型別、款式、香味、件數、組合、refill、commercial condition 阻擋仍不得回刷。 - `/api/ai/pchome-match/backfill/status` 必須把近門檻重評池與過期 identity 救援池以只讀 `revalidation_preview` / `stale_recovery_preview` 曝光給操作員;預覽只復用正式候選 SQL 並受 limit / 60 秒快取限制,不啟動 PChome 搜尋、不呼叫 LLM、不寫 `competitor_match_attempts` / `competitor_prices`。重評 preview 必須先從最新 `competitor_match_attempts` 縮小候選,再用 `JOIN LATERAL` 取單一最新 MOMO 價;救援 preview 必須從過期 `competitor_prices` 小集合出發並用 `JOIN LATERAL` 取最新 MOMO 價,兩者都不得掃全量 `price_records`;Dashboard 只能顯示「可救援」觀測值,不得在未開啟 `PCHOME_STALE_RECOVERY_ENABLED` 時提供 recover-stale 執行按鈕;其中 `review_gated_count` 僅代表窄門 `true_low_confidence` exact 候選,不得被解讀為全量人工池可自動回刷。 - PChome re-score audit 預設必須先取每個 SKU 的最新 `competitor_match_attempts` 狀態,再套用 status / reason 篩選;舊低信心歷史候選只能透過 `--include-historical-candidates` 明確進入考古掃描,避免已入隊、已否決或已修正 SKU 被舊紀錄重新推回報表。 - production re-score `--apply-accepted` 僅可追加 `rescore_accepted_current` attempt 給人工覆核;執行後需清除 Dashboard / competitor intel cache,且必須抽查 `competitor_prices` / `competitor_price_history` 未新增正式價差。 diff --git a/docs/memory/history_logs.md b/docs/memory/history_logs.md index 3227dbf..50897ef 100644 --- a/docs/memory/history_logs.md +++ b/docs/memory/history_logs.md @@ -13,6 +13,7 @@ ## 📅 詳細更新日誌 (考古存檔) ### 2026-06-01:PChome 比價新鮮度操作閉環 +- **V10.537 focused exact revalidation queue 接線**: V10.536 只補 matcher 規則會影響新抓取,但無法批次回收既有 `true_low_confidence` 舊候選。`run_retryable_candidate_revalidation()` 新增 focused true-low 窄門:花美水 Relax、St.Clare 私密呼呼、BIOPEUTIC 果酸、台塑生醫、Elizabeth Arden 與理膚寶水若無 hard veto 與型別/款式/香味/件數/組合阻擋,可進重評;`variant_selection_review` 僅在這些具名安全線允許重跑,其他人工池不打開。 - **V10.536 高分 true_low_confidence focused exact 救回**: production 抽樣顯示剩餘未覆蓋集中在 `identity_veto` 與 `true_low_confidence`,其中部分 1.0 分樣本是同品牌、同品線、同規格/同組合,但因多件組或護唇/私密護理類型辨識保守而停在 manual review。新增花美水 Relax、St.Clare 私密呼呼、BIOPEUTIC 果酸、台塑生醫嬰兒沐浴洗髮、Elizabeth Arden 八小時護唇膏、理膚寶水全面修復潤唇膏的 focused total-price 規則;不放寬 `MIN_MATCH_SCORE`,也不移除色號/香味/款式防線。 - **V10.535 ElephantAlpha price trigger 查詢瘦身**: 正式 scheduler 日誌顯示 `price_drop_alert` trigger 對整張 `price_records` 做 `DISTINCT ON` 最新價造成 statement timeout。`price_drop_alert`、`market_opportunity` 與 EA DB evidence prefetch 改為先篩最近有效 PChome identity_v2 競品,再用 `JOIN LATERAL` 只查該 SKU 最新 MOMO 價格,保留 match_score/tags/diagnostic evidence 給 Telegram HITL,不再用全表最新價子查詢。 - **V10.534 rescore accepted gate 收緊與語意修正**: 正式 96 筆 `rescore_accepted_current` 盤點顯示多數仍是 `manual_review / identity_review`,且有 2 筆 `no_match / none / suppress` 混入。收緊 `classify_match_attempt_row()`:`no_match`、`price_basis=none`、`alert_tier=suppress` 不得 gate pass;新增 `--retract-unsafe-accepted` 可把既有 unsafe accepted 退回 `true_low_confidence`。Dashboard / daily / growth / OpenClaw 文案改成「重算待人工覆核」,明確表示仍需人工確認身份後才可寫正式價差。 diff --git a/services/competitor_price_feeder.py b/services/competitor_price_feeder.py index abbb013..d74f68c 100644 --- a/services/competitor_price_feeder.py +++ b/services/competitor_price_feeder.py @@ -90,12 +90,18 @@ REVALIDATABLE_REVIEW_BLOCK_REASONS = { "accessory_case_conflict", "named_component_quantity_conflict", } +FOCUSED_REVALIDATABLE_REVIEW_BLOCK_REASONS = REVALIDATABLE_REVIEW_BLOCK_REASONS - { + "variant_selection_review", +} REVALIDATABLE_REVIEW_SQL_REASON_LIST = ", ".join( f"'{reason}'" for reason in sorted(REVALIDATABLE_REVIEW_GATE_REASONS) ) REVALIDATABLE_REVIEW_BLOCK_SQL_REASON_LIST = ", ".join( f"'{reason}'" for reason in sorted(REVALIDATABLE_REVIEW_BLOCK_REASONS) ) +FOCUSED_REVALIDATABLE_REVIEW_BLOCK_SQL_REASON_LIST = ", ".join( + f"'{reason}'" for reason in sorted(FOCUSED_REVALIDATABLE_REVIEW_BLOCK_REASONS) +) STALE_IDENTITY_RECOVERY_BLOCK_REASONS = { "accessory_case_conflict", "aroma_lamp_style_selection_gap", @@ -1252,6 +1258,70 @@ class CompetitorPriceFeeder: ) ) ) + OR ( + la.attempt_status = 'true_low_confidence' + AND COALESCE(la.best_match_score, 0) >= 0.95 + AND COALESCE(la.hard_veto, false) = false + AND COALESCE(la.match_diagnostic_json->>'comparison_mode', 'exact_identity') = 'exact_identity' + AND NOT ( + COALESCE(la.match_diagnostic_json->'reasons', '[]'::jsonb) + ?| array[{FOCUSED_REVALIDATABLE_REVIEW_BLOCK_SQL_REASON_LIST}] + ) + AND ( + ( + COALESCE(p.name, '') LIKE '%花美水%' + AND COALESCE(la.best_competitor_product_name, '') LIKE '%花美水%' + AND lower(COALESCE(p.name, '')) LIKE '%relax%' + AND lower(COALESCE(la.best_competitor_product_name, '')) LIKE '%relax%' + AND COALESCE(p.name, '') LIKE '%薰衣草%' + AND COALESCE(la.best_competitor_product_name, '') LIKE '%薰衣草%' + AND COALESCE(p.name, '') LIKE '%潤滑凝膠%' + AND COALESCE(la.best_competitor_product_name, '') LIKE '%潤滑凝膠%' + ) + OR ( + COALESCE(p.name, '') LIKE '%聖克萊爾%' + AND COALESCE(la.best_competitor_product_name, '') LIKE '%聖克萊爾%' + AND COALESCE(p.name, '') LIKE '%私密呼呼溫和潔淨慕斯%' + AND COALESCE(la.best_competitor_product_name, '') LIKE '%私密呼呼溫和潔淨慕斯%' + ) + OR ( + ( + lower(COALESCE(p.name, '')) LIKE '%biopeutic%' + OR COALESCE(p.name, '') LIKE '%葆療美%' + ) + AND ( + lower(COALESCE(la.best_competitor_product_name, '')) LIKE '%biopeutic%' + OR COALESCE(la.best_competitor_product_name, '') LIKE '%葆療美%' + ) + AND COALESCE(p.name, '') LIKE '%果酸煥膚水凝乳%' + AND COALESCE(la.best_competitor_product_name, '') LIKE '%果酸煥膚水凝乳%' + ) + OR ( + COALESCE(p.name, '') LIKE '%台塑生醫%' + AND COALESCE(la.best_competitor_product_name, '') LIKE '%台塑生醫%' + AND COALESCE(p.name, '') LIKE '%嬰兒沐浴洗髮%' + AND COALESCE(la.best_competitor_product_name, '') LIKE '%嬰兒沐浴洗髮%' + AND COALESCE(p.name, '') LIKE '%嬰兒沐浴精%' + AND COALESCE(la.best_competitor_product_name, '') LIKE '%嬰兒沐浴精%' + AND COALESCE(p.name, '') LIKE '%嬰幼童洗髮精%' + AND COALESCE(la.best_competitor_product_name, '') LIKE '%嬰幼童洗髮精%' + ) + OR ( + COALESCE(p.name, '') LIKE '%雅頓%' + AND COALESCE(la.best_competitor_product_name, '') LIKE '%雅頓%' + AND COALESCE(p.name, '') LIKE '%八小時潤澤護唇膏%' + AND COALESCE(la.best_competitor_product_name, '') LIKE '%八小時潤澤護唇膏%' + AND lower(COALESCE(p.name, '')) LIKE '%spf15%' + AND lower(COALESCE(la.best_competitor_product_name, '')) LIKE '%spf15%' + ) + OR ( + COALESCE(p.name, '') LIKE '%理膚寶水%' + AND COALESCE(la.best_competitor_product_name, '') LIKE '%理膚寶水%' + AND COALESCE(p.name, '') LIKE '%全面修復潤唇膏%' + AND COALESCE(la.best_competitor_product_name, '') LIKE '%全面修復潤唇膏%' + ) + ) + ) ) ORDER BY la.best_match_score DESC NULLS LAST, latest_price.price DESC NULLS LAST, p.i_code LIMIT :limit diff --git a/tests/test_competitor_match_attempts_persistence.py b/tests/test_competitor_match_attempts_persistence.py index ba71583..548c5b6 100644 --- a/tests/test_competitor_match_attempts_persistence.py +++ b/tests/test_competitor_match_attempts_persistence.py @@ -149,6 +149,13 @@ def test_competitor_feeder_persists_all_match_attempt_outcomes(): assert "beauty foot" in retryable_source assert "蜜愛潤滑液" in retryable_source assert "嬰兒高純修護凝膠" in retryable_source + assert "FOCUSED_REVALIDATABLE_REVIEW_BLOCK_SQL_REASON_LIST" in retryable_source + assert "花美水" in retryable_source + assert "私密呼呼溫和潔淨慕斯" in retryable_source + assert "果酸煥膚水凝乳" in retryable_source + assert "嬰兒沐浴洗髮" in retryable_source + assert "八小時潤澤護唇膏" in retryable_source + assert "全面修復潤唇膏" in retryable_source assert "COALESCE(la.hard_veto, false) = false" in retryable_source assert "match_diagnostic_json->>'comparison_mode'" in retryable_source assert "?| array[" in retryable_source