---
id: TST-ACC-CLS-018
title: 'Close-state, run and snapshot database constraints'
kind: integration
product_area: accounting
module: close
revision: 1
status: draft
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
repository: services-accounting
files:
  - >-
    modules/fiscal-close/tests/integration/db/fiscal-close.table.integration.spec.js
implements:
  - ATS-ACC-CLS-001-02
  - ATS-ACC-CLS-006-03
  - ATS-ACC-CLS-008-02
  - ATS-ACC-CLS-014-01
  - ATS-ACC-CLS-014-04
  - ATS-ACC-CLS-014-05
  - ATS-ACC-CLS-003-07
environment: local
implementation_state: implemented
latest_result: not-run
latest_run_at: null
latest_run_ref: null
conformance: not-verified
estimated_minutes: 3
isolation: >-
  The suite owns test-identifier workspaces and fixture records, removed by its
  teardown.
binding_policy: >-
  Each binding identifies the assertions this suite executes; combined scenarios
  may require other bound suites. Existence is not a recorded execution result.
evidence:
  - >-
    services-accounting:modules/fiscal-close/tests/integration/db/fiscal-close.table.integration.spec.js
  - provenance: test
    source: >-
      services-accounting:modules/fiscal-close/tests/integration/db/fiscal-close.table.integration.spec.js
    assertion_titles:
      - 'fiscal close’s tables (integration, table)'
      - accounting.fiscal_periods
      - 'generates a period open, with no closer, no close run and no reopening'
      - >-
        accepts closing and reopening with no closer, and closed with its closer
        and time
      - refuses a status that is not one of the four
      - refuses a closed period without the time it was closed
      - refuses a closed period without its closer
      - >-
        refuses a blank closer on a closed period, which the trigger stores as
        null
      - refuses an open period that names a closer and a time
      - refuses a reopening period that still names its closer
      - refuses a negative reopen count
      - trims the closer it stores
      - accounting.period_close_runs
      - 'stores a run queued, with the period and requester it names'
      - 'refuses a second queued run of a period, by the active-run index'
      - refuses a running run beside a queued one of the same period
      - accepts a new run of a period once its earlier runs have finished
      - accepts active runs of two periods at once
      - 'refuses an idempotency key the tenant already used, by the unique key'
      - accepts the same idempotency key in another tenant
      - >-
        stores a blank idempotency key as none, so two runs without a key are
        both accepted
      - refuses a kind that is not one of the three
      - refuses a status that is not one of the five
      - refuses a period number outside 1 to 12
      - refuses a finished run without the time it finished
      - refuses an active run that names a time it finished
      - refuses a run that finished before it was requested
      - refuses a reopen without its reason
      - 'refuses a reopen whose reason is blank, which the trigger stores as none'
      - refuses a note longer than 2000 characters
      - refuses an idempotency key longer than 255 characters
      - refuses a job id longer than 255 characters
      - 'refuses a period that does not exist, by the period’s foreign key'
      - >-
        refuses a business unit that is not the year’s, by the year’s foreign
        key
      - 'refuses a period of another tenant, by the period’s foreign key'
      - refuses deleting a period a run names
      - 'refuses changing the period a run names, which is written once'
      - 'refuses changing a run’s kind, which is written once'
      - trims the note it stores
      - accounting.period_close_snapshots
      - 'stores one snapshot of a run, its documents as given'
      - 'refuses a second snapshot of the run, by the primary key'
      - >-
        refuses a snapshot that names a period other than its run’s, by the
        run’s foreign key
      - refuses a snapshot of a run that does not exist
      - refuses a readiness document that is not an object
      - refuses a reconciliation document that is not an object
      - refuses a totals document of 512 kB or more
      - refuses deleting a run its snapshot names
      - >-
        refuses the application role any update of a snapshot, which is written
        once
      - row-level security
      - shows the run and the snapshot to their own tenant (premise)
      - hides the run and the snapshot from another tenant
      - changes nothing of another tenant’s run
      - 'refuses a run written for another tenant, by the policy’s check'
      - 'refuses a snapshot written for another tenant, by the policy’s check'
      - accounting.settings
      - >-
        does not require bank-verified payouts to close a period when the
        settings do not say
real_dependencies: >-
  Production migrations, application-role SQL, execution-context transactions
  and workspace session settings exercise database refusal directly. These
  enforcement boundaries are not doubled.
product_intent: proposed
implementation_evidence: observed
---
# Close-state, run and snapshot database constraints

## Verification Boundary

The suite checks its declared service or persistence boundary against local PostgreSQL. Bindings identify the assertions it contributes to a capability case; they do not establish every assertion in a combined case.

## What This Suite Proves

Database assertions cover close stamps, valid states, active-run uniqueness, command bounds, references and immutable snapshot storage. Workspace policies isolate both reads and writes.

## What It Does Not Prove

This register records assertion scope without claiming a passing run or complete coverage of every rule and scenario variant.

## Real Dependencies and Test Doubles

Production migrations, application-role SQL, execution-context transactions and workspace session settings exercise database refusal directly. These enforcement boundaries are not doubled.

## Must Not Be Doubled

Keep production queries, writes, mappings, application-role privileges and database constraints real wherever they are the subject of an assertion. Recording financial ports establish invocation behavior; actual recognition and reversal require the suite using the real posting service.
