---
id: TST-PFM-NOT-030
title: contact role compliance communication
kind: integration
product_area: platform
module: notifications
revision: 1
status: draft
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
repository: services-platform
files:
  - >-
    modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js
implements:
  - ATS-PFM-NOT-016-01
  - ATS-PFM-NOT-016-06
  - ATS-PFM-NOT-016-08
  - ATS-PFM-NOT-016-14
  - ATS-PFM-NOT-017-05
  - ATS-PFM-NOT-017-06
  - ATS-PFM-NOT-017-08
  - ATS-PFM-NOT-018-02
  - ATS-PFM-NOT-018-13
  - ATS-PFM-NOT-019-01
  - ATS-PFM-NOT-019-02
  - ATS-PFM-NOT-019-03
  - ATS-PFM-NOT-019-07
  - ATS-PFM-NOT-020-01
  - ATS-PFM-NOT-020-06
  - ATS-PFM-NOT-020-12
  - FAS-PFM-NOT-07-01
  - FAS-PFM-NOT-07-02
  - FAS-PFM-NOT-07-03
  - FAS-PFM-NOT-07-05
environment: local
implementation_state: implemented
latest_result: not-run
latest_run_at: null
latest_run_ref: null
conformance: not-verified
estimated_minutes: 5
isolation: >-
  Suite-owned records in the prepared integration workspaces; seeded workspace
  identities remain shared fixtures.
assertion_bindings:
  - scenario: ATS-PFM-NOT-016-01
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#offers
        starter text that the purpose itself never sends
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#stores
        configuration_blocked behind the queue, naming the purpose and the
        record that owns no template
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#sends
        nothing at all
  - scenario: ATS-PFM-NOT-016-06
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#refuses
        content that reads an undeclared variable and includes a file
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#names
        both problems in the refusal, so the screen can show them
  - scenario: ATS-PFM-NOT-016-08
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#publishes
        no second version for a save that changes nothing
  - scenario: ATS-PFM-NOT-016-14
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#sends
        nothing at all
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#stores
        configuration_blocked behind the queue, naming the purpose and the
        record that owns no template
  - scenario: ATS-PFM-NOT-017-05
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#stores
        it invalid where staff can read it, naming the paths
  - scenario: ATS-PFM-NOT-017-06
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#accepts
        the request with the owner’s published version pinned
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#names
        the messages in the receipt, under ids derived from the request, before
        any of them exists
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#escapes
        the contact’s name in the HTML it rendered and stored
  - scenario: ATS-PFM-NOT-017-08
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#fills
        the platform’s variables: the association and the message’s own
        reference
  - scenario: ATS-PFM-NOT-018-02
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#never
        sends again when the run is repeated
  - scenario: ATS-PFM-NOT-018-13
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#publishes
        the request once, whatever its recipients turn out to be
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#never
        sends again when the run is repeated
  - scenario: ATS-PFM-NOT-019-01
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#records
        each new event and recognizes the repeated delivery as a duplicate
  - scenario: ATS-PFM-NOT-019-02
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#keeps
        the message delivered when a deferral arrives after the delivery
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#keeps
        the delivery time the provider reported
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#lists
        the provider’s events in the order they happened, whatever order they
        arrived in
  - scenario: ATS-PFM-NOT-019-03
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#counts
        an open by an image proxy as an open, not as a likely human one
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#counts
        the click and keeps its link without the query string
  - scenario: ATS-PFM-NOT-019-07
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#shows
        another tenant nothing of it
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#refuses
        another tenant the message itself
  - scenario: ATS-PFM-NOT-020-01
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#marks
        the bounced message bounced_permanent with the diagnostic
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#suppresses
        the address for the tenant
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#stores
        the next notice to that address suppressed, with the reason, and sends
        nothing
  - scenario: ATS-PFM-NOT-020-06
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#queues
        the deliverable contact, withholds the suppressed one and the one this
        environment may not e-mail
  - scenario: ATS-PFM-NOT-020-12
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js#stores
        the next notice to that address suppressed, with the reason, and sends
        nothing
  - scenario: FAS-PFM-NOT-07-01
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js
  - scenario: FAS-PFM-NOT-07-02
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js
  - scenario: FAS-PFM-NOT-07-03
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js
  - scenario: FAS-PFM-NOT-07-05
    suite: TST-PFM-NOT-030
    assertions:
      - >-
        services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js
evidence:
  - >-
    services-platform:modules/communications/tests/integration/lifecycle/contact-role-compliance-communication.integration.spec.js
  - The file and referenced assertion titles exist at the pinned commit.
dependency_evidence:
  - >-
    The first association communication end to end, below AWS
    (`docs/communications/architecture.md` §14, phase 1 criteria,
  - >-
    Real: PostgreSQL (the prepared integration database, row-level security on),
    the template, owned-template, submission,
  - >-
    acceptance, dispatcher, send and feedback services, the LiquidJS renderer.
    Doubled: SES at the transport
  - >-
    (`recordingTransport`), the object store, the dispatcher's nudge (recorded)
    and the send queue (recorded). Never doubled:
---

# contact role compliance communication

## Verification Boundary

This suite exercises the local services and prepared PostgreSQL database. API lifecycle cases use signed test contexts through the real route handler; they do not invoke the deployed gateway.

## What This Suite Proves

Its cases exercise block Platform-rendered mail without publication; report unsafe and invalid content locations; save one record-owned template with partial updates; require publication before workflow delivery; retain all non-sending outcomes and reasons; pin published content and derive message identities.

The registered scenario bindings identify the assertions this executable file contributes. They retain individual test references so that a composite scenario does not become a claim of complete execution by one file.

## What It Does Not Prove

Local outcomes do not prove deployed queues, external provider acceptance, production credentials or complete browser behavior. No fresh execution or conformance result is claimed.

## Real Dependencies and Test Doubles

The communication fixtures use real PostgreSQL and module logic. Shared support records queue and transport calls and stores objects in memory; sender provisioning substitutes a provider identity store. Signed API contexts replace the authorizer key in API suites.

## Must Not Be Doubled

Database constraints, workspace policy, state guards and the service operation under test must remain real. Recording a provider or queue call must not replace the submission, claim or outcome logic being checked.
