---
id: WF-ACC-REC-004
title: Finalize a reconciliation and request its ledger entries
trigger: >-
  An authorized independent approver submits finalization of a balanced
  explanation.
product_area: accounting
module: reconciliation
revision: 3
status: draft
design_intent: confirmed
origin: >-
  ACCT-M8 plan D3 (second person by default, audited waiver) and D7 (posting
  generator at finalize), approved by Andrew 2026-10-22; services-accounting
  docs/reconciliation/architecture.md §9.3 Finalize, §16.2 (agreed with the
  batch posting owner 2026-10-17) and §24a
implementation_evidence: observed
inference: []
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
  - CAP-ACC-REC-011
  - CAP-ACC-REC-014
  - CAP-ACC-REC-020
moves:
  - STATE-ACC-REC-003
  - STATE-ACC-REC-001
  - STATE-ACC-REC-004
  - STATE-ACC-REC-005
crosses:
  - SVC-ACC-REC-reconciliation
idempotency: >-
  Retained caller-scoped answers replay identical finalize requests. A fresh key
  on an approved record fails; unique accounting effect keys protect request
  creation.
concurrency: >-
  The lifecycle locks its explanation, linked payouts and claimed items, then
  relevant periods and the selected operational batch. Posting-period locks
  coordinate finalization with close.
hops:
  - 'n': 1
    actor_or_service: Lifecycle command
    action: >-
      Replay any retained answer, then lock and check the explanation’s open
      state and version.
    anchor: >-
      services-accounting:modules/reconciliation/services/batch-lifecycle/finalize-batch.ts:finalizeReconciliationBatch
    seam: sync
    on_failure: Audited rule refusal commits an attempt event before returning the error.
    left_inconsistent: Only refusal evidence persists.
    observer: The history read and response code expose the refusal.
    provenance: observed
    source: >-
      services-accounting:modules/reconciliation/services/batch-lifecycle/batch-commands.ts:auditedCommand
  - 'n': 2
    actor_or_service: Segregation rule
    action: >-
      Read qualifying preparers and the independence setting; reject
      self-approval or retain a waiver mark.
    anchor: >-
      services-accounting:modules/reconciliation/services/rules/segregation.ts:segregationDecision
    seam: sync
    on_failure: A disqualified approver receives an audited refusal.
    left_inconsistent: Approval and accounting remain unchanged.
    observer: The service withholds finalize with a preparation reason.
    provenance: observed
    source: >-
      services-accounting:modules/reconciliation/services/rules/segregation.ts:segregationDecision
  - 'n': 3
    actor_or_service: Lifecycle command
    action: >-
      Lock holdings and recompute exact balance; reject missing, voided,
      resolved or undocumented inputs.
    anchor: >-
      services-accounting:modules/reconciliation/services/batch-lifecycle/finalize-batch.ts:finalizeReconciliationBatch
    seam: sync
    on_failure: An audited validation refusal leaves the open draft intact.
    left_inconsistent: No approval or accounting request commits.
    observer: The error and retained attempt identify the guard.
    provenance: observed
    source: >-
      services-accounting:modules/reconciliation/services/batch-lifecycle/finalize-batch.ts:finalizeReconciliationBatch
  - 'n': 4
    actor_or_service: Lifecycle command with Books
    action: >-
      Resolve bank, clearing and purpose accounts and share-lock the document
      period.
    anchor: >-
      services-accounting:modules/reconciliation/services/close-readiness/assess-period.ts:assertPeriodWritable
    seam: sync
    on_failure: Missing configuration or period fails within the audited guard section.
    left_inconsistent: Only the refusal event can commit.
    observer: The response names the required setup.
    provenance: observed
    source: >-
      services-accounting:modules/reconciliation/services/persistence/reconciliation-batch-lifecycles.ts:postingAccountsOf
  - 'n': 5
    actor_or_service: Ledger request writer with Transactions' default-batch rule
    action: >-
      Choose an accepting operational batch and create transfer and required
      recognition requests on its date.
    anchor: >-
      services-accounting:modules/reconciliation/services/persistence/reconciliation-ledger-postings.ts:recordPostings
    seam: sync
    on_failure: >-
      A missing open batch or unsupported exponent rolls back without an audited
      attempt.
    left_inconsistent: The explanation remains open and no request persists.
    observer: Only the error response exposes this attempt.
    provenance: observed
    source: >-
      services-accounting:modules/reconciliation/services/persistence/reconciliation-ledger-postings.ts:recordPostings
  - 'n': 6
    actor_or_service: Lifecycle command
    action: >-
      Retain approval, recomputed counters, waiver activity, cleared payout
      concerns and the keyed answer.
    anchor: >-
      services-accounting:modules/reconciliation/services/persistence/reconciliation-batch-lifecycles.ts:recordFinalization
    seam: sync
    on_failure: Any write failure aborts all business effects.
    left_inconsistent: Approval and requests cannot commit separately.
    observer: History and the returned explanation show the completed approval.
    provenance: observed
    source: >-
      services-accounting:modules/reconciliation/services/persistence/reconciliation-batch-lifecycles.ts:resolveUnbalancedPayoutExceptions
  - 'n': 7
    actor_or_service: Batch Management
    action: >-
      Batch Management later consumes the operational batch’s requests and
      generates ledger entries.
    anchor: 'services-accounting:modules/batches/services/engine/posting-documents.ts'
    seam: sync
    on_failure: Posting errors belong to the batch job; requests remain pending.
    left_inconsistent: Approval can be complete while accounting is absent from the ledger.
    observer: Readiness reports pending posting; batch work reports its error.
    provenance: observed
    source: >-
      services-accounting:modules/reconciliation/services/persistence/reconciliation-ledger-postings.ts:listPendingPostings
branches:
  - An empty plan bypasses operational-batch and exponent checks.
  - >-
    Disabling independence permits preparer approval and marks every approval
    waived.
waits:
  - Ledger completion waits for operational batch posting.
evidence:
  - >-
    services-accounting at f47cb263:
    modules/reconciliation/services/batch-lifecycle/finalize-batch.ts,
    batch-commands.ts; services/persistence/reconciliation-batch-lifecycles.ts,
    reconciliation-ledger-postings.ts, idempotency-keys.ts,
    fiscal-period-locks.ts; services/rules/segregation.ts, posting-plans.ts;
    tests/integration/services/batch-lifecycle/finalize-batch.integration.spec.js,
    finalize-concurrency.integration.spec.js,
    finalize-posts-to-subledger.integration.spec.js.
  - >-
    react-console at baf6dae3: lib/accounting/reconciliation/store.tsx
    (finalizeRecon).
controls: [TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-IAM-006, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-AZ-006, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-DAT-001, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-005, TC-AI-005]
---
# Finalize a reconciliation and request its ledger entries

## What It Does

Finalization approves the explanation and records the transfer and recognition requests atomically. Batch Management later converts those requests into ledger entries.

## The Flow

```mermaid
sequenceDiagram
  participant A as Approver
  participant L as Finalize command
  participant B as Books and Transactions rules
  participant D as Accounting database
  participant P as Batch Management
  A->>L: finalize (key, version)
  L->>D: replay check, lock reconciliation
  L->>L: segregation, recompute difference
  alt refused by a rule
    L->>D: commit only the refusal event
    L-->>A: refusal code
  else allowed
    L->>B: accounts, period share lock, operational batch
    L->>D: requests, finalized state, events, cleared blockers, stored answer
    D-->>A: finalized reconciliation
    P->>D: later, post the batch and its requests
  end
```

## When Something Fails

Guard refusals retain audit evidence, but errors during request writing can roll back without it. Pending requests leave approval intact and continue to block the relevant close until operational posting completes.

## Open Design Questions

Operational batch dating differs from automatic forward-date selection. Contributor independence and missing refusal history remain open.
