---
id: CAP-PFM-SEC-010
title: Assign roles within a controlled scope
feature: FEAT-PFM-SEC-03
product_area: platform
module: security
revision: 1
status: draft
product_intent: confirmed
implementation_evidence: observed
supersedes: []
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - >-
    services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-11
    Final acceptance)
  - >-
    services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-13/14
    Final acceptance)
  - 'services-platform:docs/security/security-administration.md#4. Delegation, escalation and lockout'
  - >-
    services-platform:docs/security/security-administration.md#12. Approved omissions and tracked gaps
    (resource-scoped grants, PLAT-M5 D10)
purpose: >-
  Security administrators assign and withdraw roles at the customer, workspace or supported record scope
  and explain the resulting authority.
outcomes:
  - Role assignments identify where access applies.
  - Delegation refuses authority beyond the administrator’s effective permissions.
  - Assignment history and access explanation support review.
concepts:
  - CON-PFM-SEC-003
actors:
  - ACT-PFM-001
  - ACT-PFM-004
surfaces:
  - console
  - api
preconditions: []
postconditions: []
permissions:
  - key: platform.security-access.manage
    where_checked: api
    scope: tenant
  - key: platform.security-access.explain
    where_checked: api
    scope: tenant
  - key: platform.users.read
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-PFM-SEC-010-01
    proved_by: [ATS-PFM-SEC-010-01, TST-PFM-SEC-051]
    statement: >-
      Assignment creation, withdrawal and scope changes require access-management permission covering the
      target scope; read-only authority cannot write grants.
    kind: permission
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/console-users.e2e.spec.js#refuses the reader’s attempt
      to grant as 403, and grants nothing
    origin: >-
      services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-11
      Final acceptance)
  - id: BR-CAP-PFM-SEC-010-02
    proved_by: [ATS-PFM-SEC-008-22, ATS-PFM-SEC-010-02, ATS-PFM-SEC-010-19, ATS-PFM-SEC-017-19, TST-PFM-SEC-060, TST-PFM-SEC-213]
    statement: >-
      Delegation requires the administrator to hold every affected permission unconditionally and without
      a deny at the target scopes; failures identify the missing keys and scopes without disclosing
      others’ grants, and self-widening fails.
    kind: permission
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/unit/services/invitations/widening.spec.ts#refuses a scope
      the caller does not manage, and says which scope rather than which role
    origin: 'services-platform:docs/security/security-administration.md#4. Delegation, escalation and lockout'
  - id: BR-CAP-PFM-SEC-010-03
    proved_by: [ATS-PFM-SEC-010-03, ATS-PFM-SEC-015-14, TST-PFM-SEC-051, TST-PFM-SEC-063, TST-PFM-SEC-129]
    statement: >-
      Customer assignments can cover the whole customer, one of its workspaces or an existing unarchived
      custom record type in a workspace; unsupported single-record kinds fail.
    kind: validation
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/membership/resource-scopes.integration.spec.js#refuses
      an archived custom object, naming the object key, and writes nothing
    origin: >-
      services-platform:docs/security/security-administration.md#12. Approved omissions and tracked gaps
      (resource-scoped grants, PLAT-M5 D10)
  - id: BR-CAP-PFM-SEC-010-04
    proved_by: [ATS-PFM-SEC-010-04, TST-PFM-SEC-122]
    statement: >-
      Customer security operations cannot create or amend platform-scope staff authority, including its
      duration, conditions or scope, and refusals direct staff to HQ.
    kind: permission
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/membership/amend-grant.integration.spec.js#refuses
      a window that would have ended the staff grant, naming where such a change is made
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#D1'
  - id: BR-CAP-PFM-SEC-010-05
    proved_by: [ATS-PFM-SEC-005-18, ATS-PFM-SEC-005-20, ATS-PFM-SEC-010-05, ATS-PFM-SEC-010-14, ATS-PFM-SEC-010-15, TST-PFM-SEC-051, TST-PFM-SEC-128]
    statement: >-
      Assignments for active memberships are active, assignments for invited memberships remain pending
      until acceptance, and future validity windows contribute no access until they open.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/console-users.e2e.spec.js#answers a grant whose window
      opens tomorrow as scheduled, in the grant and in the list
    origin: >-
      services-platform:docs/security/security-administration.md#2. Capability checklist (U8,
      DEF-CRM-0551)
  - id: BR-CAP-PFM-SEC-010-06
    proved_by: [ATS-PFM-SEC-010-06, TST-PFM-SEC-123, TST-PFM-SEC-128]
    statement: >-
      A person can hold only one non-revoked role assignment for the same scope and validity window;
      sequential or concurrent duplicates fail, and revocation allows a replacement grant.
    kind: invariant
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/membership/concurrent-grants.integration.spec.js#grants
      once and refuses the other as already_assigned
    origin: >-
      services-platform:docs/security/security-administration.md#2. Capability checklist (U8,
      DEF-CRM-0552)
  - id: BR-CAP-PFM-SEC-010-07
    proved_by: [ATS-PFM-SEC-007-15, ATS-PFM-SEC-009-18, ATS-PFM-SEC-010-07, ATS-PFM-SEC-010-16, ATS-PFM-SEC-010-17, ATS-PFM-SEC-010-20, ATS-PFM-SEC-010-21, ATS-PFM-SEC-012-16, TST-PFM-SEC-051, TST-PFM-SEC-128]
    statement: >-
      Withdrawal preserves assignment history, guards against losing the last administrator and requests
      an authorizer flush after commit without guaranteeing eviction of cached decisions.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/membership/manage-assignments.integration.spec.js#revokes
      the grant, keeps the row, and audits what was withdrawn
    origin: >-
      services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-11
      Final acceptance)
  - id: BR-CAP-PFM-SEC-010-08
    proved_by: [ATS-PFM-SEC-010-08, ATS-PFM-SEC-010-22, ATS-PFM-SEC-014-11, TST-PFM-SEC-129, TST-PFM-SEC-130]
    statement: >-
      Setting role scope atomically reconciles customer-wide or 1–100 selected-workspace assignments,
      retains matching rows, creates missing rows under delegation checks and revokes unwanted rows;
      outside-customer workspaces fail and resource assignments remain unchanged.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/membership/set-role-scope.integration.spec.js#turns
      the customer grant into one active grant per tenant asked for, revoking the customer grant
    origin: >-
      services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-13/14
      Final acceptance)
  - id: BR-CAP-PFM-SEC-010-09
    proved_by: [ATS-PFM-SEC-010-09, ATS-PFM-SEC-010-18, TST-PFM-SEC-122]
    statement: >-
      Weakening an assignment’s deny by narrowing scope, shortening validity or adding a condition
      requires widening authority; extending validity or removing that restriction can strengthen the
      deny instead.
    kind: permission
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/membership/amend-grant.integration.spec.js#refuses
      a narrowing of the scope for an editor who is not allowed the key the grant was denying
    origin: 'services-platform:docs/security/security-administration.md#12 (gap D1 closed 2026-10-11)'
  - id: BR-CAP-PFM-SEC-010-10
    proved_by: []
    statement: >-
      Grant checking reports the role and whether the caller can assign it at a proposed scope without
      making a write, including checks within a workspace administrator’s scope.
    kind: policy
    enforced_at:
      - api
      - service
    must_prove: false
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/grant-checks.e2e.spec.js#writes no assignment and no
      audit event, however many checks were asked
    origin: none
  - id: BR-CAP-PFM-SEC-010-11
    proved_by: [ATS-PFM-SEC-010-10, TST-PFM-SEC-051, TST-PFM-SEC-125]
    statement: >-
      Access explanation evaluates a member’s permissions and traces allowed keys to assignments, roles
      and policies; denies remove keys and absent grants produce an empty explanation.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/membership/effective-permissions.integration.spec.js#leaves
      out a key the role's own deny takes back, although its policy still names it
    origin: >-
      services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-11
      Final acceptance)
  - id: BR-CAP-PFM-SEC-010-12
    proved_by: [ATS-PFM-SEC-010-11, TST-PFM-SEC-052, TST-PFM-SEC-128]
    statement: >-
      Staff-only roles and roles outside the customer cannot be assigned to customer memberships and are
      presented as not found.
    kind: permission
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/membership/manage-assignments.integration.spec.js#refuses
      a staff-only role for a customer's user as not found, by its key or its id, and grants nothing
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#D1'
  - id: BR-CAP-PFM-SEC-010-13
    proved_by: [ATS-PFM-SEC-010-12, ATS-PFM-SEC-011-09, TST-PFM-SEC-126]
    statement: >-
      Assignment creation, withdrawal and scope changes produce both assignment and membership history
      entries.
    kind: invariant
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/membership/grant-history.integration.spec.js#lists
      the grant, the move and the withdrawal, each naming the grant it was about
    origin: >-
      services-platform:docs/security/security-administration.md#2. Capability checklist (U8,
      DEF-CRM-0553)
  - id: BR-CAP-PFM-SEC-010-14
    proved_by: []
    statement: >-
      Role-member pagination includes only reached people holding the role and presents each assignment’s
      scope.
    kind: policy
    enforced_at:
      - api
      - service
    must_prove: false
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#lists the people who hold a
      role, which is whoever the caller reaches and not every customer's
    origin: >-
      services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-11
      Final acceptance)
scenarios:
  - id: SC-CAP-PFM-SEC-010-01
    given: A colleague needs access to two of the customer’s five workspaces.
    when: The administrator changes the Standard User assignment to selected workspaces.
    then: The role applies to those two workspaces and the membership history records the change.
    provenance: test
    source: >-
      react-console:e2e/mock/security-admin.mock.spec.ts#Edit on a role restores its saved tenants and
      saves All, Selected and All again
  - id: SC-CAP-PFM-SEC-010-02
    given: An investigator needs access to a particular custom record type.
    when: An authorized administrator grants the investigator role at that record-type scope.
    then: 'The scoped assignment can be inspected and withdrawn, while a duplicate assignment is refused.'
    provenance: test
    source: >-
      react-console:e2e/mock/security-scoped-roles.mock.spec.ts#grant Investigators on Enforcement
      Actions, see it listed with its scope, and remove it
edge_cases: []
constraints: []
depends_on:
  - CAP-PFM-SEC-015
related:
  - CAP-PFM-SEC-008
  - CAP-PFM-SEC-009
  - CAP-PFM-SEC-012
  - CAP-PFM-SEC-014
journeys:
  - JNY-PFM-SEC-003
  - JNY-PFM-SEC-004
open_questions: []
evidence:
  - >-
    Pinned services-platform references for the structured rows: docs/hq/rhythm-hq-plan.md;
    docs/security/security-administration.md; modules/security/tests/e2e/console-users.e2e.spec.js;
    modules/security/tests/e2e/definitions.e2e.spec.js;
    modules/security/tests/e2e/grant-checks.e2e.spec.js;
    modules/security/tests/integration/services/membership/amend-grant.integration.spec.js;
    modules/security/tests/integration/services/membership/concurrent-grants.integration.spec.js;
    modules/security/tests/integration/services/membership/effective-permissions.integration.spec.js;
    modules/security/tests/integration/services/membership/grant-history.integration.spec.js;
    modules/security/tests/integration/services/membership/manage-assignments.integration.spec.js;
    modules/security/tests/integration/services/membership/resource-scopes.integration.spec.js;
    modules/security/tests/integration/services/membership/set-role-scope.integration.spec.js;
    modules/security/tests/unit/services/invitations/widening.spec.ts.
  - >-
    Pinned react-console references for the structured rows: e2e/mock/security-admin.mock.spec.ts;
    e2e/mock/security-scoped-roles.mock.spec.ts.
controls: [TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-AZ-006, TC-CRY-001, TC-CRY-002, TC-CRY-003, TC-CRY-004, TC-IAM-001, TC-IAM-002, TC-IAM-003, TC-IAM-004, TC-IAM-005, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-MON-001, TC-PI-001, TC-PI-003, TC-PI-005, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-TEN-004, TC-VEN-001, TC-VEN-002, TC-VEN-003]
exercised_by: [FAS-PFM-SEC-03-01, FAS-PFM-SEC-03-02, FAS-PFM-SEC-03-03, FAS-PFM-SEC-03-04, FAS-PFM-SEC-03-05, FAS-PFM-SEC-04-01]
suites: [TST-PFM-SEC-051, TST-PFM-SEC-052, TST-PFM-SEC-060, TST-PFM-SEC-063, TST-PFM-SEC-122, TST-PFM-SEC-123, TST-PFM-SEC-125, TST-PFM-SEC-126, TST-PFM-SEC-128, TST-PFM-SEC-129, TST-PFM-SEC-130, TST-PFM-SEC-213]
---
# Assign roles within a controlled scope

## Purpose

A role becomes useful when an administrator assigns it where the colleague will work. The assignment records that scope and makes the decision available for later review.

## How It Works

The administrator opens the colleague’s role management view and chooses an available role. Customer-wide and selected-workspace choices support different responsibilities. Supported record scopes serve narrower work through their own assignment surface. The delegation check explains missing authority before an excessive grant can take effect. Pending membership and future validity windows affect when an otherwise valid offer can be used. Scope editing reconciles existing assignments rather than ask staff to rebuild each row manually. Withdrawal preserves the history needed to explain earlier access. The Access view lets an administrator inspect the evaluated permissions and their origins. Staff authority remains on the HQ administration surface, keeping it separate from customer role management.

## Relationships

- Role and policy definitions supply the assigned authority.
- Authorization evaluation supplies delegation checks and permission explanations.
- Automatic assignment owns derived grants that ordinary management cannot edit.
- Security history records assignment decisions and refusals.
