---
id: STATE-PFM-SEC-006
title: Role assignment
object: DOM-PFM-SEC-003
product_area: platform
module: security
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
states:
- name: pending
  meaning: The assignment is pending invitation acceptance and contributes no authority.
  provenance: observed
  source: 'services-platform at ad3f6a65: modules/security/db/security-assignments.table.ts; services/persistence/assignments.ts;
    services/membership/manage-assignments.ts; services/invitations/widening.ts.'
- name: scheduled
  meaning: Stored status is active but the validity interval starts later; evaluation ignores it for now.
  provenance: observed
  source: services-platform:modules/security/services/persistence/assignments.ts:activatePendingAssignments
- name: live
  meaning: Stored status is active and the current time falls within the validity interval.
  provenance: observed
  source: services-platform:modules/security/services/persistence/assignments.ts:activatePendingAssignments
- name: ended
  meaning: Stored status is active but its validity interval ended; evaluation retains it as history without
    granting access.
  provenance: observed
  source: services-platform:modules/security/db/security-assignments.table.ts (valid_until)
- name: revoked
  meaning: The assignment was withdrawn by administration, membership removal, its grant or its derivation
    source.
  provenance: observed
  source: services-platform:modules/security/services/persistence/assignments.ts:revokeAssignment
transitions:
- from: pending
  to: live
  trigger: Invitation acceptance activates a current-window assignment.
  guard: Present inviter authority covers it, unless the invitation carries the explicit exemption.
  side_effects:
  - Record assignment and membership history
  who: The invited person
  provenance: observed
  source: services-platform:modules/security/services/persistence/assignments.ts:activatePendingAssignments
- from: pending
  to: scheduled
  trigger: Invitation acceptance activates an assignment with a future start.
  guard: Apply the same acceptance authority checks.
  side_effects: []
  who: The invited person
  provenance: observed
  source: services-platform:modules/security/services/persistence/assignments.ts:activatePendingAssignments
- from: scheduled
  to: live
  trigger: The validity start is reached.
  guard: Request-time evaluation derives usability without changing stored status.
  side_effects: []
  who: nobody (clock)
  provenance: observed
  source: services-platform:modules/security/db/security-assignments.table.ts (valid_from)
- from: live
  to: ended
  trigger: The validity end is reached.
  guard: Request-time evaluation derives expiry without a status write.
  side_effects:
  - An earlier signed context must respect the assignment’s end
  who: nobody (clock)
  provenance: observed
  source: services-platform:modules/security/db/security-assignments.table.ts (valid_until)
- from: live
  to: revoked
  trigger: Administration or the owning capability withdraws the assignment.
  guard: Manual withdrawal requires scope authority, refuses derived rows and passes lockout checks.
  side_effects:
  - Record assignment and membership history
  - Submit a post-commit flush request
  who: Customer Administrator, Rhythm staff, or Platform System
  provenance: observed
  source: services-platform:modules/security/services/persistence/assignments.ts:revokeAssignment
- from: pending
  to: revoked
  trigger: Invitation withdrawal or membership revocation ends a pending assignment.
  guard: The owning membership capability performs withdrawal.
  side_effects: []
  who: Customer Administrator or Rhythm staff
  provenance: observed
  source: services-platform:modules/security/services/persistence/assignments.ts:revokeAssignmentsOfUser
- from: scheduled
  to: revoked
  trigger: Administration withdraws a future-window assignment.
  guard: Apply the manual withdrawal checks used for a currently usable row.
  side_effects: []
  who: Customer Administrator or Rhythm staff
  provenance: observed
  source: services-platform:modules/security/services/persistence/assignments.ts:revokeAssignment
- from: live
  to: live
  trigger: Administration amends validity, conditions or scope, or source synchronization renews derived validity.
  guard: Widening and weakened denies need delegation authority; derived changes require the source capability.
  side_effects:
  - Record widening or narrowing in history
  who: Customer Administrator, Rhythm staff, or Platform System
  provenance: observed
  source: services-platform:modules/security/services/persistence/assignments.ts:amendAssignment
invalid:
- from: revoked
  to: live
  why: Revoked rows are not revived; replacement uses a new assignment.
  provenance: observed
  source: 'services-platform at ad3f6a65: modules/security/db/security-assignments.table.ts; services/persistence/assignments.ts;
    services/membership/manage-assignments.ts; services/invitations/widening.ts.'
- from: pending
  to: live
  why: Acceptance cannot activate grants beyond the inviter’s remaining authority and leaves token and grants
    unchanged on refusal.
  provenance: observed
  source: services-platform:modules/security/services/persistence/assignments.ts:activatePendingAssignments
- from: live
  to: revoked
  why: Manual administration cannot withdraw a source-managed derived assignment.
  provenance: observed
  source: services-platform:modules/security/services/persistence/assignments.ts:revokeAssignment
concurrency: Unique indexes refuse duplicate live grants. Source reconciliation locks derivation keys before
  inspecting current rows. Scope checks take a shared membership lock. Commit changes fresh evaluation; gateway
  caches can lag for sixty seconds, with signed contexts subject to their own expiry. Window-based labels are
  derived views, so amendments can move between them without a dedicated status transition.
invariants:
- INV-DOM-PFM-SEC-003-06
- INV-DOM-PFM-SEC-003-07
- INV-DOM-PFM-SEC-003-08
- INV-DOM-PFM-SEC-003-09
- INV-DOM-PFM-SEC-003-10
evidence:
- 'services-platform at ad3f6a65: modules/security/db/security-assignments.table.ts; services/persistence/assignments.ts;
  services/membership/manage-assignments.ts; services/invitations/widening.ts.'
examined_at: '2026-10-23'
examiner: codex
---

# Role assignment

## The Lifecycle

```mermaid
stateDiagram-v2
    state "Pending" as pending
    state "Scheduled" as scheduled
    state "Live" as live
    state "Ended" as ended
    state "Revoked" as revoked
    pending --> live
    pending --> scheduled
    scheduled --> live
    live --> ended
    live --> revoked
    pending --> revoked
    scheduled --> revoked
    live --> live
```

The diagram summarizes the observed transition rows; declared edges without an observed writer remain outside the operational graph.

## Transitions Explained

Only pending, active and revoked are stored statuses. Scheduled, live and ended describe active rows relative to their validity windows; the table lists representative changes rather than an exhaustive graph of every amended window.

Source-managed assignments retain their derivation ownership. A renewal or amendment can make a previously ended active row usable again; it does not revive a revoked row.

## What Cannot Happen

Revoked rows are not revived; replacement uses a new assignment.

Acceptance cannot activate grants beyond the inviter’s remaining authority and leaves token and grants unchanged on refusal.

Manual administration cannot withdraw a source-managed derived assignment.

## Concurrency and Timing

Unique indexes refuse duplicate live grants. Source reconciliation locks derivation keys before inspecting current rows. Scope checks take a shared membership lock. Commit changes fresh evaluation; gateway caches can lag for sixty seconds, with signed contexts subject to their own expiry. Window-based labels are derived views, so amendments can move between them without a dedicated status transition.
