---
id: CAP-PFM-SEC-012
title: Model customer responsibilities with roles and policies
feature: FEAT-PFM-SEC-04
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#Placeholder roles (D-18, Andrew
    2026-10-19)
  - 'services-platform:docs/security/security-administration.md#3. Built-in and custom policies'
purpose: >-
  Security administrators assemble permission policies and roles that fit the customer’s responsibilities
  while respecting delegation and definition integrity.
outcomes:
  - Customers compose their own reusable access definitions.
  - Validation explains invalid permissions and conditions before saving.
  - Definition lifecycle and version checks protect users of existing roles and policies.
concepts:
  - CON-PFM-SEC-003
actors:
  - ACT-PFM-001
  - ACT-PFM-002
surfaces:
  - console
  - api
preconditions: []
postconditions: []
permissions:
  - key: platform.security-roles.read
    where_checked: api
    scope: tenant
  - key: platform.security-roles.manage
    where_checked: api
    scope: tenant
  - key: platform.security-policies.read
    where_checked: api
    scope: tenant
  - key: platform.security-policies.manage
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-PFM-SEC-012-01
    proved_by: [ATS-PFM-SEC-012-01, TST-PFM-SEC-028, TST-PFM-SEC-052]
    statement: >-
      Definition and catalog reads use their read permissions, while creation, modification, copying and
      archive require the corresponding management permissions.
    kind: permission
    enforced_at:
      - api
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#lets a caller holding only the
      read key read a role, and refuses the same caller the write
    origin: 'services-platform:docs/security/security-administration.md#4. Delegation, escalation and lockout'
  - id: BR-CAP-PFM-SEC-012-02
    proved_by: [ATS-PFM-SEC-012-02, ATS-PFM-SEC-013-14, TST-PFM-SEC-033, TST-PFM-SEC-052, TST-PFM-SEC-074]
    statement: >-
      Built-in roles and policies reject edits as read-only through service and database safeguards;
      copying creates a customer-owned definition retaining source identity and version.
    kind: invariant
    enforced_at:
      - api
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#refuses a write against a
      built-in as read-only rather than as a record that is not there
    origin: >-
      services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-11
      Final acceptance)
  - id: BR-CAP-PFM-SEC-012-03
    proved_by: [ATS-PFM-SEC-012-03, TST-PFM-SEC-033, TST-PFM-SEC-215]
    statement: >-
      Allow rules require exact catalog permissions, deny rules may use matching patterns, and unknown,
      unmatched, repeated or empty permission selections fail validation.
    kind: validation
    enforced_at:
      - api
      - service
      - console
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/unit/services/persistence/rule-validation.spec.ts#names
      the key the catalog does not have, and the rule it is in
    origin: >-
      services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-11
      Final acceptance)
  - id: BR-CAP-PFM-SEC-012-04
    proved_by: [ATS-PFM-SEC-012-04, ATS-PFM-SEC-012-18, TST-PFM-SEC-215]
    statement: >-
      Conditions must use supported schedule, network or enabled eligibility forms; an eligibility
      reference must resolve to an allowed binding, and unsupported forms fail.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: 'services-platform:modules/security/services/persistence/rules.ts:parseConditions'
    origin: >-
      services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-11
      Final acceptance)
  - id: BR-CAP-PFM-SEC-012-05
    proved_by: []
    statement: >-
      Rule validation can return indexed problems without saving and warns, without rejecting the rules,
      when application permissions lack the application-access key.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#warns, without refusing, that
      CRM keys allowed without crm.application.access grant nothing in CRM
    origin: >-
      services-platform:docs/security/security-administration.md#Policies and catalog (DEF-CRM-0557,
      2026-10-19)
  - id: BR-CAP-PFM-SEC-012-06
    proved_by: [ATS-PFM-SEC-012-05, TST-PFM-SEC-074, TST-PFM-SEC-101]
    statement: >-
      Roles compose built-in policies, active customer-owned policies and inline rules; cross-customer or
      archived policies and customer policies on built-in roles fail service and database checks.
    kind: invariant
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/db/security-definition-integrity.integration.spec.js#refuses
      another customer's policy, the one way authority could cross a wall through a definition
    origin: >-
      services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-11
      Final acceptance)
  - id: BR-CAP-PFM-SEC-012-07
    proved_by: [ATS-PFM-SEC-012-06, TST-PFM-SEC-102]
    statement: A role definition cannot carry scope; assignments determine where the role applies.
    kind: validation
    enforced_at:
      - api
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/definitions/role-request-scope.integration.spec.js#refuses
      a create that states intended_scope as an unknown field, and writes no role
    origin: >-
      services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-13/14
      Final acceptance)
  - id: BR-CAP-PFM-SEC-012-08
    proved_by: [ATS-PFM-SEC-012-07, TST-PFM-SEC-052]
    statement: >-
      An empty role is allowed and labelled as granting nothing, as are deny-only roles or roles whose
      policies supply no active allow rules.
    kind: calculation
    enforced_at:
      - service
      - console
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#answers a role whose only rule
      denies as granting nothing
    origin: >-
      services-platform:docs/security/security-administration.md#Placeholder roles (D-18, Andrew
      2026-10-19)
  - id: BR-CAP-PFM-SEC-012-09
    proved_by: [ATS-PFM-SEC-010-21, ATS-PFM-SEC-012-08, ATS-PFM-SEC-012-14, ATS-PFM-SEC-012-16, TST-PFM-SEC-034, TST-PFM-SEC-052]
    statement: >-
      Custom definitions use archive rather than deletion; assigned roles and referenced policies cannot
      be archived, and refusal details identify their users.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/definitions/manage-roles.integration.spec.js#refuses
      to archive a role somebody still holds, names them, and leaves it active
    origin: >-
      services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-11
      Final acceptance)
  - id: BR-CAP-PFM-SEC-012-10
    proved_by: [ATS-PFM-SEC-011-10, ATS-PFM-SEC-012-09, ATS-PFM-SEC-012-15, ATS-PFM-SEC-012-17, TST-PFM-SEC-100, TST-PFM-SEC-101]
    statement: >-
      Definition edits that free permissions, including conditional-deny weakening, require the editor’s
      effective authority at affected grant scopes and reject widening affecting the editor’s own grants.
    kind: permission
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/definitions/manage-roles.integration.spec.js#refuses
      an edit that would widen a role the editor holds themselves, whoever else holds it
    origin: 'services-platform:docs/security/security-administration.md#4. Delegation, escalation and lockout'
  - id: BR-CAP-PFM-SEC-012-11
    proved_by: [ATS-PFM-SEC-012-10, TST-PFM-SEC-101, TST-PFM-SEC-192]
    statement: A role edit that removes the customer’s remaining qualifying security administrator rolls back.
    kind: invariant
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/definitions/manage-roles.integration.spec.js#refuses
      an edit that would leave the customer with no security administrator, and detaches nothing
    origin: >-
      services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-11
      Final acceptance)
  - id: BR-CAP-PFM-SEC-012-12
    proved_by: [ATS-PFM-SEC-012-11, TST-PFM-SEC-025, TST-PFM-SEC-052, TST-PFM-SEC-100, TST-PFM-SEC-101]
    statement: >-
      Definition changes require the current version and reject stale edits without overwriting the saved
      definition.
    kind: validation
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/definitions/manage-policies.integration.spec.js#refuses
      an edit made against a version the policy has moved past, leaving the row as it was
    origin: 'services-platform:docs/standards/record-write-contracts.md#D-05'
  - id: BR-CAP-PFM-SEC-012-13
    proved_by: []
    statement: >-
      Permission-changing saves and archive request an authorizer flush after commit; renames and
      unchanged saves do not, and submission does not establish gateway eviction.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/definitions/definition-flush.integration.spec.js#submits
      no flush for a rename alone
    origin: >-
      services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-13/14
      Final acceptance)
  - id: BR-CAP-PFM-SEC-012-14
    proved_by: [ATS-PFM-SEC-012-12, TST-PFM-SEC-052]
    statement: >-
      Customer definition operations hide staff-only roles and policies as unavailable and prohibit
      copying or composing from them.
    kind: permission
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#refuses a role built from a
      staff-only policy, and copying a staff-only role or policy
    origin: 'services-platform:docs/hq/rhythm-hq-plan.md#D1'
  - id: BR-CAP-PFM-SEC-012-15
    proved_by: []
    statement: >-
      The editor’s permission catalog includes application, tier and sensitivity and omits staff-only
      keys for non-staff callers.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#leaves the staff-only keys out
      for a caller who is not staff
    origin: >-
      services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-13/14
      Final acceptance)
scenarios:
  - id: SC-CAP-PFM-SEC-012-01
    given: The finance team needs export access constrained by its work schedule.
    when: An authorized administrator prepares the relevant deny policy and attaches it to the Finance role.
    then: >-
      Evaluation applies the policy’s schedule conditions, and the policy view identifies the role using
      it.
    provenance: test
    source: 'react-console:e2e/security/policies.spec.ts#is used by a role, and the policy says so'
  - id: SC-CAP-PFM-SEC-012-02
    given: The customer wants a variation of Standard User.
    when: An authorized administrator duplicates that built-in role and adds an allowed inline permission.
    then: The customer owns the copy and can identify the built-in version it came from.
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#answers a copied role where it
      came from, with the version copied and the version of the source today
edge_cases: []
constraints: []
depends_on:
  - CAP-PFM-SEC-013
related:
  - CAP-PFM-SEC-010
  - CAP-PFM-SEC-011
  - CAP-PFM-SEC-014
journeys:
  - 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; docs/standards/record-write-contracts.md;
    modules/security/services/persistence/rules.ts; modules/security/tests/e2e/definitions.e2e.spec.js;
    modules/security/tests/integration/db/security-definition-integrity.integration.spec.js;
    modules/security/tests/integration/services/definitions/definition-flush.integration.spec.js;
    modules/security/tests/integration/services/definitions/manage-policies.integration.spec.js;
    modules/security/tests/integration/services/definitions/manage-roles.integration.spec.js;
    modules/security/tests/integration/services/definitions/role-request-scope.integration.spec.js;
    modules/security/tests/unit/services/persistence/rule-validation.spec.ts.
  - 'Pinned react-console references for the structured rows: e2e/security/policies.spec.ts.'
controls: [TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-AZ-006, TC-CHG-001, TC-CHG-002, TC-CHG-003, TC-CHG-004, TC-CHG-005, TC-CHG-006, TC-CRY-001, TC-CRY-002, TC-CRY-003, TC-CRY-004, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-DAT-005, TC-IAM-001, TC-IAM-002, TC-IAM-003, TC-IAM-004, TC-IAM-005, TC-IAM-006, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-MON-001, TC-MON-003, TC-PI-001, TC-PI-003, TC-PI-005, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-VEN-001, TC-VEN-002, TC-VEN-003]
exercised_by: [FAS-PFM-SEC-04-01, FAS-PFM-SEC-04-02, FAS-PFM-SEC-04-03, FAS-PFM-SEC-04-04]
suites: [TST-PFM-SEC-025, TST-PFM-SEC-028, TST-PFM-SEC-033, TST-PFM-SEC-034, TST-PFM-SEC-052, TST-PFM-SEC-074, TST-PFM-SEC-100, TST-PFM-SEC-101, TST-PFM-SEC-102, TST-PFM-SEC-192, TST-PFM-SEC-215]
---
# Model customer responsibilities with roles and policies

## Purpose

Customers need access definitions that reflect how their staff work. Roles and policies provide the reusable building blocks administrators assemble before assigning authority to colleagues.

## How It Works

The administrator starts with available policies or creates a customer policy. The rule editor supplies catalog choices and validation feedback. Conditions can express supported restrictions, while eligibility references depend on the separate binding owner and deployed switch. The administrator assembles a role from policies and inline rules. A placeholder role can be saved without implying it already grants access. Copying a built-in provides a starting point for customer changes while preserving a reference to its source. Before changing a definition in use, staff inspect affected assignments and any delegation refusal. A stale save asks the editor to reconcile newer work instead of overwrite it. Archive gives an unused definition a retained history; in-use refusal identifies what staff must address first. Permission changes request cache propagation but do not promise that every previously cached request immediately sees the edit.

## Relationships

- The release catalog supplies built-in definitions and permission names.
- Scoped role assignment applies the composed role to people.
- Security history explains definition edits and their impact.
- Eligibility owns the bindings used by supported eligibility conditions.
