C32 Updated 2026-06-20
Pillar 3 - Evaluating and choosing memory

Permission-Aware Retrieval: Enforce ACLs at the Vector Layer

Permission-aware retrieval applies tenant, library, visibility, and user scope before vector or hybrid search can return candidate memories.

Permission-aware retrieval means access control is applied before memory candidates reach the model. Do not retrieve everything and filter the final answer. Bind tenant, library, visibility, and user scope in the retrieval query first, then enrich, rank, cite, and answer only from allowed source artifacts.

Last updated: June 20, 2026.

Why is permission-aware retrieval different from app-layer filtering?

App-layer filtering can hide an answer after the model has already seen restricted text. That is too late. In a RAG or memory system, the sensitive moment is candidate retrieval. If an out-of-scope document enters the model context, the leak has already happened.

The NIST AI Risk Management Framework frames trustworthy AI around risk management and trustworthiness. The EU AI Act reinforces the importance of logging, governance, and risk controls for AI systems. For memory retrieval, the practical control is simple: enforce scope before the model sees data.

What does the Answer Engine tenant-isolation story show?

Issue #527 hardened the tenant-isolation story around content retrieval. The current repository code shows the pattern:

  • src/repositories/content.repository.ts starts content lookup with WHERE c.tenant_id = $1.
  • Tag joins include c.tenant_id = ct.tenant_id and ct.tenant_id = t.tenant_id.
  • Shared-content joins include cs.tenant_id = c.tenant_id.
  • Library scope uses libraryRepository.effectiveMembershipSqlFragment(tenantId, libraryId, ...).
  • src/services/qa/qa.service.ts starts retrieval conditions with c.tenant_id = $1 before full-text retrieval.
  • Vector retrieval prefilters allowed content ids when match filters apply, then enriches by tenant.

That is the product proof: scope is not a UI decoration. It is carried into repository SQL and retrieval prefilters before content is enriched for an answer.

Where should permissions be enforced?

Apply permissions at every candidate-producing layer:

LayerRequired control
Content lookuptenant_id, content id, status, visibility
Tag joinsJoin on content id and tenant id
Library scopeEffective membership filter before ranking
Full-text searchScope conditions before websearch_to_tsquery
Vector searchPrefilter allowed ids or pass scoped filters into the search function
EnrichmentFetch full content by tenant and allowed ids only
AnsweringCite only retrieved allowed sources

The MCP architecture docs describe tools and resources as server-exposed primitives. A memory MCP tool should never return resources outside the authenticated scope, even if the client asks broadly.

What can go wrong?

The classic failure is “filter after search.” A vector search returns nearest neighbors across a whole table, then the app removes disallowed records. This is risky because search scores were computed against data the requester should not reach, and implementation mistakes can leak candidates into logs or prompts.

Another failure is tenant-safe content lookup but tenant-unsafe joins. If content_tags, content_shares, or library membership joins do not include tenant ids, a row from another tenant can influence filtering or enrichment.

A third failure is permission-aware full-text search but permission-blind vector search. Both paths must enforce the same scope.

How do you test permission-aware retrieval?

Create tests that prove absence, not only presence:

  1. Tenant A asks for a fact only Tenant B has; no result should return.
  2. A non-owner asks for private content; no result should return.
  3. A user with a share asks for shared content; the result should return.
  4. A library-scoped question asks for a fact outside the library; no result should return.
  5. Hybrid search and full-text search should produce the same permission boundary.

The GDPR right to erasure is also relevant to lifecycle controls. A deleted or disabled source should not be retrievable by any delivery path.

What should you ask vendors?

Ask for the exact enforcement point. “We have RBAC” is not enough. Ask whether ACLs filter the vector candidate pool before retrieval, whether joins include tenant boundaries, whether logs contain out-of-scope snippets, and whether negative tests cover cross-tenant search.

Also ask for the layer where filters apply. A statement that the app supports roles is weaker than proof that candidate generation, enrichment, and citation assembly all use the same permission boundary.

Then use the Memory Leaderboard and RAG leaks docs to wrong users to compare the control surface.

Sources

Fig. 9 FAQPage schema / visible answers
FIG. 9

FAQ

What is permission-aware retrieval?

Permission-aware retrieval applies tenant, workspace, library, visibility, and user permissions before candidate memories are returned to the agent.

Why not filter after the answer?

Post-answer filtering is too late because the model may already have seen out-of-scope source text. Permissions need to constrain retrieval candidates first.

What did the tenant-isolation fix prove?

It proved that retrieval and content queries must bind tenant_id and library scope in repository SQL before enriching or answering.

How do I test permission-aware retrieval?

Create cross-tenant negative cases, private-content cases, shared-content cases, and library-scoped vector searches that must not return out-of-scope records.

NEXT

Build memory you can inspect.

Answer Engine gives agents a persistent, tenant-isolated memory layer via MCP, with source-aware recall and roadmap-labeled inspection work.