---
id: ATS-PFM-QRY-008
scope: CAP-PFM-QRY-008
product_area: platform
module: queries
revision: 2
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
  rhythm-v2-docs: 99376625d3e7ac26936413cfc31a88fba6562464
scenarios:
  - id: ATS-PFM-QRY-008-01
    title: Recipes advertise availability without hiding subjects
    level: api
    proves:
      - BR-CAP-PFM-QRY-008-01
    preconditions: Recipes cover different datasets and include a retired entry.
    steps: List with one dataset grant and with none.
    expected: The same ordered active entries carry input declarations and appropriate authorization flags.
    negative: false
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#answers the recipes under the
        name of what it holds, by category then name
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#marks a recipe of a dataset this
        caller may query as authorized, and one it may not as not
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#leaves a retired recipe out of
        the list
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#answers the same recipes to a
        caller with no dataset at all, every one of them unauthorized
      - TST-PFM-QRY-229
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#answers the recipes under the name
      of what it holds, by category then name
    category: rule
  - id: ATS-PFM-QRY-008-02
    title: Joined recipe use checks every dataset
    level: api
    proves:
      - BR-CAP-PFM-QRY-008-02
    preconditions: A recipe joins a subject unavailable to the caller.
    steps: Create its draft and run it before and after adding the missing grant.
    expected: Both initially return 403 and then succeed with access.
    negative: true
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#refuses a draft of a dataset
        this caller may not query as 403
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#refuses the draft as 403 to a
        caller holding everything but crm.contact-types.read
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#refuses the run as 403 to that
        caller
      - TST-PFM-QRY-229
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#refuses a draft of a dataset this
      caller may not query as 403
    category: permission
  - id: ATS-PFM-QRY-008-03
    title: Draft refusal follows the specified order
    level: api
    proves:
      - BR-CAP-PFM-QRY-008-03
    preconditions: An unknown recipe and a recipe requiring input are requested.
    steps: Draft the unknown recipe and omit the known recipe’s required value.
    expected: Absence returns 404 and missing input returns a labeled 400 problem.
    negative: true
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#tells a caller that a recipe
        nobody registered does not exist, as 404
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#refuses a missing required
        parameter as 400, naming it and the label its form shows
      - TST-PFM-QRY-229
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#tells a caller that a recipe
      nobody registered does not exist, as 404
    category: validation
  - id: ATS-PFM-QRY-008-04
    title: Released recipes cannot rewrite saved derivatives
    level: api
    proves:
      - BR-CAP-PFM-QRY-008-04
      - INV-DOM-PFM-QRY-002-08
    preconditions: A version-one recipe draft has been saved.
    steps: Register a later version and reopen the saved question.
    expected: Origin remains recorded and the saved definition stays unchanged.
    negative: false
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#records which recipe and which
        version the draft came from
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#stores the definition the person
        sent, not the recipe’s template
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#leaves the saved query untouched
        when the recipe is registered again at version 2
      - TST-PFM-QRY-229
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#records which recipe and which
      version the draft came from
    category: invariant
  - id: ATS-PFM-QRY-008-05
    title: Origins may outlive retired recipes
    level: api
    proves:
      - BR-CAP-PFM-QRY-008-05
    preconditions: One origin recipe never existed and another was retired.
    steps: Save definitions naming each origin.
    expected: The nonexistent origin is rejected; the retired registered origin remains acceptable.
    negative: true
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#refuses a save naming a recipe
        nobody ever registered as 400
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#accepts a save naming a recipe
        that has since been retired, because provenance is not a link
      - TST-PFM-QRY-229
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#refuses a save naming a recipe
      nobody ever registered as 400
    category: edge
  - id: ATS-PFM-QRY-008-06
    title: Recipe refinements keep recipe criteria
    level: api
    proves:
      - BR-CAP-PFM-QRY-008-06
    preconditions: A recipe selects active contacts.
    steps: Refine to a surname and try an unsupported refinement component.
    expected: The result remains active contacts of that surname and the unsupported input is refused.
    negative: true
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#ANDs the refinement’s criteria
        with the recipe’s: exactly the active contacts who are Smiths
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#keeps the recipe’s own criteria
        under a refinement, so a run never widens it
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#refuses a refinement naming what
        a run may not change as 400
      - TST-PFM-QRY-229
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#ANDs the refinement’s criteria
      with the recipe’s: exactly the active contacts who are Smiths
    category: rule
  - id: ATS-PFM-QRY-008-07
    title: Recipe validation prevents partial registration
    level: unit
    proves:
      - BR-CAP-PFM-QRY-008-07
    preconditions: Declarations contain the documented invalid model cases.
    steps: Register each declaration set.
    expected: Each response identifies a problem and no partial library is written.
    negative: true
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/integration/services/recipe-registration/register-query-recipes.integration.spec.js#refuses
        a recipe whose dataset nobody registered for queries
      - >-
        services-platform:modules/queries/tests/integration/services/recipe-registration/register-query-recipes.integration.spec.js#refuses
        a recipe naming a field the dataset does not have
      - >-
        services-platform:modules/queries/tests/integration/services/recipe-registration/register-query-recipes.integration.spec.js#refuses
        a recipe naming the field a tenant’s configuration row defines, saying only that tenant has it
      - >-
        services-platform:modules/queries/tests/integration/services/recipe-registration/register-query-recipes.integration.spec.js#refuses
        a joined recipe naming a field of an instance its model never joins
      - TST-PFM-QRY-326
    provenance: test
    source: >-
      services-platform:modules/queries/tests/integration/services/recipe-registration/register-query-recipes.integration.spec.js#refuses
      a recipe whose dataset nobody registered for queries
    category: validation
  - id: ATS-PFM-QRY-008-08
    title: Content revisions advance recipe versions
    level: unit
    proves:
      - BR-CAP-PFM-QRY-008-08
    preconditions: A recipe is already registered.
    steps: Resubmit changed content with its existing version.
    expected: Registration rejects the unchanged version.
    negative: true
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/integration/services/recipe-registration/register-query-recipes.integration.spec.js#refuses
        a recipe whose content changed but whose version did not
      - TST-PFM-QRY-326
    provenance: test
    source: >-
      services-platform:modules/queries/tests/integration/services/recipe-registration/register-query-recipes.integration.spec.js#refuses
      a recipe whose content changed but whose version did not
    category: concurrency
  - id: ATS-PFM-QRY-008-09
    title: Recipe retirement follows release content
    level: unit
    proves:
      - BR-CAP-PFM-QRY-008-09
    preconditions: An application library has existing entries.
    steps: 'Register unchanged content, omit an entry and later reintroduce it.'
    expected: Unchanged content writes nothing; removal retires and reintroduction restores the entry.
    negative: false
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/integration/services/recipe-registration/register-query-recipes.integration.spec.js#writes
        nothing for a manifest that declares exactly what is stored, and answers them as unchanged
      - >-
        services-platform:modules/queries/tests/integration/services/recipe-registration/register-query-recipes.integration.spec.js#retires
        a recipe the manifest no longer declares, and leaves the rest alone
      - >-
        services-platform:modules/queries/tests/integration/services/recipe-registration/register-query-recipes.integration.spec.js#revives
        the row a retired recipe always was when the manifest declares it again
      - TST-PFM-QRY-326
    provenance: test
    source: >-
      services-platform:modules/queries/tests/integration/services/recipe-registration/register-query-recipes.integration.spec.js#writes
      nothing for a manifest that declares exactly what is stored, and answers them as unchanged
    category: transition
  - id: ATS-PFM-QRY-008-10
    title: Personal recipe values require a user field
    level: unit
    proves:
      - BR-CAP-PFM-QRY-008-11
    preconditions: A recipe uses the current-person token on a non-user field.
    steps: Register the recipe.
    expected: The refusal identifies that field’s incompatible meaning.
    negative: true
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/integration/services/execute/current-user-criterion.integration.spec.js#refuses
        at registration the same recipe written on a field that holds no user, naming the field
      - TST-PFM-QRY-270
    provenance: test
    source: >-
      services-platform:modules/queries/tests/integration/services/execute/current-user-criterion.integration.spec.js#refuses
      at registration the same recipe written on a field that holds no user, naming the field
    category: validation
  - id: ATS-PFM-QRY-008-11
    title: A retained recipe derivative survives a later release
    category: interaction
    level: api
    exercises:
      - CAP-PFM-QRY-006
      - CAP-PFM-QRY-008
    proves:
      - BR-CAP-PFM-QRY-006-10
      - BR-CAP-PFM-QRY-008-04
    preconditions: A staff member saves a concrete contact recipe draft as a private question.
    steps: Register a later recipe release changing its criteria and rerun the saved question.
    expected: The retained definition and origin version remain unchanged; a new draft uses the newer release.
    negative: false
    data_needs: >-
      Use an isolated workspace with the described source records, access grants and a surviving control
      workspace.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-platform:modules/queries/tests/e2e/saved-queries.e2e.spec.js#refuses a body whose definition
        cannot be run as written as 400
      - >-
        services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js#leaves the saved query untouched
        when the recipe is registered again at version 2
  - id: ATS-PFM-QRY-008-12
    title: A retired recipe leaves a view repairable
    category: interaction
    level: api
    exercises:
      - CAP-PFM-QRY-008
      - CAP-PFM-QRY-009
    proves:
      - BR-CAP-PFM-QRY-008-09
      - BR-CAP-PFM-QRY-009-04
    preconditions: A person retains a contact view anchored to an active recipe.
    steps: 'Release a manifest without the recipe, read the retained view and try saving it again.'
    expected: The read identifies the missing anchor; a new save is refused until the recipe becomes valid again.
    negative: true
    data_needs: >-
      Use an isolated workspace with the described source records, access grants and a surviving control
      workspace.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-platform:modules/queries/tests/integration/services/recipe-registration/register-query-recipes.integration.spec.js#retires
        a recipe the manifest no longer declares, and leaves the rest alone
      - >-
        services-platform:modules/explorer/tests/integration/services/definitions/recipe-anchors.integration.spec.js#answers
        recipe_missing for a recipe that has gone, rather than an error
evidence:
  - 'Pinned reference: services-platform:modules/queries/tests/e2e/query-recipes.e2e.spec.js'
  - >-
    Pinned reference:
    services-platform:modules/queries/tests/integration/services/execute/current-user-criterion.integration.spec.js
  - >-
    Pinned reference:
    services-platform:modules/queries/tests/integration/services/recipe-registration/register-query-recipes.integration.spec.js
coverage:
  rule: covered
  transition: 'gap: FND-PFM-QRY-058'
  validation: covered
  permission: covered
  edge: covered
  failure: 'gap: FND-PFM-QRY-058'
  boundary: 'gap: FND-PFM-QRY-058'
  concurrency: covered
  invariant: covered
  interaction: covered
coverage_findings:
  - FND-PFM-QRY-058
transition_obligations:
  - state: STATE-PFM-QRY-004
    transition: 1
    from: active
    to: active
    trigger: Registration supplies changed recipe content.
    source: >-
      services-platform:modules/queries/services/recipe-registration/register-query-recipes.ts:registerQueryRecipes
    gap: FND-PFM-QRY-058
  - state: STATE-PFM-QRY-004
    transition: 2
    from: active
    to: retired
    trigger: The new release omits the recipe.
    source: 'services-platform:modules/queries/db/query-recipes.table.ts (retired_at)'
    gap: FND-PFM-QRY-058
  - state: STATE-PFM-QRY-004
    transition: 3
    from: retired
    to: active
    trigger: A later release includes the retired recipe.
    source: 'services-platform:modules/queries/db/query-recipes.table.ts'
    gap: FND-PFM-QRY-058
unproved_rules: []
---

# Begin a question from an application recipe: Capability Test Specification

## Coverage

| Rule | Scenario or Finding |
|---|---|
| `BR-CAP-PFM-QRY-008-01` | `ATS-PFM-QRY-008-01` |
| `BR-CAP-PFM-QRY-008-02` | `ATS-PFM-QRY-008-02` |
| `BR-CAP-PFM-QRY-008-03` | `ATS-PFM-QRY-008-03` |
| `BR-CAP-PFM-QRY-008-04` | `ATS-PFM-QRY-008-04`, `ATS-PFM-QRY-008-11` |
| `BR-CAP-PFM-QRY-008-05` | `ATS-PFM-QRY-008-05` |
| `BR-CAP-PFM-QRY-008-06` | `ATS-PFM-QRY-008-06` |
| `BR-CAP-PFM-QRY-008-07` | `ATS-PFM-QRY-008-07` |
| `BR-CAP-PFM-QRY-008-08` | `ATS-PFM-QRY-008-08` |
| `BR-CAP-PFM-QRY-008-09` | `ATS-PFM-QRY-008-09`, `ATS-PFM-QRY-008-12` |
| `BR-CAP-PFM-QRY-008-11` | `ATS-PFM-QRY-008-10` |

## Interactions With Related Capabilities

The combined examples change a source, its audience or its retained state before checking the dependent outcome. Unbound examples remain proposed, and the coverage finding retains design obligations that these examples do not establish.

| Related Capability | Scenario |
|---|---|
| `CAP-PFM-QRY-006` | `ATS-PFM-QRY-008-11` |
| `CAP-PFM-QRY-009` | `ATS-PFM-QRY-008-12` |

## Evidence and Binding Limits

The source revisions pin the inspected assertions. A test binding identifies written assertions, and does not establish a successful run or approval of the expected behavior.
