---
id: TST-ACC-PRD-040
title: 'Product persistence, lifecycle and dependency protection'
kind: integration
product_area: accounting
module: products
revision: 1
status: draft
product_intent: proposed
implementation_evidence: observed
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
repository: services-accounting
files:
  - modules/products/tests/integration/services/persistence/products.integration.spec.js
implements:
  - ATS-ACC-PRD-002-01
  - ATS-ACC-PRD-002-02
  - ATS-ACC-PRD-002-03
  - ATS-ACC-PRD-002-04
  - ATS-ACC-PRD-002-07
  - ATS-ACC-PRD-002-09
  - ATS-ACC-PRD-002-10
  - ATS-ACC-PRD-002-11
  - ATS-ACC-PRD-004-01
  - ATS-ACC-PRD-004-02
  - ATS-ACC-PRD-004-03
  - ATS-ACC-PRD-004-04
  - ATS-ACC-PRD-004-05
  - ATS-ACC-PRD-004-06
  - ATS-ACC-PRD-005-02
  - ATS-ACC-PRD-005-03
  - ATS-ACC-PRD-005-04
  - ATS-ACC-PRD-005-05
  - ATS-ACC-PRD-006-01
  - ATS-ACC-PRD-006-04
  - ATS-ACC-PRD-006-05
  - ATS-ACC-PRD-006-06
  - ATS-ACC-PRD-008-01
  - ATS-ACC-PRD-008-02
  - ATS-ACC-PRD-008-03
  - ATS-ACC-PRD-008-04
  - ATS-ACC-PRD-008-05
  - ATS-ACC-PRD-008-06
  - ATS-ACC-PRD-008-07
  - ATS-ACC-PRD-008-08
  - ATS-ACC-PRD-008-09
  - ATS-ACC-PRD-011-01
  - ATS-ACC-PRD-011-02
  - ATS-ACC-PRD-011-03
  - ATS-ACC-PRD-011-04
  - ATS-ACC-PRD-011-05
  - ATS-ACC-PRD-011-06
  - ATS-ACC-PRD-011-07
environment: local
implementation_state: implemented
latest_result: not-run
latest_run_at: null
latest_run_ref: null
conformance: not-verified
estimated_minutes: 3
estimation_note: Planning estimate; no runtime measurement is claimed.
isolation: 'Suite-named local workspaces, isolated fixture records and explicit cleanup or rollback.'
evidence:
  - 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
assertion_bindings:
  - scenario: ATS-ACC-PRD-002-01
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        an id that is not a configuration id, with the configuration-id sentence, and writes nothing
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a reserved id
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-002-02
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a second product whose name suggests a taken id, as other configuration does, naming the id
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#creates
        the second product of that name once the client names an id of its own
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#asks
        for an id when the name suggests none
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#generates
        the id from the name when the client gives none, as every configuration id is
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-002-03
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        the same id under another type: a product id is unique across every type
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-002-04
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a product type the registry does not hold
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a business unit the tenant does not have
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-002-07
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a sale window that ends before it starts
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-002-09
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        components on a Donation Product
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-002-10
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#leaves
        nothing behind after a refusal
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-002-11
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a replacement, 409, saying why, and leaves the product unchanged
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#reads
        as any other product, under its uuid
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#may
        be bundled by a new product (the reference is the text form)
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-004-01
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a replacement at a version the product has moved on from
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-004-02
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#answers
        the replaced record at version 2, the cleared fields left out and both collections replaced
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-004-03
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a change of type, leaving the product unchanged
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-004-04
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        replacing a retired product
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-004-05
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a locked product replaced without stating sys_locked, or with the same lock
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#unlocks
        a locked product replaced with sys_locked null, then edits and deletes it
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-004-06
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#leaves
        the old prices and components when a rule refuses the replacement
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#leaves
        the old prices and components when a new price is refused by the database after the old ones were
        removed
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#leaves
        the old prices and components when a new component is refused by the database after the old ones were
        removed
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-005-02
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#retires
        the product at version 2, changing nothing else
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        retiring a retired product
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-005-03
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#reactivates
        an inactive product
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#reactivates
        the retired product at version 3
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        reactivating an active product
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-005-04
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        retiring at a version the product has moved on from
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-005-05
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#names
        the lock when a locked product is retired
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-006-01
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        deleting a product another product bundles, 409, and keeps it
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-006-04
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#takes
        its prices, components, accounting setup and the setup’s collections with it
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#answers
        the id it deleted
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-006-05
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a product locked against deletes
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-006-06
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a product whose accounting setup is locked against deletes, leaving the product and its setup
        (DEF-ACT-0101)
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-008-01
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        an Accounting Product without a standard price in the base currency
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a Donation Product with prices
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a Legacy Product without prices
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-008-02
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a price in a currency the business unit is not enabled for
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-008-03
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a percentage cell without a percent, and a set cell with one
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a set price without an amount
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a percentage above 100 or with more than two decimals
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a calculated cell with an amount
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-008-04
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        prohibiting purchases in the base currency
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-008-05
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a percentage cell on the standard audience, and one with no standard price to be a percentage of
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#lets
        a period cell inherit the always cell of its audience (a percentage in a period needs a standard price
        in that period or always)
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-008-06
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a calculated cell in the base currency, and one whose audience has no base-currency price to convert
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-008-07
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a dated price beside one that applies always, in the same audience and currency
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        two standard prices in one currency whose periods overlap
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#accepts
        two periods of one audience and currency that meet without overlapping
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#accepts
        the same period in two audiences
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-008-08
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        an audience the vocabulary does not know while Commerce’s pricing audiences do not exist (the
        built-ins are admitted)
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-008-09
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        more than 500 prices (the bound of the grid)
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-011-01
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        components on a Donation Product
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        components on a Legacy Product
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-011-02
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a component of another business unit, naming both units
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a component whose type is not sellable
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a component the tenant does not have
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a product including itself
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        the same component twice
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-011-03
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#keeps
        a retired component the bundle already holds when a replacement resends it, and refuses a new retired
        one
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a retired component
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-011-04
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        closing a cycle: B including A when A includes B
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-011-05
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        a component sent without a price, naming it, and stores nothing (ACCT-M1 D10.1, DEF-ACT-0107)
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-011-06
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#totals
        each component price times its quantity (ACCT-M1 D12 A2)
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        component prices that add up to more than the product price, in Rhythm 1.0’s words
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        component member prices that add up to more than the product member price, in Rhythm 1.0’s words
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        component member prices when the product has no member price
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#accepts
        component prices that add up to exactly the product price
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
  - scenario: ATS-ACC-PRD-011-07
    assertions:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#refuses
        more than 50 bundled products
    provenance: test
    source: 'services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js'
coverage_note: Scenario references name existing assertion evidence; broader unexecuted variants remain findings.
---

# Product persistence, lifecycle and dependency protection

## Verification Boundary

The suite exercises real PostgreSQL and Accounting persistence or database functions with isolated local workspace fixtures.

## What This Suite Proves

Persistence exercises readable identities, prices, components, replacement versions, locks, lifecycle, local rollback and deletion guards.

## What It Does Not Prove

Local execution does not prove deployed infrastructure, downstream purchase behavior, real domain extension completion or atomic remote-template recovery.

## Real Dependencies and Test Doubles

PostgreSQL, transaction context, constraints, foreign keys and Accounting persistence are real. The test owns its workspace fixtures and clock.

## Must Not Be Doubled

Do not double PostgreSQL, row-level security, transaction boundaries, constraints or the persistence implementation when claiming these local guarantees.
