---
id: ATS-PFM-NOT-003
scope: CAP-PFM-NOT-003
product_area: platform
module: notifications
revision: 2
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-PFM-NOT-003-01
    title: Validate each audience selection
    level: unit
    proves:
      - BR-CAP-PFM-NOT-003-01
    preconditions: Prepare a definition accepting user and responsibility.
    steps: >-
      Plan audiences with a role entry, an empty list, an unrecognized kind and
      a resource scope with no id.
    expected: >-
      Invalid entries identify their own list positions and processing records
      an invalid request.
    negative: true
    data_needs: Use only records created and owned by this suite.
    bound_to:
      - >-
        services-platform:modules/notifications/tests/unit/audience-planner.spec.js#refuses
        a kind the definition does not accept, naming the kinds it does
      - >-
        services-platform:modules/notifications/tests/unit/audience-planner.spec.js#refuses
        an empty audience
      - >-
        services-platform:modules/notifications/tests/unit/audience-planner.spec.js#refuses
        a kind this release does not know
      - >-
        services-platform:modules/notifications/tests/unit/audience-planner.spec.js#refuses
        a resource scope with no id, naming the reference
      - >-
        services-platform:modules/notifications/tests/unit/audience-planner.spec.js#reports
        every refused entry at its own index
      - >-
        services-platform:modules/notifications/tests/integration/services/orchestration/orchestrate-request.integration.spec.js#refuses
        an audience kind the definition does not accept
      - TST-PFM-NOT-079
      - TST-PFM-NOT-104
    provenance: test
    source: >-
      services-platform:modules/notifications/tests/unit/audience-planner.spec.js#refuses
      a kind the definition does not accept, naming the kinds it does
    category: validation
    binding_scope: >-
      Each binding supplies its own assertions; the aggregate references do not
      imply that one executable file proves every step.
  - id: ATS-PFM-NOT-003-02
    title: Resolve responsibility holders at processing time
    level: api
    proves:
      - BR-CAP-PFM-NOT-003-02
    preconditions: >-
      Prepare a responsibility held by Jane; a published request for its holders
      not yet dispatched.
    steps: Transfer the responsibility from Jane to Sam before running dispatch.
    expected: The new holder Sam receives the notice; former holder Jane does not.
    negative: false
    data_needs: Use only records created and owned by this suite.
    bound_to:
      - >-
        services-platform:modules/notifications/tests/integration/services/orchestration/resolve-audience.integration.spec.js#changes
        the people when the responsibility is reassigned between the publish and
        the dispatch
      - TST-PFM-NOT-080
    provenance: test
    source: >-
      services-platform:modules/notifications/tests/integration/services/orchestration/resolve-audience.integration.spec.js#changes
      the people when the responsibility is reassigned between the publish and
      the dispatch
    category: interaction
    binding_scope: >-
      Each binding supplies its own assertions; the aggregate references do not
      imply that one executable file proves every step.
  - id: ATS-PFM-NOT-003-03
    title: 'Resolve scoped holders, delegates and fallback'
    level: api
    proves:
      - BR-CAP-PFM-NOT-003-03
    preconditions: >-
      Jane holds Northeast Batch posting and delegates it to Sam; Lee holds it
      in a different unit, and a fallback holder is available.
    steps: Resolve the holders at Northeast; next with nobody with it at Northeast.
    expected: >-
      Jane and her delegate Sam qualify, while Lee in another unit does not.
      With no holder, the applicable fallback holder qualifies.
    negative: false
    data_needs: Use only records created and owned by this suite.
    bound_to:
      - >-
        services-platform:modules/notifications/tests/integration/services/orchestration/resolve-audience.integration.spec.js#is
        the holders of that unit and not the holder of another unit
      - >-
        services-platform:modules/notifications/tests/integration/services/orchestration/resolve-audience.integration.spec.js#is
        the delegates of that unit’s holders too, worded as covering the
        responsibility
      - >-
        services-platform:modules/notifications/tests/integration/services/orchestration/resolve-audience.integration.spec.js#falls
        back to the fallback’s holders when nobody holds it at that unit, and
        not to the holder of another unit
      - >-
        react-console:acceptance/notifications/playwright/journeys/pipeline/NT-ACC-0201.spec.ts#NT-ACC-0201
      - TST-PFM-NOT-012
      - TST-PFM-NOT-080
    provenance: test
    source: >-
      services-platform:modules/notifications/tests/integration/services/orchestration/resolve-audience.integration.spec.js#is
      the holders of that unit and not the holder of another unit
    category: rule
    binding_scope: >-
      Each binding supplies its own assertions; the aggregate references do not
      imply that one executable file proves every step.
  - id: ATS-PFM-NOT-003-04
    title: Resolve active role and permission audiences
    level: api
    proves:
      - BR-CAP-PFM-NOT-003-04
    preconditions: >-
      Prepare a built-in role with two active holders; a permission granted by
      one role.
    steps: Resolve the role; the permission; a absent role; an ungranted permission.
    expected: >-
      Existing active role holders and permission grantees qualify; missing
      roles and ungranted permissions produce empty audiences.
    negative: false
    data_needs: Use only records created and owned by this suite.
    bound_to:
      - >-
        services-platform:modules/notifications/tests/integration/services/orchestration/resolve-audience.integration.spec.js#is
        the active holders of the built-in role at the tenant
      - >-
        services-platform:modules/notifications/tests/integration/services/orchestration/resolve-audience.integration.spec.js#is
        the people whose active roles grant it, compared as the authorizer does
      - >-
        services-platform:modules/notifications/tests/integration/services/orchestration/resolve-audience.integration.spec.js#is
        nobody for a role that does not exist
      - >-
        services-platform:modules/notifications/tests/integration/services/orchestration/resolve-audience.integration.spec.js#is
        nobody for a permission no role of the organization grants
      - TST-PFM-NOT-080
    provenance: test
    source: >-
      services-platform:modules/notifications/tests/integration/services/orchestration/resolve-audience.integration.spec.js#is
      the active holders of the built-in role at the tenant
    category: rule
    binding_scope: >-
      Each binding supplies its own assertions; the aggregate references do not
      imply that one executable file proves every step.
  - id: ATS-PFM-NOT-003-05
    title: Union recipients with exclusions and actor control
    level: unit
    proves:
      - BR-CAP-PFM-NOT-003-05
    preconditions: >-
      Prepare a audience of two entries overlapping on one person, an exclusion
      and the actor among them.
    steps: >-
      Evaluate recipient selection twice, excluding the actor first and enabling
      actor inclusion next.
    expected: >-
      Every selected user occurs once. Explicit exclusions and the actor are
      removed unless actor inclusion is requested.
    negative: false
    data_needs: Use only records created and owned by this suite.
    bound_to:
      - >-
        services-platform:modules/notifications/tests/unit/audience-planner.spec.js#is
        the union of what the lookups found, once each, in order of user id
      - >-
        services-platform:modules/notifications/tests/unit/audience-planner.spec.js#leaves
        out the excluded
      - >-
        services-platform:modules/notifications/tests/unit/audience-planner.spec.js#leaves
        out the actor, who is not told of their own act
      - >-
        services-platform:modules/notifications/tests/unit/audience-planner.spec.js#keeps
        the actor when the producer asks for it
      - >-
        services-platform:modules/notifications/tests/integration/services/orchestration/orchestrate-request.integration.spec.js#keeps
        the actor out of the audience unless the producer asks
      - TST-PFM-NOT-079
      - TST-PFM-NOT-104
    provenance: test
    source: >-
      services-platform:modules/notifications/tests/unit/audience-planner.spec.js#is
      the union of what the lookups found, once each, in order of user id
    category: invariant
    binding_scope: >-
      Each binding supplies its own assertions; the aggregate references do not
      imply that one executable file proves every step.
  - id: ATS-PFM-NOT-003-06
    title: Enforce the whole-request recipient limit
    level: api
    proves:
      - BR-CAP-PFM-NOT-003-06
      - INV-DOM-PFM-NOT-003-05
    preconditions: >-
      Prepare one two-hundred-person audience and another containing two hundred
      and one people.
    steps: Process a publication for each audience through the notification pipeline.
    expected: >-
      Two hundred recipients succeed. Two hundred and one makes the whole
      request invalid and inspectable in History.
    negative: true
    data_needs: Use only records created and owned by this suite.
    bound_to:
      - >-
        services-platform:modules/notifications/tests/unit/audience-planner.spec.js#accepts
        exactly 200 people
      - >-
        services-platform:modules/notifications/tests/unit/audience-planner.spec.js#refuses
        201 people as a whole, selecting nobody
      - >-
        services-platform:modules/notifications/tests/unit/audience-planner.spec.js#does
        not count the excluded and the actor towards the 200
      - >-
        services-platform:modules/notifications/tests/integration/services/orchestration/orchestrate-request.integration.spec.js#accepts
        an audience of exactly 200 people and refuses 201 as invalid
      - >-
        react-console:acceptance/notifications/playwright/journeys/pipeline/NT-ACC-0203.spec.ts#NT-ACC-0203
      - TST-PFM-NOT-014
      - TST-PFM-NOT-079
      - TST-PFM-NOT-104
    provenance: test
    source: >-
      services-platform:modules/notifications/tests/unit/audience-planner.spec.js#accepts
      exactly 200 people
    category: boundary
    binding_scope: >-
      Each binding supplies its own assertions; the aggregate references do not
      imply that one executable file proves every step.
    invariant_source: >-
      services-platform:modules/notifications/tests/unit/audience-planner.spec.js#refuses
      201 people as a whole, selecting nobody
  - id: ATS-PFM-NOT-003-07
    title: Exclude ineligible and cross-customer users
    level: api
    proves:
      - BR-CAP-PFM-NOT-003-07
      - INV-DOM-PFM-NOT-003-04
    preconditions: >-
      Prepare a request naming a member, a user of another customer, an invited
      user and a portal user.
    steps: Process the queued publication.
    expected: >-
      Only the eligible member receives a notice; isolation refusals identify
      the excluded candidates.
    negative: true
    data_needs: Use only records created and owned by this suite.
    bound_to:
      - >-
        services-platform:modules/notifications/tests/integration/services/orchestration/orchestrate-request.integration.spec.js#drops
        a user of another customer, an invited user and a portal user, recording
        isolation_refused
      - >-
        services-platform:modules/notifications/tests/integration/services/centre/hq-notifications.integration.spec.js#leaves
        out an invited user, a portal user, a user of another customer and an id
        that is nobody’s
      - >-
        react-console:acceptance/notifications/playwright/journeys/pipeline/NT-ACC-0202.spec.ts#NT-ACC-0202
      - TST-PFM-NOT-013
      - TST-PFM-NOT-072
      - TST-PFM-NOT-079
    provenance: test
    source: >-
      services-platform:modules/notifications/tests/integration/services/orchestration/orchestrate-request.integration.spec.js#drops
      a user of another customer, an invited user and a portal user, recording
      isolation_refused
    category: permission
    binding_scope: >-
      Each binding supplies its own assertions; the aggregate references do not
      imply that one executable file proves every step.
    invariant_source: >-
      services-platform:modules/notifications/tests/integration/services/orchestration/orchestrate-request.integration.spec.js#drops
      a user of another customer, an invited user and a portal user, recording
      isolation_refused
  - id: ATS-PFM-NOT-003-08
    title: Retain empty-audience outcomes
    level: api
    proves:
      - BR-CAP-PFM-NOT-003-08
    preconditions: Prepare a responsibility nobody has; a request naming only outsiders.
    steps: Process each queued audience fixture.
    expected: >-
      Both requests finish with no recipients; the isolated case also retains
      its refusal information.
    negative: true
    data_needs: Use only records created and owned by this suite.
    bound_to:
      - >-
        services-platform:modules/notifications/tests/integration/services/orchestration/resolve-audience.integration.spec.js#is
        nobody when nobody holds it and nothing covers it, settling
        no_recipients
      - >-
        services-platform:modules/notifications/tests/integration/services/orchestration/orchestrate-request.integration.spec.js#notifies
        nobody when everyone named is outside the organization, recording
        no_recipients with the refusal
      - TST-PFM-NOT-079
      - TST-PFM-NOT-080
    provenance: test
    source: >-
      services-platform:modules/notifications/tests/integration/services/orchestration/resolve-audience.integration.spec.js#is
      nobody when nobody holds it and nothing covers it, settling no_recipients
    category: transition
    binding_scope: >-
      Each binding supplies its own assertions; the aggregate references do not
      imply that one executable file proves every step.
  - id: ATS-PFM-NOT-003-09
    title: >-
      Current audience selection is explained in both personal and workspace
      views
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-NOT-003-02
    exercises:
      - CAP-PFM-NOT-003
      - CAP-PFM-NOT-010
      - CAP-PFM-NOT-011
      - CAP-PFM-NOT-014
    preconditions: >-
      Create a scoped responsibility held by Jane, with Sam as the later holder
      and a foreign-workspace candidate.
    steps: >-
      Transfer the responsibility before processing; process the request; read
      personal detail and administrator History; publish an explicit assignment
      to Sam.
    expected: >-
      Sam receives the current-holder notice and its selection explanation. The
      foreign candidate receives nothing, and History retains the exclusion and
      the explicit assignment request.
    negative: false
    data_needs: >-
      A suite-owned workspace, named staff accounts and unique occurrence keys;
      external adapters record attempts without shared writes.
    bound_to: []
    provenance: proposed
    source:
      - >-
        rhythm-v2-docs:specs/platform/notifications/planning/capabilities/CAP-PFM-NOT-003-reach-the-right-people-and-only-people-of-the-organization.md#frontmatter
      - >-
        rhythm-v2-docs:specs/platform/notifications/planning/capabilities/CAP-PFM-NOT-010-understand-why-i-was-told.md#frontmatter
      - >-
        rhythm-v2-docs:specs/platform/notifications/planning/capabilities/CAP-PFM-NOT-011-see-what-the-organization-told-whom.md#frontmatter
      - >-
        rhythm-v2-docs:specs/platform/notifications/planning/capabilities/CAP-PFM-NOT-014-tell-staff-about-changes-to-their-own-responsibilities.md#frontmatter
    interaction_with:
      - CAP-PFM-NOT-010
      - CAP-PFM-NOT-011
      - CAP-PFM-NOT-014
evidence:
  - >-
    Pinned evidence inventory 1:
    services-platform:modules/notifications/tests/unit/audience-planner.spec.js;
    services-platform:modules/notifications/tests/integration/services/orchestration/resolve-audience.integration.spec.js;
    react-console:acceptance/notifications/playwright/journeys/pipeline/NT-ACC-0203.spec.ts;
    react-console:acceptance/notifications/playwright/journeys/pipeline/NT-ACC-0202.spec.ts
  - >-
    Pinned evidence inventory 2:
    services-platform:modules/notifications/tests/integration/services/orchestration/orchestrate-request.integration.spec.js;
    react-console:acceptance/notifications/playwright/journeys/pipeline/NT-ACC-0201.spec.ts;
    services-platform:modules/notifications/tests/integration/services/centre/hq-notifications.integration.spec.js
coverage:
  rule: covered
  transition: covered
  validation: covered
  permission: covered
  edge: 'gap: FND-PFM-NOT-064'
  failure: 'gap: FND-PFM-NOT-064'
  boundary: covered
  concurrency: 'gap: FND-PFM-NOT-064'
  invariant: covered
  interaction: covered
coverage_notes:
  edge: Exceptional but valid input needs a dedicated expected-outcome case.
  failure: The suite lacks an isolated dependency failure and recovery case.
  concurrency: >-
    The suite lacks a complete race case with controlled interleaving and
    post-race assertions.
findings:
  - FND-PFM-NOT-064
transition_coverage: []
workflow_coverage:
  - workflow: WF-PFM-NOT-003
    capabilities:
      - CAP-PFM-NOT-003
      - CAP-PFM-NOT-004
      - CAP-PFM-NOT-005
      - CAP-PFM-NOT-006
      - CAP-PFM-NOT-007
      - CAP-PFM-NOT-008
    scenario_candidate: ATS-PFM-NOT-003-09
    coverage: 'gap: FND-PFM-NOT-084'
    reason: >-
      The proposed related-capability sequence does not independently isolate
      every workflow hop, failure seam and interleaving.
  - workflow: WF-PFM-NOT-006
    capabilities:
      - CAP-PFM-NOT-013
      - CAP-PFM-NOT-003
      - CAP-PFM-NOT-007
    scenario_candidate: ATS-PFM-NOT-003-09
    coverage: 'gap: FND-PFM-NOT-084'
    reason: >-
      The proposed related-capability sequence does not independently isolate
      every workflow hop, failure seam and interleaving.
domain_invariant_coverage:
  - invariant: INV-DOM-PFM-NOT-003-04
    scenarios:
      - ATS-PFM-NOT-003-07
    coverage: specified
    source: >-
      rhythm-v2-docs:specs/platform/notifications/design/objects/DOM-PFM-NOT-003-staff-notification.md
    verification_note: >-
      The candidate supplies the fixture outcome; individual binding limits
      remain applicable.
  - invariant: INV-DOM-PFM-NOT-003-05
    scenarios:
      - ATS-PFM-NOT-003-06
    coverage: specified
    source: >-
      rhythm-v2-docs:specs/platform/notifications/design/objects/DOM-PFM-NOT-003-staff-notification.md
    verification_note: >-
      The candidate supplies the fixture outcome; individual binding limits
      remain applicable.
---

# Select eligible notification recipients: Capability Test Specification

## Coverage

Each scenario names the guarantee it proves. Category coverage describes specified cases; executable bindings retain their narrower assertion boundaries. Lifecycle coverage remains a gap wherever guards and effects lack independent verification.

| Rule | Proof |
|---|---|
| `BR-CAP-PFM-NOT-003-01` | `ATS-PFM-NOT-003-01`, `ATS-PFM-NOT-003-09` |
| `BR-CAP-PFM-NOT-003-02` | `ATS-PFM-NOT-003-02` |
| `BR-CAP-PFM-NOT-003-03` | `ATS-PFM-NOT-003-03` |
| `BR-CAP-PFM-NOT-003-04` | `ATS-PFM-NOT-003-04` |
| `BR-CAP-PFM-NOT-003-05` | `ATS-PFM-NOT-003-05` |
| `BR-CAP-PFM-NOT-003-06` | `ATS-PFM-NOT-003-06` |
| `BR-CAP-PFM-NOT-003-07` | `ATS-PFM-NOT-003-07` |
| `BR-CAP-PFM-NOT-003-08` | `ATS-PFM-NOT-003-08` |

## Interactions With Related Capabilities

Create a scoped responsibility held by Jane, with Sam as the later holder and a foreign-workspace candidate. Transfer the responsibility before processing; process the request; read personal detail and administrator History; publish an explicit assignment to Sam.

The interaction case combines the producing, processing and reading outcomes named in its frontmatter. It remains proposed until an executable suite performs that complete sequence.
