---
id: TST-CRM-ENT-792
title: Organization compliance and notice preparation integration
kind: integration
product_area: crm
module: entities
revision: 1
status: draft
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
repository: services-crm
files:
  - modules/entities/tests/integration/db/organization-compliance-violations.table.integration.spec.js
  - modules/entities/tests/integration/services/email-previews/email-preview.integration.spec.js
  - >-
    modules/entities/tests/integration/services/organizations/compliance/compliance-change-events.integration.spec.js
  - modules/entities/tests/integration/services/organizations/compliance/compliance-reads.integration.spec.js
  - >-
    modules/entities/tests/integration/services/organizations/compliance/compliance-reprocess-errors.integration.spec.js
  - >-
    modules/entities/tests/integration/services/organizations/compliance/compliance-reprocess.integration.spec.js
  - >-
    modules/entities/tests/integration/services/organizations/compliance/organization-compliance.integration.spec.js
  - >-
    modules/entities/tests/integration/services/persistence/communication-request-submissions.integration.spec.js
  - modules/entities/tests/integration/services/persistence/communication-templates.integration.spec.js
  - >-
    modules/entities/tests/integration/services/persistence/communication-templates.queries.integration.spec.js
  - modules/entities/tests/integration/services/persistence/compliance-reprocesses.integration.spec.js
  - modules/entities/tests/integration/services/persistence/compliance-reprocesses.queries.integration.spec.js
  - modules/entities/tests/integration/services/persistence/organization-attention-items.integration.spec.js
  - >-
    modules/entities/tests/integration/services/persistence/organization-attention-items.queries.integration.spec.js
  - modules/entities/tests/integration/services/templates/compliance-notification-template.integration.spec.js
implements:
  - VT-IMC-CRM-ENT-018-02
  - VT-IMC-CRM-ENT-016-01
  - VT-IMC-CRM-ENT-018-01
  - VT-IMC-CRM-ENT-019-01
  - VT-IMC-CRM-ENT-019-02
  - VT-IMC-CRM-ENT-002-01
  - ATS-CRM-ENT-012-11
  - ATS-CRM-ENT-012-01
  - ATS-CRM-ENT-012-04
  - ATS-CRM-ENT-012-03
  - ATS-CRM-ENT-012-08
  - ATS-CRM-ENT-012-10
  - ATS-CRM-ENT-012-05
  - ATS-CRM-ENT-012-07
  - ATS-CRM-ENT-012-09
  - ATS-CRM-ENT-012-14
  - ATS-CRM-ENT-012-16
  - VT-IMC-CRM-ENT-133-02
environment: local
implementation_state: implemented
latest_result: not-run
latest_run_at: null
latest_run_ref: null
conformance: not-verified
estimated_minutes: null
estimate_basis: No measured duration is available for this cohesive group; per-file allowances are not runtime estimates.
isolation: >-
  Tests create their own organizations, compliance types, role fixtures and reprocess records. Template tests
  restore injected Platform behavior. Reprocess fixtures own unfinished-run premises so a cleanup cannot
  cancel another run; the selected serial invocation avoids overlapping process-level adapters.
binding_scope: >-
  Bindings preserve the existing assertion contributions and exact source file. Composite scenarios still
  require every bound contribution and any unbound checks; consolidation does not certify conformance.
bindings:
  - scenario: ATS-CRM-ENT-012-11
    source: >-
      services-crm:modules/entities/tests/integration/services/email-previews/email-preview.integration.spec.js#refuses
      a contact whose only affiliation to the organization has ended
  - scenario: ATS-CRM-ENT-012-11
    source: >-
      services-crm:modules/entities/tests/integration/services/email-previews/email-preview.integration.spec.js#is
      previewed with the purpose contract’s example violations, and says so in sample_data
  - scenario: ATS-CRM-ENT-012-01
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-change-events.integration.spec.js#an
      organization no type holds that still carries a status, so the recalculation clears it
  - scenario: ATS-CRM-ENT-012-04
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-change-events.integration.spec.js#a
      save that changes neither the affiliations nor the roles: nothing
  - scenario: ATS-CRM-ENT-012-04
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-change-events.integration.spec.js#a
      contact saved with the notes DISABLE_CONTACT_ROLE_COMPLIANCE_CHECK: nothing (its delete still records)
  - scenario: ATS-CRM-ENT-012-04
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-change-events.integration.spec.js#an
      affiliation added that is not primary: its organization
  - scenario: ATS-CRM-ENT-012-04
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-change-events.integration.spec.js#a
      role ended on an affiliation that goes on: its organization
  - scenario: ATS-CRM-ENT-012-04
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-change-events.integration.spec.js#a
      contact affiliated with two organizations deleted: both
  - scenario: ATS-CRM-ENT-012-03
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-reads.integration.spec.js#counts
      a role held on a current affiliation that is not the contact’s primary one
  - scenario: ATS-CRM-ENT-012-08
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-reads.integration.spec.js#answers
      one recipient for the contact with a primary address: the whole record as the API reads it, and that
      address
  - scenario: ATS-CRM-ENT-012-08
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-reads.integration.spec.js#leaves
      out the contact with no e-mail address at all, there being nowhere to send it
  - scenario: ATS-CRM-ENT-012-08
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-reads.integration.spec.js#leaves
      out the contact whose addresses sit past the primary slot, no secondary address standing in
  - scenario: ATS-CRM-ENT-012-10
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-reprocess-errors.integration.spec.js#fails
      the run on that last receive, because nothing will deliver its event again
  - scenario: ATS-CRM-ENT-012-10
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-reprocess-errors.integration.spec.js#records
      no value of the batch that failed: not the organization, the tenant, the statement or its parameters
  - scenario: ATS-CRM-ENT-012-10
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-reprocess.integration.spec.js#answers
      the legacy message, naming every organization of the tenant
  - scenario: ATS-CRM-ENT-012-10
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-reprocess.integration.spec.js#answers
      the run completed once the following batches reach the end, every organization counted
  - scenario: ATS-CRM-ENT-012-01
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/organization-compliance.integration.spec.js#with
      a type that holds it to no rule, or with no type: no status and no violations
  - scenario: ATS-CRM-ENT-012-03
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/organization-compliance.integration.spec.js#brings
      an organization into compliance for a role held on a current affiliation that is not primary
  - scenario: ATS-CRM-ENT-012-03
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/organization-compliance.integration.spec.js#takes
      an organization out of compliance when the affiliation holding its role ends
  - scenario: ATS-CRM-ENT-012-03
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/organization-compliance.integration.spec.js#takes
      an organization out of compliance when the role ends on an affiliation that goes on
  - scenario: ATS-CRM-ENT-012-03
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/organization-compliance.integration.spec.js#reports
      too many holders of a role with a maximum
  - scenario: ATS-CRM-ENT-012-05
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/organization-compliance.integration.spec.js#writes
      nothing for a duplicate delivery, or a second run on an unchanged organization
  - scenario: ATS-CRM-ENT-012-05
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/organization-compliance.integration.spec.js#serializes
      two runs at once on one organization: one writes, the other finds nothing to change
  - scenario: ATS-CRM-ENT-012-07
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/organization-compliance.integration.spec.js#is
      submitted by the recalculation that takes an organization out of compliance, one request to the contacts
      to notify
  - scenario: ATS-CRM-ENT-012-07
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/organization-compliance.integration.spec.js#submits
      nothing when the organization is recalculated again, unchanged: the transition already happened
  - scenario: ATS-CRM-ENT-012-07
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/organization-compliance.integration.spec.js#is
      not submitted again while the organization stays out of compliance, nor for a type that does not notify
  - scenario: ATS-CRM-ENT-012-10
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/compliance-reprocesses.integration.spec.js#refuses
      a second running run for the tenant
  - scenario: ATS-CRM-ENT-012-09
    source: >-
      services-crm:modules/entities/tests/integration/services/templates/compliance-notification-template.integration.spec.js#answers
      null for a type that owns none
  - scenario: ATS-CRM-ENT-012-14
    source: >-
      services-crm:modules/entities/tests/integration/services/templates/compliance-notification-template.integration.spec.js#merges
      a partial template onto the saved one, keeping the fields the save did not mention
  - scenario: ATS-CRM-ENT-012-14
    source: >-
      services-crm:modules/entities/tests/integration/services/templates/compliance-notification-template.integration.spec.js#leaves
      the template untouched when the property is omitted, and asks Platform for nothing
  - scenario: ATS-CRM-ENT-012-14
    source: >-
      services-crm:modules/entities/tests/integration/services/templates/compliance-notification-template.integration.spec.js#clears
      the template when the property is null, and the type then owns none
  - scenario: ATS-CRM-ENT-012-16
    source: >-
      services-crm:modules/entities/tests/integration/services/templates/compliance-notification-template.integration.spec.js#clears
      the template the deleted type owned, so no template is left owned by a type that is gone
  - scenario: ATS-CRM-ENT-012-16
    source: >-
      services-crm:modules/entities/tests/integration/services/templates/compliance-notification-template.integration.spec.js#keeps
      the delete and logs the type id when Platform cannot clear it: the type is gone either way
evidence:
  - >-
    services-crm:modules/entities/tests/integration/db/organization-compliance-violations.table.integration.spec.js
  - 'services-crm:modules/entities/tests/integration/services/email-previews/email-preview.integration.spec.js'
  - >-
    services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-change-events.integration.spec.js
  - >-
    services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-reads.integration.spec.js
  - >-
    services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-reprocess-errors.integration.spec.js
  - >-
    services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-reprocess.integration.spec.js
  - >-
    services-crm:modules/entities/tests/integration/services/organizations/compliance/organization-compliance.integration.spec.js
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/communication-request-submissions.integration.spec.js
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/communication-templates.integration.spec.js
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/communication-templates.queries.integration.spec.js
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/compliance-reprocesses.integration.spec.js
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/compliance-reprocesses.queries.integration.spec.js
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/organization-attention-items.integration.spec.js
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/organization-attention-items.queries.integration.spec.js
  - >-
    services-crm:modules/entities/tests/integration/services/templates/compliance-notification-template.integration.spec.js
source_observations:
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/db/organization-compliance-violations.table.integration.spec.js
    declared_test_titles:
      - crm.organization_compliance_violations and the compliance status (integration)
      - what the database refuses
      - a status other than the two legacy ones
      - a violation type other than too few and too many
      - a negative count of contacts
      - 'an organization not in compliance with no violation, when the transaction commits'
      - 'the removal of the last violation of an organization not in compliance, when the transaction commits'
      - what the database allows
      - 'the status written before its violations, in one transaction'
      - violations without a status
      - an organization in compliance with no violation
      - 'the delete of an organization not in compliance, its violations going with it'
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/email-previews/email-preview.integration.spec.js
    declared_test_titles:
      - rendering an unsaved e-mail template (integration)
      - the invocation Platform receives
      - >-
        is one renderPreview naming the tenant, the purpose and the contract version, with the content as it
        was sent
      - 'carries the data a real compliance notice carries for the same records, element for element'
      - 'satisfies the purpose’s own contract, as a message that is really sent must'
      - 'sends the contact as the API reads it, its collections and custom fields included'
      - the answer
      - >-
        is Platform’s rendering, its problems and its empty fields, with nothing of the purpose’s example in
        it
      - an organization that breaks no rule
      - 'is previewed with the purpose contract’s example violations, and says so in sample_data'
      - 'is the premise of that case: the organization really has no violations'
      - the refusals
      - 'refuses a purpose this macroservice does not preview, before any record is read'
      - >-
        refuses a caller holding the route’s permission but not the read keys of the records the answer
        contains
      - 'refuses a caller holding only one of the two read keys: both are required, and nothing is read'
      - 'refuses an organization the tenant does not have, and one another tenant has'
      - refuses a contact the tenant does not have
      - refuses a contact that is not linked to the organization
      - refuses a contact linked to no organization at all
      - refuses a contact whose only affiliation to the organization has ended
      - previews for a contact whose current affiliation to the organization is not its primary one
      - answers Platform’s refusal of the call as the error its own prefix names
      - answers a refusal with no prefix it knows as the caller’s own request being wrong
      - what a preview leaves behind
      - 'is nothing: no row of any table changes, whether it renders or is refused'
      - 'counted rows at all, so the comparison above means something (premise)'
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-change-events.integration.spec.js
    declared_test_titles:
      - the organizations a contact change calls for a compliance recalculation of (integration)
      - decides as the Rhythm 1.0 extraction did
      - 'a contact created in an organization: that organization'
      - 'a contact that moves: both organizations'
      - 'a contact whose roles change: its organization'
      - 'a contact deleted: its organization'
      - 'a contact without an organization, created and deleted: nothing'
      - 'a save that changes neither the affiliations nor the roles: nothing'
      - 'the same roles in another order: nothing'
      - >-
        a contact saved with the notes DISABLE_CONTACT_ROLE_COMPLIANCE_CHECK: nothing (its delete still
        records)
      - decides on the affiliations Rhythm 1.0 did not have
      - 'an affiliation added that is not primary: its organization'
      - 'a role given on an affiliation that is not primary: its organization'
      - 'a role ended on an affiliation that goes on: its organization'
      - 'an affiliation that is not primary ended in place: its organization'
      - 'an affiliation that is not primary removed: its organization'
      - 'a contact affiliated with two organizations deleted: both'
      - recalculates only what a recalculation could change
      - >-
        nothing for an organization whose type holds it to no rule, or that has no type, and carries no
        compliance
      - 'an organization no type holds that still carries a status, so the recalculation clears it'
      - records nothing at all for a write that changes only the contact's version (as a flowdown does)
      - in the transaction of the save
      - one organization to recalculate for two contacts joining it in one transaction
      - nothing from a save that rolls back
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-reads.integration.spec.js
    declared_test_titles:
      - contact role compliance reads (integration)
      - 'list_compliance_contacts, the contacts the rule counts'
      - >-
        answers every contact with an affiliation to the organization effective today in id order, each with
        its roles and its primary address
      - counts a role held on a current affiliation that is not the contact’s primary one
      - leaves out a contact whose only affiliation to the organization has ended
      - leaves out a contact whose only affiliation to the organization starts in the future
      - 'leaves out a role that has ended, and one that has not started, on a current affiliation'
      - >-
        answers a contact with two current affiliations to the organization once, each role it holds on either
        once
      - >-
        answers no address at all for a contact whose addresses sit in the second and third slots, never a
        secondary one
      - 'answers an empty list of roles, not null, for a contact that holds none'
      - answers nothing for an organization that has no contact at all
      - answers nothing for an organization the tenant does not have
      - answers nothing in another tenant for the organization of the first
      - 'notice_organization, the subject a notice or a preview describes'
      - 'answers the organization number the database allocated, which the literal below then states'
      - >-
        answers the whole subject: the organization as the API reads it, its type and its violations in their
        stored order
      - names a violation stored without a role name by the role the tenant still has
      - names a violation of a role the tenant no longer has by the role’s own id
      - 'answers an empty type for an organization with no type at all, which is what blocks the preview'
      - 'carries at most the fifty violations the contract allows, the first fifty in their stored order'
      - 'leaves out the violations past the fiftieth, keeping the ones before it'
      - answers undefined for an organization the tenant does not have
      - 'answers the OTHER tenant’s own organization for the shared id, never the first tenant’s'
      - 'notice_recipients, the contacts a notice is addressed to'
      - >-
        answers the contact number and the e-mail ids the database allocated, which the literals below then
        state
      - >-
        answers one recipient for the contact with a primary address: the whole record as the API reads it,
        and that address
      - 'leaves out the contact with no e-mail address at all, there being nowhere to send it'
      - 'leaves out the contact whose addresses sit past the primary slot, no secondary address standing in'
      - 'addresses every message to the one address a preview names, whatever the contact’s own is'
      - 'answers the recipients in contact id order, however the ids were asked for'
      - 'leaves out an id the tenant has no contact for, rather than refusing the notice'
      - answers nothing when it is asked about no contact at all
      - answers nothing in another tenant for a contact of the first
      - 'notice_recipients, the name the notice addresses each recipient by'
      - >-
        answers the contact numbers and the e-mail ids the database allocated, which the literals below then
        state
      - answers the stored full name of a contact whose prefix makes it differ from the name
      - 'carries no full name at all for a row that holds none, leaving the name the row does hold as it is'
      - >-
        carries none of the computed names for a row that holds none, so the notice names the recipient by the
        address it sends to
      - 'answers the three of them in contact id order, one recipient each'
      - sends to the one address a preview names while the record still carries the contact’s own
      - 'leaves the contact with no address out of the answer entirely, naming only the one it can send to'
      - recalculate_organization_compliance
      - 'answers that an organization the tenant does not have is gone, writing and notifying nothing'
      - >-
        answers that an organization of another tenant is gone, though the first tenant holds one of that very
        id
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-reprocess-errors.integration.spec.js
    declared_test_titles:
      - a compliance reprocess that fails (integration)
      - the reason it records
      - 'answers the caller the error the batch failed with, so the queue delivers the event again'
      - 'carried the organization''s own id in the raw error, which is what the reason below must not hold'
      - 'records the redacted reason on a run it leaves running, so the next delivery can get past the cause'
      - 'throws again on the delivery after it, rather than letting a second failure settle anything'
      - 'leaves that run running too: how many failures are enough is the queue’s decision, not the run’s'
      - >-
        records no value of the batch that failed: not the organization, the tenant, the statement or its
        parameters
      - 'the last delivery of a run’s event, through the consumer'
      - 'published the run’s INSERT as one message for its runner, which is the delivery under test'
      - >-
        asks the queue for the message back when the handler throws, rather than acknowledging a batch that
        failed
      - 'leaves the run running on that delivery, so the next receive resumes it from its cursor'
      - 'asks for the message back on the last receive as well, which is what sends it to the dead-letter queue'
      - 'fails the run on that last receive, because nothing will deliver its event again'
      - a run that gets past what stopped it
      - 'recorded a reason on the run before it was delivered again, so the clearing below is a proof'
      - 'answers the whole record of the completed run, with no reason left on it'
      - 'clears the column itself, as the table holds it'
      - a run that never fails
      - 'answers the whole record of the finished run, which holds no reason at all'
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/compliance-reprocess.integration.spec.js
    declared_test_titles:
      - the contact role compliance reprocess (integration)
      - a request to reprocess
      - 'answers the legacy message, naming every organization of the tenant'
      - 'records one run, running, with nothing walked yet: the work is the runner’s'
      - 'reaches the runner by the run’s own INSERT, which is the only event recording a run makes'
      - 'answers the run already under way to a second request, instead of starting another'
      - asks for no further worker when the run in progress has not advanced for an hour
      - the run worked a batch at a time
      - 'answers what the first batch did: still running, two organizations examined and repaired'
      - 'leaves the cursor on the second organization, so the next batch starts after it'
      - 'asks for the next worker by incrementing `continuation`, which is a change event of the run'
      - 'answers the run completed once the following batches reach the end, every organization counted'
      - 'leaves the run completed, with the cursor cleared and a moment of completion'
      - 'recalculated every organization of the tenant, not only the batch it started with'
      - 'does nothing more when the same event is delivered again: the run is already completed'
      - 'reports a run the tenant no longer has as gone, rather than failing the delivery'
      - a request delivered through the dispatcher and the consumer
      - sends the run’s INSERT to the runner and nothing else
      - 'finishes the run on the deployed path, every organization of the tenant recalculated'
      - 'leaves the holding area empty: every event it recorded was published and delivered'
      - a run over organizations already in compliance
      - 'examines every organization and reports none recalculated, because none needed it'
      - leaves every organization’s status as it was
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/organizations/compliance/organization-compliance.integration.spec.js
    declared_test_titles:
      - contact role compliance through the saves and the change events (integration)
      - an organization created
      - >-
        with a type that holds it to rules: not in compliance, every rule with a minimum violated (it has no
        contact yet)
      - 'with a type that holds it to no rule, or with no type: no status and no violations'
      - ignores a status and violations the client sends
      - the recalculation after a contact change (the real dispatcher and consumer)
      - 'brings an organization into compliance when the role it lacked joins, bumping its version once'
      - reports too many holders of a role with a maximum
      - 'writes nothing for a duplicate delivery, or a second run on an unchanged organization'
      - 'serializes two runs at once on one organization: one writes, the other finds nothing to change'
      - 'is reported back to the queue when the run fails, and applied by the redelivery'
      - 'reports the last receive as a failure like any other, leaving the organization as it was'
      - leaves another tenant's organization with the same id alone
      - clears the status of an organization whose type no longer holds it to rules
      - 'counting the roles held on affiliations, after the contact change (the real dispatcher and consumer)'
      - brings an organization into compliance for a role held on a current affiliation that is not primary
      - >-
        brings an organization into compliance when a role is given on an affiliation the save leaves
        otherwise as it was
      - takes an organization out of compliance when the affiliation holding its role ends
      - takes an organization out of compliance when the role ends on an affiliation that goes on
      - does not count a role held on an affiliation that ended before the contact was saved
      - the notification
      - >-
        is submitted by the recalculation that takes an organization out of compliance, one request to the
        contacts to notify
      - leaves no submission behind when the recalculation it was composed in rolls back
      - >-
        submits nothing when the organization is recalculated again, unchanged: the transition already
        happened
      - 'sends the contact as the API reads it, collections included, and names no template of its own'
      - 'records who the recalculation acted for: the same actor that stamped the write it commits with'
      - >-
        is not submitted again while the organization stays out of compliance, nor for a type that does not
        notify
      - an organization save
      - 'keeps the computed status and violations, whatever the client sends back'
      - the reprocess
      - 'records one run for the tenant, only the tenant''s, and answers the legacy message'
      - recalculates an organization whose type gained rules after it was created
      - the preview
      - >-
        asks Platform for a test send of the wording typed in, to the destination, with the violations' role
        names filled in
      - 'previews a saved template by id, and answers why Platform refused one'
      - refuses a contact or an organization the tenant does not have
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/communication-request-submissions.integration.spec.js
    declared_test_titles:
      - crm submits communication requests to Platform (integration)
      - a submission written in the caller transaction
      - is invisible on another connection until the caller commits
      - 'stores the request object before the row it points at, so a committed row always names an object'
      - 'writes exactly the pointer columns: the identifiers, the key of the object, the purpose and the source'
      - 'stores the whole request in the bucket, under requests/<tenant>/<request id>.json'
      - writes it to the bucket the deploy named and no other
      - several submissions in one call
      - writes one row for each submission it is given
      - the same transition submitted twice
      - 'ends with ONE request when the same transition is submitted twice, as a retried transaction would'
      - 'stores the retry own content over the first attempt, under the one derived key'
      - a submission CRM shaped wrong
      - refuses the call by the problems of the submission it cannot send
      - 'writes neither of them: the one already inserted goes with the caller transaction'
      - 'stores no object for the one it refused: the shape is checked before anything is written'
      - a caller transaction that rolls back
      - 'takes the submission with it, so Platform is never asked for the e-mail'
      - 'leaves the stored object behind as an orphan, which no row names and the bucket expires'
      - a function the deploy gave no bucket
      - refuses the submission rather than storing the request nowhere
      - 'takes the business change with it: the transaction the submission was made in rolls back whole'
      - a submission made outside a transaction
      - 'is refused by the table forced tenant policy, because the pool itself names no tenant'
      - 'writes nothing, and the same submission inside a transaction is written'
      - the tenant boundary
      - 'refuses a submission for another tenant: the submissions table''s own forced policy decides it'
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/communication-templates.integration.spec.js
    declared_test_titles:
      - crm reads the owned communication templates of Platform (integration)
      - a record that owns a published template
      - 'answers the published content keyed by the owner record id, field by field'
      - 'answers the current published version, not the one it replaced'
      - several owner records in one call
      - answers each record its own template
      - 'leaves out the record that owns none, rather than answering it an empty template'
      - answers empty lists of copy addresses for a template published without any
      - a template that is not the one asked for
      - 'leaves out an archived template, which the owner no longer owns'
      - leaves out a template the same record owns for another purpose
      - leaves out a template owned by another registered object
      - leaves out a template that has never been published
      - no owner records
      - answers an empty map without going to the database
      - the tenant boundary
      - 'answers nothing of another tenant''s template, whatever owner record id is asked for'
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/communication-templates.queries.integration.spec.js
    declared_test_titles:
      - owned communication template reads (integration)
      - a record that owns a published template
      - 'answers the whole published content of the template, every field of the version mapped'
      - 'answers one entry for the one owner asked for, the join never duplicating a record'
      - answers the content of the CURRENT published version after a second publication
      - a template published with only the fields it cannot be published without
      - answers null for each optional field and an empty list for each copy list
      - several owners in one read
      - answers each owner the content of its own template
      - leaves a record that owns no template out of the map entirely
      - 'answers an empty map, asking the database nothing, when no owner is named'
      - 'leaves out an owner the caller did not ask for, however many templates the tenant holds'
      - a record whose template cannot be sent
      - 'leaves out a record whose template has been cleared, an archived template being no template'
      - leaves out a record whose template has no published version at all
      - leaves out a record that owns a template for another purpose
      - leaves out a record of another object that happens to share the id
      - another tenant
      - 'answers nothing for an owner of the first tenant, whatever id it is asked for'
      - answers each tenant its own template when both tenants own one at the same id
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies. Platform communication operations use the local test adapter, so this suite does not
      prove deployed template validation or delivery.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/compliance-reprocesses.integration.spec.js
    declared_test_titles:
      - compliance reprocesses table (integration)
      - 'starts a run running, at the beginning of its walk, with nothing counted'
      - refuses a second running run for the tenant
      - allows a running run in another tenant at the same time
      - refuses a status outside the list
      - refuses a moment of completion on a run that is still running
      - refuses a completed run with no moment of completion
      - refuses more organizations recalculated than examined
      - refuses a negative count
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/compliance-reprocesses.queries.integration.spec.js
    declared_test_titles:
      - compliance reprocesses read (integration)
      - insert_reprocess
      - 'answers the whole row the INSERT wrote: running, at the beginning of its walk, with nothing counted'
      - 'maps that row to the whole record a caller reads: no cursor, no error, no moment of completion'
      - running_reprocess
      - 'answers the whole row of the one run that is running, as the table holds it'
      - answers undefined in a tenant whose only run has finished
      - answers undefined in a tenant of its own while another tenant's run is running
      - lock_reprocess
      - 'answers the whole row as the table holds it, null where the run has nothing'
      - answers undefined in another tenant for the first tenant's run
      - advance_reprocess
      - 'answers the whole row of the batch that moved the run on: its cursor, its counts and its version'
      - 'answers the whole row of the batch that finished it, its counts added to the ones before'
      - 'maps the finished row to the whole record, the moment it completed among them'
      - answers undefined from a batch that names an id the tenant does not have
      - record_reprocess_continuation
      - 'answers that the tenant still had the run, both times'
      - 'counts each ask, and moves the moment the staleness check reads, writing nothing else of the run'
      - 'answers false for a run the tenant does not have, so a worker stops rather than ask again for nothing'
      - a run that recorded an error
      - >-
        answers the whole record of a failed run: its status, its counts, its error, and no moment of
        completion
      - >-
        leaves `last_error` out of the record of a run whose column holds none, as it leaves out
        `completed_at`
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/organization-attention-items.integration.spec.js
    declared_test_titles:
      - the organizations out of compliance items (integration)
      - 'has the tenant, its role and its type (premise)'
      - at source
      - >-
        publishes the organization out of compliance as it is created, from today, addressed to data quality
        review
      - publishes nothing for an organization its type holds to no rule
      - resolves the item when a contact’s change returns the organization to compliance
      - publishes the next generation when the organization falls out of compliance again
      - resolves the item deleted when the organization out of compliance is deleted
      - >-
        publishes from the tenant’s reprocess, which recalculates an organization whose compliance was never
        computed
      - the daily sweep
      - 'sweeps the one tenant asked for, failing none'
      - 'publishes the organization no recalculation published, since the day its record last changed'
      - 'resolves the item of the organization back in compliance, which the pass did not republish'
      - stamps the sweep with what it published and resolved
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/organization-attention-items.queries.integration.spec.js
    declared_test_titles:
      - the organizations out of compliance page (integration)
      - 'answers the organizations out of compliance by id, and no other'
      - >-
        maps every element of an organization, its violations in order and since the tenant’s day of its last
        change
      - 'pages by id, the second page beginning after the first one’s last'
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/templates/compliance-notification-template.integration.spec.js
    declared_test_titles:
      - the organization type composes its compliance notification template (integration)
      - reading a type
      - answers the published template of the type that owns one
      - answers null for a type that owns none
      - listing types
      - 'hydrates every type of the page with its own template, and one that owns none with null'
      - 'reads the templates of a whole page in ONE statement, however many types the page holds'
      - saving a type
      - 'creates the template on the first save, as version 1'
      - 'updates the one template on the second save, publishing version 2 and leaving no duplicate'
      - 'leaves the template untouched when the property is omitted, and asks Platform for nothing'
      - 'merges a partial template onto the saved one, keeping the fields the save did not mention'
      - 'clears the template when the property is null, and the type then owns none'
      - asks Platform for nothing when a save clears a type that owns no template
      - a template Platform refuses
      - 'refuses the create as an invalid organization type, naming the property, and writes no type at all'
      - 'refuses the update, and changes neither the type nor the template it already owns'
      - a template Platform accepted the content of but could not save
      - puts the type back as it was and tells the caller nothing was changed
      - 'removes the type a create had just written, so no half-saved type is left behind'
      - deleting a type
      - 'clears the template the deleted type owned, so no template is left owned by a type that is gone'
      - asks Platform to clear it once
      - leaves the template of a type it did not delete alone
      - 'keeps the delete and logs the type id when Platform cannot clear it: the type is gone either way'
      - another tenant
      - does not see the template of a type of the same id in the first tenant
      - saving its own type of that id leaves the first tenant's template alone
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies. Platform communication operations use the local test adapter, so this suite does not
      prove deployed template validation or delivery.
command: >-
  npx mocha --timeout 60000
  'modules/entities/tests/integration/db/organization-compliance-violations.table.integration.spec.js'
  'modules/entities/tests/integration/services/email-previews/email-preview.integration.spec.js'
  'modules/entities/tests/integration/services/organizations/compliance/compliance-change-events.integration.spec.js'
  'modules/entities/tests/integration/services/organizations/compliance/compliance-reads.integration.spec.js'
  'modules/entities/tests/integration/services/organizations/compliance/compliance-reprocess-errors.integration.spec.js'
  'modules/entities/tests/integration/services/organizations/compliance/compliance-reprocess.integration.spec.js'
  'modules/entities/tests/integration/services/organizations/compliance/organization-compliance.integration.spec.js'
  'modules/entities/tests/integration/services/persistence/communication-request-submissions.integration.spec.js'
  'modules/entities/tests/integration/services/persistence/communication-templates.integration.spec.js'
  'modules/entities/tests/integration/services/persistence/communication-templates.queries.integration.spec.js'
  'modules/entities/tests/integration/services/persistence/compliance-reprocesses.integration.spec.js'
  'modules/entities/tests/integration/services/persistence/compliance-reprocesses.queries.integration.spec.js'
  'modules/entities/tests/integration/services/persistence/organization-attention-items.integration.spec.js'
  'modules/entities/tests/integration/services/persistence/organization-attention-items.queries.integration.spec.js'
  'modules/entities/tests/integration/services/templates/compliance-notification-template.integration.spec.js'
retries: none
proves_controls: []
product_intent: proposed
implementation_evidence: observed
narrative:
  status: enriched
---

# Organization compliance and notice preparation integration

## Verification Boundary

Organization compliance calculation, violation persistence, reprocess progress, attention reads and notice preparation cross local service and database seams.

## What This Suite Proves

Tests establish stored violations, computed compliance status, changes to attention items and reprocess progress or failure. Communication submission tests establish caller-transaction visibility. Template tests exercise publication, partial updates, clearing and compensation when Platform refuses or cannot save. Notification preparation remains distinct from actual delivery to a recipient.

## What It Does Not Prove

This group does not prove final mail delivery, deployed Platform template validation or the authorization of a public reprocess request. Organization CRUD is separate. A reprocess counter or an accepted request is not by itself evidence that every organization reaches its terminal recomputed state.

## Level and Rationale

Violation rows, attention publication and reprocess progress must agree with organization state across transactions. A lower-level calculation cannot establish rollback, terminal failure accounting or compensation across the owned-template seam. The database tier verifies the retained facts that staff later review.

## Real Dependencies and Test Doubles

PostgreSQL, compliance services, CRM notice composition and progress queries are real. Platform communication operations use the local adapter described by the tests. Object storage for communication payloads is prepared by the repository test bootstrap. These substitutes intentionally exclude deployed publication and delivery availability.

## Must Not Be Doubled

Keep violation persistence, progress updates and caller transactions real. Do not substitute the comparison of current role counts with stored violations. When testing template compensation, keep the CRM compensating behavior and the refused remote outcome; replacing both with an accepted result would remove the failure boundary.

## Fixtures and Isolation

Tests create their own organizations, compliance types, role fixtures and reprocess records. Template tests restore injected Platform behavior. Reprocess fixtures own unfinished-run premises so a cleanup cannot cancel another run; the selected serial invocation avoids overlapping process-level adapters.

## Determinism and Retries

Explicit role-count and date fixtures drive the expected compliance result. Retry and failure cases retain the source-declared sequence and counters. This register adds no runner retries; retrying a failed reprocess test could conceal an unfinished run or duplicate submission.

## How It Runs

Run the command in the frontmatter from the service repository after preparing the test database. It selects every file in this aggregate register under the repository Mocha bootstrap and runs serially. This is the aggregate selection of the integration gate; the complete repository integration command includes other modules and is wider than this register.

## Coverage Gaps

Integration coverage does not fill the API lifecycle gap for terminal reprocess settlement or prove delivered notices. Existing recipient batching, policy-state and recovery findings remain open. No control is claimed solely because a permitted notice or successful template publication is tested.
