---
id: WF-CRM-ENT-007
title: Give automatic roles on the start day
trigger: >-
  Each five-minute job-reconciler pass attempts automatic roles for pending
  affiliations whose start date has arrived.
product_area: crm
module: entities
revision: 1
status: draft
design_intent: confirmed
origin: >-
  D-46 (Andrew, 2026-10-19) "do not grant a future job's role early";
  DEF-CRM-0756; cited in
  services-crm:modules/entities/services/contacts/role-assignment/automatic-role-reconciliation.ts
implementation_evidence: observed
inference: []
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
  - CAP-CRM-ENT-011
  - CAP-CRM-ENT-010
moves:
  - STATE-CRM-ENT-005
crosses:
  - SVC-CRM-ENT-entities
idempotency: >-
  The save records pending assignment. A contact transaction assigns eligible
  missing roles and clears its pending marker together. Repeating settled work
  does not restore roles later removed by a user; an ended affiliation can be
  cleared without assignment.
concurrency: >-
  The worker locks each contact and due affiliation, serializing with contact
  saves. Full locks retain pending work. The sweep has a 60-second budget and
  visits at most 200 contacts per workspace, so backlog can defer assignment
  beyond one interval.
hops:
  - 'n': 1
    actor_or_service: Job reconciler (crm_job_reconciler)
    action: >-
      Invoke automatic-role settlement in its own job context on each scheduled
      pass.
    anchor: 'services-crm:aws/lambda/JOB_RECONCILER.ts:handler'
    seam: schedule
    on_failure: Log step failure and retry eligibility on a later pass.
    left_inconsistent: Due assignments remain pending without a fixed recovery deadline.
    observer: Job reconciler logs show step failures.
    provenance: observed
    source: 'services-crm:aws/lambda/JOB_RECONCILER.ts:reconcileAutomaticRoles'
  - 'n': 2
    actor_or_service: Automatic role sweep
    action: >-
      Enumerate workspaces and select contacts with pending affiliations due in
      each workspace’s calendar.
    anchor: >-
      services-crm:modules/entities/services/contacts/role-assignment/automatic-role-reconciliation.ts:sweepAutomaticRoles
    seam: sync
    on_failure: >-
      Caught pass failures are logged and skipped. Obtaining workspace context
      occurs outside that catch and can abort the sweep.
    left_inconsistent: Unvisited or failed workspaces retain pending affiliations.
    observer: Sweep logs identify completed and failed passes.
    provenance: observed
    source: >-
      services-crm:modules/entities/services/contacts/role-assignment/automatic-role-reconciliation.ts:sweepAutomaticRoles
  - 'n': 3
    actor_or_service: Automatic role reconciliation (one transaction per contact)
    action: >-
      Lock the contact and pending affiliations, choose active automatic roles
      allowed by organization policy, serialize first-contact decisions and
      persist assignments with marker clearing. Inactive and deceased contacts
      receive no roles.
    anchor: >-
      services-crm:modules/entities/services/persistence/contact-affiliations.ts:giveDueAutomaticRoles
    seam: sync
    on_failure: Rollback preserves pending assignment when the contact transaction fails.
    left_inconsistent: Failed or locked work can remain due.
    observer: System-attributed contact revisions show successful assignment.
    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
  - 'n': 4
    actor_or_service: Database change capture and compliance handler
    action: >-
      Capture contact events and revisions for assigned roles, then process the
      organization compliance reaction.
    anchor: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-change-events.ts:organizationComplianceRecalculationHandler
    seam: queue
    on_failure: >-
      Retry failed compliance messages through SQS and dead-letter after five
      receives.
    left_inconsistent: Assigned roles can precede updated organization compliance.
    observer: Consumer logs and dead-letter messages expose reaction failure.
    provenance: documented
    source: 'services-crm:docs/change-events.md#The handlers CRM registers'
branches:
  - Restricted roles are skipped and the restricting type is reported.
  - >-
    A later contact save can settle an already-due affiliation before the
    scheduled worker reaches it.
waits:
  - >-
    The start date establishes eligibility. Five-minute scheduling is an attempt
    cadence, subject to workspace order, budgets and locks.
evidence:
  - >-
    services-crm at 7ea48a41:
    modules/entities/services/contacts/role-assignment/automatic-role-reconciliation.ts,
    contact-role-assignment.ts; services/persistence/contact-affiliations.ts
    (listContactsWithAutomaticRolesDue, lockDueAutomaticRolesAffiliations,
    giveDueAutomaticRoles); aws/lambda/JOB_RECONCILER.ts;
    docs/affiliations/README.md §5.6a.
controls:
  - TC-AZ-001
  - TC-AZ-002
  - TC-AZ-003
  - TC-AZ-004
  - TC-AZ-006
  - TC-DAT-001
  - TC-DAT-002
  - TC-DAT-003
  - TC-IAM-001
  - TC-IAM-005
  - TC-IAM-006
  - TC-LOG-004
  - TC-LOG-005
  - TC-MON-001
  - TC-MON-002
  - TC-PI-001
  - TC-PI-002
  - TC-PI-003
  - TC-PI-004
  - TC-PI-005
  - TC-PRV-001
  - TC-PRV-002
  - TC-TEN-001
  - TC-TEN-002
  - TC-TEN-003
narrative:
  status: verified
  review: NARRATIVE-REVIEW-2026-10-23
narrative_sources:
  - section: What It Does
    provenance: observed
    source: 'services-crm:aws/lambda/JOB_RECONCILER.ts:handler'
  - section: What It Does
    provenance: observed
    source: >-
      services-crm:modules/entities/services/contacts/role-assignment/automatic-role-reconciliation.ts:sweepAutomaticRoles
  - section: What It Does
    provenance: observed
    source: >-
      services-crm:modules/entities/services/persistence/contact-affiliations.ts:giveDueAutomaticRoles
  - section: What It Does
    provenance: documented
    source: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-change-events.ts:organizationComplianceRecalculationHandler
  - section: What Starts It
    provenance: observed
    source: 'services-crm:aws/lambda/JOB_RECONCILER.ts:handler'
  - section: What Starts It
    provenance: observed
    source: >-
      services-crm:modules/entities/services/contacts/role-assignment/automatic-role-reconciliation.ts:sweepAutomaticRoles
  - section: What Starts It
    provenance: observed
    source: >-
      services-crm:modules/entities/services/persistence/contact-affiliations.ts:giveDueAutomaticRoles
  - section: What Starts It
    provenance: documented
    source: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-change-events.ts:organizationComplianceRecalculationHandler
  - section: The Flow
    provenance: observed
    source: 'services-crm:aws/lambda/JOB_RECONCILER.ts:handler'
  - section: The Flow
    provenance: observed
    source: >-
      services-crm:modules/entities/services/contacts/role-assignment/automatic-role-reconciliation.ts:sweepAutomaticRoles
  - section: The Flow
    provenance: observed
    source: >-
      services-crm:modules/entities/services/persistence/contact-affiliations.ts:giveDueAutomaticRoles
  - section: The Flow
    provenance: documented
    source: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-change-events.ts:organizationComplianceRecalculationHandler
  - section: Hop by Hop
    provenance: observed
    source: 'services-crm:aws/lambda/JOB_RECONCILER.ts:handler'
  - section: Hop by Hop
    provenance: observed
    source: >-
      services-crm:modules/entities/services/contacts/role-assignment/automatic-role-reconciliation.ts:sweepAutomaticRoles
  - section: Hop by Hop
    provenance: observed
    source: >-
      services-crm:modules/entities/services/persistence/contact-affiliations.ts:giveDueAutomaticRoles
  - section: Hop by Hop
    provenance: documented
    source: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-change-events.ts:organizationComplianceRecalculationHandler
  - section: When Something Fails
    provenance: observed
    source: 'services-crm:aws/lambda/JOB_RECONCILER.ts:handler'
  - section: When Something Fails
    provenance: observed
    source: >-
      services-crm:modules/entities/services/contacts/role-assignment/automatic-role-reconciliation.ts:sweepAutomaticRoles
  - section: When Something Fails
    provenance: observed
    source: >-
      services-crm:modules/entities/services/persistence/contact-affiliations.ts:giveDueAutomaticRoles
  - section: When Something Fails
    provenance: documented
    source: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-change-events.ts:organizationComplianceRecalculationHandler
  - section: Repeats and Races
    provenance: observed
    source: 'services-crm:aws/lambda/JOB_RECONCILER.ts:handler'
  - section: Repeats and Races
    provenance: observed
    source: >-
      services-crm:modules/entities/services/contacts/role-assignment/automatic-role-reconciliation.ts:sweepAutomaticRoles
  - section: Repeats and Races
    provenance: observed
    source: >-
      services-crm:modules/entities/services/persistence/contact-affiliations.ts:giveDueAutomaticRoles
  - section: Repeats and Races
    provenance: documented
    source: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-change-events.ts:organizationComplianceRecalculationHandler
  - section: What Is Observable
    provenance: observed
    source: 'services-crm:aws/lambda/JOB_RECONCILER.ts:handler'
  - section: What Is Observable
    provenance: observed
    source: >-
      services-crm:modules/entities/services/contacts/role-assignment/automatic-role-reconciliation.ts:sweepAutomaticRoles
  - section: What Is Observable
    provenance: observed
    source: >-
      services-crm:modules/entities/services/persistence/contact-affiliations.ts:giveDueAutomaticRoles
  - section: What Is Observable
    provenance: documented
    source: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-change-events.ts:organizationComplianceRecalculationHandler
  - section: What It Does
    provenance: inferred
    source: >-
      services-crm:aws/lambda/JOB_RECONCILER.ts:handler;
      services-crm:modules/entities/services/contacts/role-assignment/automatic-role-reconciliation.ts:sweepAutomaticRoles;
      services-crm:modules/entities/services/persistence/contact-affiliations.ts:giveDueAutomaticRoles;
      services-crm:modules/entities/services/organizations/compliance/compliance-change-events.ts:organizationComplianceRecalculationHandler
    note: >-
      The explicitly labeled rationale interprets the existing transaction,
      transport and recovery boundaries; it is not a product decision.
  - section: Open Design Questions
    provenance: documented
    source: 'rhythm-v2-docs:specs/crm/entities/FINDINGS.md#Findings'
---

# Give automatic roles on the start day

## What It Does

This flow supplies configured automatic responsibilities when a saved future affiliation becomes due. A coordinator can enter a member’s employment before the start day without assigning current responsibilities too early. Later bounded work settles the saved pending marker and records the resulting person change.

Our reading is that the marker separates a one-time assignment decision from ongoing enforcement. Staff may remove an automatic role after settlement without every later pass restoring it. The schedule attempts eligibility; it does not establish a fixed deadline for all work when locks or backlog delay a contact.

## What Starts It

Each five-minute job-reconciler pass attempts automatic roles for pending affiliations whose start date has arrived.

The system selects eligible work using the workspace calendar and pending or cursor state. Operational lifecycle and deployment conditions described in the hop contract determine whether a scheduled pass reaches it. A scheduled invocation begins an attempt; the observable result comes from the writes it actually commits.

## The Flow

The diagram shows the sequence and service seams. Each synchronous stage waits for its result, while captured-event, queue and scheduled stages can run after the originating request has returned. The hop descriptions below identify the write and failure boundary, so the last arrow must not be mistaken for one atomic transaction across every participant.

```mermaid
sequenceDiagram
  participant J as Five-minute reconciler
  participant W as Automatic-role worker
  participant D as CRM database
  participant Q as Change queue
  J->>W: bounded workspace sweep
  W->>D: lock contact and due affiliations
  W->>D: assign eligible roles and clear pending markers
  D->>Q: capture contact changes
  Q->>D: later compliance recalculation
```

## Hop by Hop

### 1. Job reconciler (crm_job_reconciler)

The five-minute reconciler attempts automatic-role work in its own system context. A step failure is logged and eligibility can be tried on a later interval. The scheduled invocation itself neither changes the contact nor guarantees that an eligible role has been assigned.

### 2. Automatic role sweep

The sweep selects workspace contacts whose affiliations still have pending assignment and whose start day has arrived in that workspace’s calendar. Caught workspace-pass failures allow later passes, but obtaining a workspace execution context can fail outside that catch and stop the sweep.

### 3. Automatic role reconciliation (one transaction per contact)

The contact transaction locks due affiliations and chooses eligible active automatic roles allowed by organization policy. It also serializes first-contact decisions at the organization and persists assigned periods with marker clearing. Inactive or deceased people receive no new automatic responsibility; full restrictions can defer settlement.

### 4. Database change capture and compliance handler

Changed responsibility data enters contact capture and later compliance processing. The contact revision establishes what was assigned under system attribution, while the queue reaction updates the organization’s assessment separately. A failing compliance consumer cannot undo a responsibility already committed to the contact.

## When Something Fails

### Hop 1 — Job reconciler (crm_job_reconciler)

The failure boundary is: Log step failure and retry eligibility on a later pass. The remaining work or data is: Due assignments remain pending without a fixed recovery deadline. Job reconciler logs show step failures. A later attempt can be required; the scheduling or publication boundary does not establish an immediate user-visible completion.

### Hop 2 — Automatic role sweep

The failure boundary is: Caught pass failures are logged and skipped. Obtaining workspace context occurs outside that catch and can abort the sweep. The remaining work or data is: Unvisited or failed workspaces retain pending affiliations. Sweep logs identify completed and failed passes.

### Hop 3 — Automatic role reconciliation (one transaction per contact)

The failure boundary is: Rollback preserves pending assignment when the contact transaction fails. The remaining work or data is: Failed or locked work can remain due. System-attributed contact revisions show successful assignment.

### Hop 4 — Database change capture and compliance handler

The failure boundary is: Retry failed compliance messages through SQS and dead-letter after five receives. The remaining work or data is: Assigned roles can precede updated organization compliance. Consumer logs and dead-letter messages expose reaction failure. This failure is downstream of committed input; operators investigate its own delivery rather than treating the caller’s original save as failed.

## Repeats and Races

Assignment and clearing the pending marker share the contact transaction. A successful repeat sees settled work and does not reinstate a responsibility that staff later removed. An ended pending tie can be decided without assigning a role. This supports one-time settlement rather than permanent automatic repair of user corrections.

The worker locks each contact and due affiliation and coordinates destination first-contact decisions. A sixty-second sweep budget and a maximum of two hundred contacts per workspace bound each attempt. Failed or fully locked work can remain due after its start day; a later ordinary save can settle eligible work first.

## What Is Observable

Job reconciler logs show step failures. Sweep logs identify completed and failed passes. System-attributed contact revisions show successful assignment. Consumer logs and dead-letter messages expose reaction failure.

Contact revisions identify successful system changes. Pass results and logs report actual work and failures; a pending marker or an open date window explains why later work remains. Reading effective dates does not establish that a worker reached the record or that every resulting notice was delivered.

## Open Design Questions

The evidence does not establish a universal recovery deadline for pending assignments or absence of every cross-record deadlock. Existing findings also distinguish save-time and scheduled eligibility. The user-facing result is the committed responsibility period and system revision, rather than an assurance that a schedule ran successfully for every workspace.
