Why we read every sold comp twice

Short answer: an eBay "sold" search finds sales that share your item's words, not sales of your item. A search for a commercial ice machine came back full of $23–$53 thermostat kits. Every one of them really sold, and none of them was an ice machine. So before a sold comp is allowed to price a GovDeals lot, we now check it one more time: is this actually the same product? Across 1,228 lots and 83,293 sold comps, the answer was "no" 40% of the time.

We've written before about why real sold data beats an AI's guess. This post is about the uncomfortable follow-up. Real sold data is only better if the sales are of the right thing, and keyword search can't tell the difference between the thing and everything sold to go with it.

Real sales of the wrong thing

Here is what the comp pile looked like for some ordinary government-surplus items. Every row is real: the comps the search returned, and what the price looked like before and after the wrong ones were removed.

The itemWhat the "sold" search returnedBefore → after vetting
Hoshizaki ice machine with binBin control switches and thermostat kits, $23–$53$36 → $2,495
PianoPlayer-piano rolls, a pedal extender, a tuning tool$35 → $300
Victory refrigeratorFridge magnets, a "V for Victory" button badge, replacement keys$20 → $152
Kärcher steam cleanerMop pads, nozzles, brushes for the steamer$40 → $149
Audiovisual cartGolf cart bags and a turntable cartridge$45 → $127
Samsung Galaxy XCover ProThe newer XCover 6 Pro and XCover 7 Pro$120 → $48
OTC Genisys scan toolOther brands' scanners and a cartridge reader module$90 → $20

Notice the direction. Most of the time the wrong comps are cheaper than the real thing: a part sells for a fraction of the machine it fits. That's the expensive failure for a reseller, because it hides the deal. An ice machine "worth $36" is a hard pass on any bid, and that is exactly the lot you want to be bidding on. But it runs the other way too. The XCover Pro was being priced partly off two newer, pricier models, which would have made a mediocre lot look like a win.

Why our filters didn't catch these

We already filter comps hard before they price anything. Lots and bundles go, because we price one unit and multiply. Anything that reads like a part or accessory goes ("charger for…", "replacement…", "fits…"). Comps missing the model number go. Salvage "for parts or not working" sales go. Those rules remove a lot of junk.

But rules match patterns, and the comps above beat them. "Hoshizaki Ice Machine Bin Control" contains every word in "Hoshizaki ice machine with bin". It doesn't say "for" or "replacement". By every keyword test, it's a perfect match. A person sees in half a second that it's a $40 switch. A regex never will.

A second opinion on every comp

So after the rules run, each surviving comp now goes to Jev, a product-matching classifier from TypeSafe AI. It isn't a chatbot: it takes a short piece of text plus one typed question and returns calibrated answers with probabilities. We ask it one question per comp. Here is the GovDeals listing, and here is an eBay sale: is that sale a fair per-unit comparison for what's being auctioned? It must pick one of five answers:

A comp stays only if Jev rates it at least 50% likely to be the same product. If fewer than three comps survive, the lot gets no eBay-sold price at all, and it falls back to our other sources or to an honest "unknown". It never falls back to the comps we just rejected.

One design choice matters more than it looks: Jev never sees the auction's price or the comp's price. The question is about identity only. A reseller's whole edge is a real comp that's surprisingly cheap or an auction that's surprisingly low. If the checker could see prices, it might learn that "cheap looks wrong" and throw out exactly the deals we exist to find.

We got the question wrong first

The first version of the question rejected 84% of comps. That sounds like a great filter until you read what it threw out.

GovDeals titles are vague and often plural: "dell latitude computers", "groen tilting skillet gas". Our first wording asked whether a comp matched the listing's brand, model and variant as one complete unit. Jev took that literally. A single Dell Latitude laptop is not "computers", so it was rejected as a multi-unit mismatch. A genuine Groen gas tilting skillet was rejected as a "different model", because the listing never named a model to match. Had we switched it on, one laptop lot's comp price would have collapsed from $219 to $25. A filter meant to remove wrong comps would have buried real deals.

We never let that version touch a price. Every change we make to pricing runs first in shadow mode: it calculates what it would do and records it beside the live price, and we read the results by hand before anything changes. The second version of the question was rewritten around how auction listings are actually written:

What the second version found

Lots checked1,228
Sold comps checked, one question each83,293
Comps rejected40% (it was 84% under the first wording)
Change in a typical lot's estimateNone: median after ÷ before = 1.00
Lots whose estimate moved more than 20%398 (about 1 in 3)
Biggest movers (top 10%)4.2× higher or more once parts and accessories were removed
Lots left with too few real comps to price164, which now fall back to other sources or "unknown"

That shape is what you'd hope for from a correctness fix. Most lots already had clean comps and didn't move. The ones that moved were mostly the ice-machine kind: whole products priced off their own spare parts. When we read the rejected comps of the biggest movers by hand, the rejections were overwhelmingly right.

"Overwhelmingly" is not "always". In one spot check Jev rejected a "Herman Miller Mirra 2 Stool" as a different model against a listing for a Mirra work stool. A person would probably keep that comp. No checker is perfect, which is why the rules stay in front of it, the "unknown" verdict stays behind it, and we keep reading samples by hand.

After those numbers and that read-through, we switched it on for live pricing this week.

The other half of the problem: the search itself

Vetting fixes comps that are wrong. While measuring it, we found a different problem: lots with no comps at all. Through mid-October, only about one sold search in four came back with anything usable. We assumed eBay was blocking our data provider. It wasn't. Their logs showed 99.8% of our requests succeeding. The searches were succeeding and finding nothing, for two reasons that were entirely our own doing:

The obvious next step is to let the classifier rescue those misses: when our word filters reject everything, ask it which of the returned sales are actually the product. That is built and running in shadow mode right now. It goes live only after we've read enough of what it keeps. The risk there is the opposite one, keeping a wrong product rather than rejecting a right one, so the samples we check are the comps it keeps.

Doing it 20,000 times a day, carefully

One unglamorous lesson to finish. Our first full run with the checker asked 20,000 questions and hit our own safety cap partway through. Each eBay search can return up to 200 sales, and we were asking about all of them, every time we refreshed a lot. Most of a lot's sales are the same from one week to the next, so most of those questions had already been answered. The checker now handles each lot's 40 most recent sales and remembers its verdicts, so a weekly refresh only asks about sales it hasn't seen. Comps past that 40 are simply left out of the price. They are never used without being checked.

None of this is a breakthrough. It's what "use real sold data" turns out to mean once you do it thousands of times a day: read every comp, measure each change before trusting it, and admit "unknown" when the real comps run out.

What this means if you flip

GavelGap scores every GovDeals listing in your browser sidebar. Resale comes from vetted sold comps, and we subtract buyer's premium, shipping and friction to show the profit gap. If the comps don't hold up, it says "unknown" instead of making up a number.

See how GavelGap works →

Frequently asked questions

Why aren't eBay sold listings enough to price an item?

Because a sold search matches words, not products. Search "Hoshizaki ice machine with bin" and the sold results are full of bin thermostat kits and control switches at $23–$53. They are real sales of the wrong item. In our checks, 40% of the sold comps that survived keyword filtering were not actually the product being priced.

What does a wrong comp do to a resale estimate?

It usually drags the estimate down, because parts and accessories sell for a fraction of the item they fit. Across 1,228 lots the typical estimate didn't move, but the top 10% rose about 4× once parts and accessories were removed. It can also inflate one: a Samsung XCover Pro was being priced partly off the newer XCover 6 and 7 Pro.

How does GavelGap decide whether a sold comp is the same product?

First, rule-based filters remove lots, bundles, accessories and off-model listings. Then each remaining comp goes to Jev, a product-matching classifier, with one question: is this sale a fair per-unit comparison for what the auction is selling? It answers same product, different model, accessory or part, multi-unit lot, or unrelated, with a probability. Neither the auction's price nor the comp's price is shown to it, so a cheap comp can't be thrown out for looking too cheap.

Does vetting comps make GavelGap's prices perfect?

No. It removes a large class of wrong-product comps, but it can still be wrong. In our spot checks it occasionally rejected a comp a person would keep. That's why every change runs in shadow mode first, we read the rejected comps by hand, and the rule-based filters and the "unknown" verdict stay in place as backstops.

Related: Why AI alone can't price your flips · What sold comps are · Receipts →