---
id: WF-PFM-MTD-014
title: Capture a custom record's change history at commit
trigger: Database capture attributes business changes at commit, including changes made through cross-service functions.
product_area: platform
module: metadata
revision: 1
status: draft
design_intent: confirmed
origin: Record change history plan approved 2026-10-11, adopted for custom records and links by CO-H1 under the
  custom objects architecture approved 2026-10-18 (services-platform:docs/record-history.md); PLAT-M5 Product Accepted
  2026-10-20
implementation_evidence: observed
inference: []
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
- CAP-PFM-MTD-014
crosses:
- SVC-PFM-MTD-custom-objects
- SVC-PFM-MTD-associations
idempotency: Capture settles once with the transaction and excludes unchanged business values. Opposite-direction
  custom-record links can deadlock under history locks and require the refused caller to retry.
concurrency: Capture settles once with the transaction and excludes unchanged business values. Opposite-direction
  custom-record links can deadlock under history locks and require the refused caller to retry.
hops:
- n: 1
  actor_or_service: Database capture triggers (custom record stream)
  action: Record-stream triggers collect changes to record fields, properties and links into the transaction’s record
    event.
  anchor: services-platform:modules/custom-objects/db/custom-object-record-change-events.table.ts
  seam: sync
  on_failure: A capture statement failure aborts the write.
  left_inconsistent: No uncaptured change is independently committed.
  observer: The initiating person or service and its operation logs.
  provenance: documented
  source: services-platform:docs/record-history.md#The two streams
- n: 2
  actor_or_service: Database settle trigger (deferred to commit)
  action: Deferred settlement creates the record revision with attribution and before-and-after values, rejecting
    missing actor or source.
  anchor: services-platform:modules/custom-objects/db/record-revisions.table.ts
  seam: sync
  on_failure: Fail commit and roll back the complete mutation.
  left_inconsistent: The record and revision remain atomic.
  observer: The initiating person or service and its operation logs.
  provenance: test
  source: services-platform:modules/custom-objects/tests/integration/services/history/custom-object-record-history.integration.spec.js#answers
    the association, the update
- n: 3
  actor_or_service: Database association stream (deferred, after the settle)
  action: The association stream writes native first-side connection revisions into Platform’s revision store with
    directional labels and opposite-record names.
  anchor: services-platform:modules/associations/db/association-change-events.table.ts
  seam: sync
  on_failure: Fail the changing transaction if deferred capture cannot settle.
  left_inconsistent: The connection change cannot commit without its revision.
  observer: The initiating person or service and its operation logs.
  provenance: documented
  source: services-platform:docs/record-history.md#The two streams
- n: 4
  actor_or_service: Database discard trigger (last at commit)
  action: The final deferred cleanup removes settled capture events because Platform publishes no capture-event
    stream.
  anchor: services-platform:docs/record-history.md#What Platform added
  seam: sync
  on_failure: Reject commit if this trigger fails.
  left_inconsistent: Mutation and revision roll back together.
  observer: The initiating person or service and its operation logs.
  provenance: documented
  source: services-platform:docs/record-history.md#What Platform added
- n: 5
  actor_or_service: Records API history routes
  action: Authorized history reads return timeline, revision or actors under object reach, history permission and
    current property/audience projection.
  anchor: services-platform:modules/custom-objects/aws/api/custom-object-record-history.routes.ts:customObjectRecordHistoryRoutes
  seam: sync
  on_failure: Return not found when object or required record reach is unavailable.
  left_inconsistent: History storage is unchanged by a refused read.
  observer: The initiating person or service and its operation logs.
  provenance: test
  source: services-platform:modules/custom-objects/tests/integration/services/history/custom-object-record-history.integration.spec.js#refuses
    a caller who may read boats
branches:
- Reset and purge suppress history capture for their own removal work.
waits: []
evidence:
- 'services-platform at ad3f6a65: docs/record-history.md; modules/custom-objects/db/record-revisions.table.ts, custom-object-record-change-events.table.ts;
  modules/associations/db/association-change-events.table.ts; modules/custom-objects/services/persistence/record-revisions.ts;
  history/custom-object-record-history.config.ts; aws/api/custom-object-record-history.routes.ts'
controls: [TC-AVL-004, TC-AVL-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-MON-001, 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, TC-TEN-004, TC-VEN-001, TC-VEN-002, TC-VEN-003]
---

# Capture a custom record's change history at commit

## What It Does

Database capture attributes business changes at commit, including changes made through cross-service functions. History presentation later applies current definition and readership filtering.

## The Flow

```mermaid
sequenceDiagram
  participant Writer as Any writer (API, job, CRM merge or deletion)
  participant Cap as Capture triggers
  participant Settle as Settle at commit
  participant Rev as Revisions (append-only)
  Writer->>Cap: write record, values, links
  Cap->>Cap: fold into one change event per record
  Writer->>Settle: commit
  Settle->>Settle: refuse if no source or actor
  Settle->>Rev: revision per record; native first-side link revisions
  Settle->>Settle: discard settled events
  Settle-->>Writer: committed
```

## When Something Fails

Fail commit and roll back the complete mutation. The record and revision remain atomic. Fail the changing transaction if deferred capture cannot settle. The connection change cannot commit without its revision. Reject commit if this trigger fails. Mutation and revision roll back together. Return not found when object or required record reach is unavailable. History storage is unchanged by a refused read.

## Open Design Questions

Native-record timeline presentation needs an agreement with CRM.
