Published from docs/guides/concepts-and-glossary.md. Edit that file — this page is generated when the docs site builds.

Concepts and glossary

Deeper narrative definitions also live in root CONCEPTS.md (relationships, grant model, machinery). This page is the short front door for adopters and agents.

Decision order

Every allow/deny question routes through one pure resolver, in this fixed order:

1. SoD veto        → initiator? (opt-in, off by default)  DENY (overrides all)
2. full_access     → role grants everything, forever     ALLOW
3. org-wide role   → role's permission set includes it   ALLOW
4. scoped role     → a role held on THIS record, or an   ALLOW
                     ancestor role that ticks the key
                     (opt-in; not scoped full_access)
5. record-less     → no record: a scoped grant of the     ALLOW
                     named type opens a listed
                     collection read (index by default)
6. otherwise       → default deny

Step 4 also matches a grant on a declared parent when the child opted in with current_scope_parent. Step 5 is why a scoped-only subject can reach an index. A collection action names the type with current_scope_model. The class form allowed_to?(:index, Report) names the type itself. Without a type the grant is type-unbound and the gate stays closed (reason :model_undeclared). The listed read still opens only when the subject’s scoped list is not empty, including rows reached through a declared parent. Other record-less keys (for example create) need an explicit tick on the named type; a scoped full_access grant does not open those. An action in config.sod_actions never opens on this arm: the veto needs a record.

No grant means denied. The gate enforces that answer before the action runs. The scoped list narrows which records the action sees. For listed collection reads (index by default) the gate derives admission from the list so gate and list agree by construction.

Glossary

Subject The identity permissions resolve against. Usually a person. Distinct from the actor when someone is impersonating.

Subject identity The portable natural key for a subject (config.subject_identity): one column, a composite list, or a host identify / resolve object. Default is the primary key. Grants still store that primary key. Duplicate natural keys raise. This is not subject_label.

Subject label The display string in the management UI (config.subject_label). Fail-soft and never used to find a subject.

Actor The real account behind the request. Equals the subject unless impersonating. Attribution and the audit trail follow the actor; permission checks follow the subject.

Effective subject The subject the request acts as (impersonated user when act-as is live). Same as current_scope_user / the ambient subject.

Org-wide role The single application-wide role a subject may hold. Its permissions apply to every record of every type. At most one per subject (DB-enforced).

Scoped role The same role concept attached to one record (“Editor of Project #7”). Grants nothing on other records. A subject may hold many, on different records.

full_access A role property that satisfies every permission without listing them. Org-wide it means everything; scoped it means everything on that record (plus listed collection reads of that type). Step 2 of the decision order.

Permission key A controller#action pair. The route pair is the permission. The catalog of grantable keys is derived from routes, not hand-maintained.

SoD veto Optional four-eyes rule: the record’s initiator can never perform listed member actions on their own record. Not grantable in the UI. Overrides even full_access. Which identity counts is config.sod_identity: the default :either weighs the effective subject and, while impersonating, the real actor — so an initiator cannot approve their own record by acting as someone else. Under :subject only the effective subject is weighed, which reopens that impersonation path. See Separation of duties.

Initiator Who raised the record (current_scope_initiator). The identity SoD measures against. Declared per model by the host.

Break-glass An audited, privileged waiver of the SoD veto (allow_sod_bypass). Not SoD itself. Requires config, a record flag, and an initiator-held permission. See Break-glass.

Fail-closed Anything not granted is denied. Misconfiguration should fail loud, not look like success.

Ambient context Subject (and actor) carried on ActiveSupport::CurrentAttributes so allowed_to? is identical in controller, view, and ViewComponent.

Gate The enforcement point (Guard) that refuses an action unless the resolver allows it. Admits or refuses; does not narrow lists.

Scoped list scope_for — the records a subject may act on. Advisory unless the host uses it (except collection-read actions, where the gate derives from it).

Ledger Append-only history of authorization changes (grants, roles, impersonation boundaries, lifted vetoes). Not a log of every allow/deny decision.