---
id: ATS-ACC-PRD-012
scope: CAP-ACC-PRD-012
product_area: accounting
module: products
revision: 3
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-ACC-PRD-012-01
    title: Ceilings require compatible intervals
    level: unit
    proves:
      - BR-CAP-ACC-PRD-012-01
      - BR-CAP-ACC-PRD-012-02
    preconditions: A sellable product supports ceiling fixtures.
    steps: 'Try zero maximum, missing rolling window, extra all-time window and valid rolling configuration.'
    expected: Invalid configurations fail and the valid setting reads back.
    negative: true
    data_needs: A sellable product supports ceiling fixtures.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#refuses
        a purchase limit of zero by the database’s check
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#refuses
        an all-time purchase limit with a window
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#refuses
        a rolling purchase limit without its window
      - >-
        services-accounting:modules/products/tests/e2e/product-features.e2e.spec.js#refuses a rolling purchase
        limit without its window
      - TST-ACC-PRD-039
      - TST-ACC-PRD-027
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#refuses
      a purchase limit of zero by the database’s check
    category: validation
    binding_scope:
      - suite: TST-ACC-PRD-039
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#refuses
            a purchase limit of zero by the database’s check
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#refuses
            an all-time purchase limit with a window
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#refuses
            a rolling purchase limit without its window
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#refuses
          a purchase limit of zero by the database’s check;
          services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#refuses
          an all-time purchase limit with a window;
          services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#refuses
          a rolling purchase limit without its window;
          services-accounting:modules/products/tests/e2e/product-features.e2e.spec.js#refuses a rolling
          purchase limit without its window
      - suite: TST-ACC-PRD-027
        assertions:
          - >-
            services-accounting:modules/products/tests/e2e/product-features.e2e.spec.js#refuses a rolling
            purchase limit without its window
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#refuses
          a purchase limit of zero by the database’s check;
          services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#refuses
          an all-time purchase limit with a window;
          services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#refuses
          a rolling purchase limit without its window;
          services-accounting:modules/products/tests/e2e/product-features.e2e.spec.js#refuses a rolling
          purchase limit without its window
  - id: ATS-ACC-PRD-012-02
    title: Console correction preserves a stored ceiling
    level: browser
    proves:
      - BR-CAP-ACC-PRD-012-05
    preconditions: The API has configured a product ceiling.
    steps: Rename the product through its editor.
    expected: The ceiling remains unchanged.
    negative: false
    data_needs: The API has configured a product ceiling.
    bound_to:
      - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0112.spec.ts#ACT-ACC-0112'
      - TST-ACC-PRD-006
    provenance: test
    source: 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0112.spec.ts#ACT-ACC-0112'
    category: interaction
    binding_scope:
      - suite: TST-ACC-PRD-006
        assertions:
          - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0112.spec.ts#ACT-ACC-0112'
        provenance: test
        source: 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0112.spec.ts#ACT-ACC-0112'
    exercises:
      - CAP-ACC-PRD-012
      - CAP-ACC-PRD-004
  - id: ATS-ACC-PRD-012-03
    title: API replacement deliberately removes a purchase ceiling
    category: transition
    level: api
    proves:
      - BR-CAP-ACC-PRD-012-03
    preconditions: Two products each hold an all-time ceiling.
    steps: Replace one omitting the ceiling and the other sending an explicit empty setting.
    expected: Both products read back without ceilings and their replacement versions advance.
    negative: true
    data_needs: Two products each hold an all-time ceiling.
    bound_to: []
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/e2e/product-features.e2e.spec.js#switches every feature off
      with null
    binding_scope: []
  - id: ATS-ACC-PRD-012-04
    title: A console correction preserves an API purchase ceiling
    category: interaction
    level: browser
    proves:
      - BR-CAP-ACC-PRD-012-05
      - BR-CAP-ACC-PRD-004-10
    preconditions: An API-created product holds an all-time ceiling and hidden settings.
    steps: 'Rename it in the console, deactivate it from the list, and reread the ceiling after both writes.'
    expected: Both saves retain the ceiling and other fixture settings.
    negative: true
    data_needs: An API-created product holds an all-time ceiling and hidden settings.
    bound_to:
      - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0112.spec.ts#ACT-ACC-0112'
      - TST-ACC-PRD-006
    provenance: test
    source: >-
      react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0112.spec.ts#ACT-ACC-0112;
      react-console:lib/accounting-config/product-form.ts:formToWrite
    exercises:
      - CAP-ACC-PRD-012
      - CAP-ACC-PRD-004
    binding_scope:
      - suite: TST-ACC-PRD-006
        assertions:
          - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0112.spec.ts#ACT-ACC-0112'
        provenance: test
        source: 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0112.spec.ts#ACT-ACC-0112'
evidence:
  - 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0112.spec.ts'
  - 'services-accounting:modules/products/db/products.table.ts'
  - 'services-accounting:modules/products/services/rules/product-rules.ts'
  - 'services-accounting:modules/products/tests/e2e/product-features.e2e.spec.js'
  - >-
    services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js
  - >-
    rhythm-v2-docs:specs/accounting/products/design/workflows/WF-ACC-PRD-001-create-or-replace-a-product-with-its-owned-settings.md
coverage:
  rule: 'gap: FND-ACC-PRD-061'
  transition: covered
  validation: covered
  permission: 'gap: FND-ACC-PRD-061'
  edge: 'gap: FND-ACC-PRD-061'
  failure: 'gap: FND-ACC-PRD-061'
  boundary: 'gap: FND-ACC-PRD-061'
  concurrency: 'gap: FND-ACC-PRD-061'
  invariant: 'gap: FND-ACC-PRD-061'
  interaction: covered
coverage_notes:
  rule:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-061
  permission:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-061
  edge:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-061
  failure:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-061
  boundary:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-061
  concurrency:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-061
  invariant:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-061
  remaining_obligations:
    reason: >-
      Explicit all-time clearing, every interval endpoint, permission refusal and concurrent product edits
      need dedicated execution; order-time ceilings are outside these suites. Workflow edges not named by a
      scenario remain in this finding rather than gaining a binding from shared workflow membership.
    provenance: unknown
    source: FND-ACC-PRD-061
  meaning:
    reason: >-
      Covered means a specification scenario exists in this category. Executable coverage and run results
      remain independent.
    provenance: documented
    source: 'rhythm-v2-docs:specs/CONVENTIONS.md#9.10 Capability Test Specification (`ATS`, under `design/tests/`)'
coverage_findings:
  - FND-ACC-PRD-061
related_capabilities:
  - CAP-ACC-PRD-004
workflows:
  - WF-ACC-PRD-001
rule_coverage:
  - rule: BR-CAP-ACC-PRD-012-01
    scenarios:
      - ATS-ACC-PRD-012-01
  - rule: BR-CAP-ACC-PRD-012-02
    scenarios:
      - ATS-ACC-PRD-012-01
  - rule: BR-CAP-ACC-PRD-012-05
    scenarios:
      - ATS-ACC-PRD-012-02
      - ATS-ACC-PRD-012-04
interaction_coverage:
  - scenario: ATS-ACC-PRD-012-02
    exercises:
      - CAP-ACC-PRD-012
      - CAP-ACC-PRD-004
    provenance: test
    source: 'react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0112.spec.ts#ACT-ACC-0112'
  - scenario: ATS-ACC-PRD-012-04
    exercises:
      - CAP-ACC-PRD-012
      - CAP-ACC-PRD-004
    provenance: test
    source: >-
      react-console:acceptance/accounting/playwright/journeys/products/ACT-ACC-0112.spec.ts#ACT-ACC-0112;
      react-console:lib/accounting-config/product-form.ts:formToWrite
permission_coverage:
  - key: accounting.products.update
    where_checked: api
    scope: tenant
    scenarios: []
    finding: FND-ACC-PRD-061
    provenance: unknown
    source: >-
      rhythm-v2-docs:specs/accounting/products/planning/capabilities/CAP-ACC-PRD-012-limit-how-much-one-customer-may-buy.md#permissions
---

# Configure a customer purchase ceiling: Capability Test Specification

## Coverage

The frontmatter lists a proof scenario or finding for every required rule and records each applicable category. Scenario coverage describes what to check; bindings identify the assertions that already exist, and execution results remain unverified. Explicit all-time clearing, every interval endpoint, permission refusal and concurrent product edits need dedicated execution; order-time ceilings are outside these suites. Workflow edges not named by a scenario remain in this finding rather than gaining a binding from shared workflow membership.

## Interactions With Related Capabilities

A console correction preserves an API purchase ceiling. An API-created product holds an all-time ceiling and hidden settings. Rename it in the console, deactivate it from the list, and reread the ceiling after both writes. Both saves retain the ceiling and other fixture settings.
