---
id: ATS-PFM-SEC-012
scope: CAP-PFM-SEC-012
product_area: platform
module: security
revision: 3
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-PFM-SEC-012-01
    title: Separate read and management permissions
    level: api
    proves:
      - BR-CAP-PFM-SEC-012-01
    preconditions: Prepare a caller holding only definition-read keys.
    steps: Read a role and attempt creation.
    expected: Reading succeeds while the write is refused.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        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
      - TST-PFM-SEC-052
      - >-
        react-console:e2e/mock/security-view-edit.mock.spec.ts#somebody who may only read roles gets
        no Edit, and the edit page sends them to the view
      - TST-PFM-SEC-028
    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
    category: permission
    test_references:
      - >-
        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
      - >-
        react-console:e2e/mock/security-view-edit.mock.spec.ts#somebody who may only read roles gets
        no Edit, and the edit page sends them to the view
    action_evidence:
      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
    assertion_evidence:
      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
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-012-02
    title: Built-in integrity and copy provenance
    level: api
    proves:
      - BR-CAP-PFM-SEC-012-02
    preconditions: Prepare a built-in policy and role.
    steps: 'Edit and copy each, then attempt a direct built-in mutation.'
    expected: >-
      Edits fail as read-only, copies retain source and version and database safeguards refuse the
      direct mutation.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        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
      - TST-PFM-SEC-052
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#copies a built-in into
        the customer, recording what it was copied from
      - >-
        services-platform:modules/security/tests/integration/db/security-definition-integrity.integration.spec.js#refuses
        an insert, an update and a delete of a built-in policy outside a reconciliation
      - TST-PFM-SEC-074
      - >-
        react-console:e2e/security/policies.spec.ts#shows a built-in policy read-only, and
        duplicates it into one that can be changed
      - TST-PFM-SEC-033
    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
    category: invariant
    test_references:
      - >-
        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
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#copies a built-in into
        the customer, recording what it was copied from
      - >-
        services-platform:modules/security/tests/integration/db/security-definition-integrity.integration.spec.js#refuses
        an insert, an update and a delete of a built-in policy outside a reconciliation
      - >-
        react-console:e2e/security/policies.spec.ts#shows a built-in policy read-only, and
        duplicates it into one that can be changed
    action_evidence:
      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
    assertion_evidence:
      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
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-012-03
    title: 'Catalog keys, patterns and nonempty selections'
    level: api
    proves:
      - BR-CAP-PFM-SEC-012-03
    preconditions: Use the current permission catalog.
    steps: >-
      Try allow and deny patterns, an unknown key, duplicate selections and an empty permission
      list.
    expected: >-
      The tested matching deny pattern succeeds; allow patterns and malformed selections fail with
      rule-specific guidance.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        react-console:e2e/security/policies.spec.ts#refuses an allow rule that names a wildcard, and
        accepts it as a deny
      - TST-PFM-SEC-033
      - >-
        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
      - TST-PFM-SEC-215
      - >-
        services-platform:modules/security/tests/unit/services/persistence/rule-validation.spec.ts#refuses
        an unknown key in a DENY too, because a deny nobody matches takes nothing away
      - >-
        services-platform:modules/security/tests/unit/services/persistence/rule-validation.spec.ts#refuses
        the same permission named twice, which is a mistake worth naming rather than absorbing
      - >-
        services-platform:modules/security/tests/unit/services/persistence/rule-validation.spec.ts#refuses
        a rule naming no permission, which would say nothing at all
    provenance: test
    source: >-
      react-console:e2e/security/policies.spec.ts#refuses an allow rule that names a wildcard, and
      accepts it as a deny
    category: validation
    test_references:
      - >-
        react-console:e2e/security/policies.spec.ts#refuses an allow rule that names a wildcard, and
        accepts it as a deny
      - >-
        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
      - >-
        services-platform:modules/security/tests/unit/services/persistence/rule-validation.spec.ts#refuses
        an unknown key in a DENY too, because a deny nobody matches takes nothing away
      - >-
        services-platform:modules/security/tests/unit/services/persistence/rule-validation.spec.ts#refuses
        the same permission named twice, which is a mistake worth naming rather than absorbing
      - >-
        services-platform:modules/security/tests/unit/services/persistence/rule-validation.spec.ts#refuses
        a rule naming no permission, which would say nothing at all
    action_evidence:
      provenance: test
      source: >-
        react-console:e2e/security/policies.spec.ts#refuses an allow rule that names a wildcard, and
        accepts it as a deny
    assertion_evidence:
      provenance: test
      source: >-
        react-console:e2e/security/policies.spec.ts#refuses an allow rule that names a wildcard, and
        accepts it as a deny
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-012-04
    title: Condition interpretation
    level: unit
    proves:
      - BR-CAP-PFM-SEC-012-04
    preconditions: Prepare a rule-validation request.
    steps: Validate a supported condition and an unsupported shape.
    expected: The supported form passes and the unsupported condition is refused.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/unit/services/persistence/rule-validation.spec.ts#accepts
        a rule carrying a condition the evaluator can read
      - TST-PFM-SEC-215
      - >-
        services-platform:modules/security/tests/unit/services/persistence/rule-validation.spec.ts#refuses
        a condition the evaluator could only read as UNKNOWN
    provenance: test
    source: >-
      services-platform:modules/security/tests/unit/services/persistence/rule-validation.spec.ts#accepts
      a rule carrying a condition the evaluator can read
    category: validation
    test_references:
      - >-
        services-platform:modules/security/tests/unit/services/persistence/rule-validation.spec.ts#accepts
        a rule carrying a condition the evaluator can read
      - >-
        services-platform:modules/security/tests/unit/services/persistence/rule-validation.spec.ts#refuses
        a condition the evaluator could only read as UNKNOWN
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/unit/services/persistence/rule-validation.spec.ts#accepts
        a rule carrying a condition the evaluator can read
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/unit/services/persistence/rule-validation.spec.ts#accepts
        a rule carrying a condition the evaluator can read
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-012-05
    title: Policy ownership and lifecycle on attachments
    level: api
    proves:
      - BR-CAP-PFM-SEC-012-06
      - INV-DOM-PFM-SEC-003-14
    preconditions: Prepare policies from two customers and an archived policy.
    steps: 'Attach the foreign and archived policies, then try a custom policy on a built-in role.'
    expected: The tested API and database paths reject every invalid attachment.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/integration/services/definitions/manage-roles.integration.spec.js#refuses
        a reference to another customer's policy, and writes no role at all
      - TST-PFM-SEC-101
      - >-
        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
      - TST-PFM-SEC-074
      - >-
        services-platform:modules/security/tests/integration/db/security-definition-integrity.integration.spec.js#refuses
        a customer's policy on a built-in role, which must mean the same thing for everybody
      - >-
        services-platform:modules/security/tests/integration/db/security-definition-integrity.integration.spec.js#refuses
        an archived policy, because an attachment is a live grant
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/definitions/manage-roles.integration.spec.js#refuses
      a reference to another customer's policy, and writes no role at all
    category: boundary
    test_references:
      - >-
        services-platform:modules/security/tests/integration/services/definitions/manage-roles.integration.spec.js#refuses
        a reference to another customer's policy, and writes no role at all
      - >-
        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
      - >-
        services-platform:modules/security/tests/integration/db/security-definition-integrity.integration.spec.js#refuses
        a customer's policy on a built-in role, which must mean the same thing for everybody
      - >-
        services-platform:modules/security/tests/integration/db/security-definition-integrity.integration.spec.js#refuses
        an archived policy, because an attachment is a live grant
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/services/definitions/manage-roles.integration.spec.js#refuses
        a reference to another customer's policy, and writes no role at all
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/services/definitions/manage-roles.integration.spec.js#refuses
        a reference to another customer's policy, and writes no role at all
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-012-06
    title: Role requests cannot declare scope
    level: api
    proves:
      - BR-CAP-PFM-SEC-012-07
    preconditions: Prepare role creation and edit requests.
    steps: Include a scope field in both requests.
    expected: Both fail unknown-field validation.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        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
      - TST-PFM-SEC-102
      - >-
        services-platform:modules/security/tests/integration/services/definitions/role-request-scope.integration.spec.js#refuses
        an edit that states intended_scope as an unknown field, and leaves the role as it was
    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
    category: validation
    test_references:
      - >-
        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
      - >-
        services-platform:modules/security/tests/integration/services/definitions/role-request-scope.integration.spec.js#refuses
        an edit that states intended_scope as an unknown field, and leaves the role as it was
    action_evidence:
      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
    assertion_evidence:
      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
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-012-07
    title: Grants-nothing presentation
    level: api
    proves:
      - BR-CAP-PFM-SEC-012-08
    preconditions: Prepare empty and deny-only role requests.
    steps: 'Save both, inspect record and list, then attach an active allowing policy to the empty role.'
    expected: >-
      The initial definitions are labelled as granting nothing; the label clears when allowing
      authority is added.
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#saves a role with
        neither policies nor rules, and answers that it grants nothing
      - TST-PFM-SEC-052
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#answers a role whose
        only rule denies as granting nothing
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#stops answering
        grants-nothing once the draft is given a policy
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#saves a role with neither
      policies nor rules, and answers that it grants nothing
    category: edge
    test_references:
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#saves a role with
        neither policies nor rules, and answers that it grants nothing
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#answers a role whose
        only rule denies as granting nothing
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#stops answering
        grants-nothing once the draft is given a policy
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#saves a role with
        neither policies nor rules, and answers that it grants nothing
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#saves a role with
        neither policies nor rules, and answers that it grants nothing
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-012-08
    title: Archive dependency refusals
    level: api
    proves:
      - BR-CAP-PFM-SEC-012-09
      - INV-DOM-PFM-SEC-003-15
    preconditions: 'Prepare an assigned role, referenced policy and unused definitions.'
    steps: Archive each definition.
    expected: >-
      The in-use definitions fail with holder or role details; unused definitions archive
      successfully.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#refuses to archive a
        role somebody still holds, naming the holders in the details
      - TST-PFM-SEC-052
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#refuses to archive a
        policy a role still uses, naming the roles in the details
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#archives a role nobody
        holds, through the same route a held one is refused by
      - >-
        react-console:e2e/security/roles.spec.ts#refuses to archive a role somebody still holds, and
        names them
      - TST-PFM-SEC-034
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#refuses to archive a role
      somebody still holds, naming the holders in the details
    category: transition
    test_references:
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#refuses to archive a
        role somebody still holds, naming the holders in the details
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#refuses to archive a
        policy a role still uses, naming the roles in the details
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#archives a role nobody
        holds, through the same route a held one is refused by
      - >-
        react-console:e2e/security/roles.spec.ts#refuses to archive a role somebody still holds, and
        names them
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#refuses to archive a
        role somebody still holds, naming the holders in the details
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#refuses to archive a
        role somebody still holds, naming the holders in the details
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-012-09
    title: Widening and self-widening during edits
    level: api
    proves:
      - BR-CAP-PFM-SEC-012-10
    preconditions: Prepare a held role and an editor lacking some affected keys.
    steps: >-
      Add a missing key, weaken a conditional deny, widen an editor-held role and rename a
      definition.
    expected: The tested widening attempts fail while the rename succeeds.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/integration/services/definitions/manage-policies.integration.spec.js#refuses
        an edit that would add a key the editor is not allowed where the policy is already held
      - TST-PFM-SEC-100
      - >-
        services-platform:modules/security/tests/integration/services/definitions/manage-policies.integration.spec.js#refuses
        an edit that weakens a conditional deny, for an editor who is not allowed the key it was
        holding back
      - >-
        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
      - TST-PFM-SEC-101
      - >-
        services-platform:modules/security/tests/integration/services/definitions/manage-policies.integration.spec.js#allows
        the same editor to rename a held policy, because a rename frees nothing
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/definitions/manage-policies.integration.spec.js#refuses
      an edit that would add a key the editor is not allowed where the policy is already held
    category: permission
    test_references:
      - >-
        services-platform:modules/security/tests/integration/services/definitions/manage-policies.integration.spec.js#refuses
        an edit that would add a key the editor is not allowed where the policy is already held
      - >-
        services-platform:modules/security/tests/integration/services/definitions/manage-policies.integration.spec.js#refuses
        an edit that weakens a conditional deny, for an editor who is not allowed the key it was
        holding back
      - >-
        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
      - >-
        services-platform:modules/security/tests/integration/services/definitions/manage-policies.integration.spec.js#allows
        the same editor to rename a held policy, because a rename frees nothing
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/services/definitions/manage-policies.integration.spec.js#refuses
        an edit that would add a key the editor is not allowed where the policy is already held
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/services/definitions/manage-policies.integration.spec.js#refuses
        an edit that would add a key the editor is not allowed where the policy is already held
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-012-10
    title: Last-administrator role protection
    level: api
    proves:
      - BR-CAP-PFM-SEC-012-11
      - INV-DOM-PFM-SEC-003-12
    preconditions: Prepare the role supplying the only qualifying security administrator.
    steps: Detach its security-administrator policy.
    expected: The edit fails and preserves the policy attachment.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        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
      - TST-PFM-SEC-101
      - >-
        services-platform:modules/security/tests/integration/services/staff-access/staff-customer-administration.integration.spec.js#refuses
        staff taking the Security Administrator policy off the role that makes them administrator,
        as a lockout
      - TST-PFM-SEC-192
    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
    category: invariant
    test_references:
      - >-
        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
      - >-
        services-platform:modules/security/tests/integration/services/staff-access/staff-customer-administration.integration.spec.js#refuses
        staff taking the Security Administrator policy off the role that makes them administrator,
        as a lockout
    action_evidence:
      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
    assertion_evidence:
      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
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-012-11
    title: Stale definition edits
    level: api
    proves:
      - BR-CAP-PFM-SEC-012-12
    preconditions: Prepare a definition changed after its earlier read.
    steps: Save using the old version.
    expected: The edit fails and preserves the newer stored definition.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        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
      - TST-PFM-SEC-100
      - >-
        services-platform:modules/security/tests/integration/services/definitions/manage-roles.integration.spec.js#refuses
        an edit made against a version the role has moved past, leaving the row as it was
      - TST-PFM-SEC-101
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#changes a policy at the
        version If-Match states, and refuses the same change twice
      - TST-PFM-SEC-052
      - >-
        react-console:e2e/mock/security-editor-bar.mock.spec.ts#a stale save is the bar's conflict,
        and Reload takes what was saved
      - TST-PFM-SEC-025
    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
    category: concurrency
    test_references:
      - >-
        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
      - >-
        services-platform:modules/security/tests/integration/services/definitions/manage-roles.integration.spec.js#refuses
        an edit made against a version the role has moved past, leaving the row as it was
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#changes a policy at the
        version If-Match states, and refuses the same change twice
      - >-
        react-console:e2e/mock/security-editor-bar.mock.spec.ts#a stale save is the bar's conflict,
        and Reload takes what was saved
    action_evidence:
      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
    assertion_evidence:
      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
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-012-12
    title: Staff-definition isolation
    level: api
    proves:
      - BR-CAP-PFM-SEC-012-14
      - INV-DOM-PFM-SEC-003-14
    preconditions: Sign in as a customer administrator.
    steps: 'List definitions, read a staff role and its members, and try copying or composing from it.'
    expected: 'Lists omit staff-only definitions, reads return 404 and composition attempts fail.'
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#lists every role but
        the staff-only ones, the built-ins a customer assigns among them
      - TST-PFM-SEC-052
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#answers 404 for a
        staff-only role and policy read by their keys, as for a role that is not there
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#answers 404 for the
        members of a staff-only role
      - >-
        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
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#lists every role but the
      staff-only ones, the built-ins a customer assigns among them
    category: boundary
    test_references:
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#lists every role but
        the staff-only ones, the built-ins a customer assigns among them
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#answers 404 for a
        staff-only role and policy read by their keys, as for a role that is not there
      - >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#answers 404 for the
        members of a staff-only role
      - >-
        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
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#lists every role but
        the staff-only ones, the built-ins a customer assigns among them
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#lists every role but
        the staff-only ones, the built-ins a customer assigns among them
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-012-13
    title: Custom definition creation and dependencies
    level: browser
    proves:
      - AS-JNY-PFM-SEC-004-01
      - AS-JNY-PFM-SEC-004-02
    preconditions: Sign in as a security administrator.
    steps: >-
      Create a policy and role, find the role in its list and archive the policy after removing its
      use.
    expected: >-
      The rule requires a permission, the role is searchable and custom, and policy presentation
      identifies its dependent role before archive.
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        react-console:e2e/security/policies.spec.ts#is created with a rule, and the rule has to name
        a permission
      - TST-PFM-SEC-033
      - 'react-console:e2e/security/roles.spec.ts#is created from a name and a permission'
      - TST-PFM-SEC-034
      - 'react-console:e2e/security/roles.spec.ts#is on the Roles list, searchable, and marked custom'
      - 'react-console:e2e/security/policies.spec.ts#is used by a role, and the policy says so'
      - 'react-console:e2e/security/policies.spec.ts#is archived once no role references it'
    provenance: test
    source: >-
      react-console:e2e/security/policies.spec.ts#is created with a rule, and the rule has to name a
      permission
    category: interaction
    test_references:
      - >-
        react-console:e2e/security/policies.spec.ts#is created with a rule, and the rule has to name
        a permission
      - 'react-console:e2e/security/roles.spec.ts#is created from a name and a permission'
      - 'react-console:e2e/security/roles.spec.ts#is on the Roles list, searchable, and marked custom'
      - 'react-console:e2e/security/policies.spec.ts#is used by a role, and the policy says so'
      - 'react-console:e2e/security/policies.spec.ts#is archived once no role references it'
    action_evidence:
      provenance: test
      source: >-
        react-console:e2e/security/policies.spec.ts#is created with a rule, and the rule has to name
        a permission
    assertion_evidence:
      provenance: test
      source: >-
        react-console:e2e/security/policies.spec.ts#is created with a rule, and the rule has to name
        a permission
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-012-14
    title: 'Custom and built-in access definition: active to archived'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-012-09
    state_model: STATE-PFM-SEC-008
    transition:
      from: active
      to: archived
      index: 0
    preconditions: >-
      Prepare a run-owned custom and built-in access definition in active state with the authority
      and inputs required by the cited transition.
    steps:
      - do: >-
          Archive an unreferenced custom definition with management permission and its current
          version.
        expect: >-
          After the stated action, observe the custom and built-in access definition in archived
          state. This case does not require an additional history event unless the transition
          explicitly defines one.
        provenance: proposed
        source:
          - >-
            services-platform:modules/security/services/definitions/manage-roles.ts:archiveCustomRole
          - >-
            services-platform at ad3f6a65: modules/security/db/security-roles.table.ts,
            security-policies.table.ts; services/definitions/manage-roles.ts, manage-policies.ts,
            impact.ts; services/catalog/*.
    expected: >-
      After the stated action, observe the custom and built-in access definition in archived state.
      This case does not require an additional history event unless the transition explicitly
      defines one.
    negative: false
    data_needs: >-
      A disposable customer, workspace and named actor; a controllable clock where the transition
      depends on time.
    bound_to: []
    provenance: proposed
    source:
      - 'services-platform:modules/security/services/definitions/manage-roles.ts:archiveCustomRole'
      - >-
        services-platform at ad3f6a65: modules/security/db/security-roles.table.ts,
        security-policies.table.ts; services/definitions/manage-roles.ts, manage-policies.ts,
        impact.ts; services/catalog/*.
    guard_cases: >-
      Management authority is required; a supplied version is checked, and assignments or policy
      references must not prevent archive.
    side_effects_to_verify:
      - Record security history and request a post-commit flush
    transition_assertion:
      state: archived
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/definitions/manage-roles.ts:archiveCustomRole'
        - >-
          services-platform at ad3f6a65: modules/security/db/security-roles.table.ts,
          security-policies.table.ts; services/definitions/manage-roles.ts, manage-policies.ts,
          impact.ts; services/catalog/*.
    action_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/definitions/manage-roles.ts:archiveCustomRole'
        - >-
          services-platform at ad3f6a65: modules/security/db/security-roles.table.ts,
          security-policies.table.ts; services/definitions/manage-roles.ts, manage-policies.ts,
          impact.ts; services/catalog/*.
    assertion_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/definitions/manage-roles.ts:archiveCustomRole'
        - >-
          services-platform at ad3f6a65: modules/security/db/security-roles.table.ts,
          security-policies.table.ts; services/definitions/manage-roles.ts, manage-policies.ts,
          impact.ts; services/catalog/*.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-012-15
    title: 'Custom and built-in access definition: active to active'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-012-10
    state_model: STATE-PFM-SEC-008
    transition:
      from: active
      to: active
      index: 3
    preconditions: >-
      Prepare a run-owned custom and built-in access definition in active state with the authority
      and inputs required by the cited transition.
    steps:
      - do: >-
          Change the active custom definition, then independently change a built-in through release
          reconciliation.
        expect: >-
          After the stated action, observe the custom and built-in access definition in active
          state. This case does not require an additional history event unless the transition
          explicitly defines one.
        provenance: proposed
        source:
          - 'services-platform:modules/security/services/definitions/manage-roles.ts:updateCustomRole'
          - >-
            services-platform at ad3f6a65: modules/security/db/security-roles.table.ts,
            security-policies.table.ts; services/definitions/manage-roles.ts, manage-policies.ts,
            impact.ts; services/catalog/*.
    expected: >-
      After the stated action, observe the custom and built-in access definition in active state.
      This case does not require an additional history event unless the transition explicitly
      defines one.
    negative: false
    data_needs: >-
      A disposable customer, workspace and named actor; a controllable clock where the transition
      depends on time.
    bound_to: []
    provenance: proposed
    source:
      - 'services-platform:modules/security/services/definitions/manage-roles.ts:updateCustomRole'
      - >-
        services-platform at ad3f6a65: modules/security/db/security-roles.table.ts,
        security-policies.table.ts; services/definitions/manage-roles.ts, manage-policies.ts,
        impact.ts; services/catalog/*.
    guard_cases: >-
      Custom edits validate rules, check any supplied version, delegation and lockout; built-in
      edits require a material content change.
    side_effects_to_verify:
      - >-
        Increment the changed record’s version, return impact and request flushing when permissions
        change
    transition_assertion:
      state: active
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/definitions/manage-roles.ts:updateCustomRole'
        - >-
          services-platform at ad3f6a65: modules/security/db/security-roles.table.ts,
          security-policies.table.ts; services/definitions/manage-roles.ts, manage-policies.ts,
          impact.ts; services/catalog/*.
    action_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/definitions/manage-roles.ts:updateCustomRole'
        - >-
          services-platform at ad3f6a65: modules/security/db/security-roles.table.ts,
          security-policies.table.ts; services/definitions/manage-roles.ts, manage-policies.ts,
          impact.ts; services/catalog/*.
    assertion_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/definitions/manage-roles.ts:updateCustomRole'
        - >-
          services-platform at ad3f6a65: modules/security/db/security-roles.table.ts,
          security-policies.table.ts; services/definitions/manage-roles.ts, manage-policies.ts,
          impact.ts; services/catalog/*.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-012-16
    title: >-
      Model customer responsibilities with roles and policies with assign roles within a controlled
      scope
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-010-07
      - BR-CAP-PFM-SEC-012-09
    exercises:
      - CAP-PFM-SEC-012
      - CAP-PFM-SEC-010
    preconditions: A custom role is assigned to an active member.
    steps: 'Try archiving the role, withdraw its assignment, and archive again.'
    expected: >-
      The held role cannot be archived; after withdrawal it can leave the active list while history
      remains.
    negative: true
    data_needs: >-
      An isolated customer with two workspaces, ordinary and staff identities, and records owned by
      this run.
    bound_to: []
    provenance: proposed
    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
      - >-
        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
    action_evidence:
      provenance: proposed
      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
        - >-
          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
    assertion_evidence:
      provenance: proposed
      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
        - >-
          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
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-012-17
    title: >-
      Model customer responsibilities with roles and policies with review security changes and
      refused attempts
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-011-02
      - BR-CAP-PFM-SEC-012-10
    exercises:
      - CAP-PFM-SEC-012
      - CAP-PFM-SEC-011
    preconditions: A role editor lacks authority for a requested widening change.
    steps: Attempt the edit and inspect the definition and refusal history.
    expected: The definition is unchanged and the classified refusal survives rollback.
    negative: true
    data_needs: >-
      An isolated customer with two workspaces, ordinary and staff identities, and records owned by
      this run.
    bound_to: []
    provenance: proposed
    source:
      - 'services-platform:modules/security/services/audit/refused-attempts.ts:auditedAttempt'
      - >-
        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
    action_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/audit/refused-attempts.ts:auditedAttempt'
        - >-
          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
    assertion_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/audit/refused-attempts.ts:auditedAttempt'
        - >-
          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
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-012-18
    title: >-
      Model customer responsibilities with roles and policies with derive member access from
      appointments and eligibility
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-012-04
      - BR-CAP-PFM-SEC-014-12
    exercises:
      - CAP-PFM-SEC-012
      - CAP-PFM-SEC-014
    preconditions: A customer role uses an eligibility condition binding in its own workspace.
    steps: 'Evaluate the condition, then try replacing it with another customer’s binding.'
    expected: >-
      The owned condition participates in evaluation; the foreign replacement is refused without
      changing the definition.
    negative: true
    data_needs: >-
      An isolated customer with two workspaces, ordinary and staff identities, and records owned by
      this run.
    bound_to: []
    provenance: proposed
    source:
      - 'services-platform:modules/security/services/persistence/rules.ts:parseConditions'
      - >-
        services-platform:modules/security/tests/integration/services/definitions/eligibility-conditions.integration.spec.js#refuses
        a binding of another customer’s tenant, naming it, and stores no policy
    action_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/persistence/rules.ts:parseConditions'
        - >-
          services-platform:modules/security/tests/integration/services/definitions/eligibility-conditions.integration.spec.js#refuses
          a binding of another customer’s tenant, naming it, and stores no policy
    assertion_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/persistence/rules.ts:parseConditions'
        - >-
          services-platform:modules/security/tests/integration/services/definitions/eligibility-conditions.integration.spec.js#refuses
          a binding of another customer’s tenant, naming it, and stores no policy
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
evidence:
  - >-
    Pinned services-platform references for the structured rows:
    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/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/integration/services/staff-access/staff-customer-administration.integration.spec.js;
    modules/security/tests/unit/services/persistence/rule-validation.spec.ts.
  - >-
    Pinned react-console references for the structured rows:
    e2e/mock/security-editor-bar.mock.spec.ts; e2e/mock/security-view-edit.mock.spec.ts;
    e2e/security/policies.spec.ts; e2e/security/roles.spec.ts.
  - >-
    Testing back-fill reviews the pinned suite assertions, related capabilities, domain invariants,
    state transitions and workflow failure boundaries. New unbound rows remain proposed.
coverage:
  rule: 'gap: FND-PFM-SEC-069'
  transition: covered
  validation: covered
  permission: covered
  edge: covered
  failure: 'gap: FND-PFM-SEC-069'
  boundary: covered
  concurrency: covered
  invariant: covered
  interaction: covered
coverage_notes:
  rule: No scenario isolates this category. The referenced finding retains the missing design proof.
  failure: No scenario isolates this category. The referenced finding retains the missing design proof.
invariant_proofs:
  - scenario: ATS-PFM-SEC-012-05
    proves:
      - INV-DOM-PFM-SEC-003-14
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/definitions/manage-roles.integration.spec.js#refuses
      a reference to another customer's policy, and writes no role at all
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
  - scenario: ATS-PFM-SEC-012-08
    proves:
      - INV-DOM-PFM-SEC-003-15
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#refuses to archive a role
      somebody still holds, naming the holders in the details
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
  - scenario: ATS-PFM-SEC-012-10
    proves:
      - INV-DOM-PFM-SEC-003-12
    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
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
  - scenario: ATS-PFM-SEC-012-12
    proves:
      - INV-DOM-PFM-SEC-003-14
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/definitions.e2e.spec.js#lists every role but the
      staff-only ones, the built-ins a customer assigns among them
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
permission_proof_review:
  - key: platform.security-roles.read
    scenario_candidates:
      - ATS-PFM-SEC-012-01
      - ATS-PFM-SEC-012-09
      - ATS-PFM-SEC-012-12
      - ATS-PFM-SEC-012-15
      - ATS-PFM-SEC-012-17
    qualification: >-
      These are candidate scenarios for the authority boundary, not an exhaustive allowed/refused
      matrix for this key. The finding retains combinations not established by the executable
      assertions.
    gap: FND-PFM-SEC-069
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-012-define-a-customer-s-own-roles-and-policies.md
  - key: platform.security-roles.manage
    scenario_candidates:
      - ATS-PFM-SEC-012-01
      - ATS-PFM-SEC-012-09
      - ATS-PFM-SEC-012-12
      - ATS-PFM-SEC-012-15
      - ATS-PFM-SEC-012-17
    qualification: >-
      These are candidate scenarios for the authority boundary, not an exhaustive allowed/refused
      matrix for this key. The finding retains combinations not established by the executable
      assertions.
    gap: FND-PFM-SEC-069
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-012-define-a-customer-s-own-roles-and-policies.md
  - key: platform.security-policies.read
    scenario_candidates:
      - ATS-PFM-SEC-012-01
      - ATS-PFM-SEC-012-09
      - ATS-PFM-SEC-012-12
      - ATS-PFM-SEC-012-15
      - ATS-PFM-SEC-012-17
    qualification: >-
      These are candidate scenarios for the authority boundary, not an exhaustive allowed/refused
      matrix for this key. The finding retains combinations not established by the executable
      assertions.
    gap: FND-PFM-SEC-069
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-012-define-a-customer-s-own-roles-and-policies.md
  - key: platform.security-policies.manage
    scenario_candidates:
      - ATS-PFM-SEC-012-01
      - ATS-PFM-SEC-012-09
      - ATS-PFM-SEC-012-12
      - ATS-PFM-SEC-012-15
      - ATS-PFM-SEC-012-17
    qualification: >-
      These are candidate scenarios for the authority boundary, not an exhaustive allowed/refused
      matrix for this key. The finding retains combinations not established by the executable
      assertions.
    gap: FND-PFM-SEC-069
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-012-define-a-customer-s-own-roles-and-policies.md
examiner: codex
examined_at: '2026-10-23'
final_text: OpenAI
---
# Model customer responsibilities with roles and policies: Capability Test Specification

## Coverage

| Required rule | Scenario or finding |
|---|---|
| `BR-CAP-PFM-SEC-012-01` | `ATS-PFM-SEC-012-01` |
| `BR-CAP-PFM-SEC-012-02` | `ATS-PFM-SEC-012-02` |
| `BR-CAP-PFM-SEC-012-03` | `ATS-PFM-SEC-012-03` |
| `BR-CAP-PFM-SEC-012-04` | `ATS-PFM-SEC-012-04`, `ATS-PFM-SEC-012-18` |
| `BR-CAP-PFM-SEC-012-06` | `ATS-PFM-SEC-012-05` |
| `BR-CAP-PFM-SEC-012-07` | `ATS-PFM-SEC-012-06` |
| `BR-CAP-PFM-SEC-012-08` | `ATS-PFM-SEC-012-07` |
| `BR-CAP-PFM-SEC-012-09` | `ATS-PFM-SEC-012-08`, `ATS-PFM-SEC-012-14`, `ATS-PFM-SEC-012-16` |
| `BR-CAP-PFM-SEC-012-10` | `ATS-PFM-SEC-012-09`, `ATS-PFM-SEC-012-15`, `ATS-PFM-SEC-012-17` |
| `BR-CAP-PFM-SEC-012-11` | `ATS-PFM-SEC-012-10` |
| `BR-CAP-PFM-SEC-012-12` | `ATS-PFM-SEC-012-11` |
| `BR-CAP-PFM-SEC-012-14` | `ATS-PFM-SEC-012-12` |

The category map records specified proof. A covered category can contain proposed scenarios; it does not mean the checks have run. The bindings identify individual executable contributions, while findings retain missing rules, permissions, transitions and assertions.

## Interactions With Related Capabilities

The interaction scenarios connect this capability to the related actions and workflow handoffs named in their proof references. Each case observes the outcome after the connected action changes records or available authority. A collection of separately bound checks does not establish an ordered feature journey.

Source revisions and assertion references are recorded in frontmatter. Steps and expected observations carry separate evidence annotations. Proposed checks remain distinct from executable test statements, and static review supplies no run result.
