Three things I left out of the permission intersection demo, on purpose

The permission intersection demo from the last post is deliberately minimal: one function, one hardcoded agent scope, one in-memory role map. That's the right size for proving the model works. It is the wrong size for anything touching real data, and the README says so on purpose. Three specific things are missing, and each one is a real gap, not a nitpick.
The agent scope is a constant. It needs to be an identity.
AGENT_SCOPE in the demo is a TypeScript object, the same for every request, forever, until someone edits the file and redeploys. A real agent needs its own identity, issued and revocable independently of the code that defines its logic, the way Microsoft's Entra Agent ID or AWS IAM roles for workloads do it. The difference matters the moment you have more than one agent: without separate identities, revoking one agent's access means redeploying the code that every agent shares.
// Demo: fine for proving the model
const AGENT_SCOPE = { regions: ['EU', 'US', 'APAC'], maxVisibleAmount: 10_000 }
// Production: the scope is looked up, not hardcoded
const agentIdentity = await identityProvider.verify(request.agentToken)
const agentScope = await policyStore.getScope(agentIdentity.agentId)There is no record of what actually happened
Run the demo and you get an answer. You do not get a trace of which scope was actually applied to produce it. The first time someone asks "why did the agent show this customer their own order but not the one next to it," a policy document that says what should happen is worthless without a log of what did happen, for that specific call, that specific agent, that specific user. This is the cheapest of the three fixes and the one with the worst consequences for skipping it: one line, after the intersection is computed, before the query runs.
const effective = intersectScope(agentScope, userScope)
auditLog.record({ agentId, userId, effective, timestamp: new Date() })
// then, and only then, run the queryThe policy lives in code, which means changing it means shipping code
USER_SCOPES is a hardcoded map in the demo. That's fine for five roles you'll never revisit. It stops being fine the moment a business user needs to adjust who can see what, and "adjust a permission" turns into "open a PR, get it reviewed, wait for a deploy." The fix isn't exotic, move the scope definitions into whatever policy store or admin table your stack already has, and have the intersection function read from it instead of importing it. The intersection logic itself does not need to change at all, it already treats both scopes as data, not as code.
None of these three make the intersection model wrong or incomplete as an idea. They're exactly the gap between a demo that proves a concept and a system someone can be held accountable to. If you're evaluating whether an AI-to-database integration is actually production-ready, these three are a faster checklist than reading the whole vendor whitepaper: whose identity is this, is there a record of what it did, and can the policy change without a deploy.