Field-level security for derived indexes: which fields of an entity must never be written into
an embedding, vector metadata, stored document text or any other artifact that is built once
and then served to many readers.
Reads are projected per user, but an index is built once — usually by a privileged account —
and shared. An embedding cannot be projected after the fact, so the only way to keep a
restricted value out of it is to never render that value into the indexed text. The rule is
deliberately coarser than any single user's view: a field is excluded when any role is
kept from reading it, so the index holds only what every reader of the entity may see.
A field counts as restricted on an entity with EnableFieldLevelSecurity set when:
it has no permission rows at all (field security fails closed on such a field for everyone), or
any of its rows does not grant Read — a Deny, or a No Access row (snapshot
initialization only ever writes Allow for Read, so a No Access row is an administrator
taking Read away from that role), or
a role that can read the entity has no Allow Read row for the field. Runtime enforcement
grants nothing to a role without a row, so a holder of only that role cannot read the field.
"A role that can read the entity" means a role with an entity-level Allow permission row
granting Read and no entity-level Deny row on Read. Roles outside that set are left out on
purpose: they cannot read any record of the entity, so they never see the field either way,
and counting them would exclude every field the moment any unrelated role exists.
Primary keys, __mj_ system columns and fields on the unrestrictable security/identity
entities are never restricted, matching runtime enforcement.
Each restricted field is returned under both its Name and its CodeName, lowercased so
callers match case-insensitively. Rows can be keyed either way: a view row carries the column's
Name, while an explicit field list selects [Name] AS [CodeName] whenever the two differ (a
name with a space or a symbol), so a set of names alone would let such a row's value through.
Field-level security for derived indexes: which fields of an entity must never be written into an embedding, vector metadata, stored document text or any other artifact that is built once and then served to many readers.
Reads are projected per user, but an index is built once — usually by a privileged account — and shared. An embedding cannot be projected after the fact, so the only way to keep a restricted value out of it is to never render that value into the indexed text. The rule is deliberately coarser than any single user's view: a field is excluded when any role is kept from reading it, so the index holds only what every reader of the entity may see.
A field counts as restricted on an entity with
EnableFieldLevelSecurityset when:Deny, or aNo Accessrow (snapshot initialization only ever writesAllowfor Read, so aNo Accessrow is an administrator taking Read away from that role), orAllowRead row for the field. Runtime enforcement grants nothing to a role without a row, so a holder of only that role cannot read the field."A role that can read the entity" means a role with an entity-level
Allowpermission row granting Read and no entity-levelDenyrow on Read. Roles outside that set are left out on purpose: they cannot read any record of the entity, so they never see the field either way, and counting them would exclude every field the moment any unrelated role exists.Primary keys,
__mj_system columns and fields on the unrestrictable security/identity entities are never restricted, matching runtime enforcement.Each restricted field is returned under both its
Nameand itsCodeName, lowercased so callers match case-insensitively. Rows can be keyed either way: a view row carries the column'sName, while an explicit field list selects[Name] AS [CodeName]whenever the two differ (a name with a space or a symbol), so a set of names alone would let such a row's value through.