Build in public
Lead routing rules a human won't override
A lead routing rule is only as good as the number of times a human leaves it alone.
I built lead routing before I had anyone to route leads to. There's still no override rate to show you, because LeadSurface records that a human reassigned a lead but not which rule they overruled. What I have instead is a design decision and a flag in the schema that I now think is the most useful column in it.
My first question was the comfortable one. How do we route a lead to the right person? That one has an answer and a dashboard. Every lead has an owner, coverage reads 100%, ship it. The better question was sitting underneath it. How do we find out when we routed it wrong?
What are lead routing rules?
Lead routing rules are ordered conditions that decide which person owns an incoming lead. Each rule pairs a match against the lead (a named competitor, a source, a signal type, or a keyword) with an owner. Rules evaluate in priority order, first match wins, and a lead matching nothing stays unassigned rather than going to somebody at random.
In LeadSurface the whole decision is one function, pickAssignee, and it's deliberately boring:
export const pickAssignee = (ev: Routable, rules: RoutingRule[]): string | null => {
for (const rule of rules) {
if (rule.enabled && matches(rule, ev)) return rule.assignee_user_id;
}
return null;
};
Four match types. It touches no database, no clock, and no network. It runs at classification time, right after the model decides what a post is, so a buying signal gets a signal type, a score, and an owner on the same write. Change the rules and unviewed leads are reevaluated against the new set.
The purity isn't decoration. Because the function takes an event and a list of rules and returns a string or null, the test file beside it needs no database, no fixtures, and no mocks. Seven cases cover every match type, first-match-wins, disabled rules, and the empty result. That's the whole feature, verified in under a hundred lines. I trust the routing because it's trivially checkable, and it's trivially checkable because it touches nothing. The scar is that pickAssignee can't sort itself, so priority ordering lives in an ORDER BY priority ASC at both call sites.
Why do reps override automatic routing?
Because they have more context than the rule does, and their week is already full of triage. The rule sees five fields. The rep knows the account was worked six months ago, or that the poster reports to someone they already emailed. Overrides aren't rebellion. They're the rule meeting a fact it was never given.
Salesforce's State of Sales, sixth edition, surveyed 5,500 sales professionals in 2024 and found reps spend 30% of an average week selling. Of the rest, 9% goes to researching prospects, 8% to prospecting, and 8% to prioritizing leads and opportunities. A quarter of the week deciding who to talk to, before a single conversation. (A seventh edition exists reporting a higher selling share. Its PDF was unreachable, so I quote the verified sixth.)
The rep is already doing assignment by hand. If your rules disagree with the judgment they were going to make anyway, they redo the work and the dashboard keeps reporting full coverage.
This is where the skeptical case about signal tooling has real teeth. Alexa Grabell, who runs Pocus and sells signal software, wrote in September 2025:
Reps are drowning in signals and expected to be detectives, manually connecting dots ...
Demandbase's Jay Tuel added a month later that signals don't scale linearly in value, so adding more won't necessarily improve precision or add revenue. Forrester's Brett Kahnke, reporting the Q1 2023 Global B2B Intent Data Survey, put it plainer. More companies expected benefits than achieved them, especially for sales use cases and revenue growth, and the top execution challenge was identifying the specific contact to target.
That's three people who sell into this category, all saying the tooling has outrun the workflow. They're right, and routing is where it shows. Assignment is the moment a signal stops being a number and becomes somebody's job.
How should a lead routing rule be evaluated?
By what it does when it's wrong, not by how often it fires. Every match type buys precision somewhere and loses it somewhere else, and the losses are what a feature comparison leaves out. Here are the four types LeadSurface supports, each with its failure attached.
| Match type | How it matches | Good at | Where it breaks |
|---|---|---|---|
| Competitor | Case-insensitive equality against the competitor the classifier named | Territory by account, how most teams already divide work | Only as good as the classifier. A competitor named in passing routes like one being abandoned |
| Signal | Exact match on the classified signal type | Switching intent to a senior rep, complaints to support | Coarse. Every switching lead lands on one person |
| Source | Exact match on the platform tag | A rep who knows one community's norms and posts there credibly | Says nothing about the buyer. Fine as a fallback, weak as a first rule |
| Keyword | Case-insensitive substring across title and body | Codenames no classifier models | A substring has no idea what a word means. "Sunset" hits the product and the photograph |
| No match | Nothing fires | An explicit unrouted bucket instead of a wrong owner | Only works if somebody reads that bucket. Silence looks identical to zero leads |
The last row is the one I'd push hardest. A default catch-all rule guarantees full coverage, and it guarantees the leads nobody wrote a rule for look identical to the ones somebody chose. Leaving them null is a worse dashboard and a truer one.
What happens when a human disagrees with the routing?
The reassignment wins, permanently. Assigning a lead by hand sets assignee_overridden = true on that row, and every automatic rerouting pass excludes overridden leads by name. Rerouting also skips anything a rep has opened. The human decision outranks the rule, which is the right default when the rule was written by someone guessing.
The reroute query says it in two lines:
AND viewed_at IS NULL
AND assignee_overridden = false
That's the protective reading, and it's all the flag does today. The more interesting reading is that an override is a feedback signal.
Consider what an override is. A human looked at a lead, looked at who the system gave it to, and disagreed enough to spend a click fixing it. That's a labeled example, and the only one a routing system gets for free, because nobody fills in a survey about routing quality. A rule people accept and a rule people undo every time report identically on coverage. One is working. The other is a tax your team pays quietly, forever.
Coverage is an output metric. Override rate is an accuracy metric. Only one of them can tell you a rule is wrong.
Now the part where I hold myself to it. LeadSurface stores the flag and not the history. A manual assignment overwrites assignee_user_id in place, so the row remembers that a human intervened and forgets what the system decided and which rule decided it. Enough to protect the lead, not enough to grade the rule. It needs the rule ID that made the call and the assignee it replaced, written at override time, so rules can be ranked by how often humans undo them. That's a schema change and a report. It isn't built, and I'm naming it here so the omission is on the record. This is what I intend to measure, not what I've measured.
Why does routing have to be fast?
Because the window closes when the shortlist forms, not when a timer expires. Every hour a lead sits with the wrong owner is an hour the buyer spends collecting names, and early names get chosen. Misrouting doesn't cost you minutes. It costs a whole reassignment cycle, and that cycle starts only if somebody notices.
Later is how leads die, and I want to be careful about why, because the usual argument here is folklore. The "respond in five minutes or lose the deal" multiplier has no reachable primary source. The real study underneath it is Harvard Business Review, March 2011, an audit of 2,241 US companies where 23% never responded to a test lead at all. It's 15 years old, it's about web forms, and it was co-authored by the CEO of a company selling response-time software. That isn't a foundation.
The durable argument is about shortlists. 6sense's 2025 buyer research found buyers choose from their day-one shortlist about 95% of the time, and 83% of buyers had their requirements fully or mostly defined before speaking to any seller. Liam Moroney put the consequence bluntly in MarTech in March 2024:
If you're not in the consideration set by the time they come in-market, you are almost certainly already too late.
That's the real clock. A competitor-switching thread is one of the few moments the consideration set is still being assembled in public, and it closes because the buyer picks a replacement, not because an SLA lapsed. How fast it closes is practitioner observation, not a measured half-life. Routing is the last hop before a human reads any of it. Get it wrong and the fastest ingest pipeline in the world delivers a lead into a queue nobody opens.
One argument against all of this is worth ending on. Ebsta and Pavilion analyzed 655,000 opportunities across 387 companies and ranked channels by efficiency: partner referral 1.3x, organic inbound 1.2x, and outbound 1.05x. Improving outbound targeting improves the third-best channel, and 78% of sellers missed quota last year. I have no rebuttal, and I wouldn't trust one built from the vendor lift figures the category cites. The claim I defend is narrower. Running the third-best channel on a thread where somebody named their own problem beats running it on a purchased list.
LeadSurface watches public developer communities, classifies each post, and hands the ones worth a reply to a named person with the source thread attached. Routing rules pick the person. A human decides and sends. Nothing goes out automatically.
Test it without my code. Write down who should own a lead about your biggest competitor, then look at the last 10 your team worked and see who ended up with them. The gap is your override rate. You have one already. You're not measuring it.
The routing rule is not the product. The record of when the rule was wrong is.