A user submits their email. You validate it, write a row to the database, and that part's clean. Then it scatters. A service somewhere looks up the company behind the domain. Another checks whether the address is disposable. A rules function, sitting three files away from either of those, decides if the lead is worth a rep's time. If it clears, a Slack message fires. And at some point, something loops back and updates the original record with everything that was just learned.
None of those lives in one place. The company lookup runs in a cron job. The disposable-email check is buried inside the signup handler. The routing rules live in a service nobody quite remembers writing. The Slack notification comes from a queue consumer that hasn't been touched in eight months, and everyone's a little afraid to touch it now.
Ask five engineers to draw this from memory and you'll get five different diagrams, and honestly, none of them will be complete. That's not a documentation gap. It's a sign the workflow was never actually designed. It accumulated.
Why it ends up this way
Nobody sits down and decides to build a distributed, five-hop lead enrichment process. It happens one ticket at a time.
Someone notices the company-lookup API is flaky, so a retry gets bolted on. Someone else wants visibility, so a Slack ping gets added. Traffic grows, so the lookup moves into a background job so it doesn't block the signup request. A new enrichment vendor gets added, and now there's a second lookup with its own error handling.
Every one of these changes was the right call in isolation. The problem is that "right call" decisions don't compound into a coherent system on their own. They compound into a scavenger hunt.
How to tell if you have one
You probably don't need to guess. A few questions usually settle it fast:
- Can one person explain the full path from "user signs up" to "lead reaches a rep," without opening more than one file? If not, the workflow is hidden.
- When enrichment fails silently, does anyone find out, or does the lead just sit unrouted? Silent failure is the clearest sign that no single piece of code owns the outcome, only a step.
- If you had to add a new enrichment source tomorrow, would you know every place that needs to change? If the answer takes more than a minute, the logic isn't centralized. It's distributed by accident.
If any of those gave you pause, the workflow already exists. You just don't have a place to look at it.
What actually breaks
Two things, mostly.
Debugging turns into archaeology. A lead didn't get routed. Was it the domain lookup that failed, or did it fail the disposable-email check, or did the Slack call time out after everything else succeeded? Nothing tells you. You're stitching together logs from three services and hoping the timestamps line up.
Changes cost more than they should. Swapping enrichment vendors, adding a new qualification rule, changing the Slack channel based on lead score: each of these touches code in places that have nothing to do with each other conceptually, but everything to do with each other functionally. The blast radius of a small change is larger than it looks, because the actual dependency graph isn't written down anywhere. It's implied.
What changes when the steps are explicit
The fix isn't more logging or better diagrams drawn after the fact. It's giving the sequence (lookup, disposable check, scoring, routing, notification, record update) a single definition, so the order of operations and the failure points are visible before something breaks, not reconstructed after.
That's the difference between a workflow platform and application code with retries duct-taped on: one tells you where a lead is stuck by looking at it; the other tells you by grepping five repos.
We built a working version of this exact lead enrichment process using Unmeshed and Supabase, mapping each step (lookup, validation, scoring, routing, notification) as one explicit sequence instead of five separate pieces of code. If your enrichment flow already looks like the one described above, it's worth seeing what it looks like once it's not scattered anymore.
Top comments (0)