---
id: WF-ACC-BAT-002
title: Close a batch automatically and request its posting
trigger: The scheduler delivers an Open batch automatic-close occurrence.
product_area: accounting
module: batches
revision: 1
status: draft
design_intent: confirmed
origin: >-
  D13 (Andrew, 2026-10-16: a rolled or auto-closed batch is posted
  automatically), recorded at
  services-accounting:docs/migrations/transaction-processing/batches/README.md#D13:
  automatic posting
implementation_evidence: observed
inference: []
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
implements:
  - CAP-ACC-BAT-005
  - CAP-ACC-BAT-013
moves:
  - STATE-ACC-BAT-001
  - STATE-ACC-BAT-003
crosses:
  - SVC-ACC-BAT-batches
idempotency: >-
  The schedule run key identifies the posting request. Redelivery after
  retirement sees a non-Open batch and skips; a pre-commit rollback leaves no
  retirement or job.
concurrency: >-
  Automatic close locks and rechecks the collection. Posting preparation runs in
  a savepoint while that lock is held, before the outer commit.
hops:
  - 'n': 1
    actor_or_service: Accounting schedule consumer
    action: >-
      Deliver the claimed occurrence to automatic-close work in the owning
      workspace.
    anchor: >-
      services-accounting:modules/batches/services/auto-close/batch-auto-close.ts:batchAutoCloseWork
    seam: schedule
    on_failure: >-
      The imported scheduler retries thrown delivery errors; refusal follows its
      failed-run path.
    left_inconsistent: A collection can remain Open until delivery succeeds.
    observer: The scheduling run record
    provenance: observed
    source: >-
      services-accounting:modules/batches/services/auto-close/batch-auto-close.ts:batchAutoCloseWork
  - 'n': 2
    actor_or_service: Batches persistence
    action: >-
      Retire an existing Open collection, or return a skipped outcome when it is
      missing or already retired.
    anchor: >-
      services-accounting:modules/batches/services/persistence/batches.ts:closeBatchOnSchedule
    seam: sync
    on_failure: A mutation refusal aborts the run transaction.
    left_inconsistent: No retirement change commits.
    observer: The scheduling run outcome
    provenance: test
    source: >-
      services-accounting:modules/batches/tests/integration/services/persistence/batches.integration.spec.js#skips
      a run whose batch is no longer open
  - 'n': 3
    actor_or_service: Automatic posting
    action: Check posting admission and create the run-keyed job inside a savepoint.
    anchor: >-
      services-accounting:modules/batches/services/auto-post/automatic-posting.ts:prepareAutomaticPosting
    seam: sync
    on_failure: >-
      A recognized preparation refusal is recorded while retirement commits; an
      unexpected error aborts retirement.
    left_inconsistent: A refused preparation can leave Closed work without a posting job.
    observer: Run outcome and enabled posting attention
    provenance: observed
    source: >-
      services-accounting:modules/batches/services/auto-post/automatic-posting.ts:prepareAutomaticPosting
  - 'n': 4
    actor_or_service: Database
    action: >-
      Commit the retirement, enabled attention and prepared job as one business
      change.
    anchor: >-
      services-accounting:modules/batches/services/auto-close/batch-auto-close.ts:batchAutoCloseWork
    seam: sync
    on_failure: Commit failure prevents all those writes.
    left_inconsistent: No partial retirement or job creation remains.
    observer: The scheduling run record
    provenance: test
    source: >-
      services-accounting:modules/batches/tests/integration/services/persistence/batches.integration.spec.js#posts
      nothing more when the same occurrence runs again: the batch is no longer
      open
  - 'n': 5
    actor_or_service: Automatic posting
    action: >-
      After commit, attempt workflow start and include the job in the run
      outcome.
    anchor: >-
      services-accounting:modules/batches/services/auto-post/automatic-posting.ts:startAutomaticPosting
    seam: state_machine
    on_failure: Start failure is logged; there is no posting reconciler to restart it.
    left_inconsistent: A Pending job can remain beside a Closed collection.
    observer: Platform job monitoring and enabled attention
    provenance: observed
    source: >-
      services-accounting:modules/batches/services/jobs/batch-posting-jobs.ts:startBatchJob
  - 'n': 6
    actor_or_service: Posting job
    action: Execute the prepared job using the ordinary posting task.
    anchor: >-
      services-accounting:modules/batches/services/jobs/batch-posting-job-tasks.ts:postBatchesOperation
    seam: state_machine
    on_failure: >-
      The posting task distinguishes document-generation errors from
      whole-request failure.
    left_inconsistent: Post-commit settlement can disagree with the collection outcome.
    observer: Job phases and the resulting collection state
    provenance: observed
    source: >-
      services-accounting:modules/batches/services/auto-post/automatic-posting.ts
      (header)
branches:
  - Missing or non-Open collections yield a skipped run without a new posting.
  - >-
    Recognized posting preparation refusal yields a completed retirement with
    the refusal in its outcome.
waits:
  - >-
    Delivery follows the configured local minute; the schedule library owns
    dispatch timing.
evidence:
  - >-
    services-accounting at f47cb263:
    modules/batches/services/auto-close/batch-auto-close.ts;
    services/auto-post/automatic-posting.ts; services/persistence/batches.ts;
    services/jobs/batch-posting-jobs.ts;
    docs/migrations/transaction-processing/batches/README.md (D13)
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-006, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-DAT-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-AVL-001, TC-AVL-004, TC-MON-001, TC-MON-002, TC-MON-004, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005]
---

# Close a batch automatically and request its posting

## What It Does

Automatic retirement closes intake and prepares its accounting job in one transaction. The job runs separately after commit, so the retirement outcome and eventual accounting outcome remain distinct.

## The Flow

```mermaid
flowchart LR
  O[Due occurrence] --> C[Recheck and retire]
  C --> J[Prepare job in savepoint]
  J --> D[Commit retirement]
  D --> S[Attempt workflow start]
  S --> P[Ordinary posting]
```

## When Something Fails

Preparation refusal can preserve a Closed collection while reporting why no job was prepared. Unexpected transactional errors roll back retirement. A failed workflow start occurs after commit and can leave a Pending job without recovery.

## Open Design Questions

Start reconciliation is absent. Past-time close input remains accepted, with dispatch behavior at the imported scheduling boundary still needing proof.
