snipe/tests/trust/test_metadata.py
pyr0ball bccedb1fe5 fix(trust): treat feedback_ratio=0.0 as missing data for buyer-only/returning sellers (#52)
eBay omits the 12-month positive percentage for returning sellers and
buyer-only accounts with no recent sales. Previously ratio=0.0 with
count>0 triggered established_bad_actor; now it returns None from the
scorer (score_is_partial=True) and emits a soft no_recent_seller_data
flag instead. ratio=0.0 with count=0 is still treated as no-history.
2026-05-04 09:24:27 -07:00

68 lines
2.4 KiB
Python

from app.db.models import Seller
from app.trust.metadata import MetadataScorer
def _seller(**kwargs) -> Seller:
defaults = dict(
platform="ebay", platform_seller_id="u", username="u",
account_age_days=730, feedback_count=450,
feedback_ratio=0.991, category_history_json='{"ELECTRONICS": 30}',
)
defaults.update(kwargs)
return Seller(**defaults)
def test_established_seller_scores_high():
scorer = MetadataScorer()
scores = scorer.score(_seller(), market_median=1000.0, listing_price=950.0)
total = sum(scores.values())
assert total >= 80
def test_new_account_scores_zero_on_age():
scorer = MetadataScorer()
scores = scorer.score(_seller(account_age_days=3), market_median=1000.0, listing_price=950.0)
assert scores["account_age"] == 0
def test_low_feedback_count_scores_low():
scorer = MetadataScorer()
scores = scorer.score(_seller(feedback_count=2), market_median=1000.0, listing_price=950.0)
assert scores["feedback_count"] < 10
def test_suspicious_price_scores_zero():
scorer = MetadataScorer()
# 60% below market → zero
scores = scorer.score(_seller(), market_median=1000.0, listing_price=400.0)
assert scores["price_vs_market"] == 0
def test_no_market_data_returns_none():
scorer = MetadataScorer()
scores = scorer.score(_seller(), market_median=None, listing_price=950.0)
# None signals "data unavailable" — aggregator will set score_is_partial=True
assert scores["price_vs_market"] is None
def test_zero_ratio_with_nonzero_count_returns_none():
"""ratio=0.0 with count>0 means eBay didn't show a 12-month percentage.
Must return None (missing data) not 0 (catastrophically bad)."""
scorer = MetadataScorer()
scores = scorer.score(
_seller(feedback_ratio=0.0, feedback_count=117),
market_median=None, listing_price=500.0,
)
assert scores["feedback_ratio"] is None
def test_zero_ratio_with_zero_count_scores_low():
"""feedback_ratio=0.0 with count=0 is a real 'no data at all' case, not missing."""
scorer = MetadataScorer()
scores = scorer.score(
_seller(feedback_ratio=0.0, feedback_count=0),
market_median=None, listing_price=500.0,
)
# count=0 means zero_feedback; ratio=0 with count=0 is the standard no-history path
# (not the "missing 12-month window" path)
assert scores["feedback_ratio"] == 5 # ratio < 0.90 → 5