V10.534 收緊 PChome rescore 覆核語意
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s

This commit is contained in:
OoO
2026-06-01 02:14:34 +08:00
parent f3c37c471d
commit 2a11ba26a7
17 changed files with 368 additions and 26 deletions

View File

@@ -154,9 +154,9 @@ def test_dashboard_match_status_shows_rescore_accepted_review_state():
"error_message": "matcher_rescore=accepted_current; reasons=strong_exact_spec_match",
})
assert status["label"] == "重算可採用待審"
assert status["label"] == "重算待人工覆核"
assert status["tone"] == "watch"
assert "人工採用後才寫入正式 PChome 價差" in status["summary"]
assert "人工確認身份後才寫入正式 PChome 價差" in status["summary"]
def test_dashboard_match_status_uses_specific_matcher_reason_labels():

View File

@@ -132,10 +132,12 @@ def test_competitor_review_queue_is_canonical_unit_price_handoff():
assert "coverage.stale_matches" in growth_template
assert "coverage.unit_comparable_count" in growth_template
assert "coverage.rescore_accepted_count" in growth_template
assert "重算待人工覆核" in growth_template
assert "coverage.manual_accept_count" in growth_template
assert "coverage.manual_reject_count" in growth_template
assert "coverage.manual_unit_price_count" in growth_template
assert "comp_coverage.rescore_accepted_count" in daily_template
assert "重算待人工覆核" in daily_template
assert "comp_coverage.stale_matches" in daily_template
@@ -295,7 +297,7 @@ def test_review_decision_brief_is_shared_by_openclaw_and_ppt():
assert brief["auto_execute_blocked_count"] == 1
assert brief["severity_counts"]
assert brief["data_quality_counts"] == {"complete": 1}
assert "人工覆核後採用同款" in brief["text"]
assert "人工確認身份後採用同款" in brief["text"]
assert "HITL" in brief["text"]
assert "DDAO4C-A79050612" in brief["text"]

View File

@@ -131,6 +131,42 @@ def test_match_attempt_rescore_audit_keeps_variant_selection_review_out_of_gate_
assert "variant_selection_review" in decision.reasons
def test_match_attempt_rescore_audit_keeps_no_match_out_of_gate_pass(monkeypatch):
from types import SimpleNamespace
import services.competitor_match_attempt_rescore_audit as audit
monkeypatch.setattr(
audit,
"score_marketplace_match",
lambda *_args, **_kwargs: SimpleNamespace(
score=0.96,
hard_veto=False,
comparison_mode="exact_identity",
match_type="no_match",
price_basis="none",
alert_tier="suppress",
reasons=("strong_exact_spec_match",),
),
)
decision = audit.classify_match_attempt_row({
"sku": "NO-MATCH",
"attempt_status": "true_low_confidence",
"momo_product_name": "MOMO candidate",
"best_competitor_product_name": "PChome candidate",
"momo_price": 100,
"best_competitor_price": 90,
"best_match_score": 0.96,
})
assert decision.suggested_status == "low_score_current"
assert decision.gate_pass is False
assert decision.match_type == "no_match"
assert decision.price_basis == "none"
assert decision.alert_tier == "suppress"
def test_match_attempt_rescore_audit_skips_missing_identity_text():
from services.competitor_match_attempt_rescore_audit import classify_match_attempt_row
@@ -365,6 +401,69 @@ def test_match_attempt_rescore_retracts_variant_review_from_accepted_queue():
assert after_rows == []
def test_match_attempt_rescore_retracts_unsafe_accepted_queue(monkeypatch):
from types import SimpleNamespace
import services.competitor_match_attempt_rescore_audit as audit
engine = create_engine("sqlite:///:memory:")
with engine.begin() as conn:
_create_match_attempts_table(conn)
conn.execute(text("""
INSERT INTO competitor_match_attempts
(sku, source, attempt_status, momo_product_id, momo_product_name,
momo_price, candidate_count, best_competitor_product_id,
best_competitor_product_name, best_competitor_price,
best_match_score, diagnostic_codes, error_message, attempted_at)
VALUES
(
'NO-MATCH', 'pchome', 'rescore_accepted_current', 1,
'MOMO candidate',
100, 1, 'PCHOME-NO-MATCH',
'PChome candidate',
90, 0.96,
'["strong_exact_spec_match"]',
'matcher_rescore=accepted_current', '2026-05-24 14:24:17'
)
"""))
monkeypatch.setattr(
audit,
"score_marketplace_match",
lambda *_args, **_kwargs: SimpleNamespace(
score=0.96,
hard_veto=False,
comparison_mode="exact_identity",
match_type="no_match",
price_basis="none",
alert_tier="suppress",
reasons=("strong_exact_spec_match",),
),
)
rows = audit.fetch_unsafe_rescore_accept_review_rows(conn, limit=10)
stats = audit.retract_unsafe_rescore_accept_reviews(conn, rows)
latest_status = conn.execute(text("""
SELECT attempt_status
FROM competitor_match_attempts
WHERE sku = 'NO-MATCH'
ORDER BY attempted_at DESC, id DESC
LIMIT 1
""")).scalar()
error_message = conn.execute(text("""
SELECT error_message
FROM competitor_match_attempts
WHERE sku = 'NO-MATCH'
ORDER BY attempted_at DESC, id DESC
LIMIT 1
""")).scalar()
assert [row["sku"] for row in rows] == ["NO-MATCH"]
assert stats["retracted"] == 1
assert latest_status == "true_low_confidence"
assert "rescore_retracted_unsafe_accepted_current" in error_message
def test_match_attempt_rescore_materialize_does_not_enqueue_veto():
from services.competitor_match_attempt_rescore_audit import materialize_rescore_accept_reviews

View File

@@ -188,7 +188,7 @@ def test_dashboard_v2_is_production_default_and_uses_real_dashboard_data():
assert "overview.pending_priority" in dashboard
assert "overview.review_queue" in dashboard
assert "需單位價 {{ overview.unit_comparable_count" in dashboard
assert "重算可採用 {{ overview.rescore_accepted_count" in dashboard
assert "重算待覆核 {{ overview.rescore_accepted_count" in dashboard
assert "{% if review_total_is_estimated %}約 {% endif %}" in dashboard
assert "filter='ai_picks'" in dashboard
assert "filter='pchome_review'" in dashboard

View File

@@ -158,7 +158,7 @@ class TestKPIComputation:
assert "fetch_competitor_coverage" in source
assert "summarize_review_decision_envelopes" in source
assert "review_decision_text" in source
assert "重算可採用待審" in source
assert "重算待人工覆核" in source
# ═══════════════════════════════════════════════════════════════════════════