ATS
Writing

The honest relevance score.

Yogesh Laddha · August 2026 · 4 min read

TenderPulse scores government tenders against criteria a bid manager configures: industry, contract value, location, keywords. The obvious thing to build is a number between zero and one hundred, always present, always confident looking. The correct thing to build, and the one we shipped after fixing an early mistake, refuses to produce a number when it does not have enough signal behind it to trust one. This essay is about why nothing is a better answer than a fabricated number, and why explainability turned out to be a decision about the data model, not a decision about the interface.

We built the relevance engine for TenderPulse to solve an unglamorous problem. A bid manager configures a handful of criteria, industry, contract value, location, keywords, and each morning wants to know which of the tenders discovered overnight are worth reading in full out of the thousand or more a busy day can surface. The first version of that engine did what most scoring systems do by default. It produced a number for every tender against every configured criterion, always, on a scale that looked confident whether or not there was anything behind it.

The bug that taught us the rule

The first relevance engine inflated scores when a user had configured only a few criteria. A tender matching both of a user's two configured keywords looked like a near perfect match, even though the engine had almost nothing to reason from. Users trusted the number and acted on it, then noticed the pattern themselves: the fewer criteria they set, the more everything looked relevant. The fix was not a tuning pass on weights. It was a change in what the engine is allowed to say. The rationale for that change is written directly into the code, so the honesty rule outlives whoever touches that function next.

Silence is a valid output

The rule the engine follows now is simple to state and was not simple to accept: score only the criteria a user actually configured, and return nothing rather than a manufactured number when there is not enough signal to support one. A tender with no location information and a user who cares about location does not get a mediocre location score. It gets no location score, shown as such in the interface. That absence turned out to matter more than any single number the engine produces, because it is the one output type that cannot be quietly wrong. A number is always easier to build and always riskier to trust.

Evidence is a schema decision, not an interface feature

Once a score exists, the natural next question from a bid manager is why. TenderPulse answers it by decomposing every match into per criterion evidence rather than a bundled headline score: which criteria matched, on what basis, and which ones the engine had nothing to say about. That decomposition lives in the data the intelligence API returns, not layered on afterward by an interface component trying to explain a result it did not compute. Explainability treated as an interface feature is a paraphrase written after the fact, and it drifts from what the system actually did the moment either side changes. Explainability treated as a schema decision means the evidence is the same object the score was computed from. There is nothing left to reconstruct, because nothing was thrown away.

What a trustworthy score costs you

Refusing to score, and showing evidence per criterion, is more work than shipping one confident percentage. The interface has to render "not enough signal" as a legitimate state, not a loading spinner or an error. The product looks less finished in a screenshot, because a dashboard full of solid matches sells better than one with visible gaps. We shipped the gaps anyway, because the alternative was a system that quietly trained bid managers to stop reading the notices underneath the number, which is the one habit a bid desk cannot afford. Coverage is the entire value of TenderPulse: more than ten portals checked daily, over a thousand tenders discovered on some runs, precisely because a person cannot read that volume by hand. A score nobody trusts brings back the reading problem the product exists to remove.

The general version of the rule

A scoring system does not earn trust by being right most of the time. It earns trust by being legible about the times it does not know, and by building that admission into the data model rather than the marketing copy. If you are building anything that scores, ranks, or matches on partial information, and it currently produces a number for every input regardless of how little that input contains, you already have the bug we found in TenderPulse. The fix is not a smarter model underneath. It is a willingness to return nothing, and a willingness to show your evidence next to the score you did produce.

The relevance engine and its evidence model are documented in full, architecture included, at /work/tenderpulse.

Talk this through with the author

A Systems Strategy Session is thirty minutes on the architecture of your operation, with the engineer who wrote this.

Book a Systems Strategy Session