---
id: CAP-ACC-BAT-013
title: Run and monitor a batch posting job
feature: FEAT-ACC-BAT-03
product_area: accounting
module: batches
revision: 1
status: draft
product_intent: proposed
implementation_evidence: observed
supersedes:
- inventory CAP-ACC-BAT-008
- inventory CAP-ACC-BAT-019
- inventory RUL-ACC-BAT-017
- inventory RUL-ACC-BAT-018
- inventory RUL-ACC-BAT-019
- inventory RUL-ACC-BAT-020
- inventory RUL-ACC-BAT-021
- inventory RUL-ACC-BAT-022
- inventory RUL-ACC-BAT-025
- inventory RUL-ACC-BAT-061
- inventory RUL-ACC-BAT-065
- journey ACT-ACC-0518
- journey ACT-ACC-0519
- journey ACT-ACC-0537
- journey ACT-ACC-0543
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
- services-accounting:docs/architecture/accounting-2.0/02-decisions.md#D-03
- services-accounting:docs/architecture/accounting-2.0/02-decisions.md#A-1
- 'services-accounting:docs/migrations/batch-posting/README.md#Merge readiness (Andrew''s D7 of 2026-10-15: a refused
  posting fails)'
purpose: Staff submit batches together and follow a durable job through posting or refusal.
outcomes:
- Submitted accounting work has a durable job and an identifiable completion or failure result.
concepts:
- CON-ACC-BAT-003
- CON-ACC-BAT-001
actors:
- ACT-ACC-012
- ACT-ACC-014
surfaces:
- console
- api
- job
permissions:
- key: accounting.batch-postings.post
  where_checked: api
  scope: tenant
rules:
- id: BR-CAP-ACC-BAT-013-01
  proved_by: [ATS-ACC-BAT-013-01, TST-ACC-BAT-008, TST-ACC-BAT-057, TST-ACC-BAT-076]
  statement: The posting permission governs submission and is included in the staff user tier.
  kind: permission
  enforced_at:
  - api
  - console
  must_prove: true
  provenance: test
  source: services-accounting:modules/batches/tests/e2e/batch-postings.e2e.spec.js#refuses a posting without the
    posting permission, 403
  origin: none
- id: BR-CAP-ACC-BAT-013-02
  proved_by: [ATS-ACC-BAT-013-01, ATS-ACC-BAT-013-26, TST-ACC-BAT-008, TST-ACC-BAT-057, TST-ACC-BAT-076]
  statement: Submission requires one to one hundred existing batches and a unit, rejects missing references before
    creating a job and defers mismatched-unit refusal to execution.
  kind: validation
  enforced_at:
  - api
  - service
  must_prove: true
  provenance: observed
  source: services-accounting:modules/batches/services/jobs/batch-posting-jobs.ts:createBatchJob; services-accounting:modules/batches/services/rules/batch-posting-rules.ts:ensureBatchesCanBePosted
  origin: none
- id: BR-CAP-ACC-BAT-013-03
  proved_by: [ATS-ACC-BAT-004-12, ATS-ACC-BAT-005-10, ATS-ACC-BAT-006-09, ATS-ACC-BAT-007-10, ATS-ACC-BAT-008-09, ATS-ACC-BAT-009-16, ATS-ACC-BAT-013-02, ATS-ACC-BAT-013-15, ATS-ACC-BAT-013-16, ATS-ACC-BAT-013-17, ATS-ACC-BAT-013-18, ATS-ACC-BAT-013-19, ATS-ACC-BAT-013-20, ATS-ACC-BAT-013-25, ATS-ACC-BAT-019-12, TST-ACC-BAT-007, TST-ACC-BAT-057, TST-ACC-BAT-075, TST-ACC-BAT-077]
  statement: Issuance creates no posting entry; submission returns a tracked job that generates entries during batch
    posting.
  kind: lifecycle
  enforced_at:
  - service
  must_prove: true
  provenance: test
  source: 'services-accounting:modules/batches/tests/e2e/batch-postings.e2e.spec.js#posts a batch as a durable job:
    the answer is the job, and the job posts the batch'
  origin: services-accounting:docs/architecture/accounting-2.0/02-decisions.md#D-03
- id: BR-CAP-ACC-BAT-013-04
  proved_by: [ATS-ACC-BAT-013-03, ATS-ACC-BAT-013-24, ATS-ACC-BAT-016-11, TST-ACC-BAT-076, TST-ACC-BAT-078, TST-ACC-BAT-125]
  statement: Repeating a request identity or requesting the same in-flight batch set returns the existing job, and
    a set still posted by a completed job returns that job, while post, unpost and repost form separate jobs.
  kind: invariant
  enforced_at:
  - service
  - database
  must_prove: true
  provenance: test
  source: services-accounting:modules/batches/tests/integration/services/jobs/submission-identity.integration.spec.js#answers
    a colleague's retry under another key, after the posting finished, with the job that posted (DEF-ACT-0514)
  origin: none
- id: BR-CAP-ACC-BAT-013-05
  proved_by: [ATS-ACC-BAT-013-04]
  statement: The named Post action admits Open, Closed and Error; the engine additionally admits Verified and posting
    work unchanged for over five minutes, clears old errors and supports an environment override of its status check.
  kind: lifecycle
  enforced_at:
  - service
  must_prove: true
  provenance: observed
  source: services-accounting:modules/batches/services/rules/batch-rules.ts:assertBatchCanBePosted; services-accounting:modules/batches/services/rules/batch-posting-rules.ts:ensureBatchesCanBePosted
  origin: none
- id: BR-CAP-ACC-BAT-013-06
  proved_by: [ATS-ACC-BAT-012-04, ATS-ACC-BAT-013-05, ATS-ACC-BAT-013-21, TST-ACC-BAT-010, TST-ACC-BAT-070]
  statement: The named Post action checks an Open period before submission, bulk submission defers that check to
    execution, and execution holds the period shared until the posting transaction ends.
  kind: validation
  enforced_at:
  - service
  - database
  must_prove: true
  provenance: observed
  source: services-accounting:modules/batches/services/actions/batch-actions.ts:postBatch; services-accounting:modules/batches/services/engine/engine-scope.ts:lockBatchesForPosting
  origin: none
- id: BR-CAP-ACC-BAT-013-07
  proved_by: [ATS-ACC-BAT-013-06, TST-ACC-BAT-063, TST-ACC-BAT-076]
  statement: An update lock prevents both the named Post action and job execution until released.
  kind: policy
  enforced_at:
  - service
  must_prove: true
  provenance: test
  source: 'services-accounting:modules/batches/tests/integration/services/jobs/batch-posting-record.integration.spec.js#is
    not posted by a job: the check step fails with the lock, and the batch stays open (DEF-ACT-0503)'
  origin: none
- id: BR-CAP-ACC-BAT-013-08
  proved_by: [ATS-ACC-BAT-013-06, TST-ACC-BAT-063, TST-ACC-BAT-076]
  statement: An ordinary posting job containing a system batch fails its check without posting anything.
  kind: policy
  enforced_at:
  - service
  must_prove: true
  provenance: test
  source: services-accounting:modules/batches/tests/e2e/system-batches.e2e.spec.js#answers a posting naming the
    system batch with its job, and the job fails with the refusal
  origin: none
- id: BR-CAP-ACC-BAT-013-09
  proved_by: [ATS-ACC-BAT-013-07, TST-ACC-BAT-077]
  statement: A refused database write rolls back the complete posting transaction, fails the job and preserves the
    previous batch states without compensation.
  kind: invariant
  enforced_at:
  - service
  - database
  must_prove: true
  provenance: test
  source: 'services-accounting:modules/batches/tests/integration/services/jobs/deployed-task-handler.integration.spec.js#fails
    the job on a step the database refuses: refused once, recorded by the failure task, the batch open and nothing
    written'
  origin: 'services-accounting:docs/migrations/batch-posting/README.md#Merge readiness (Andrew''s D7 of 2026-10-15:
    a refused posting fails)'
- id: BR-CAP-ACC-BAT-013-10
  proved_by: [ATS-ACC-BAT-013-08, ATS-ACC-BAT-013-22, ATS-ACC-BAT-013-23, ATS-ACC-BAT-014-09, ATS-ACC-BAT-015-11, TST-ACC-BAT-011, TST-ACC-BAT-107]
  statement: Document-generation failures put their batch and affected downstream batches in Error without their
    entries, while independently valid batches in the request can still post.
  kind: lifecycle
  enforced_at:
  - service
  must_prove: true
  provenance: test
  source: services-accounting:modules/batches/tests/integration/services/posting/rebuilt-posting-edges.integration.spec.js#posts
    January, puts April in error naming the application whose credit's batch is not posted, and May in error as
    April's dependent
  origin: none
- id: BR-CAP-ACC-BAT-013-11
  proved_by: [ATS-ACC-BAT-002-08, ATS-ACC-BAT-013-09, ATS-ACC-BAT-013-14, TST-ACC-BAT-076, TST-ACC-BAT-105, TST-ACC-BAT-135]
  statement: Successful posting records time, job and counts and base totals by document kind, including the money-document
    count and payments less refunds and payment reversals.
  kind: calculation
  enforced_at:
  - service
  must_prove: true
  provenance: test
  source: 'services-accounting:modules/batches/tests/integration/services/posting/rebuilt-documents.integration.spec.js#records
    the batch''s statistics: the documents counted by kind and their base totals'
  origin: none
- id: BR-CAP-ACC-BAT-013-12
  proved_by: [ATS-ACC-BAT-013-10, TST-ACC-BAT-008, TST-ACC-BAT-107, TST-ACC-BAT-114]
  statement: Posting deletes a batch with no documents regardless of the empty-batch option, whereas a batch containing
    only a voided payment posts without an entry.
  kind: lifecycle
  enforced_at:
  - service
  must_prove: true
  provenance: test
  source: services-accounting:modules/batches/tests/integration/services/posting/rebuilt-posting-edges.integration.spec.js#posts
    February with its one entry, and June is gone (RS-1116)
  origin: none
- id: BR-CAP-ACC-BAT-013-13
  proved_by: [ATS-ACC-BAT-013-11, TST-ACC-BAT-096]
  statement: Only one current posting can exist, so a competing direct posting waits and then rejects the batch
    already posted without another write.
  kind: invariant
  enforced_at:
  - service
  - database
  must_prove: true
  provenance: test
  source: services-accounting:modules/batches/tests/integration/services/posting/concurrent-posting.integration.spec.js#makes
    a direct posting wait for the batch, then refuse it as posted, with no posting and no entry written
  origin: services-accounting:docs/architecture/accounting-2.0/02-decisions.md#A-1
- id: BR-CAP-ACC-BAT-013-14
  proved_by: [ATS-ACC-BAT-013-02, TST-ACC-BAT-007, TST-ACC-BAT-057, TST-ACC-BAT-075, TST-ACC-BAT-077]
  statement: Progress presents checking and writing steps with checked, generated and written events and a completion
    description.
  kind: policy
  enforced_at:
  - service
  - console
  must_prove: false
  provenance: test
  source: 'services-accounting:modules/batches/tests/integration/services/jobs/batch-posting-job.integration.spec.js#records
    the posting''s progress on its history: the batch checked, its entries generated and written, one event each,
    climbing to 99 before the write step completed'
  origin: none
- id: BR-CAP-ACC-BAT-013-15
  proved_by: [ATS-ACC-BAT-013-12, TST-ACC-BAT-024, TST-ACC-BAT-076]
  statement: Description text cannot activate legacy test directives or alter posting behavior.
  kind: policy
  enforced_at:
  - service
  must_prove: true
  provenance: test
  source: services-accounting:modules/batches/tests/integration/services/jobs/batch-posting-record.integration.spec.js#posts
    a batch whose description is a 1.0 test directive, as any other (DEF-ACT-0512)
  origin: none
- id: BR-CAP-ACC-BAT-013-16
  proved_by: [ATS-ACC-BAT-013-13]
  statement: The registered posting and unposting jobs disable user retry and cancellation while their workflow
    tasks retain separate retry settings.
  kind: policy
  enforced_at:
  - service
  must_prove: true
  provenance: observed
  source: services-accounting:modules/batches/services/jobs/batch-posting-jobs.ts:ensureBatchPostingJobTypesRegistered
  origin: none
scenarios:
- id: SC-CAP-ACC-BAT-013-01
  given: A Closed batch is ready for posting.
  when: Staff confirm Post.
  then: The progress display reaches completion, the batch becomes Posted and its ledger totals balance.
  provenance: documented
  source: services-accounting:docs/milestones/walkthroughs/ACCT-M3-handoff.md#Start here (step 4)
- id: SC-CAP-ACC-BAT-013-02
  given: Two staff members are viewing the same Closed batch.
  when: They submit posting concurrently.
  then: One posting is written, with the other caller receiving the existing job or an already-posted refusal.
  provenance: test
  source: react-console:acceptance/accounting/playwright/journeys/batches-posting/ACT-ACC-0519.spec.ts#ACT-ACC-0519
- id: SC-CAP-ACC-BAT-013-03
  given: One batch is valid and another needs an unconfigured account.
  when: The posting job runs for both.
  then: The independent valid batch posts, the other records its document error and the job can still succeed.
  provenance: test
  source: react-console:acceptance/accounting/playwright/journeys/batches-posting/ACT-ACC-0521.spec.ts#ACT-ACC-0521
edge_cases: []
constraints:
- Platform supplies durable-job execution and the progress record read by the console.
depends_on:
- CAP-ACC-BAT-014
- CAP-ACC-BAT-015
related:
- CAP-ACC-BAT-004
- CAP-ACC-BAT-012
- CAP-ACC-BAT-016
- CAP-ACC-BAT-019
journeys:
- JNY-ACC-BAT-001
- JNY-ACC-BAT-004
open_questions:
- OQ-ACC-BAT-004
evidence:
- 'Pinned services-accounting (f47cb263), examined sources: aws/api/batch-postings.routes.ts (postBatches), batch-postings.schemas.ts,
  services/actions/batch-actions.ts (postBatch), services/jobs/batch-posting-jobs.ts, batch-posting-job-tasks.ts,
  batch-posting-steps.ts, services/engine/post-batches.ts, engine-scope.ts, services/rules/posting-generation.ts,
  services/posting-period-guard.ts, services/persistence/batch-posting-jobs.ts, batch-postings.ts, db/batch-posting-jobs.table.ts,
  db/batch-postings.table.ts, aws/logic/batch-posting.step-functions.ts, aws/logic/batch-posting-tasks.lambda.ts;
  tests e2e/batch-postings.e2e.spec.js, integration/services/jobs/*.integration.spec.js, integration/services/posting/*.integration.spec.js,
  integration/services/close/posting-period-guard.integration.spec.js, unit/rules/batch-repost-rules.spec.js, unit/jobs/*.spec.js;
  docs/migrations/batch-posting/README.md, DESIGN.md (D6).'
- 'Pinned react-console (baf6dae3), examined sources: components/accounting/batches/batch-posting-panel.tsx, batch-posting-model.ts,
  batch-posting-breakdown.tsx; journeys ACT-ACC-0517, 0518, 0519, 0521, 0537, 0543.'
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-CRY-004, TC-DAT-001, TC-DAT-004, 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]
exercised_by: [FAS-ACC-BAT-03-01, FAS-ACC-BAT-03-02, FAS-ACC-BAT-03-03, FAS-ACC-BAT-03-04, FAS-ACC-BAT-03-05]
suites: [TST-ACC-BAT-007, TST-ACC-BAT-008, TST-ACC-BAT-010, TST-ACC-BAT-011, TST-ACC-BAT-024, TST-ACC-BAT-057, TST-ACC-BAT-063, TST-ACC-BAT-070, TST-ACC-BAT-075, TST-ACC-BAT-076, TST-ACC-BAT-077, TST-ACC-BAT-078, TST-ACC-BAT-096, TST-ACC-BAT-105, TST-ACC-BAT-107, TST-ACC-BAT-114, TST-ACC-BAT-125, TST-ACC-BAT-135]
---

# Run and monitor a batch posting job

## Purpose

Staff submit batches together and follow a durable job through posting or refusal.

## How It Works

Staff select batches for one unit and submit a posting request. The response identifies a durable job rather than completed ledger work. The job checks its batches and generates entries and schedules within its posting transaction. Staff follow progress and inspect the resulting batch states. Document problems can leave some batches in Error while independent batches post. A database refusal rolls back the whole transaction, and a failed job start can leave submitted work needing operational recovery.

## Relationships

- Prerequisite: Resolve posting accounts and retain their snapshots, which addresses the connected batch work.
- Prerequisite: Produce document entries using the applicable accounting method, which addresses the connected batch work.
- Related outcome: Use the batch’s permitted lifecycle actions, which addresses the connected batch work.
- Related outcome: Inspect posting readiness before submission, which addresses the connected batch work.
- Related outcome: Unpost a batch for correction and replacement posting, which addresses the connected batch work.
- Related outcome: Plan deferred revenue and adjust its remaining releases, which addresses the connected batch work.
