---
id: WF-CRM-ENT-011
title: Feed Quick Search from record changes
trigger: A contact or organization transaction commits a captured change event.
product_area: crm
module: entities
revision: 1
status: draft
design_intent: confirmed
origin: >-
  Andrew, 2026-10-09 (change events and the SQS hop), cited in
  services-crm:docs/change-events.md#Why
implementation_evidence: observed
inference: []
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
  - CAP-CRM-ENT-003
  - CAP-CRM-ENT-013
crosses:
  - SVC-CRM-ENT-entities
idempotency: >-
  Stable event identities accompany event snapshots. Platform returns an outcome
  for each event and owns duplicate or stale-snapshot handling; CRM can
  redeliver after ambiguous acceptance.
concurrency: >-
  Capture sequences describe record order, but the standard queue can deliver
  messages out of order. Search has its own handler messages, so its retries do
  not rerun successful compliance or region handlers.
hops:
  - 'n': 1
    actor_or_service: CRM change-events dispatcher
    action: >-
      Publish every contact and organization event to the search handler without
      a field or operation filter.
    anchor: 'services-crm:aws/crm.change-events.ts:crmChangeEventStreams'
    seam: event
    on_failure: Reclaim events whose required messages were not accepted.
    left_inconsistent: Search can wait behind publication.
    observer: Dispatcher logs report acceptance and backlog.
    provenance: documented
    source: 'services-crm:docs/change-events.md#The handlers CRM registers'
  - 'n': 2
    actor_or_service: Quick Search indexer handler
    action: >-
      Invoke the configured Platform indexer synchronously with stream and
      batches of up to 100 snapshots, then map returned outcomes to events.
    anchor: >-
      services-crm:modules/entities/services/quick-search/quick-search-indexer.ts:quickSearchIndexerOf
    seam: queue
    on_failure: >-
      Treat missing outcomes, failed invocation or missing configuration as
      failed deliveries; retry and dead-letter after five receives.
    left_inconsistent: The source record is committed while search can remain stale.
    observer: >-
      Consumer logs and search-handler dead-letter messages identify failed
      events.
    provenance: observed
    source: >-
      services-crm:modules/entities/services/quick-search/quick-search-indexer.ts:quickSearchIndexerOf
  - 'n': 3
    actor_or_service: Platform Quick Search
    action: >-
      Platform applies indexing outcomes and reports success for unsupported or
      deleting workspaces and absent records under the documented integration
      contract.
    anchor: 'services-crm:docs/change-events.md#The handlers CRM registers'
    seam: sync
    on_failure: Return per-event failure to CRM for retry.
    left_inconsistent: A failed event leaves its search projection unresolved.
    observer: Platform indexer logs and response outcomes provide evidence.
    provenance: documented
    source: 'services-crm:docs/change-events.md#The handlers CRM registers'
branches:
  - >-
    Archived events are still forwarded; Platform owns their default-result
    visibility.
waits: []
evidence:
  - >-
    services-crm at 7ea48a41:
    modules/entities/services/quick-search/quick-search-indexer.ts;
    services/contacts/contact-event-projection.ts; aws/crm.change-events.ts;
    docs/change-events.md (§5, remote handlers).
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: documented
    source: 'services-crm:aws/crm.change-events.ts:crmChangeEventStreams'
  - section: What It Does
    provenance: observed
    source: >-
      services-crm:modules/entities/services/quick-search/quick-search-indexer.ts:quickSearchIndexerOf
  - section: What It Does
    provenance: documented
    source: 'services-crm:docs/change-events.md#The handlers CRM registers'
  - section: What Starts It
    provenance: documented
    source: 'services-crm:aws/crm.change-events.ts:crmChangeEventStreams'
  - section: What Starts It
    provenance: observed
    source: >-
      services-crm:modules/entities/services/quick-search/quick-search-indexer.ts:quickSearchIndexerOf
  - section: What Starts It
    provenance: documented
    source: 'services-crm:docs/change-events.md#The handlers CRM registers'
  - section: The Flow
    provenance: documented
    source: 'services-crm:aws/crm.change-events.ts:crmChangeEventStreams'
  - section: The Flow
    provenance: observed
    source: >-
      services-crm:modules/entities/services/quick-search/quick-search-indexer.ts:quickSearchIndexerOf
  - section: The Flow
    provenance: documented
    source: 'services-crm:docs/change-events.md#The handlers CRM registers'
  - section: Hop by Hop
    provenance: documented
    source: 'services-crm:aws/crm.change-events.ts:crmChangeEventStreams'
  - section: Hop by Hop
    provenance: observed
    source: >-
      services-crm:modules/entities/services/quick-search/quick-search-indexer.ts:quickSearchIndexerOf
  - section: Hop by Hop
    provenance: documented
    source: 'services-crm:docs/change-events.md#The handlers CRM registers'
  - section: When Something Fails
    provenance: documented
    source: 'services-crm:aws/crm.change-events.ts:crmChangeEventStreams'
  - section: When Something Fails
    provenance: observed
    source: >-
      services-crm:modules/entities/services/quick-search/quick-search-indexer.ts:quickSearchIndexerOf
  - section: When Something Fails
    provenance: documented
    source: 'services-crm:docs/change-events.md#The handlers CRM registers'
  - section: Repeats and Races
    provenance: documented
    source: 'services-crm:aws/crm.change-events.ts:crmChangeEventStreams'
  - section: Repeats and Races
    provenance: observed
    source: >-
      services-crm:modules/entities/services/quick-search/quick-search-indexer.ts:quickSearchIndexerOf
  - section: Repeats and Races
    provenance: documented
    source: 'services-crm:docs/change-events.md#The handlers CRM registers'
  - section: What Is Observable
    provenance: documented
    source: 'services-crm:aws/crm.change-events.ts:crmChangeEventStreams'
  - section: What Is Observable
    provenance: observed
    source: >-
      services-crm:modules/entities/services/quick-search/quick-search-indexer.ts:quickSearchIndexerOf
  - section: What Is Observable
    provenance: documented
    source: 'services-crm:docs/change-events.md#The handlers CRM registers'
  - section: What It Does
    provenance: inferred
    source: >-
      services-crm:aws/crm.change-events.ts:crmChangeEventStreams;
      services-crm:modules/entities/services/quick-search/quick-search-indexer.ts:quickSearchIndexerOf;
      services-crm:docs/change-events.md#The handlers CRM registers
    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'
---

# Feed Quick Search from record changes

## What It Does

This workflow hands committed person and organization changes to Platform’s Quick Search projection. A coordinator who saves a corrected name needs discovery to eventually reflect it, and archive or deletion must reach the same indexing boundary. CRM transports captured snapshots; Platform owns what a workspace indexes and how the index applies them.

Our reading is that separate handler messages keep search failure from replaying successful compliance or region work. The source record can be correct while its search result is stale. This contract explains transport and recovery evidence without giving CRM a second home for Platform’s indexing policy.

## What Starts It

A committed contact or organization transaction leaves a captured change for dispatch. The dispatcher publishes a separate search-handler message carrying the snapshot and stable event identity. This input exists after the source save, so an accepted save and a refreshed search result are separate observations. The workflow starts transport to Platform rather than calculating CRM’s own indexing policy.

## 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 D as CRM capture
  participant Q as Handler queue
  participant H as Search adapter
  participant P as Platform indexer
  D->>Q: every contact or organization event
  Q->>H: deliver snapshots
  H->>P: batches of at most 100
  P-->>H: one outcome per event
  H-->>Q: acknowledge success, retry failure
```

## Hop by Hop

### 1. CRM change-events dispatcher

The dispatcher includes every contact and organization operation and field change in the search handler’s feed. It does not infer which snapshots Platform might want to ignore. Required queue acceptance controls event removal, so publication failure leaves work available for later claim or dispatch.

### 2. Quick Search indexer handler

The remote handler makes a synchronous indexer call for batches of at most one hundred snapshots and waits for outcomes associated with event identities. Missing configuration, invocation failure or an omitted event outcome counts as failed delivery. Other successful handler messages remain independent of that retry.

### 3. Platform Quick Search

Platform applies its own projection policy and returns an outcome for each event. Under the cited integration contract, unsupported or deleting workspaces and absent records can succeed without indexing a live subject. A returned per-event failure remains CRM delivery work to retry rather than an instruction to change the source record.

## When Something Fails

### Hop 1 — CRM change-events dispatcher

The failure boundary is: Reclaim events whose required messages were not accepted. The remaining work or data is: Search can wait behind publication. Dispatcher logs report acceptance and backlog. A later attempt can be required; the scheduling or publication boundary does not establish an immediate user-visible completion.

### Hop 2 — Quick Search indexer handler

The failure boundary is: Treat missing outcomes, failed invocation or missing configuration as failed deliveries; retry and dead-letter after five receives. The remaining work or data is: The source record is committed while search can remain stale. Consumer logs and search-handler dead-letter messages identify failed events. This failure is downstream of committed input; operators investigate its own delivery rather than treating the caller’s original save as failed.

### Hop 3 — Platform Quick Search

The failure boundary is: Return per-event failure to CRM for retry. The remaining work or data is: A failed event leaves its search projection unresolved. Platform indexer logs and response outcomes provide evidence.

## Repeats and Races

Stable event identities accompany each snapshot, allowing Platform to apply its duplicate and stale-snapshot policy. After an ambiguous remote acceptance, CRM may deliver again; this workflow does not assume exactly-once invocation. The transport queue can reorder events even though capture records their sequence, so freshness belongs to the indexer’s handling of those snapshots.

Search has its own handler messages. Retry or dead-letter work for search does not rerun successful compliance or region handlers and cannot roll back the record. Archive changes are forwarded without a CRM-side visibility filter; Platform owns the default search treatment.

## What Is Observable

Dispatcher logs report acceptance and backlog. Consumer logs and search-handler dead-letter messages identify failed events. Platform indexer logs and response outcomes provide evidence.

The coordinator continues to read the committed CRM identity while search can lag. Operators correlate event identities, per-event outcomes and handler queue failures. Missing configuration is observable failure rather than a silent skip, and Platform logs provide the next boundary for a message CRM successfully handed off.

## Open Design Questions

The existing findings retain limited proof of out-of-order search delivery and complete projection freshness. CRM’s per-event success means Platform accepted or intentionally ignored the event under its contract, not that a particular person saw the new result. Operational evidence for backlog and failed events is needed when investigating stale discovery.
