Case study 02
Entity resolution and layered access control
At an AI document automation platform for institutional financial services.
Extracted documents arrive as isolated records. The same entity appears across dozens of them, such as a statement, a notice, a compliance certificate, under names that don't explicitly match. "ABC Co.", "A.B.C. Ltd.", "ABC Company." Without something linking them, there's no way to see an entity's state over time, and answering a question as basic as "what's the current position for this borrower" means manual cross-referencing.
The access problem compounds it. Institutional clients don't grant blanket visibility. An analyst covering one region shouldn't see another region's holdings, and different clients organize that boundary differently. One by entity family, one by geography, one by internal company structure. Building a bespoke permission structure per client doesn't scale, and getting it wrong in a regulated environment is a compliance failure.
An entity resolution layer that maps document-level aliases to a canonical entity record. That record becomes the key linking everything else together.
- Reference-data enrichment from external datasets
- Entity-metadata validation, does this value make sense for this entity
- Point-in-time tracking across reporting periods
- Multi-channel distribution providing the same resolved data available through the UI, REST API, and MCP
A two-dimensional entitlements model sits on top of it. Access requires both to pass.
- Role-defined actions. What a user can do, view, edit, approve.
- Data-scoped entitlements. Which entities a user can see at all.

Rather than build a client-specific organization, it was crucial to identify the common structure behind governance and entitlements so it could be tailored and extended to fit every client's needs. This resulted in the architecture later being carried into an entirely new vertical with minimal incremental build.
Where enforcement lives is crucial for another reason. Ensuring AI has the same access and ability as the calling user. Putting it at the data layer, not the client layer, means an agent inherits the calling user's scope by construction.
There's no separate agent permission model to maintain, and no way for a new access channel to quietly bypass the rules that govern the others. When you add a surface such as an API, an MCP server, or an agent, you don't re-implement access control. It's already there.
As my core AI design principle, I believe this. Enforcing access at the agent or prompt level is a flimsy promise. Enforcing it at the data layer is a guarantee it can't even touch data it was never given in the first place.
Every organization deploying agents against internal data hits this. The instinct is to build permissions into the agent layer, because that's where the new capability lives. It's the wrong layer because it duplicates logic that already exists, and it drifts.
The durable version is, and should be, a bit boring. Resolve entities to something canonical, enforce access where the data lives, and let every channel inherit it. Then the question "what can this agent see" has the same answer as "what can this user see," and there shouldn't be complex logic baked on top.
This system led to more large enterprise client trust, and was extensible enough to ship a new vertical in weeks rather than months. This entity linkage also unlocks data enrichment, data tracking and notification, and point-in-time analysis, covered in the Data SITREP.