Matching 1,170 exporters against 71,349 evidence rows
In BYRIS an opportunity is a company that might buy from one specific Indonesian exporter. Any matcher can put a number on that pair. A number nobody can argue with is useless at a sales desk, because someone has to pick up the phone on the strength of it.
The claim is the easy part
So every claim points at a row. A claim is a statement about a buyer, and it is allowed to exist only when collected evidence backs it. Right now that is 71,349 rows across 1,170 exporters. When a number looks wrong you do not re-run the model, you open the row behind it and read what it actually said.
- Collected by a Python pipeline into Postgres, so provenance sits next to the claim.
- Scored by a Go matcher, because the scoring pass is the part that has to hold up under a re-run.
- Read on a SvelteKit desk that shows one opportunity with its matched candidates beside it.
What was actually hard
Not the algorithm. Keeping the provenance attached once the pipeline grew: the same company arriving twice under a different name, a source that stops answering, a score that quietly moves because a normalisation step changed underneath it. Most of the work went into making it impossible for the second thing to happen without anyone noticing.
What I would do differently
Start from the review queue instead of the score. The first version optimised a number. The useful version lets a person disagree with a single row and see what that does to the pair.
Evidence first, score second. That is the whole design.