Found while implementing #8535 (which withdraws the identical false claim on sys_capability only). Filed unassigned — out of scope for #8535's PR, which deliberately touches nothing but sys_capability.
#8535 established that sys_capability.active is read by nothing while its Deactivate dialog claims grants stop resolving. The same shape exists on the other two RBAC catalogue objects, and on those it is worse: a permission set and a position are the grant itself, not a catalogue entry.
The claims
sys-permission-set.object.ts, deactivate_permission_set:
Deactivate this permission set? Existing assignments stay in place but stop granting access until re-activated.
sys-position.object.ts, deactivate_position:
Deactivate this position? Users keep their assignment but the position stops granting permissions until re-activated.
Both ship translated into all four locales.
What actually happens (measured on b45c71e85a)
Nothing filters on active anywhere in the resolution chain:
SecurityPlugin.resolvePermissionSetsForContext (security-plugin.ts:3626) builds requested from context.positions + context.permissions plus the additive baseline. No active check.PermissionEvaluator.resolvePermissionSets (permission-evaluator.ts:398) matches metadata sets by name, then bootstrap sets by name, then falls through to the DB loader. No active check in any of the three sources.- The DB loader (
security-plugin.ts:812) queries sys_permission_set with where: { name: { $in: names } } — no active predicate — and the row is mapped to a PermissionSet that does not carry active at all, so nothing downstream could filter on it even if it wanted to. - Every non-test
sys_position row read (delegated-admin-gate.ts, security-plugin.ts, the bootstrap seeders) looks up by name or id. None reads active.
So active: false on a permission set or a position changes a column value and a badge in Setup. The assignments keep granting.
Why this is worth its own card
Same direction of falsehood as #8535, higher blast radius. An admin revoking a compromised or over-broad permission set is told in a confirmation dialog that access stopped; it did not. The admin's likely next action is to not do the thing that would actually work (delete the set, or remove the assignments).
Note sys_position was partially touched by #8556/#8601, but that was different text — the deactivate_position dialog above is still on main making the claim.
Not a recommendation
The direction is the same contract decision the maintainer already ruled on for sys_capability (2026-08-13, ADR-0049 enforce-or-remove, option B: withdraw the claim rather than put the registry on the authorization hot path). Whether that ruling extends to these two is not something this finding assumes: unlike a capability catalogue, a permission set's active flag has a plausible real enforcement point (the DB loader's where, one predicate) and a plausible real business pull (switching a grant off without deleting it). Both options are live and the trade-off is different from #8535's. Needs triage, not a rider.
Found while implementing #8535 (which withdraws the identical false claim on
sys_capabilityonly). Filed unassigned — out of scope for #8535's PR, which deliberately touches nothing butsys_capability.#8535 established that
sys_capability.activeis read by nothing while its Deactivate dialog claims grants stop resolving. The same shape exists on the other two RBAC catalogue objects, and on those it is worse: a permission set and a position are the grant itself, not a catalogue entry.The claims
sys-permission-set.object.ts,deactivate_permission_set:sys-position.object.ts,deactivate_position:Both ship translated into all four locales.
What actually happens (measured on
b45c71e85a)Nothing filters on
activeanywhere in the resolution chain:SecurityPlugin.resolvePermissionSetsForContext(security-plugin.ts:3626) buildsrequestedfromcontext.positions+context.permissionsplus the additive baseline. Noactivecheck.PermissionEvaluator.resolvePermissionSets(permission-evaluator.ts:398) matches metadata sets byname, then bootstrap sets byname, then falls through to the DB loader. Noactivecheck in any of the three sources.security-plugin.ts:812) queriessys_permission_setwithwhere: { name: { $in: names } }— noactivepredicate — and the row is mapped to aPermissionSetthat does not carryactiveat all, so nothing downstream could filter on it even if it wanted to.sys_positionrow read (delegated-admin-gate.ts,security-plugin.ts, the bootstrap seeders) looks up bynameorid. None readsactive.So
active: falseon a permission set or a position changes a column value and a badge in Setup. The assignments keep granting.Why this is worth its own card
Same direction of falsehood as #8535, higher blast radius. An admin revoking a compromised or over-broad permission set is told in a confirmation dialog that access stopped; it did not. The admin's likely next action is to not do the thing that would actually work (delete the set, or remove the assignments).
Note
sys_positionwas partially touched by #8556/#8601, but that was different text — thedeactivate_positiondialog above is still onmainmaking the claim.Not a recommendation
The direction is the same contract decision the maintainer already ruled on for
sys_capability(2026-08-13, ADR-0049 enforce-or-remove, option B: withdraw the claim rather than put the registry on the authorization hot path). Whether that ruling extends to these two is not something this finding assumes: unlike a capability catalogue, a permission set'sactiveflag has a plausible real enforcement point (the DB loader'swhere, one predicate) and a plausible real business pull (switching a grant off without deleting it). Both options are live and the trade-off is different from #8535's. Needs triage, not a rider.