---
id: STATE-CRM-ENT-004
title: Compliance reprocess run
object: DOM-CRM-ENT-002
product_area: crm
module: entities
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
states:
  - name: requested
    meaning: A reprocess has been requested but not persisted.
    entry_conditions: >-
      An authorized request has reached start composition but no run is
      persisted yet.
    allowed_actions:
      - Create a run or return the existing running run.
    terminal: false
    reversible: false
    provenance: observed
    source: >-
      services-crm at 7ea48a41:
      modules/entities/db/compliance-reprocesses.table.ts (statuses, completed
      check); services/organizations/compliance/compliance-reprocess.ts;
      services/persistence/compliance-reprocesses.ts; aws/crm.change-events.ts
      (compliance_reprocess stream).
    experience: This is a request stage rather than a durable saved status.
  - name: running
    meaning: >-
      A stored run scans organization identities in ordered batches from its
      committed cursor.
    entry_conditions: A run row has been inserted and remains eligible for worker processing.
    allowed_actions:
      - Resume uncommitted work
      - append continuation
      - record retryable failure.
    terminal: false
    reversible: true
    provenance: observed
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/compliance-reprocesses.integration.spec.js#refuses
      a second running run for the tenant
    experience: >-
      Counts and cursor reflect committed batches rather than work merely
      attempted.
  - name: completed
    meaning: >-
      The scan reached its end and retains examined and recalculated counts plus
      finish time.
    entry_conditions: The locked batch finds no further organization beyond its scan position.
    allowed_actions:
      - Inspect the final run
      - request a separate future run.
    terminal: true
    reversible: false
    provenance: observed
    source: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:complianceReprocessRunnerHandler
    experience: Examined and recalculated totals and finish time remain recorded.
  - name: failed
    meaning: >-
      The final permitted failing delivery marked the run terminal and retained
      a redacted failure reason.
    entry_conditions: A failing final receive records terminal status.
    allowed_actions:
      - Inspect the redacted reason
      - request another run.
    terminal: true
    reversible: false
    provenance: observed
    source: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:recordFailure
    experience: >-
      The workspace may be partially reprocessed; redrive does not reopen this
      run.
transitions:
  - from: requested
    to: running
    trigger: Request compliance reprocessing.
    guard: >-
      Organization update permission; return an existing running run rather than
      creating a second one.
    side_effects:
      - insert the run
      - capture an event that starts its worker
      - nudge event dispatch
    who: An authorized organization updater
    provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/compliance-reprocesses.integration.spec.js#refuses
      a second running run for the tenant
    audit_event: >-
      Run storage records cursor, examined and recalculated counts, continuation
      and completion or redacted failure information. Each organization changed
      during a batch has its own attributed revision; the run is not an
      organization revision.
  - from: running
    to: running
    trigger: Continue after the worker budget or a retryable batch failure.
    guard: The persisted run must still be running.
    side_effects:
      - commit cursor and counts with each batch
      - increase continuation counter for another worker
      - record failure reason and clear it after success
    who: The reprocess worker
    provenance: observed
    source: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:complianceReprocessRunnerHandler
    audit_event: >-
      Run storage records cursor, examined and recalculated counts, continuation
      and completion or redacted failure information. Each organization changed
      during a batch has its own attributed revision; the run is not an
      organization revision.
  - from: running
    to: completed
    trigger: Finish the batch that exhausts the scan.
    guard: No organization remains after the cursor.
    side_effects:
      - store completion status and finish time
    who: The reprocess worker
    provenance: observed
    source: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:complianceReprocessRunnerHandler
    audit_event: >-
      Run storage records cursor, examined and recalculated counts, continuation
      and completion or redacted failure information. Each organization changed
      during a batch has its own attributed revision; the run is not an
      organization revision.
  - from: running
    to: failed
    trigger: Fail on the final permitted message receive.
    guard: The consumer identifies this delivery as its final attempt.
    side_effects:
      - mark run failed with redacted reason
      - throw so queue dead-letter policy applies
    who: The reprocess worker
    provenance: observed
    source: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:recordFailure
    audit_event: >-
      Run storage records cursor, examined and recalculated counts, continuation
      and completion or redacted failure information. Each organization changed
      during a batch has its own attributed revision; the run is not an
      organization revision.
invalid:
  - from: completed
    to: running
    why: Completed runs are skipped; a later request creates a separate run.
    response: >-
      A worker presented with a completed run returns its existing outcome
      without restarting it. A new authorized request creates a separate run.
  - from: failed
    to: running
    why: >-
      Failed runs are also skipped on redrive. Recovery requires requesting
      another run.
    response: >-
      A redriven message naming a failed run is also skipped. The supported
      recovery is another reprocess request, so an operator must not treat
      dead-letter redrive as a resume command.
concurrency: >-
  The database permits one running run per workspace. A worker locks the run and
  its organization batch before committing work and cursor together. Concurrent
  workers serialize, while changes to type rules can affect subsequent batches;
  a run does not pin one policy snapshot.
invariants:
  - INV-DOM-CRM-ENT-002-09
evidence:
  - >-
    services-crm at 7ea48a41:
    modules/entities/db/compliance-reprocesses.table.ts (statuses, completed
    check); services/organizations/compliance/compliance-reprocess.ts;
    services/persistence/compliance-reprocesses.ts; aws/crm.change-events.ts
    (compliance_reprocess stream).
automatic:
  - from: running
    to: running
    when: >-
      Worker delivery advances a committed batch or records continuation when
      its budget ends.
    provenance: observed
    source: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:complianceReprocessRunnerHandler
  - from: running
    to: completed
    when: The scan is exhausted.
    provenance: observed
    source: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:complianceReprocessRunnerHandler
  - from: running
    to: failed
    when: The final permitted delivery fails and records terminal failure.
    provenance: observed
    source: >-
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:recordFailure
ai_may_recommend: false
ai_may_execute: false
permissions_by_state:
  - state: requested
    action: update
    permission: crm.organizations.update
  - state: running
    action: update
    permission: crm.organizations.update
narrative:
  status: verified
  review: NARRATIVE-REVIEW-2026-10-23
narrative_sources:
  - section: Purpose
    provenance: observed
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/compliance-reprocesses.integration.spec.js#refuses
      a second running run for the tenant;
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:complianceReprocessRunnerHandler;
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:recordFailure
  - section: Ownership and Authority
    provenance: observed
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/compliance-reprocesses.integration.spec.js#refuses
      a second running run for the tenant;
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:complianceReprocessRunnerHandler;
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:recordFailure
  - section: The Lifecycle
    provenance: observed
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/compliance-reprocesses.integration.spec.js#refuses
      a second running run for the tenant;
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:complianceReprocessRunnerHandler;
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:recordFailure
  - section: States
    provenance: observed
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/compliance-reprocesses.integration.spec.js#refuses
      a second running run for the tenant;
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:complianceReprocessRunnerHandler;
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:recordFailure
  - section: Transitions Explained
    provenance: observed
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/compliance-reprocesses.integration.spec.js#refuses
      a second running run for the tenant;
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:complianceReprocessRunnerHandler;
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:recordFailure
  - section: What Cannot Happen
    provenance: observed
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/compliance-reprocesses.integration.spec.js#refuses
      a second running run for the tenant;
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:complianceReprocessRunnerHandler;
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:recordFailure
  - section: Concurrency and Timing
    provenance: observed
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/compliance-reprocesses.integration.spec.js#refuses
      a second running run for the tenant;
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:complianceReprocessRunnerHandler;
      services-crm:modules/entities/services/organizations/compliance/compliance-reprocess.ts:recordFailure
  - section: Permissions by State
    provenance: documented
    source: 'rhythm-v2-docs:specs/crm/AUTHORIZATION.md#Role Entitlement Matrix'
  - section: Purpose
    provenance: inferred
    source: >-
      services-crm at 7ea48a41:
      modules/entities/db/compliance-reprocesses.table.ts (statuses, completed
      check); services/organizations/compliance/compliance-reprocess.ts;
      services/persistence/compliance-reprocesses.ts; aws/crm.change-events.ts
      (compliance_reprocess stream).
    note: >-
      The explicitly labeled rationale interprets the separation of state
      dimensions and the existing trigger and guard rows.
  - section: Invariants
    provenance: inferred
    source: INV-DOM-CRM-ENT-002-09
    note: >-
      Protection explanations interpret the unchanged domain-object invariants;
      no lifecycle policy is added.
  - section: Invariants
    provenance: inferred
    source: "services-crm:modules/entities/services/persistence/contacts.ts; services-crm:modules/entities/services/persistence/organizations.ts; services-crm:modules/entities/services/organizations/compliance/organization-compliance.ts; services-crm:modules/entities/services/persistence/record-locks.ts"
    note: "The rationale interprets this artifact’s sourced invariants and linked capability rules; it does not claim a recorded product decision."
---

# Compliance reprocess run

## Purpose

A compliance reprocess revisits existing organizations after policy administration or a request to refresh assessments. The request cannot realistically hold one response open for every organization in a large association. A durable run instead retains its scan position, counts and outcome while bounded workers process the remaining organizations.

Our reading is that the explicit run states make partial progress distinguishable from success. A completed run records that its scan finished; a failed run can leave earlier organizations recalculated and later ones untouched. Neither state establishes delivery of notices created during the scan.

## Ownership and Authority

An actor holding organization update authority starts reprocessing. The route returns a message and organization count after recording the request or finding an existing running run. Workers own cursor advancement, continuation and final outcome; there is no staff action that directly sets completed to make an unfinished scan disappear.

The queue identifies a final receive, and the worker uses that signal when recording terminal failure. No model recommends or executes these transitions. Request permission does not grant access to unrestricted processing controls or turn a run into a fixed policy snapshot.

## The Lifecycle


```mermaid
stateDiagram-v2
  requested --> running: persist scan
  running --> running: commit batch or request continuation
  running --> completed: reach scan end
  running --> failed: final failing receive
  completed --> [*]
  failed --> [*]
```

## States

### requested

A reprocess has been requested but not persisted. Entry requires this condition: An authorized request has reached start composition but no run is persisted yet. Available behavior is Create a run or return the existing running run.. This is a request stage rather than a durable saved status.

### running

A stored run scans organization identities in ordered batches from its committed cursor. Entry requires this condition: A run row has been inserted and remains eligible for worker processing. Available behavior is Resume uncommitted work; append continuation; record retryable failure.. Counts and cursor reflect committed batches rather than work merely attempted.

### completed

The scan reached its end and retains examined and recalculated counts plus finish time. Entry requires this condition: The locked batch finds no further organization beyond its scan position. Available behavior is Inspect the final run; request a separate future run.. Examined and recalculated totals and finish time remain recorded. This row’s lifecycle ends here; a new request or new record is separate work.

### failed

The final permitted failing delivery marked the run terminal and retained a redacted failure reason. Entry requires this condition: A failing final receive records terminal status. Available behavior is Inspect the redacted reason; request another run.. The workspace may be partially reprocessed; redrive does not reopen this run. This row’s lifecycle ends here; a new request or new record is separate work.

## Transitions Explained

### requested → running

An authorized organization updater starts this change when the following occurs: Request compliance reprocessing. The transition checks this boundary: Organization update permission; return an existing running run rather than creating a second one. The accompanying work is insert the run; capture an event that starts its worker; nudge event dispatch. Run storage records cursor, examined and recalculated counts, continuation and completion or redacted failure information. Each organization changed during a batch has its own attributed revision; the run is not an organization revision.

### running → running

The reprocess worker starts this change when the following occurs: Continue after the worker budget or a retryable batch failure. The transition checks this boundary: The persisted run must still be running. The accompanying work is commit cursor and counts with each batch; increase continuation counter for another worker; record failure reason and clear it after success. Run storage records cursor, examined and recalculated counts, continuation and completion or redacted failure information. Each organization changed during a batch has its own attributed revision; the run is not an organization revision.

### running → completed

The reprocess worker starts this change when the following occurs: Finish the batch that exhausts the scan. The transition checks this boundary: No organization remains after the cursor. The accompanying work is store completion status and finish time. Run storage records cursor, examined and recalculated counts, continuation and completion or redacted failure information. Each organization changed during a batch has its own attributed revision; the run is not an organization revision.

### running → failed

The reprocess worker starts this change when the following occurs: Fail on the final permitted message receive. The transition checks this boundary: The consumer identifies this delivery as its final attempt. The accompanying work is mark run failed with redacted reason; throw so queue dead-letter policy applies. Run storage records cursor, examined and recalculated counts, continuation and completion or redacted failure information. Each organization changed during a batch has its own attributed revision; the run is not an organization revision.

## What Cannot Happen

A worker presented with a completed run returns its existing outcome without restarting it. A new authorized request creates a separate run.

A redriven message naming a failed run is also skipped. The supported recovery is another reprocess request, so an operator must not treat dead-letter redrive as a resume command.

## Permissions by State

The state rows reference grants from the CRM authorization model. Read access is distinct from mutation, and history requires the corresponding history and read checks. Administrator and Power User hold administrative record actions; ordinary Standard User grants include applicable read and update operations, while Read Only grants do not authorize edits.

Organization update is the permission for requesting a reprocess. Workers use their internal execution context rather than requiring the requesting user to remain online. Completed and failed runs cannot be restarted by changing the permission.

## Concurrency and Timing

The database admits only one running run for a workspace. Each batch locks that run and the selected organizations and commits recalculation with cursor and counts. Duplicate workers serialize instead of independently replaying completed batches. A request racing another start can receive the already-running run.

The consumer normally takes twenty-five organizations per batch within forty seconds. If time remains, it continues; otherwise a continuation change asks for another delivery. Earlier batches survive a later failure. Policy edits can affect later batches because the run does not pin a workspace-wide version of type configuration.

## Invariants

Our reading is that one running scan and one locked cursor prevent two workers from claiming incompatible progress for the same request. A committed batch includes its organizations and progress together; attempted work cannot advance the cursor while leaving those assessments unchanged. Earlier batches remain after a later failure, which is why failed describes a partial outcome rather than a rollback. Terminal runs stay terminal under duplicate delivery. Recovery creates another request instead of silently reopening the old run.
