> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackra.figentra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 0132 — Permissions are a module catalogue; policies are providers

> Accepted · 2026-10-20

> [!NOTE]
>
> Forward note: the naming table of [0231](/adr/0231-naming-and-casing-standard) (accepted) restates
> this key form.

## Context

Permissions were a flat list, and nothing checked that an action's permission made sense for what the action does. The
owner's intent-map item P2 and the IAM answer A10 (mem L627) set a curated catalogue per module, with labels and risk, and
policy providers that decide per request. The owner confirmed the key form on 2026-10-20 (mem L930): a permission key is
`<module>.<resource>.<action>`, and each module's permissions are one `definePermissions()` value.

## Decision

1. Each module declares its permissions as one `definePermissions()` value. That value is the module's catalogue. It replaces the
   `@Permissions` class of P2, because the owner's `define*` rule makes `definePermissions()` the value form (0145).
2. Keys are `<module>.<resource>.<action>`, for example `billing.invoice.refund`, as A10 sets. The module key (0131) is the first
   segment. Each catalogue entry carries a label, a description, a risk and a verb (A10).
3. The catalogue is curated per module. Gen **warns**, and does not fail, when an action reuses a permission whose verb
   differs from the action's verb (mem L401).
4. A `@Policy` provider method returns `allow`, `deny` or `abstain`. Any `deny` wins.
5. Wildcard permissions are allowed only in system roles (A10).
6. A rename of a permission goes through deprecation ([0131](/adr/0131-module-key-version-and-deprecation)).

## Consequences

* Permission review becomes a catalogue review, per module.
* A verb mismatch is a warning, so an existing action is not broken on the day the check lands.
* A key names its module, so the registry can check uniqueness by prefix.

## Enforcement

planned — gen emits the catalogue from each module's `definePermissions()` value and warns on a verb mismatch. Wildcard use outside
system roles is planned as a gen error. The uniqueness check on keys is planned.

## Alternatives

* `resource:verb` keys: not chosen; the owner confirmed `<module>.<resource>.<action>`.
* A `@Permissions` class: replaced by the `definePermissions()` value (decision 1).

## Supersedes and sources

Supersedes: none. Sources: owner intent-map item P2 (accepted; mem L401), IAM answer A10 (mem L627), the owner's confirmed naming
of 2026-10-20 (mem L930: `billing.invoice.refund`, one `definePermissions()` per module), and the define rule (mem L546).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.