---
id: ATS-ACC-PRD-007
scope: CAP-ACC-PRD-007
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-007-01
    title: Domain ownership restricts service writes
    level: unit
    proves:
      - BR-CAP-ACC-PRD-007-01
      - BR-CAP-ACC-PRD-007-02
      - INV-DOM-ACC-PRD-001-13
    preconditions: Commerce and Membership service callers have product fixtures.
    steps: 'Try cross-owner creation, correction, retirement, reactivation and deletion.'
    expected: Cross-owner requests fail with ownership details and permitted owner writes succeed.
    negative: true
    data_needs: Commerce and Membership service callers have product fixtures.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
        Commerce creating a membership package, naming the owner, the type and the caller
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
        a service creating an Accounting-owned type
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#lets
        Commerce create merchandise, with the capabilities its seed row declares
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
        another service replacing, retiring, reactivating or deleting the package, and lets its owner
      - >-
        services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#refuses another service,
        naming the owner, the type and the caller
      - TST-ACC-PRD-042
      - TST-ACC-PRD-066
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
      Commerce creating a membership package, naming the owner, the type and the caller
    category: permission
    binding_scope:
      - suite: TST-ACC-PRD-042
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
            Commerce creating a membership package, naming the owner, the type and the caller
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
            a service creating an Accounting-owned type
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#lets
            Commerce create merchandise, with the capabilities its seed row declares
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
            another service replacing, retiring, reactivating or deleting the package, and lets its owner
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
          Commerce creating a membership package, naming the owner, the type and the caller;
          services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
          a service creating an Accounting-owned type;
          services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#lets
          Commerce create merchandise, with the capabilities its seed row declares;
          services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
          another service replacing, retiring, reactivating or deleting the package, and lets its owner;
          services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#refuses another service,
          naming the owner, the type and the caller
      - suite: TST-ACC-PRD-066
        assertions:
          - >-
            services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#refuses another
            service, naming the owner, the type and the caller
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
          Commerce creating a membership package, naming the owner, the type and the caller;
          services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
          a service creating an Accounting-owned type;
          services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#lets
          Commerce create merchandise, with the capabilities its seed row declares;
          services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
          another service replacing, retiring, reactivating or deleting the package, and lets its owner;
          services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#refuses another service,
          naming the owner, the type and the caller
  - id: ATS-ACC-PRD-007-02
    title: Console callers can create domain products
    level: unit
    proves:
      - BR-CAP-ACC-PRD-007-03
    preconditions: The caller has console product authority.
    steps: Create an active Membership package and try an inactive Events kind.
    expected: The package succeeds and the inactive kind fails.
    negative: false
    data_needs: The caller has console product authority.
    bound_to:
      - >-
        services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#lets a console caller
        write any type (the console calls Accounting first and the domain second)
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#lets
        Membership create a membership package, and a console caller too
      - >-
        services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
        a product of a type registered inactive (the Events types) for every caller
      - >-
        services-accounting:modules/products/tests/e2e/products-shared-base.e2e.spec.js#creates a membership
        package for a console caller, answering its type, the pricing model and no custom fields
      - TST-ACC-PRD-066
      - TST-ACC-PRD-042
      - TST-ACC-PRD-029
    provenance: test
    source: >-
      services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#lets a console caller write
      any type (the console calls Accounting first and the domain second)
    category: permission
    binding_scope:
      - suite: TST-ACC-PRD-066
        assertions:
          - >-
            services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#lets a console caller
            write any type (the console calls Accounting first and the domain second)
        provenance: test
        source: >-
          services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#lets a console caller
          write any type (the console calls Accounting first and the domain second);
          services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#lets
          Membership create a membership package, and a console caller too;
          services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
          a product of a type registered inactive (the Events types) for every caller;
          services-accounting:modules/products/tests/e2e/products-shared-base.e2e.spec.js#creates a membership
          package for a console caller, answering its type, the pricing model and no custom fields
      - suite: TST-ACC-PRD-042
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#lets
            Membership create a membership package, and a console caller too
          - >-
            services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
            a product of a type registered inactive (the Events types) for every caller
        provenance: test
        source: >-
          services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#lets a console caller
          write any type (the console calls Accounting first and the domain second);
          services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#lets
          Membership create a membership package, and a console caller too;
          services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
          a product of a type registered inactive (the Events types) for every caller;
          services-accounting:modules/products/tests/e2e/products-shared-base.e2e.spec.js#creates a membership
          package for a console caller, answering its type, the pricing model and no custom fields
      - suite: TST-ACC-PRD-029
        assertions:
          - >-
            services-accounting:modules/products/tests/e2e/products-shared-base.e2e.spec.js#creates a
            membership package for a console caller, answering its type, the pricing model and no custom
            fields
        provenance: test
        source: >-
          services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#lets a console caller
          write any type (the console calls Accounting first and the domain second);
          services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#lets
          Membership create a membership package, and a console caller too;
          services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
          a product of a type registered inactive (the Events types) for every caller;
          services-accounting:modules/products/tests/e2e/products-shared-base.e2e.spec.js#creates a membership
          package for a console caller, answering its type, the pricing model and no custom fields
  - id: ATS-ACC-PRD-007-03
    title: Database and API product views agree
    level: unit
    proves:
      - BR-CAP-ACC-PRD-007-04
    preconditions: Membership has a workspace database transaction.
    steps: Save a package through the database function and read it through Accounting.
    expected: The common product and its ordered collections match between views.
    negative: false
    data_needs: Membership has a workspace database transaction.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#is
        the same product Accounting’s own persistence service reads
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#wrote
        the grid in request order, each cell as the API answers it
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#wrote
        the bundle and every feature
      - TST-ACC-PRD-032
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#is
      the same product Accounting’s own persistence service reads
    category: interaction
    binding_scope:
      - suite: TST-ACC-PRD-032
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#is
            the same product Accounting’s own persistence service reads
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#wrote
            the grid in request order, each cell as the API answers it
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#wrote
            the bundle and every feature
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#is
          the same product Accounting’s own persistence service reads;
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#wrote
          the grid in request order, each cell as the API answers it;
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#wrote
          the bundle and every feature
    exercises:
      - CAP-ACC-PRD-007
      - CAP-ACC-PRD-003
  - id: ATS-ACC-PRD-007-04
    title: Database writers require trusted session context
    level: unit
    proves:
      - BR-CAP-ACC-PRD-007-05
    preconditions: Sessions lack an application role or workspace.
    steps: Invoke the saving function from each session.
    expected: Both calls fail authorization checks.
    negative: true
    data_needs: Sessions lack an application role or workspace.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
        a transaction with no tenant as RHP04
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
        a session that is no macroservice application role (the owner, no role set) as RHP04
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
        Accounting’s own role writing a membership package: the owner rule names the owner, the type and the
        caller
      - TST-ACC-PRD-032
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
      a transaction with no tenant as RHP04
    category: boundary
    binding_scope:
      - suite: TST-ACC-PRD-032
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
            a transaction with no tenant as RHP04
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
            a session that is no macroservice application role (the owner, no role set) as RHP04
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
            Accounting’s own role writing a membership package: the owner rule names the owner, the type and
            the caller
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
          a transaction with no tenant as RHP04;
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
          a session that is no macroservice application role (the owner, no role set) as RHP04;
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
          Accounting’s own role writing a membership package: the owner rule names the owner, the type and the
          caller
  - id: ATS-ACC-PRD-007-05
    title: Database refusals match service validation
    level: unit
    proves:
      - BR-CAP-ACC-PRD-007-06
    preconditions: Membership can invoke its product-saving path.
    steps: Submit matching invalid product requests through the function and service.
    expected: Both paths return matching validation sentences and classify request or state failures appropriately.
    negative: true
    data_needs: Membership can invoke its product-saving path.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
        bundled prices above the product price with one sentence on both paths
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
        a fixed-priced product without a standard price in the base currency with one sentence
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
        two prices of one cell applying at the same time with one sentence on both paths
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
        a Donation Product with prices with one sentence on both paths
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
        the version already replaced as stale (RHP02)
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
        a replacement of a product the tenant does not have (RHP03), another tenant’s among them
      - TST-ACC-PRD-032
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
      bundled prices above the product price with one sentence on both paths
    category: validation
    binding_scope:
      - suite: TST-ACC-PRD-032
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
            bundled prices above the product price with one sentence on both paths
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
            a fixed-priced product without a standard price in the base currency with one sentence
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
            two prices of one cell applying at the same time with one sentence on both paths
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
            a Donation Product with prices with one sentence on both paths
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
            the version already replaced as stale (RHP02)
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
            a replacement of a product the tenant does not have (RHP03), another tenant’s among them
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
          bundled prices above the product price with one sentence on both paths;
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
          a fixed-priced product without a standard price in the base currency with one sentence;
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
          two prices of one cell applying at the same time with one sentence on both paths;
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
          a Donation Product with prices with one sentence on both paths;
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
          the version already replaced as stale (RHP02);
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
          a replacement of a product the tenant does not have (RHP03), another tenant’s among them
  - id: ATS-ACC-PRD-007-06
    title: Domain saves reject owned confirmation content
    level: unit
    proves:
      - BR-CAP-ACC-PRD-007-07
    preconditions: Membership can invoke its product-saving path.
    steps: Submit product-owned confirmation content and duplicate creation under an existing identity.
    expected: Both requests fail.
    negative: true
    data_needs: Membership can invoke its product-saving path.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
        a product-specific confirmation e-mail, which Accounting’s API composes
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
        a second create under the same id
      - TST-ACC-PRD-032
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
      a product-specific confirmation e-mail, which Accounting’s API composes
    category: validation
    binding_scope:
      - suite: TST-ACC-PRD-032
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
            a product-specific confirmation e-mail, which Accounting’s API composes
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
            a second create under the same id
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
          a product-specific confirmation e-mail, which Accounting’s API composes;
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
          a second create under the same id
  - id: ATS-ACC-PRD-007-07
    title: Database replacement preserves omitted scalars
    level: unit
    proves:
      - BR-CAP-ACC-PRD-007-08
    preconditions: A domain product has stored description and notes.
    steps: 'Replace it omitting description, clearing notes and supplying complete collections.'
    expected: 'Description remains, notes clear and collections use the submitted replacements.'
    negative: false
    data_needs: A domain product has stored description and notes.
    bound_to:
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#replaces
        the row and every collection as a whole, keeping an omitted property and clearing a null one
      - >-
        services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#keeps
        an omitted confirmation e-mail as stored
      - TST-ACC-PRD-032
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#replaces
      the row and every collection as a whole, keeping an omitted property and clearing a null one
    category: rule
    binding_scope:
      - suite: TST-ACC-PRD-032
        assertions:
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#replaces
            the row and every collection as a whole, keeping an omitted property and clearing a null one
          - >-
            services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#keeps
            an omitted confirmation e-mail as stored
        provenance: test
        source: >-
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#replaces
          the row and every collection as a whole, keeping an omitted property and clearing a null one;
          services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#keeps
          an omitted confirmation e-mail as stored
  - id: ATS-ACC-PRD-007-08
    title: Compare database and HTTP bundle allocation contracts
    level: unit
    proves:
      - BR-CAP-ACC-PRD-007-11
    preconditions: A domain bundle has quantity greater than one and another request omits a component price.
    steps: Save each request through the database function and compare the HTTP write path.
    expected: >-
      Database saving uses unweighted totals and a zero default; HTTP saving multiplies by quantity and
      requires a component price.
    negative: false
    data_needs: A domain bundle has quantity greater than one and another request omits a component price.
    bound_to: []
    provenance: proposed
    source: FND-ACC-PRD-034
    category: interaction
    binding_scope: []
    exercises:
      - CAP-ACC-PRD-007
      - CAP-ACC-PRD-011
      - CAP-ACC-PRD-008
  - id: ATS-ACC-PRD-007-09
    title: Retain a held audience after Commerce activation
    level: unit
    proves:
      - BR-CAP-ACC-PRD-007-12
    preconditions: A product holds a migrated audience absent from the active Commerce registry.
    steps: Submit an otherwise valid database domain replacement with that audience.
    expected: The held audience remains admissible through the database path.
    negative: false
    data_needs: A product holds a migrated audience absent from the active Commerce registry.
    bound_to: []
    provenance: proposed
    source: FND-ACC-PRD-034
    category: edge
    binding_scope: []
  - id: ATS-ACC-PRD-007-10
    title: Domain creation and retirement agree with common-product reads
    category: interaction
    level: api
    proves:
      - BR-CAP-ACC-PRD-007-04
      - BR-CAP-ACC-PRD-007-08
      - BR-CAP-ACC-PRD-002-06
      - BR-CAP-ACC-PRD-004-04
      - BR-CAP-ACC-PRD-005-02
    preconditions: An owning domain caller has a valid shared transaction context.
    steps: >-
      Create a package through the domain function, replace it at the read version, retire it, and inspect
      each result through Accounting.
    expected: Readers see the common identity and ordered grid at each version; retired ordinary replacement fails.
    negative: true
    data_needs: An owning domain caller has a valid shared transaction context.
    bound_to: []
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#is
      the same product Accounting’s own persistence service reads;
      services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#replaces
      the row and every collection as a whole, keeping an omitted property and clearing a null one;
      services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses a
      change of business_unit_id (RHF01);
      services-accounting:modules/products/tests/e2e/products.e2e.spec.js#answers 409 to replacing a retired
      product;
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#retires
      the product at version 2, changing nothing else
    exercises:
      - CAP-ACC-PRD-007
      - CAP-ACC-PRD-002
      - CAP-ACC-PRD-004
      - CAP-ACC-PRD-005
    binding_scope: []
evidence:
  - 'services-accounting:docs/accounting/products.md'
  - 'services-accounting:modules/products/services/persistence/products.ts'
  - 'services-accounting:modules/products/services/rules/product-rules.ts'
  - 'services-accounting:modules/products/tests/e2e/products-shared-base.e2e.spec.js'
  - 'services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js'
  - >-
    services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js
  - 'services-accounting:modules/products/tests/unit/rules/product-rules.spec.js'
  - >-
    rhythm-v2-docs:specs/accounting/products/design/workflows/WF-ACC-PRD-002-save-a-product-and-its-accounting-setup-from.md
  - >-
    rhythm-v2-docs:specs/accounting/products/design/workflows/WF-ACC-PRD-004-save-a-domain-product-inside-the-domain-s.md
coverage:
  rule: covered
  transition: 'gap: FND-ACC-PRD-056'
  validation: covered
  permission: covered
  edge: covered
  failure: 'gap: FND-ACC-PRD-056'
  boundary: covered
  concurrency: 'gap: FND-ACC-PRD-056'
  invariant: 'gap: FND-ACC-PRD-056'
  interaction: covered
coverage_notes:
  transition:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-056
  failure:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-056
  concurrency:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-056
  invariant:
    reason: No dedicated scenario isolates this category for the capability.
    provenance: unknown
    source: FND-ACC-PRD-056
  remaining_obligations:
    reason: >-
      A real domain extension failure, every permission context and simultaneous common-record writes remain
      unproved; the browser domain scenario performs no database write. 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-056
  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-056
related_capabilities:
  - CAP-ACC-PRD-002
  - CAP-ACC-PRD-004
  - CAP-ACC-PRD-005
workflows:
  - WF-ACC-PRD-002
  - WF-ACC-PRD-004
rule_coverage:
  - rule: BR-CAP-ACC-PRD-007-01
    scenarios:
      - ATS-ACC-PRD-007-01
  - rule: BR-CAP-ACC-PRD-007-02
    scenarios:
      - ATS-ACC-PRD-007-01
  - rule: BR-CAP-ACC-PRD-007-03
    scenarios:
      - ATS-ACC-PRD-007-02
  - rule: BR-CAP-ACC-PRD-007-04
    scenarios:
      - ATS-ACC-PRD-007-03
      - ATS-ACC-PRD-007-10
  - rule: BR-CAP-ACC-PRD-007-05
    scenarios:
      - ATS-ACC-PRD-007-04
  - rule: BR-CAP-ACC-PRD-007-06
    scenarios:
      - ATS-ACC-PRD-007-05
  - rule: BR-CAP-ACC-PRD-007-07
    scenarios:
      - ATS-ACC-PRD-007-06
  - rule: BR-CAP-ACC-PRD-007-08
    scenarios:
      - ATS-ACC-PRD-007-07
      - ATS-ACC-PRD-007-10
  - rule: BR-CAP-ACC-PRD-007-11
    scenarios:
      - ATS-ACC-PRD-007-08
  - rule: BR-CAP-ACC-PRD-007-12
    scenarios:
      - ATS-ACC-PRD-007-09
interaction_coverage:
  - scenario: ATS-ACC-PRD-007-03
    exercises:
      - CAP-ACC-PRD-007
      - CAP-ACC-PRD-003
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#is
      the same product Accounting’s own persistence service reads
  - scenario: ATS-ACC-PRD-007-08
    exercises:
      - CAP-ACC-PRD-007
      - CAP-ACC-PRD-011
      - CAP-ACC-PRD-008
    provenance: proposed
    source: FND-ACC-PRD-034
  - scenario: ATS-ACC-PRD-007-10
    exercises:
      - CAP-ACC-PRD-007
      - CAP-ACC-PRD-002
      - CAP-ACC-PRD-004
      - CAP-ACC-PRD-005
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#is
      the same product Accounting’s own persistence service reads;
      services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#replaces
      the row and every collection as a whole, keeping an omitted property and clearing a null one;
      services-accounting:modules/products/tests/integration/db/products.table.integration.spec.js#refuses a
      change of business_unit_id (RHF01);
      services-accounting:modules/products/tests/e2e/products.e2e.spec.js#answers 409 to replacing a retired
      product;
      services-accounting:modules/products/tests/integration/services/persistence/products.integration.spec.js#retires
      the product at version 2, changing nothing else
state_coverage:
  - model: STATE-ACC-PRD-004
    from: 'off'
    to: product-owned
    scenarios: []
    finding: FND-ACC-PRD-056
    provenance: unknown
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#saved
      its own template in Platform, owned by the product, once
  - model: STATE-ACC-PRD-004
    from: product-owned
    to: product-owned
    scenarios: []
    finding: FND-ACC-PRD-056
    provenance: unknown
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#keeps
      one template, as its new version
  - model: STATE-ACC-PRD-004
    from: product-owned
    to: shared
    scenarios: []
    finding: FND-ACC-PRD-056
    provenance: unknown
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#clears
      the product’s own template when it switches to a shared one
  - model: STATE-ACC-PRD-004
    from: product-owned
    to: 'off'
    scenarios: []
    finding: FND-ACC-PRD-056
    provenance: unknown
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#archives
      the product’s own template in Platform
  - model: STATE-ACC-PRD-004
    from: 'off'
    to: shared
    scenarios: []
    finding: FND-ACC-PRD-056
    provenance: unknown
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.features.integration.spec.js#names
      a shared template of the purpose
  - model: STATE-ACC-PRD-004
    from: shared
    to: 'off'
    scenarios: []
    finding: FND-ACC-PRD-056
    provenance: unknown
    source: 'services-accounting:modules/products/services/persistence/products.ts:templateChangeOf'
  - model: STATE-ACC-PRD-004
    from: shared
    to: product-owned
    scenarios: []
    finding: FND-ACC-PRD-056
    provenance: unknown
    source: 'services-accounting:modules/products/services/persistence/products.ts:templateChangeOf'
permission_coverage:
  - key: accounting.products.create
    where_checked: service
    scope: record
    scenarios:
      - ATS-ACC-PRD-007-01
      - ATS-ACC-PRD-007-02
    finding: null
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
      Commerce creating a membership package, naming the owner, the type and the caller;
      services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
      a service creating an Accounting-owned type;
      services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#lets a console caller write
      any type (the console calls Accounting first and the domain second);
      services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
      a transaction with no tenant as RHP04
  - key: accounting.products.update
    where_checked: service
    scope: record
    scenarios:
      - ATS-ACC-PRD-007-01
      - ATS-ACC-PRD-007-02
    finding: null
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
      Commerce creating a membership package, naming the owner, the type and the caller;
      services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
      a service creating an Accounting-owned type;
      services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#lets a console caller write
      any type (the console calls Accounting first and the domain second);
      services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
      a transaction with no tenant as RHP04
  - key: accounting.products.delete
    where_checked: service
    scope: record
    scenarios:
      - ATS-ACC-PRD-007-01
      - ATS-ACC-PRD-007-02
    finding: null
    provenance: proposed
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
      Commerce creating a membership package, naming the owner, the type and the caller;
      services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
      a service creating an Accounting-owned type;
      services-accounting:modules/products/tests/unit/rules/product-rules.spec.js#lets a console caller write
      any type (the console calls Accounting first and the domain second);
      services-accounting:modules/products/tests/integration/db/save-product-function.integration.spec.js#refuses
      a transaction with no tenant as RHP04
invariant_coverage:
  - invariant: INV-DOM-ACC-PRD-001-09
    scenarios:
      - ATS-ACC-PRD-007-08
    finding: FND-ACC-PRD-056
    provenance: proposed
    source: >-
      services-accounting:modules/products/services/rules/product-rules.ts:bundleTotalsProblem;
      services-accounting:db/migrations/20261019201047_product_lock_and_held_bundle_components.sql:accounting.save_product
    note: >-
      The mapped scenario exercises the related behavior; the complete invariant statement still needs
      dedicated proof.
  - invariant: INV-DOM-ACC-PRD-001-13
    scenarios:
      - ATS-ACC-PRD-007-01
    finding: null
    provenance: test
    source: >-
      services-accounting:modules/products/tests/integration/services/persistence/products.shared-base.integration.spec.js#refuses
      another service replacing, retiring, reactivating or deleting the package, and lets its owner
---

# Keep domain products under their owning application: 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. A real domain extension failure, every permission context and simultaneous common-record writes remain unproved; the browser domain scenario performs no database write. Workflow edges not named by a scenario remain in this finding rather than gaining a binding from shared workflow membership.

## Interactions With Related Capabilities

Domain creation and retirement agree with common-product reads. An owning domain caller has a valid shared transaction context. Create a package through the domain function, replace it at the read version, retire it, and inspect each result through Accounting. Readers see the common identity and ordered grid at each version; retired ordinary replacement fails.
