---
id: ATS-ACC-REC-020
scope: CAP-ACC-REC-020
product_area: accounting
module: reconciliation
revision: 3
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-ACC-REC-020-01
    title: Permission count and sensitivity tiers
    level: unit
    proves:
      - BR-CAP-ACC-REC-020-01
    preconditions: The published permission catalogue is loaded.
    steps: Inspect reconciliation keys and their tier or sensitivity.
    expected: 'Sixteen keys divide into read, ordinary user changes and sensitive administrator approvals without bulk.'
    negative: false
    data_needs: No additional fixture beyond the case setup.
    bound_to:
      - >-
        services-accounting:tests/unit/reconciliation-permissions.spec.ts#publishes exactly the reconciliation
        keys of the architecture, no bulk among them
      - >-
        services-accounting:tests/unit/reconciliation-permissions.spec.ts#makes each read tier read, so the
        Read Only policy carries it
      - >-
        services-accounting:tests/unit/reconciliation-permissions.spec.ts#makes the ordinary writes tier user:
        reconciliation’s records are records, not configuration
      - >-
        services-accounting:tests/unit/reconciliation-permissions.spec.ts#makes every approval tier admin and
        sensitive
      - TST-ACC-REC-097
    provenance: test
    source: >-
      services-accounting:tests/unit/reconciliation-permissions.spec.ts#publishes exactly the reconciliation
      keys of the architecture, no bulk among them
    category: permission
  - id: ATS-ACC-REC-020-02
    title: Declared duty-separation policies
    level: unit
    proves:
      - BR-CAP-ACC-REC-020-02
    preconditions: The two reconciliation policies are published.
    steps: Compare their applications and allowed keys.
    expected: Preparer grants ordinary work only; approver adds exactly four approvals and both belong to Accounting.
    negative: false
    data_needs: No additional fixture beyond the case setup.
    bound_to:
      - >-
        services-accounting:tests/unit/reconciliation-permissions.spec.ts#lets the preparer record payouts and
        prepare reconciliations, and approve nothing
      - >-
        services-accounting:tests/unit/reconciliation-permissions.spec.ts#lets the approver do what the
        preparer does and the four approvals
      - >-
        services-accounting:tests/unit/reconciliation-permissions.spec.ts#files both policies under the
        accounting application
      - TST-ACC-REC-097
    provenance: test
    source: >-
      services-accounting:tests/unit/reconciliation-permissions.spec.ts#lets the preparer record payouts and
      prepare reconciliations, and approve nothing
    category: permission
  - id: ATS-ACC-REC-020-03
    title: Role grants span units
    level: api
    proves:
      - BR-CAP-ACC-REC-020-03
      - BR-CAP-ACC-REC-020-08
      - AS-JNY-ACC-REC-006-01
      - AS-JNY-ACC-REC-006-03
    preconditions: 'Per-run preparer, approver, reader and access-only roles are assigned.'
    steps: Exercise commands under those roles in two units.
    expected: 'Grants follow roles rather than unit boundaries, and application access alone gives no record reads.'
    negative: true
    data_needs: Provide Per-run people for this case.
    bound_to:
      - >-
        react-console:acceptance/accounting/playwright/journeys/reconciliation-close/ACT-ACC-0608.spec.ts#ACT-ACC-0608
      - >-
        services-accounting:modules/reconciliation/tests/e2e/reconciliation-lists.e2e.spec.js#refuses a
        request without a security context with 401
      - >-
        services-accounting:modules/reconciliation/tests/e2e/reconciliation-lists.e2e.spec.js#refuses a
        principal denied accounting.application.access with 403
      - TST-ACC-REC-016
      - TST-ACC-REC-026
    provenance: test
    source: >-
      react-console:acceptance/accounting/playwright/journeys/reconciliation-close/ACT-ACC-0608.spec.ts#ACT-ACC-0608
    category: permission
  - id: ATS-ACC-REC-020-04
    title: Keyed commands distinguish body and caller
    level: api
    proves:
      - BR-CAP-ACC-REC-020-04
      - AS-JNY-ACC-REC-006-02
    preconditions: Money operations have recorded request keys.
    steps: 'Repeat, alter the body and use the same key as another caller.'
    expected: 'Unchanged requests replay, changed bodies fail and the colleague’s request has a separate scope.'
    negative: true
    data_needs: Provide Two people for this case.
    bound_to:
      - >-
        react-console:acceptance/accounting/playwright/journeys/reconciliation-close/ACT-ACC-0609.spec.ts#ACT-ACC-0609
      - >-
        services-accounting:modules/reconciliation/tests/integration/db/idempotency-keys.table.integration.spec.js#refuses
        the same key twice for one principal and scope
      - >-
        services-accounting:modules/reconciliation/tests/integration/db/idempotency-keys.table.integration.spec.js#accepts
        the same key for another scope
      - >-
        services-accounting:modules/reconciliation/tests/integration/db/idempotency-keys.table.integration.spec.js#accepts
        the same key for another principal
      - >-
        services-accounting:modules/reconciliation/tests/integration/db/idempotency-ledger-converge.integration.spec.js#carries
        every row over as a completion: the actor its principal, the answer its 200 body, the creation its
        completion
      - TST-ACC-REC-017
      - TST-ACC-REC-031
      - TST-ACC-REC-032
    provenance: test
    source: >-
      react-console:acceptance/accounting/playwright/journeys/reconciliation-close/ACT-ACC-0609.spec.ts#ACT-ACC-0609
    category: validation
  - id: ATS-ACC-REC-020-05
    title: Committed immutable activity
    level: api
    proves:
      - BR-CAP-ACC-REC-020-05
    preconditions: 'Commands include successes, refusals and transaction rollback.'
    steps: 'Read recorded events, exceed detail capacity and try history mutation.'
    expected: 'Committed events retain actor and time, invalid detail and mutation fail and rollback leaves no event.'
    negative: true
    data_needs: No additional fixture beyond the case setup.
    bound_to:
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-events.integration.spec.js#answers
        the event as stored, its actor the caller and its time the clock’s
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-events.integration.spec.js#records
        nothing when the command’s transaction rolls back
      - >-
        services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-events.integration.spec.js#refuses
        a detail past 4,096 bytes
      - >-
        services-accounting:modules/reconciliation/tests/integration/db/reconciliation-events.table.integration.spec.js#refuses
        the application role an UPDATE (UPDATE is revoked)
      - >-
        services-accounting:modules/reconciliation/tests/integration/db/reconciliation-events.table.integration.spec.js#refuses
        even the owner an UPDATE, by the append-only trigger (RHF32)
      - >-
        services-accounting:modules/reconciliation/tests/integration/db/reconciliation-events.table.integration.spec.js#refuses
        the owner a DELETE outside a tenant purge, by the append-only trigger (RHF32)
      - TST-ACC-REC-064
      - TST-ACC-REC-038
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-events.integration.spec.js#answers
      the event as stored, its actor the caller and its time the clock’s
    category: invariant
  - id: ATS-ACC-REC-020-06
    title: Refusal codes are stable
    level: api
    proves:
      - BR-CAP-ACC-REC-020-06
    preconditions: 'Requests exercise validation, missing records, stale versions and malformed cursor paths.'
    steps: Submit each refusal case.
    expected: Each response carries its defined machine code independently of wording.
    negative: true
    data_needs: No additional fixture beyond the case setup.
    bound_to:
      - >-
        services-accounting:modules/reconciliation/tests/e2e/refusal-codes.e2e.spec.js#answers a payout edit
        whose body breaks its schema 400 validation_failed
      - >-
        services-accounting:modules/reconciliation/tests/e2e/refusal-codes.e2e.spec.js#answers an unknown
        payout 404 not_found
      - >-
        services-accounting:modules/reconciliation/tests/e2e/refusal-codes.e2e.spec.js#answers a payout edit
        at a version already moved on 409 stale_version
      - >-
        services-accounting:modules/reconciliation/tests/e2e/refusal-codes.e2e.spec.js#answers a cursor the
        list did not answer 400 invalid_request
      - >-
        services-accounting:modules/reconciliation/tests/unit/rules/refusal-codes.spec.js#keeps the code a
        refusal carries
      - >-
        services-accounting:modules/reconciliation/tests/unit/rules/refusal-codes.spec.js#names a state
        refusal without a refusal word illegal_operation
      - TST-ACC-REC-029
      - TST-ACC-REC-093
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/e2e/refusal-codes.e2e.spec.js#answers a payout edit
      whose body breaks its schema 400 validation_failed
    category: failure
  - id: ATS-ACC-REC-020-07
    title: Cross-workspace isolation
    level: api
    proves:
      - BR-CAP-ACC-REC-020-07
    preconditions: Two workspaces have reconciliation records.
    steps: Attempt reads and writes across their boundary.
    expected: Other-workspace rows remain invisible and writes fail.
    negative: true
    data_needs: Provide records in each of the two isolated workspaces.
    bound_to:
      - >-
        services-accounting:modules/reconciliation/tests/integration/db/payouts.table.integration.spec.js#hides
        them from another tenant
      - >-
        services-accounting:modules/reconciliation/tests/integration/db/payouts.table.integration.spec.js#refuses
        a row written for another tenant
      - >-
        react-console:acceptance/accounting/playwright/journeys/reconciliation-close/ACT-ACC-0610.spec.ts#ACT-ACC-0610
      - TST-ACC-REC-033
      - TST-ACC-REC-018
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/integration/db/payouts.table.integration.spec.js#hides
      them from another tenant
    category: boundary
  - id: ATS-ACC-REC-020-08
    title: Exact arithmetic and currency formatting
    level: unit
    proves:
      - BR-CAP-ACC-REC-020-09
    preconditions: Amounts include safe-range boundaries and different currency exponents.
    steps: 'Add, total and render amounts.'
    expected: 'Arithmetic stays exact, overflow or fractions fail and formatting uses the exponent.'
    negative: true
    data_needs: No additional fixture beyond the case setup.
    bound_to:
      - >-
        services-accounting:modules/reconciliation/tests/unit/rules/money.spec.js#refuses a sum past the
        safe-integer range
      - >-
        services-accounting:modules/reconciliation/tests/unit/rules/money.spec.js#refuses a fraction, naming
        what it expected
      - >-
        services-accounting:modules/reconciliation/tests/unit/rules/money.spec.js#formats an exponent of 0
        with no decimal point
      - TST-ACC-REC-087
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/unit/rules/money.spec.js#refuses a sum past the
      safe-integer range
    category: boundary
  - id: ATS-ACC-REC-020-09
    title: Product waiver command remains proposed
    level: api
    proves:
      - BR-CAP-ACC-REC-020-10
    preconditions: An administrator needs to waive second-person enforcement.
    steps: Change that setting through a product operation and finalize as preparer.
    expected: >-
      The product should audit the policy change and mark finalization waived; no current operation supplies
      this proof.
    negative: false
    data_needs: Provide Accounting settings for this case.
    bound_to: []
    provenance: proposed
    source: FND-ACC-REC-004
    category: permission
  - id: ATS-ACC-REC-020-10
    title: Export reference versus copied evidence
    level: api
    proves:
      - BR-CAP-ACC-REC-020-13
    preconditions: A payout has a stored evidence asset reference.
    steps: Export records and inspect the referenced document in the package.
    expected: 'The reference survives, while actual file inclusion requires independent proof.'
    negative: true
    data_needs: Provide Isolated records for the cases described for this case.
    bound_to: []
    provenance: proposed
    source: 'services-accounting:modules/reconciliation/export/reconciliation.dataset.ts'
    category: edge
  - id: ATS-ACC-REC-020-11
    title: Contribution changes approval eligibility
    category: interaction
    level: api
    proves:
      - BR-CAP-ACC-REC-020-02
      - BR-CAP-ACC-REC-011-03
      - BR-CAP-ACC-REC-011-04
    interacts_with:
      - CAP-ACC-REC-011
    relies_on:
      - ATS-ACC-REC-020-02
      - ATS-ACC-REC-011-03
    preconditions: Use one isolated workspace with the financial records and caller roles required by the relied-on cases.
    steps:
      - do: >-
          Have a second person add a manual entry, then try approval by that person and by an uninvolved third
          person.
        expect: Only the uninvolved authorized approver completes approval under the default separation setting.
        provenance: proposed
        source:
          - >-
            specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-020-keep-preparing-apart-from-approving-and-leave-a-trail-of.md
          - >-
            specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-011-approve-a-balanced-reconciliation-and-move-the-deposit-to.md
    expected: Only the uninvolved authorized approver completes approval under the default separation setting.
    negative: false
    data_needs: >-
      Local merchant and bank accounts, an open operational batch and distinct preparation and approval
      callers.
    bound_to: []
    provenance: proposed
    source:
      - >-
        specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-020-keep-preparing-apart-from-approving-and-leave-a-trail-of.md
      - >-
        specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-011-approve-a-balanced-reconciliation-and-move-the-deposit-to.md
  - id: ATS-ACC-REC-020-12
    title: Reversal retains separate approval actors
    category: interaction
    level: api
    proves:
      - BR-CAP-ACC-REC-020-05
      - BR-CAP-ACC-REC-013-04
      - BR-CAP-ACC-REC-013-05
      - BR-CAP-ACC-REC-013-06
    interacts_with:
      - CAP-ACC-REC-013
    relies_on:
      - ATS-ACC-REC-020-05
      - ATS-ACC-REC-013-04
    preconditions: Use one isolated workspace with the financial records and caller roles required by the relied-on cases.
    steps:
      - do: 'Request closed-period reversal, try requester approval and complete as another authorized person.'
        expect: The self-approval fails and completion retains separate requester and approver.
        provenance: proposed
        source:
          - >-
            specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-020-keep-preparing-apart-from-approving-and-leave-a-trail-of.md
          - >-
            specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-013-correct-a-finalized-reconciliation-by-reversing-it-and.md
    expected: The self-approval fails and completion retains separate requester and approver.
    negative: false
    data_needs: >-
      Local merchant and bank accounts, an open operational batch and distinct preparation and approval
      callers.
    bound_to: []
    provenance: proposed
    source:
      - >-
        specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-020-keep-preparing-apart-from-approving-and-leave-a-trail-of.md
      - >-
        specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-013-correct-a-finalized-reconciliation-by-reversing-it-and.md
  - id: ATS-ACC-REC-020-13
    title: Acceptance derives the acting approver
    category: interaction
    level: api
    proves:
      - BR-CAP-ACC-REC-020-02
      - BR-CAP-ACC-REC-016-03
      - BR-CAP-ACC-REC-016-04
    interacts_with:
      - CAP-ACC-REC-016
    relies_on:
      - ATS-ACC-REC-020-02
      - ATS-ACC-REC-016-03
    preconditions: Use one isolated workspace with the financial records and caller roles required by the relied-on cases.
    steps:
      - do: 'Request acceptance, try supplying an approval identity and approve as a second authorized person.'
        expect: Supplied identity fails and completion names the actual requester and approver.
        provenance: proposed
        source:
          - >-
            specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-020-keep-preparing-apart-from-approving-and-leave-a-trail-of.md
          - >-
            specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-016-accept-a-problem-under-policy-with-a-second-persons-approval.md
    expected: Supplied identity fails and completion names the actual requester and approver.
    negative: false
    data_needs: >-
      Local merchant and bank accounts, an open operational batch and distinct preparation and approval
      callers.
    bound_to: []
    provenance: proposed
    source:
      - >-
        specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-020-keep-preparing-apart-from-approving-and-leave-a-trail-of.md
      - >-
        specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-016-accept-a-problem-under-policy-with-a-second-persons-approval.md
  - id: ATS-ACC-REC-020-14
    title: Acceptance history keeps guarded refusals
    category: interaction
    level: api
    proves:
      - BR-CAP-ACC-REC-020-05
      - BR-CAP-ACC-REC-016-09
      - BR-CAP-ACC-REC-016-10
    interacts_with:
      - CAP-ACC-REC-016
    relies_on:
      - ATS-ACC-REC-020-05
      - ATS-ACC-REC-016-07
    preconditions: Use one isolated workspace with the financial records and caller roles required by the relied-on cases.
    steps:
      - do: 'Request acceptance, try self-approval, approve independently and inspect history.'
        expect: Refusal and completion retain their actual actors without allowing requester approval.
        provenance: proposed
        source:
          - >-
            specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-020-keep-preparing-apart-from-approving-and-leave-a-trail-of.md
          - >-
            specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-016-accept-a-problem-under-policy-with-a-second-persons-approval.md
    expected: Refusal and completion retain their actual actors without allowing requester approval.
    negative: true
    data_needs: >-
      Local merchant and bank accounts, an open operational batch and distinct preparation and approval
      callers.
    bound_to: []
    provenance: proposed
    source:
      - >-
        specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-020-keep-preparing-apart-from-approving-and-leave-a-trail-of.md
      - >-
        specs/accounting/reconciliation/planning/capabilities/CAP-ACC-REC-016-accept-a-problem-under-policy-with-a-second-persons-approval.md
evidence:
  - >-
    Bindings identify existing tests at the pinned revisions; proposed cases remain unbound and describe the
    proof still needed.
coverage:
  validation: covered
  permission: covered
  edge: covered
  failure: covered
  boundary: covered
  invariant: covered
  interaction: covered
  rule: 'gap: FND-ACC-REC-065'
  transition: 'gap: FND-ACC-REC-065'
  concurrency: 'gap: FND-ACC-REC-065'
coverage_notes:
  design_completeness: >-
    Covered categories count specified cases, including proposed cases. Exhaustive state-transition,
    permission-key and domain-invariant traceability remains a separate proof gap.
---

# Separate duties and retain trustworthy reconciliation records: Capability Test Specification

## Coverage

| Rule | Proved by |
|---|---|
| `BR-CAP-ACC-REC-020-01` | `ATS-ACC-REC-020-01` |
| `BR-CAP-ACC-REC-020-02` | `ATS-ACC-REC-020-02` |
| `BR-CAP-ACC-REC-020-03` | `ATS-ACC-REC-020-03` |
| `BR-CAP-ACC-REC-020-04` | `ATS-ACC-REC-020-04` |
| `BR-CAP-ACC-REC-020-05` | `ATS-ACC-REC-020-05` |
| `BR-CAP-ACC-REC-020-06` | `ATS-ACC-REC-020-06` |
| `BR-CAP-ACC-REC-020-07` | `ATS-ACC-REC-020-07` |
| `BR-CAP-ACC-REC-020-08` | `ATS-ACC-REC-020-03` |
| `BR-CAP-ACC-REC-020-09` | `ATS-ACC-REC-020-08` |
| `BR-CAP-ACC-REC-020-10` | `ATS-ACC-REC-020-09` |
| `BR-CAP-ACC-REC-020-13` | `ATS-ACC-REC-020-10` |

## Interactions With Related Capabilities

Contribution changes approval eligibility. Reversal retains separate approval actors. Acceptance derives the acting approver. Acceptance history keeps guarded refusals. Proposed interaction cases require executable proof.
