---
id: ATS-CRM-ENT-011
scope: CAP-CRM-ENT-011
product_area: crm
module: entities
revision: 1
status: proposed
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-CRM-ENT-011-01
    title: Roles name the workspace’s roles and lie within the affiliation
    level: api
    proves:
      - BR-CAP-CRM-ENT-011-01
      - BR-CAP-CRM-ENT-011-02
      - INV-DOM-CRM-ENT-003-08
    preconditions: Prepare an affiliation from 2024-01-01.
    steps: >-
      Add a role starting 2023-12-01; a role id the workspace lacks; shorten the
      affiliation under a dated role.
    expected: 400 naming the field; rejected; rejected at commit.
    negative: true
    data_needs: No additional fixtures.
    bound_to:
      - TST-CRM-ENT-786
      - TST-CRM-ENT-790
    provenance: test
    source: >-
      services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#refuses
      a role whose dates lie outside its affiliation's
    category: validation
    action_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#refuses
        a role whose dates lie outside its affiliation's
    assertion_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#refuses
        a role whose dates lie outside its affiliation's
    test_anchors:
      - >-
        services-crm:modules/entities/tests/e2e/contact-affiliations.e2e.spec.js#answers
        400 for a role that starts before its affiliation, naming the field
      - >-
        services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#refuses
        a role whose dates lie outside its affiliation's
      - >-
        services-crm:modules/entities/tests/integration/db/contact-organization-roles.table.integration.spec.js#commits
        the role, within its affiliation by then
    binding_scope: >-
      contributions: the cited executable assertions collectively support only
      the observations they contain; additional matrix and journey checks remain
      proposed.
  - id: ATS-CRM-ENT-011-02
    title: No role overlaps itself; 25 per affiliation
    level: browser
    proves:
      - BR-CAP-CRM-ENT-011-03
      - INV-DOM-CRM-ENT-003-07
    preconditions: Prepare an affiliation.
    steps: >-
      Add Billing twice in overlapping periods; in separate periods; add 26
      roles.
    expected: Rejected; accepted; rejected at 26.
    negative: true
    data_needs: No additional fixtures.
    bound_to:
      - TST-CRM-ENT-790
      - TST-CRM-ENT-776
    provenance: test
    source: >-
      services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#refuses
      the same role overlapping itself on one affiliation
    category: boundary
    action_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#refuses
        the same role overlapping itself on one affiliation
    assertion_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#refuses
        the same role overlapping itself on one affiliation
    test_anchors:
      - >-
        services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#refuses
        the same role overlapping itself on one affiliation
      - >-
        services-crm:modules/entities/tests/integration/db/contact-organization-roles.table.integration.spec.js#refuses
        a second Billing role on one affiliation whose period overlaps the first
      - >-
        services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#refuses
        more than 25 roles on one affiliation, and takes 25
      - >-
        react-console:acceptance/crm/playwright/journeys/affiliations/CRM-ACC-0182.spec.ts#CRM-ACC-0182
    binding_scope: >-
      contributions: the cited executable assertions collectively support only
      the observations they contain; additional matrix and journey checks remain
      proposed.
  - id: ATS-CRM-ENT-011-03
    title: Ending a affiliation ends its open roles
    level: api
    proves:
      - BR-CAP-CRM-ENT-011-04
    preconditions: Prepare a affiliation with an undated role.
    steps: Patch the affiliation's end date.
    expected: The role ends the same day.
    negative: false
    data_needs: No additional fixtures.
    bound_to:
      - TST-CRM-ENT-786
    provenance: test
    source: >-
      services-crm:modules/entities/tests/e2e/contact-affiliations.e2e.spec.js#ends
      the open roles of the ended affiliation the same day
    category: transition
    action_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/e2e/contact-affiliations.e2e.spec.js#ends
        the open roles of the ended affiliation the same day
    assertion_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/e2e/contact-affiliations.e2e.spec.js#ends
        the open roles of the ended affiliation the same day
    test_anchors:
      - >-
        services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#ends
        the open roles of an affiliation the save ends, on the same day
      - >-
        services-crm:modules/entities/tests/e2e/contact-affiliations.e2e.spec.js#ends
        the open roles of the ended affiliation the same day
    binding_scope: >-
      contributions: the cited executable assertions collectively support only
      the observations they contain; additional matrix and journey checks remain
      proposed.
  - id: ATS-CRM-ENT-011-04
    title: Restricted types refuse other roles; unmodified roles not re-checked
    level: browser
    proves:
      - BR-CAP-CRM-ENT-011-05
    preconditions: Prepare an organization whose type allows three roles.
    steps: >-
      Add an allowed role; a forbidden one new, added and changed; re-save a
      role stored before the restriction.
    expected: 'Accepted; rejected naming role, type and allowed list; accepted.'
    negative: true
    data_needs: No additional fixtures.
    bound_to:
      - TST-CRM-ENT-790
      - TST-CRM-ENT-776
    provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#refuses
      a role outside the list added to an existing affiliation
    category: validation
    action_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#refuses
        a role outside the list added to an existing affiliation
    assertion_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#refuses
        a role outside the list added to an existing affiliation
    test_anchors:
      - >-
        services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#takes
        an allowed role on a new affiliation (premise)
      - >-
        services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#refuses
        a role outside the list on a new affiliation, naming the role and the
        type
      - >-
        services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#refuses
        a role outside the list added to an existing affiliation
      - >-
        services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#refuses
        an existing role changed to one outside the list
      - >-
        services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#does
        not check a role the save leaves as it is
      - >-
        react-console:acceptance/crm/playwright/journeys/affiliations/CRM-ACC-0188.spec.ts#CRM-ACC-0188
    binding_scope: >-
      contributions: the cited executable assertions collectively support only
      the observations they contain; additional matrix and journey checks remain
      proposed.
  - id: ATS-CRM-ENT-011-05
    title: Joining gives automatic and first-contact roles
    level: browser
    proves:
      - BR-CAP-CRM-ENT-011-06
    preconditions: Prepare automatic and first-contact roles; an empty company.
    steps: >-
      Create two contacts joining it; Make Primary on an existing affiliation;
      save with the primary unmodified.
    expected: >-
      First gets both, second only automatic; roles on the affiliation made
      primary; nothing.
    negative: false
    data_needs: No additional fixtures.
    bound_to:
      - TST-CRM-ENT-790
      - TST-CRM-ENT-776
    provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
      the organization's first contact the automatic and first-contact roles,
      besides the roles it states
    category: rule
    action_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
        the organization's first contact the automatic and first-contact roles,
        besides the roles it states
    assertion_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
        the organization's first contact the automatic and first-contact roles,
        besides the roles it states
    test_anchors:
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
        the organization's first contact the automatic and first-contact roles,
        besides the roles it states
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
        a later contact only the automatic roles
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
        the roles on an existing affiliation the save makes primary (Make
        Primary)
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#leaves
        the roles as sent when the primary organization does not change
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#stores
        an automatic role once when the contact already states it
      - >-
        react-console:acceptance/crm/playwright/journeys/affiliations/CRM-ACC-0183.spec.ts#CRM-ACC-0183
    binding_scope: >-
      contributions: the cited executable assertions collectively support only
      the observations they contain; additional matrix and journey checks remain
      proposed.
  - id: ATS-CRM-ENT-011-06
    title: 'Future affiliations get their roles on the start day, corrections followed'
    level: api
    proves:
      - BR-CAP-CRM-ENT-011-07
    preconditions: Prepare a affiliation starting tomorrow in the workspace’s calendar.
    steps: >-
      Reconcile on the eve and on the day; correct the start earlier, later; end
      it before the day.
    expected: >-
      Nothing on the eve; roles on the day; roles in the correcting save; on the
      new day; nothing.
    negative: false
    data_needs: No additional fixtures.
    bound_to:
      - TST-CRM-ENT-790
    provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
      the automatic and first-contact roles on the start day in the tenant
      calendar
    category: transition
    action_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
        the automatic and first-contact roles on the start day in the tenant
        calendar
    assertion_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
        the automatic and first-contact roles on the start day in the tenant
        calendar
    test_anchors:
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
        nothing on the eve of the start day, when UTC has already reached it
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
        the automatic and first-contact roles on the start day in the tenant
        calendar
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
        the roles in the save that moves the start to a day already past
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
        the roles on the new start day when a correction moved the start later
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
        nothing to an affiliation a correction ended before its roles were given
    binding_scope: >-
      contributions: the cited executable assertions collectively support only
      the observations they contain; additional matrix and journey checks remain
      proposed.
  - id: ATS-CRM-ENT-011-07
    title: Automatic roles only add and are never given back
    level: api
    proves:
      - BR-CAP-CRM-ENT-011-08
      - INV-DOM-CRM-ENT-003-10
    preconditions: Prepare a affiliation given automatic roles.
    steps: End the affiliation; remove a role then reconcile; lock the contact.
    expected: Roles end with it; not given back; nothing while locked.
    negative: false
    data_needs: No additional fixtures.
    bound_to:
      - TST-CRM-ENT-790
    provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#does
      not give back a role a person removed after it was given
    category: edge
    action_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#does
        not give back a role a person removed after it was given
    assertion_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#does
        not give back a role a person removed after it was given
    test_anchors:
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
        roles with no dates of their own, so they last exactly as long as the
        affiliation
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#ends
        the given roles with the affiliation when a correction ends it
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#does
        not give back a role a person removed after it was given
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
        a contact locked against updates nothing while it is locked
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#changes
        nothing on a second pass, version included
    binding_scope: >-
      contributions: the cited executable assertions collectively support only
      the observations they contain; additional matrix and journey checks remain
      proposed.
  - id: ATS-CRM-ENT-011-08
    title: Inactive and deceased contacts get no automatic roles
    level: browser
    proves:
      - BR-CAP-CRM-ENT-011-09
    preconditions: Prepare automatic roles.
    steps: >-
      Create inactive and deceased contacts with a primary; make one inactive in
      the moving save; reconcile a deceased contact's due affiliation.
    expected: No roles; preserved roles; still counted as belonging.
    negative: false
    data_needs: No additional fixtures.
    bound_to:
      - TST-CRM-ENT-790
      - TST-CRM-ENT-774
    provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#counts
      an inactive contact as already belonging to the organization, so the next
      contact is not its first
    category: edge
    action_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#counts
        an inactive contact as already belonging to the organization, so the
        next contact is not its first
    assertion_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#counts
        an inactive contact as already belonging to the organization, so the
        next contact is not its first
    test_anchors:
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#is
        given no roles when it is created inactive with a primary organization
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#is
        given no roles when it is created deceased with a primary organization
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#keeps
        the roles it already holds when it becomes inactive
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#counts
        an inactive contact as already belonging to the organization, so the
        next contact is not its first
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
        a deceased contact no roles on the start day
      - >-
        react-console:acceptance/crm/playwright/journeys/contacts/CRM-ACC-0031.spec.ts#CRM-ACC-0031
    binding_scope: >-
      contributions: the cited executable assertions collectively support only
      the observations they contain; additional matrix and journey checks remain
      proposed.
  - id: ATS-CRM-ENT-011-09
    title: the restriction wins over the automatic flag
    level: api
    proves:
      - BR-CAP-CRM-ENT-011-10
    preconditions: Prepare a restricting type and an automatic role it does not allow.
    steps: Save a primary affiliation there; reconcile a due affiliation there.
    expected: 'The role skipped at save and on the day, reported as not allowed.'
    negative: false
    data_needs: No additional fixtures.
    bound_to:
      - TST-CRM-ENT-790
    provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/affiliations/affiliation-date-reconciliation.follow-ups.integration.spec.js#skips
      the forbidden role on the start day
    category: interaction
    action_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/integration/services/affiliations/affiliation-date-reconciliation.follow-ups.integration.spec.js#skips
        the forbidden role on the start day
    assertion_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/integration/services/affiliations/affiliation-date-reconciliation.follow-ups.integration.spec.js#skips
        the forbidden role on the start day
    test_anchors:
      - >-
        services-crm:modules/entities/tests/integration/services/affiliations/affiliation-date-reconciliation.follow-ups.integration.spec.js#gives
        a primary affiliation to such an organization no automatic role the type
        forbids, at its save
      - >-
        services-crm:modules/entities/tests/integration/services/affiliations/affiliation-date-reconciliation.follow-ups.integration.spec.js#skips
        the forbidden role on the start day
      - >-
        services-crm:modules/entities/tests/integration/services/affiliations/affiliation-date-reconciliation.follow-ups.integration.spec.js#says
        so in the change list: not allowed for the type
    binding_scope: >-
      contributions: the cited executable assertions collectively support only
      the observations they contain; additional matrix and journey checks remain
      proposed.
  - id: ATS-CRM-ENT-011-10
    title: Re-joining gives the automatic roles again
    level: api
    proves:
      - BR-CAP-CRM-ENT-011-11
    preconditions: >-
      Prepare a person who retained the automatic roles on an ended affiliation
      at Acme.
    steps: Make Acme their primary organization again on a new affiliation.
    expected: >-
      The new affiliation holds the automatic roles; the old affiliation
      preserves its ended roles.
    negative: false
    data_needs: No additional fixtures.
    bound_to: []
    provenance: proposed
    source: >-
      services-crm:modules/entities/services/contacts/role-assignment/contact-role-assignment.ts:automaticRolesDecidedFor
    category: transition
    action_evidence:
      provenance: proposed
      source: >-
        services-crm:modules/entities/services/contacts/role-assignment/contact-role-assignment.ts:automaticRolesDecidedFor
    assertion_evidence:
      provenance: proposed
      source: >-
        services-crm:modules/entities/services/contacts/role-assignment/contact-role-assignment.ts:automaticRolesDecidedFor
    test_anchors: []
    binding_scope: 'unbound: the detailed scenario still needs executable proof.'
  - id: ATS-CRM-ENT-011-11
    title: One first contact among simultaneous joiners
    level: api
    proves:
      - BR-CAP-CRM-ENT-011-12
      - INV-DOM-CRM-ENT-003-11
    preconditions: Prepare an empty organization with a first-contact role.
    steps: Several contacts join at once.
    expected: Exactly one holds the first-contact role.
    negative: false
    data_needs: No additional fixtures.
    bound_to:
      - TST-CRM-ENT-790
    provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
      the first-contact roles to exactly one of several contacts joining an
      empty organization at once
    category: concurrency
    action_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
        the first-contact roles to exactly one of several contacts joining an
        empty organization at once
    assertion_evidence:
      provenance: test
      source: >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
        the first-contact roles to exactly one of several contacts joining an
        empty organization at once
    test_anchors:
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
        the first-contact roles to exactly one of several contacts joining an
        empty organization at once
      - >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#also
        when contacts move into the empty organization at once
    binding_scope: >-
      contributions: the cited executable assertions collectively support only
      the observations they contain; additional matrix and journey checks remain
      proposed.
  - id: ATS-CRM-ENT-011-12
    title: Refuse an unknown role without changing the affiliation
    category: failure
    level: api
    proves:
      - BR-CAP-CRM-ENT-011-01
      - BR-CAP-CRM-ENT-009-02
    preconditions: A person has a current affiliation and a known role period.
    steps: >-
      Add a role identifier absent from the workspace while changing the
      affiliation title.
    expected: The complete save is refused; the known role and original title remain.
    negative: true
    data_needs: Run-owned records and configuration in an isolated workspace.
    bound_to: []
    provenance: proposed
    source: >-
      services-crm:modules/entities/services/persistence/contact-affiliations.ts:affiliationRefusal
    test_anchors: []
    action_evidence:
      provenance: proposed
      source: >-
        services-crm:modules/entities/services/persistence/contact-affiliations.ts:affiliationRefusal
    assertion_evidence:
      provenance: proposed
      source: >-
        services-crm:modules/entities/services/persistence/contact-affiliations.ts:affiliationRefusal
    binding_scope: 'unbound: the detailed scenario still needs executable proof.'
  - id: ATS-CRM-ENT-011-13
    title: End a primary tie and its open responsibility period
    category: interaction
    level: api
    proves:
      - BR-CAP-CRM-ENT-009-06
      - BR-CAP-CRM-ENT-011-04
    preconditions: A person’s primary affiliation has an open role period.
    steps: >-
      Save an end date for that affiliation; read the relationship and role
      periods.
    expected: >-
      Primary designation clears and the open role ends with the affiliation
      without promoting another tie.
    negative: false
    data_needs: Run-owned records and configuration in an isolated workspace.
    bound_to: []
    provenance: proposed
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#makes
      nothing primary in its place;
      services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#ends
      the open roles of an affiliation the save ends, on the same day
    exercises:
      - CAP-CRM-ENT-009
      - CAP-CRM-ENT-011
    workflows:
      - WF-CRM-ENT-001
      - WF-CRM-ENT-002
    test_anchors: []
    action_evidence:
      provenance: proposed
      source: >-
        services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#makes
        nothing primary in its place;
        services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#ends
        the open roles of an affiliation the save ends, on the same day
    assertion_evidence:
      provenance: proposed
      source: >-
        services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#makes
        nothing primary in its place;
        services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#ends
        the open roles of an affiliation the save ends, on the same day
    binding_scope: 'unbound: the detailed scenario still needs executable proof.'
  - id: ATS-CRM-ENT-011-14
    title: Due dates settle automatic responsibilities
    category: interaction
    level: api
    proves:
      - BR-CAP-CRM-ENT-010-05
      - BR-CAP-CRM-ENT-011-07
    preconditions: A future affiliation has an eligible active automatic role.
    steps: 'Reconcile before the local start day, then on that day and once again.'
    expected: >-
      No role is assigned early; the due pass assigns it and the repeated pass
      adds no duplicate.
    negative: false
    data_needs: Run-owned records and configuration in an isolated workspace.
    bound_to: []
    provenance: proposed
    source: >-
      services-crm:modules/entities/tests/integration/services/affiliations/affiliation-date-reconciliation.integration.spec.js#takes
      the organization out of compliance the next morning, with no save of the
      contact;
      services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
      the automatic and first-contact roles on the start day in the tenant
      calendar
    exercises:
      - CAP-CRM-ENT-010
      - CAP-CRM-ENT-011
    workflows:
      - WF-CRM-ENT-002
      - WF-CRM-ENT-006
      - WF-CRM-ENT-007
    test_anchors: []
    action_evidence:
      provenance: proposed
      source: >-
        services-crm:modules/entities/tests/integration/services/affiliations/affiliation-date-reconciliation.integration.spec.js#takes
        the organization out of compliance the next morning, with no save of the
        contact;
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
        the automatic and first-contact roles on the start day in the tenant
        calendar
    assertion_evidence:
      provenance: proposed
      source: >-
        services-crm:modules/entities/tests/integration/services/affiliations/affiliation-date-reconciliation.integration.spec.js#takes
        the organization out of compliance the next morning, with no save of the
        contact;
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
        the automatic and first-contact roles on the start day in the tenant
        calendar
    binding_scope: 'unbound: the detailed scenario still needs executable proof.'
  - id: ATS-CRM-ENT-011-15
    title: Allowed responsibility satisfies organizational policy
    category: interaction
    level: api
    proves:
      - BR-CAP-CRM-ENT-011-05
      - BR-CAP-CRM-ENT-012-03
    preconditions: A governed organization allows a required role on a current affiliation.
    steps: Assign that role through the person and recalculate the organization.
    expected: >-
      The allowed assignment persists and its effective holder satisfies the
      configured minimum.
    negative: false
    data_needs: Run-owned records and configuration in an isolated workspace.
    bound_to: []
    provenance: proposed
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#refuses
      a role outside the list added to an existing affiliation;
      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
    exercises:
      - CAP-CRM-ENT-011
      - CAP-CRM-ENT-012
    workflows:
      - WF-CRM-ENT-004
      - WF-CRM-ENT-006
    test_anchors: []
    action_evidence:
      provenance: proposed
      source: >-
        services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#refuses
        a role outside the list added to an existing affiliation;
        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
    assertion_evidence:
      provenance: proposed
      source: >-
        services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#refuses
        a role outside the list added to an existing affiliation;
        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
    binding_scope: 'unbound: the detailed scenario still needs executable proof.'
  - id: ATS-CRM-ENT-011-16
    title: Automatic assignment creates a catalogue dependency
    category: interaction
    level: api
    proves:
      - BR-CAP-CRM-ENT-011-06
      - BR-CAP-CRM-ENT-017-03
    preconditions: An active catalogue role is automatic and has no holder yet.
    steps: Join an eligible person as primary; try deleting the assigned role.
    expected: >-
      The new affiliation holds the role and deletion is refused while that role
      period remains.
    negative: false
    data_needs: Run-owned records and configuration in an isolated workspace.
    bound_to: []
    provenance: proposed
    source: >-
      services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
      the organization's first contact the automatic and first-contact roles,
      besides the roles it states;
      services-crm:modules/entities/tests/integration/services/persistence/contact-roles.integration.spec.js#refuses
      it with the legacy words, naming the organization types whose rules depend
      on it
    exercises:
      - CAP-CRM-ENT-011
      - CAP-CRM-ENT-017
    workflows: []
    test_anchors: []
    action_evidence:
      provenance: proposed
      source: >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
        the organization's first contact the automatic and first-contact roles,
        besides the roles it states;
        services-crm:modules/entities/tests/integration/services/persistence/contact-roles.integration.spec.js#refuses
        it with the legacy words, naming the organization types whose rules
        depend on it
    assertion_evidence:
      provenance: proposed
      source: >-
        services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
        the organization's first contact the automatic and first-contact roles,
        besides the roles it states;
        services-crm:modules/entities/tests/integration/services/persistence/contact-roles.integration.spec.js#refuses
        it with the legacy words, naming the organization types whose rules
        depend on it
    binding_scope: 'unbound: the detailed scenario still needs executable proof.'
  - id: ATS-CRM-ENT-011-17
    title: Exercise every declared authority independently
    category: permission
    level: api
    proves:
      - BR-CAP-CRM-ENT-003-07
      - BR-CAP-CRM-ENT-003-09
    preconditions: >-
      An eligible record and configuration fixture exist for each operation; the
      caller can reach only the run’s workspace.
    steps: >-
      For each declared permission, execute its matching operation with that
      permission, then without it while retaining the other required grants.
      Read affected records after every refused mutation.
    expected: >-
      The authorized case reaches the operation; the missing-grant case is
      refused and preserves saved data. Record access alone does not authorize
      the other declared actions.
    negative: true
    data_needs: Run-owned records and configuration in an isolated workspace.
    bound_to: []
    provenance: proposed
    source: >-
      services-crm:aws/crm.service.ts:ApplicationPermissions;
      services-crm:modules/entities/aws/api/entities.routes.ts
    permission_keys:
      - crm.contacts.update
      - crm.contact-roles.read
    test_anchors: []
    action_evidence:
      provenance: proposed
      source: >-
        services-crm:aws/crm.service.ts:ApplicationPermissions;
        services-crm:modules/entities/aws/api/entities.routes.ts
    assertion_evidence:
      provenance: proposed
      source: >-
        services-crm:aws/crm.service.ts:ApplicationPermissions;
        services-crm:modules/entities/aws/api/entities.routes.ts
    binding_scope: 'unbound: the detailed scenario still needs executable proof.'
evidence:
  - >-
    services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#refuses
    a role whose dates lie outside its affiliation's
  - >-
    services-crm:modules/entities/tests/e2e/contact-affiliations.e2e.spec.js#answers
    400 for a role that starts before its affiliation, naming the field
  - >-
    services-crm:modules/entities/tests/integration/db/contact-organization-roles.table.integration.spec.js#commits
    the role, within its affiliation by then
  - >-
    services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#refuses
    the same role overlapping itself on one affiliation
  - >-
    services-crm:modules/entities/tests/integration/db/contact-organization-roles.table.integration.spec.js#refuses
    a second Billing role on one affiliation whose period overlaps the first
  - >-
    services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#refuses
    more than 25 roles on one affiliation, and takes 25
  - >-
    react-console:acceptance/crm/playwright/journeys/affiliations/CRM-ACC-0182.spec.ts#CRM-ACC-0182
  - >-
    services-crm:modules/entities/tests/e2e/contact-affiliations.e2e.spec.js#ends
    the open roles of the ended affiliation the same day
  - >-
    services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#ends
    the open roles of an affiliation the save ends, on the same day
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#refuses
    a role outside the list added to an existing affiliation
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#takes
    an allowed role on a new affiliation (premise)
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#refuses
    a role outside the list on a new affiliation, naming the role and the type
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#refuses
    an existing role changed to one outside the list
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#does
    not check a role the save leaves as it is
  - >-
    react-console:acceptance/crm/playwright/journeys/affiliations/CRM-ACC-0188.spec.ts#CRM-ACC-0188
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
    the organization's first contact the automatic and first-contact roles,
    besides the roles it states
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
    a later contact only the automatic roles
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
    the roles on an existing affiliation the save makes primary (Make Primary)
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#leaves
    the roles as sent when the primary organization does not change
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#stores
    an automatic role once when the contact already states it
  - >-
    react-console:acceptance/crm/playwright/journeys/affiliations/CRM-ACC-0183.spec.ts#CRM-ACC-0183
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
    the automatic and first-contact roles on the start day in the tenant
    calendar
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
    nothing on the eve of the start day, when UTC has already reached it
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
    the roles in the save that moves the start to a day already past
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
    the roles on the new start day when a correction moved the start later
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
    nothing to an affiliation a correction ended before its roles were given
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#does
    not give back a role a person removed after it was given
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
    roles with no dates of their own, so they last exactly as long as the
    affiliation
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#ends
    the given roles with the affiliation when a correction ends it
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
    a contact locked against updates nothing while it is locked
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#changes
    nothing on a second pass, version included
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#counts
    an inactive contact as already belonging to the organization, so the next
    contact is not its first
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#is
    given no roles when it is created inactive with a primary organization
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#is
    given no roles when it is created deceased with a primary organization
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#keeps
    the roles it already holds when it becomes inactive
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
    a deceased contact no roles on the start day
  - >-
    react-console:acceptance/crm/playwright/journeys/contacts/CRM-ACC-0031.spec.ts#CRM-ACC-0031
  - >-
    services-crm:modules/entities/tests/integration/services/affiliations/affiliation-date-reconciliation.follow-ups.integration.spec.js#skips
    the forbidden role on the start day
  - >-
    services-crm:modules/entities/tests/integration/services/affiliations/affiliation-date-reconciliation.follow-ups.integration.spec.js#gives
    a primary affiliation to such an organization no automatic role the type
    forbids, at its save
  - >-
    services-crm:modules/entities/tests/integration/services/affiliations/affiliation-date-reconciliation.follow-ups.integration.spec.js#says
    so in the change list: not allowed for the type
  - >-
    services-crm:modules/entities/services/contacts/role-assignment/contact-role-assignment.ts:automaticRolesDecidedFor
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
    the first-contact roles to exactly one of several contacts joining an empty
    organization at once
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#also
    when contacts move into the empty organization at once
  - >-
    services-crm:modules/entities/services/persistence/contact-affiliations.ts:affiliationRefusal
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#makes
    nothing primary in its place;
    services-crm:modules/entities/tests/unit/services/persistence/contact-affiliations.spec.js#ends
    the open roles of an affiliation the save ends, on the same day
  - >-
    services-crm:modules/entities/tests/integration/services/affiliations/affiliation-date-reconciliation.integration.spec.js#takes
    the organization out of compliance the next morning, with no save of the
    contact;
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/automatic-role-reconciliation.integration.spec.js#gives
    the automatic and first-contact roles on the start day in the tenant
    calendar
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/contact-affiliations.integration.spec.js#refuses
    a role outside the list added to an existing affiliation;
    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
  - >-
    services-crm:modules/entities/tests/integration/services/contacts/role-assignment/contact-role-assignment.integration.spec.js#gives
    the organization's first contact the automatic and first-contact roles,
    besides the roles it states;
    services-crm:modules/entities/tests/integration/services/persistence/contact-roles.integration.spec.js#refuses
    it with the legacy words, naming the organization types whose rules depend
    on it
  - >-
    services-crm:aws/crm.service.ts:ApplicationPermissions;
    services-crm:modules/entities/aws/api/entities.routes.ts
coverage:
  rule: covered
  transition: covered
  validation: covered
  permission: covered
  edge: covered
  failure: covered
  boundary: covered
  concurrency: covered
  invariant: 'gap: FND-CRM-ENT-059'
  interaction: covered
previous_approval:
  revision: 1
  approved_by: Andrew
  approved_at: '2026-10-22T00:00:00.000Z'
coverage_notes:
  invariant:
    reason: >-
      No detailed invariant scenario currently specifies this aspect; the
      coverage finding records the required follow-through.
    provenance: unknown
    source: FND-CRM-ENT-059
coverage_findings:
  - FND-CRM-ENT-059
  - FND-CRM-ENT-075
permission_coverage:
  - key: crm.contacts.update
    where_checked: api
    scenario: ATS-CRM-ENT-011-17
    provenance: documented
    source: >-
      rhythm-v2-docs:specs/crm/entities/planning/capabilities/CAP-CRM-ENT-011-give-people-roles-at-their-organizations-automatically-where.md
  - key: crm.contact-roles.read
    where_checked: api
    scenario: ATS-CRM-ENT-011-17
    provenance: documented
    source: >-
      rhythm-v2-docs:specs/crm/entities/planning/capabilities/CAP-CRM-ENT-011-give-people-roles-at-their-organizations-automatically-where.md
related_coverage:
  - capability: CAP-CRM-ENT-009
    scenarios:
      - ATS-CRM-ENT-011-13
    provenance: documented
    source: >-
      rhythm-v2-docs:specs/crm/entities/planning/capabilities/CAP-CRM-ENT-011-give-people-roles-at-their-organizations-automatically-where.md:related
  - capability: CAP-CRM-ENT-010
    scenarios:
      - ATS-CRM-ENT-011-14
    provenance: documented
    source: >-
      rhythm-v2-docs:specs/crm/entities/planning/capabilities/CAP-CRM-ENT-011-give-people-roles-at-their-organizations-automatically-where.md:related
  - capability: CAP-CRM-ENT-012
    scenarios:
      - ATS-CRM-ENT-011-15
    provenance: documented
    source: >-
      rhythm-v2-docs:specs/crm/entities/planning/capabilities/CAP-CRM-ENT-011-give-people-roles-at-their-organizations-automatically-where.md:related
  - capability: CAP-CRM-ENT-017
    scenarios:
      - ATS-CRM-ENT-011-16
    provenance: documented
    source: >-
      rhythm-v2-docs:specs/crm/entities/planning/capabilities/CAP-CRM-ENT-011-give-people-roles-at-their-organizations-automatically-where.md:related
examination_evidence:
  provenance: documented
  source: 'rhythm-v2-docs:specs/crm/entities/reports/EXAMINATION-2026-10-23.md'
  heading_conflict: FND-CRM-ENT-075
---

# Maintain responsibilities on organizational relationships
## Coverage

The category map separates specified cases from recorded gaps. A proposed case describes proof to implement; a binding identifies the assertions supplied by an existing executable file. The permission and transition ledgers record the individual checks needed for the capability.

| Required rule | Scenario or finding |
|---|---|
| `BR-CAP-CRM-ENT-011-01` | `ATS-CRM-ENT-011-01`, `ATS-CRM-ENT-011-12` |
| `BR-CAP-CRM-ENT-011-02` | `ATS-CRM-ENT-011-01` |
| `BR-CAP-CRM-ENT-011-03` | `ATS-CRM-ENT-011-02` |
| `BR-CAP-CRM-ENT-011-04` | `ATS-CRM-ENT-011-03`, `ATS-CRM-ENT-011-13` |
| `BR-CAP-CRM-ENT-011-05` | `ATS-CRM-ENT-011-04`, `ATS-CRM-ENT-011-15` |
| `BR-CAP-CRM-ENT-011-06` | `ATS-CRM-ENT-011-05`, `ATS-CRM-ENT-011-16` |
| `BR-CAP-CRM-ENT-011-07` | `ATS-CRM-ENT-011-06`, `ATS-CRM-ENT-011-14` |
| `BR-CAP-CRM-ENT-011-08` | `ATS-CRM-ENT-011-07` |
| `BR-CAP-CRM-ENT-011-09` | `ATS-CRM-ENT-011-08` |
| `BR-CAP-CRM-ENT-011-10` | `ATS-CRM-ENT-011-09` |
| `BR-CAP-CRM-ENT-011-11` | `ATS-CRM-ENT-011-10` |
| `BR-CAP-CRM-ENT-011-12` | `ATS-CRM-ENT-011-11` |

## Interactions With Related Capabilities

The interaction scenarios exercise maintain a person’s organizational relationships; keep dated relationships current; review organization role compliance and prepare notices; configure affiliation types and contact roles. They change one part of a prepared record and inspect the dependent outcome. Unbound interactions remain proposed rather than implying an existing end-to-end implementation.

## Source Evidence

The frontmatter pins the repositories and identifies the source anchors for each scenario. Bindings record inspected assertions, while unbound cases remain proposed. Source inspection supplies no execution result or product approval.
