Appearance
M1, M2, and M3 valuation engines
Date: 2026-09-14.
Environment: staging.
Rule version: pdf-2026-09-14.
M1 values a raw card, M2 a sealed product, and M3 a graded card. Identity and evidence never cross engine boundaries. A missing value remains null, never 0.
Sources in the current environment
Snag does not have open Cardmarket or eBay API access. The backend therefore makes no live call to either service and never turns a missing source into fabricated data.
| Source | Staging use |
|---|---|
| CardTrader | structured alternative NM anchor for recent M1; always labelled cardtrader |
| GCC | exact successful sales for M2/M3 |
| eBay/Cardmarket | observations only through an authorised, reviewed feed or import |
| Personal value | local app fallback when no qualified quote can be produced |
Observations live in valuation_evidence, decisions in valuation_decisions, and the M1 ladder in m1_prices/m1_refusals.
M1 — raw cards
The document covers Poor, Played, Light Played, Good, Excellent, and Near Mint. Mint is outside its scope.
Recent blocks
For Mega Evolution, Scarlet & Violet, and Sword & Shield, the engine starts with the first same-language NM price and applies:
| Condition | Factor |
|---|---|
| Near Mint | 100% |
| Excellent | 85% |
| Good | 60% |
| Played | 40% |
| Poor | 20% |
The PDF defines no Light Played factor. Snag refuses to invent one and offers a personal value instead. On staging, CardTrader can technically replace the unavailable Cardmarket anchor; the alternative source remains visible in the response.
Other blocks
M1 uses only successful eBay sales in the exact condition. It selects the first non-empty window—30 days, 3 months, 6 months, then 12 months—and averages it. Without proven eBay coverage or without a sale in 12 months, no quote is published and a personal value is offered.
GET /cards/:id/m1-prices?language=&variant= returns all six conditions in one request. The app switches values immediately when the user changes condition.
M2 — sealed products
Exact identity includes product, language, format/SKU, variant, and currency.
- Take the first same-language Cardmarket price.
- Add all successful eBay/GCC sales from the first non-empty window: 30 days, 3 months, 6 months, 12 months.
- Give the anchor the same weight as one sale.
- Calculate the mean, remove values outside ±30%, and recalculate once.
- Without a sale in 12 months or without a qualified anchor, publish no quote.
GCC can supply sales, but a GCC-only mean is not presented as a PDF-compliant M2 quote. Until an authorised Cardmarket anchor is available, the frontend shows the unavailable state and allows a personal value.
M3 — graded cards
Card, language, variant, grading company, grade, and qualifier must match exactly. M3 never extrapolates from raw and never converts grades between graders.
- Clear market: at least three exact eBay/GCC sales in the last three calendar months; mean, remove values outside ±30%, recalculate.
- Unclear market: at least one exact sale in 12 months; the lowest exact, fixed, active, plausible Cardmarket/eBay listing replaces the latest sale only when it is cheaper.
- Doubtful market: no exact sale in 12 months; no quote, personal value allowed.
When eBay/Cardmarket listings are unavailable, the latest exact sale remains the best evidence and the decision carries listings-unavailable. A GCC listing is not silently substituted.
Frontend contract
GET /valuations serves one exact M2/M3 market and GET /valuations/batch supplies collection totals without N+1 calls. Quotes older than 48 hours are not served. The frontend shows source, sample size, and freshness, and offers a personal M1/M2/M3 value whenever the engine refuses to price.
This delivery targets staging. It is not a merge or deployment of main to production.