Pull a company field from six sources and you will get six answers. Not six wrong answers and one right one. Six answers that are each correct about a different thing, and a pipeline that has to pick one.
That choice is the product. The language model at the end writes a readable summary, which is the part people notice, and it is not where the difficulty lives.
The case that taught me this
Financial advisors sit inside a deep hierarchy: parent firm, the legal RIA or broker-dealer, the public brand, the branch, the wealth team, then the individual. An advisor can operate under a four-person team brand while the regulatory record points at a firm with fifteen thousand registered reps.
Generic enrichment flattens all of that into one company field. Whichever layer it happens to pick becomes the truth, and a rep walks into a call believing they are talking to an enterprise when they are talking to four people in Ohio. That is not a data quality problem you can fix downstream. The call is already wrong.
Resolution needs a stated rule, not a best guess
So the pipeline resolves in a fixed order. Wealth team if one exists. Otherwise the smallest client-facing entity that holds its own regulatory ID. Then the brand paired with the legal entity. Parent firm appears only when it is structurally distinct from everything below it.
Writing that order down was more valuable than any model upgrade. It turned an argument about output quality into a question about whether the rule was right, which is a question you can actually settle.
Matching is several problems wearing one name
Search by email, by full name, and by regulatory ID are not variations on a theme. They fail differently. Email carries a domain you can compare against a firm. A common full name resolves to the wrong person quietly and confidently. An ID is exact but frequently missing.
One fuzzy matcher across all three produces a system that is wrong in ways nobody can predict. Each path gets its own scoring and its own verification step instead: token overlap, domain against firm, normalized name scoring, positional weighting, then a profile check before anything is accepted.
Two things worth building early
Every tier writes its own provenance column. Months later I can still tell which source produced a given value, which has settled more disagreements than any dashboard I have built.
And no data is tracked separately from error. A lookup that ran correctly and found nothing is a fact about the world. A lookup that threw is a fact about your code. Pipelines that collapse those two into one status are the ones where nobody trusts the numbers six months in. One recent view of these pipelines shows 234,501 successfully enriched cells against 441 genuine errors, and that ratio only means something because misses are counted elsewhere.
What I would tell someone starting
Spend your first week on the resolution rule and the provenance schema. Spend your second on the difference between empty and broken. The model can be swapped in an afternoon. Those two decisions are load bearing for as long as the system runs.
The model writes the sentence. Reconciliation is what makes the sentence true.