ProtectedapplicableKeep only grants that are in force at this moment and apply to this tenant.
Both dimensions are additive: a row that leaves StartAt/EndAt/PrimaryScopeRecordID
NULL is always in force and applies to every tenant, which is exactly how every row
behaved before those columns existed.
ProtectedisA grant with a NULL tenant applies everywhere. A tenant-scoped grant applies ONLY to that tenant — and, notably, does not apply when the search supplies no tenant at all, because "this grant is for org A" cannot be honoured by an untenanted search.
ProtectedisA grant with no window is always in force; otherwise now must fall inside it.
ProtectedisChecks whether the given scope is in the agent's assigned-scope list via __mj.AIAgentSearchScope. Used to enforce the SearchScopeAccess='Assigned' deny-list rule. Returns true when at least one matching row exists with Status='Active'; false otherwise.
ProtectedisWhether the scope is in the skill's assigned-scope list via __mj.AISkillSearchScope.
Mirrors isScopeAssignedToAgent, including honouring Status and the optional time window
(which the agent table also has). Fails closed on an unreadable table.
ProtectedloadLoads all SearchScopePermission rows scoped to the given SearchScope. Caller-supplied ContextUser ensures the RunView runs under the same identity the rest of the request is using.
Resolves the effective permission. All UUID comparisons go through UUIDsEqual to remain case-insensitive across SQL Server / PostgreSQL.
Resolves the effective SearchScope permission for a (user, scope, agent) triple.
Resolution order (later steps only run if the earlier did not produce a definitive answer):
The user-direct-None rule (step 2) is intentional: an admin who explicitly denies a user on a scope should not have that decision overridden by a role membership the user happens to also hold. Role-level None entries are not authoritative because they are usually authored as a placeholder (e.g., to make a row exist before granting it later) and would create surprising lockouts when a user joins a role.