---
id: ADR-ACC-REC-004
title: 'Money Has One Active Holder, Decided by the Database'
product_area: accounting
module: reconciliation
revision: 3
status: proposed
design_intent: confirmed
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
decision: >-
  Use database uniqueness for exclusive active holdings, with row locks and
  versions on participating financial commands.
constrains:
  - DOM-ACC-REC-001
  - DOM-ACC-REC-002
  - DOM-ACC-REC-003
  - STATE-ACC-REC-003
  - WF-ACC-REC-003
  - WF-ACC-REC-004
origin: >-
  ACCT-M8 plan §4 assumptions (a partial unique index forbids two batches
  claiming one item) and D10, approved by Andrew 2026-10-22; architecture §9.3
  and §18.5
alternatives:
  - option: Check availability only in application logic.
    why_not: Two competing requests can both pass an unlocked check.
  - option: Require serializable isolation for all preparation.
    why_not: >-
      The current implementation has no general serialization-retry protocol and
      already uses explicit locks and constraints.
consequences:
  - >-
    Conflict responses identify the existing holder where the service maps that
    race.
  - Released holding rows remain outside the active unique index as history.
  - >-
    Ancillary unversioned commands retain narrower protections than financial
    versioned commands.
supersedes: []
evidence:
  - >-
    services-accounting at f47cb263:
    modules/reconciliation/db/reconciliation-batch-links.table.ts;
    services/persistence/reconciliation-allocations.ts;
    tests/integration/services/reconciliation-batches/claim-concurrency.integration.spec.js.
---
# Money Has One Active Holder, Decided by the Database

## Context

Competing preparation must not count the same effect or payout twice.

## Decision

Use database uniqueness for exclusive active holdings, with row locks and versions on participating financial commands.

## Alternatives Considered

Check availability only in application logic. Two competing requests can both pass an unlocked check.

Require serializable isolation for all preparation. The current implementation has no general serialization-retry protocol and already uses explicit locks and constraints.

## Consequences

Conflict responses identify the existing holder where the service maps that race. Released holding rows remain outside the active unique index as history. Ancillary unversioned commands retain narrower protections than financial versioned commands.
