---
id: ATS-ACC-PRD-009
scope: CAP-ACC-PRD-009
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-009-01
    title: Migration retains every special-price handover
    level: unit
    proves:
      - BR-CAP-ACC-PRD-009-01
    preconditions: Two products have former special-price fixtures.
    steps: Run the migration’s backfill.
    expected: Prices and handovers retain source values and ordering and the retired collection is emptied.
    negative: false
    data_needs: Two products have former special-price fixtures.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/db/special-prices-a12-migration.integration.spec.js#hands
        each special price over as a product-local audience: minted id, product, name, criteria, amount in the
        base currency, formula, rank
      - >-
        services-accounting:modules/products/tests/integration/db/special-prices-a12-migration.integration.spec.js#mints
        one always price row per special price under its audience, after the product’s existing prices, in 1.0
        order
      - >-
        services-accounting:modules/products/tests/integration/db/special-prices-a12-migration.integration.spec.js#leaves
        the retired table empty, which is the condition the migration drops it under
      - TST-ACC-PRD-033
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/db/special-prices-a12-migration.integration.spec.js#hands
      each special price over as a product-local audience: minted id, product, name, criteria, amount in the
      base currency, formula, rank
    category: transition
    binding_scope:
      - suite: TST-ACC-PRD-033
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/db/special-prices-a12-migration.integration.spec.js#hands
            each special price over as a product-local audience: minted id, product, name, criteria, amount in
            the base currency, formula, rank
          - >-
            services-accounting:modules/products/tests/integration/db/special-prices-a12-migration.integration.spec.js#mints
            one always price row per special price under its audience, after the product’s existing prices, in
            1.0 order
          - >-
            services-accounting:modules/products/tests/integration/db/special-prices-a12-migration.integration.spec.js#leaves
            the retired table empty, which is the condition the migration drops it under
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/db/special-prices-a12-migration.integration.spec.js#hands
          each special price over as a product-local audience: minted id, product, name, criteria, amount in
          the base currency, formula, rank;
          services-accounting:modules/products/tests/integration/db/special-prices-a12-migration.integration.spec.js#mints
          one always price row per special price under its audience, after the product’s existing prices, in
          1.0 order;
          services-accounting:modules/products/tests/integration/db/special-prices-a12-migration.integration.spec.js#leaves
          the retired table empty, which is the condition the migration drops it under
  - id: ATS-ACC-PRD-009-02
    title: The retired wire accepts only empty special pricing
    level: api
    proves:
      - BR-CAP-ACC-PRD-009-02
    preconditions: An existing product is available.
    steps: Send the old special-price field empty and then as a list.
    expected: Empty compatibility input succeeds and the list fails with migration guidance.
    negative: true
    data_needs: An existing product is available.
    bound_to:
      - >-
        services-accounting:modules/products/tests/e2e/product-features.e2e.spec.js#refuses a list of special
        prices, naming where the feature went (A12)
      - >-
        services-accounting:modules/products/tests/e2e/product-features.e2e.spec.js#accepts special_prices as
        null (the old wire’s switched-off), which the record no longer answers
      - TST-ACC-PRD-027
    provenance: test
    source: >-
      services-accounting:modules/products/tests/e2e/product-features.e2e.spec.js#refuses a list of special
      prices, naming where the feature went (A12)
    category: validation
    binding_scope:
      - suite: TST-ACC-PRD-027
        assertions:
          - >-
            services-accounting:modules/products/tests/e2e/product-features.e2e.spec.js#refuses a list of
            special prices, naming where the feature went (A12)
          - >-
            services-accounting:modules/products/tests/e2e/product-features.e2e.spec.js#accepts special_prices
            as null (the old wire’s switched-off), which the record no longer answers
        provenance: test
        source: >-
          services-accounting:modules/products/tests/e2e/product-features.e2e.spec.js#refuses a list of
          special prices, naming where the feature went (A12);
          services-accounting:modules/products/tests/e2e/product-features.e2e.spec.js#accepts special_prices
          as null (the old wire’s switched-off), which the record no longer answers
  - id: ATS-ACC-PRD-009-03
    title: An unrealized audience can block correction
    level: api
    proves:
      - BR-CAP-ACC-PRD-009-05
    preconditions: Commerce vocabulary exists but lacks a migrated audience still held by a product.
    steps: Replace the product description while resubmitting its price grid.
    expected: >-
      The proposed proof should demonstrate the current refusal; intended admission remains a product
      question.
    negative: true
    data_needs: Commerce vocabulary exists but lacks a migrated audience still held by a product.
    bound_to: []
    provenance: proposed
    source: FND-ACC-PRD-026
    category: interaction
    binding_scope: []
    exercises:
      - CAP-ACC-PRD-009
      - CAP-ACC-PRD-004
      - CAP-ACC-PRD-008
  - id: ATS-ACC-PRD-009-04
    title: Deleting a migrated product removes its handover
    category: interaction
    level: api
    proves:
      - BR-CAP-ACC-PRD-009-01
      - BR-CAP-ACC-PRD-006-03
      - INV-DOM-ACC-PRD-002-10
    preconditions: A migrated product has a local-audience price and a handover with a controlled realization timestamp.
    steps: 'Delete products with unstamped and stamped handovers, after satisfying ordinary deletion guards.'
    expected: >-
      Both local handovers disappear with their owning products; Commerce audience deletion is outside this
      proof.
    negative: true
    data_needs: A migrated product has a local-audience price and a handover with a controlled realization timestamp.
    bound_to: []
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/db/special-prices-a12-migration.integration.spec.js#hands
      each special price over as a product-local audience: minted id, product, name, criteria, amount in the
      base currency, formula, rank;
      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
    exercises:
      - CAP-ACC-PRD-009
      - CAP-ACC-PRD-006
    binding_scope: []
evidence:
  - 'services-accounting:modules/products/db/pricing-audience-handovers.table.ts'
  - 'services-accounting:modules/products/services/persistence/pricing-audiences.ts'
  - 'services-accounting:modules/products/tests/e2e/product-features.e2e.spec.js'
  - 'services-accounting:modules/products/tests/integration/db/special-prices-a12-migration.integration.spec.js'
  - >-
    services-accounting:modules/products/tests/integration/services/persistence/pricing-audiences.integration.spec.js
  - >-
    rhythm-v2-docs:specs/accounting/products/design/workflows/WF-ACC-PRD-006-hand-migrated-special-prices-over-to-commerce.md
coverage:
  rule: 'gap: FND-ACC-PRD-058'
  transition: covered
  validation: covered
  permission: 'gap: FND-ACC-PRD-058'
  edge: 'gap: FND-ACC-PRD-058'
  failure: 'gap: FND-ACC-PRD-058'
  boundary: 'gap: FND-ACC-PRD-058'
  concurrency: 'gap: FND-ACC-PRD-058'
  invariant: 'gap: FND-ACC-PRD-058'
  interaction: covered
coverage_notes:
  rule:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-058
  permission:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-058
  edge:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-058
  failure:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-058
  boundary:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-058
  concurrency:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-058
  invariant:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-058
  remaining_obligations:
    reason: >-
      Commerce realization, completion stamping, retry and consumer concurrency remain unknown; realization
      and removal transitions are not exercised end to end. 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-058
  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-058
related_capabilities:
  - CAP-ACC-PRD-006
workflows:
  - WF-ACC-PRD-006
rule_coverage:
  - rule: BR-CAP-ACC-PRD-009-01
    scenarios:
      - ATS-ACC-PRD-009-01
      - ATS-ACC-PRD-009-04
  - rule: BR-CAP-ACC-PRD-009-02
    scenarios:
      - ATS-ACC-PRD-009-02
  - rule: BR-CAP-ACC-PRD-009-05
    scenarios:
      - ATS-ACC-PRD-009-03
interaction_coverage:
  - scenario: ATS-ACC-PRD-009-03
    exercises:
      - CAP-ACC-PRD-009
      - CAP-ACC-PRD-004
      - CAP-ACC-PRD-008
    provenance: proposed
    source: FND-ACC-PRD-026
  - scenario: ATS-ACC-PRD-009-04
    exercises:
      - CAP-ACC-PRD-009
      - CAP-ACC-PRD-006
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/db/special-prices-a12-migration.integration.spec.js#hands
      each special price over as a product-local audience: minted id, product, name, criteria, amount in the
      base currency, formula, rank;
      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
state_coverage:
  - model: STATE-ACC-PRD-005
    from: handed over
    to: realised
    scenarios: []
    finding: FND-ACC-PRD-058
    provenance: unknown
    source: FND-ACC-PRD-046
  - model: STATE-ACC-PRD-005
    from: handed over
    to: removed
    scenarios:
      - ATS-ACC-PRD-009-04
    finding: null
    provenance: proposed
    source: 'services-accounting:modules/products/db/pricing-audience-handovers.table.ts:pricingAudienceHandovers'
  - model: STATE-ACC-PRD-005
    from: realised
    to: removed
    scenarios:
      - ATS-ACC-PRD-009-04
    finding: null
    provenance: proposed
    source: 'services-accounting:modules/products/db/pricing-audience-handovers.table.ts:pricingAudienceHandovers'
permission_coverage:
  - key: accounting.products.update
    where_checked: api
    scope: tenant
    scenarios: []
    finding: FND-ACC-PRD-058
    provenance: unknown
    source: >-
      rhythm-v2-docs:specs/accounting/products/planning/capabilities/CAP-ACC-PRD-009-hand-rhythm-1-0-special-prices-over-to-commerce.md#permissions
invariant_coverage:
  - invariant: INV-DOM-ACC-PRD-002-10
    scenarios:
      - ATS-ACC-PRD-009-04
    finding: FND-ACC-PRD-058
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/db/special-prices-a12-migration.integration.spec.js#hands
      each special price over as a product-local audience: minted id, product, name, criteria, amount in the
      base currency, formula, rank
    note: >-
      The mapped scenario exercises the related behavior; the complete invariant statement still needs
      dedicated proof.
---

# Preserve migrated special prices for Commerce: 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. Commerce realization, completion stamping, retry and consumer concurrency remain unknown; realization and removal transitions are not exercised end to end. Workflow edges not named by a scenario remain in this finding rather than gaining a binding from shared workflow membership.

## Interactions With Related Capabilities

Deleting a migrated product removes its handover. A migrated product has a local-audience price and a handover with a controlled realization timestamp. Delete products with unstamped and stamped handovers, after satisfying ordinary deletion guards. Both local handovers disappear with their owning products; Commerce audience deletion is outside this proof.
