---
id: ATS-PFM-QRY-013
scope: CAP-PFM-QRY-013
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-013-01
    title: Export admission checks report authority and audience
    level: api
    proves:
      - BR-CAP-PFM-QRY-013-01
    preconditions: A report is private and callers lack either visibility or report use.
    steps: Request export under those callers and through another workspace.
    expected: Requests return the appropriate 404 or 403 without creating exports.
    negative: true
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js#answers
        a colleague who may not see the private report 404, writing nothing
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js#refuses
        a caller without platform.reports.use 403, writing nothing
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js#answers
        the report from another tenant’s path 404: it is not that tenant’s
      - >-
        services-platform:modules/queries/tests/e2e/read-tier.e2e.spec.js#is refused starting an export of a
        report with 403
      - >-
        services-platform:modules/queries/tests/e2e/report-exports.e2e.spec.js#answers 403 without
        platform.reports.use
      - TST-PFM-QRY-334
      - TST-PFM-QRY-231
      - TST-PFM-QRY-232
    provenance: test
    source: >-
      services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js#answers
      a colleague who may not see the private report 404, writing nothing
    category: permission
    binding_note: >-
      The cited suites contribute separate assertions. The complete combined example is not a single
      executable journey.
  - id: ATS-PFM-QRY-013-02
    title: Report kinds determine output formats
    level: api
    proves:
      - BR-CAP-PFM-QRY-013-02
    preconditions: 'Table, designed and dashboard reports exist.'
    steps: 'Request PDF and Excel for each, then CSV.'
    expected: 'PDF works for each, Excel works only for the eligible table form, and unsupported formats fail.'
    negative: true
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js#accepts
        an Excel export of a table report
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js#refuses
        an Excel export of an AG Studio layout at format, writing nothing
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js#refuses
        an Excel export of a dashboard, writing nothing
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js#refuses
        a CSV, a query’s format, writing nothing
      - TST-PFM-QRY-334
    provenance: test
    source: >-
      services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js#accepts
      an Excel export of a table report
    category: validation
  - id: ATS-PFM-QRY-013-03
    title: Rendering inputs preserve valid values and reject invalid ones
    level: api
    proves:
      - BR-CAP-PFM-QRY-013-03
    preconditions: An accessible report accepts print parameters.
    steps: 'Use a reserved name, an object value and whitespace-bearing text.'
    expected: Reserved and unsupported values fail; valid text remains exact.
    negative: true
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js#refuses
        the renderer’s own parameter name at parameters, writing nothing
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js#refuses
        a value that is an object, writing nothing
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js#keeps
        a value exactly as sent, untrimmed
      - TST-PFM-QRY-334
    provenance: test
    source: >-
      services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js#refuses
      the renderer’s own parameter name at parameters, writing nothing
    category: boundary
  - id: ATS-PFM-QRY-013-04
    title: Access is checked before browser startup
    level: api
    proves:
      - BR-CAP-PFM-QRY-013-04
    preconditions: Queued exports have a deleted source or a requester who lost report use.
    steps: Run both render jobs.
    expected: Both end as access lost before a browser or file is created.
    negative: true
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#fails
        a requester who may not use reports access_lost, saying so plainly
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#starts
        no browser for them
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#fails
        the export of a deleted report access_lost, starting no browser
      - TST-PFM-QRY-333
    provenance: test
    source: >-
      services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#fails
      a requester who may not use reports access_lost, saying so plainly
    category: permission
  - id: ATS-PFM-QRY-013-05
    title: Interception restricts origins and operations
    level: unit
    proves:
      - BR-CAP-PFM-QRY-013-05
    preconditions: The rendering interception fixture is ready.
    steps: 'Try console reads and writes, foreign origins, unlisted routes, another workspace and another report.'
    expected: Only the specified permitted requests continue; refusals omit query-string details from logs.
    negative: true
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/unit/services/rendering/api-interception.spec.ts#continues the
        console’s own GET
      - >-
        services-platform:modules/queries/tests/unit/services/rendering/api-interception.spec.ts#aborts a
        write to the console’s origin
      - >-
        services-platform:modules/queries/tests/unit/services/rendering/api-interception.spec.ts#aborts
        another origin, a macroservice’s or a third party’s
      - >-
        services-platform:modules/queries/tests/unit/services/rendering/api-interception.spec.ts#aborts a
        route of Platform off the allowlist, a write among them
      - >-
        services-platform:modules/queries/tests/unit/services/rendering/api-interception.spec.ts#aborts an
        allowlisted route in another tenant
      - >-
        services-platform:modules/queries/tests/unit/services/rendering/api-interception.spec.ts#aborts
        another report
      - >-
        services-platform:modules/queries/tests/unit/services/rendering/api-interception.spec.ts#logs a
        refusal with the method, origin, path and reason, never the query string
      - TST-PFM-QRY-409
    provenance: test
    source: >-
      services-platform:modules/queries/tests/unit/services/rendering/api-interception.spec.ts#continues the
      console’s own GET
    category: invariant
  - id: ATS-PFM-QRY-013-06
    title: Mid-render revocation stops file production
    level: api
    proves:
      - BR-CAP-PFM-QRY-013-06
    preconditions: A requester’s grant is revoked during page reads.
    steps: Allow requests before and after revocation.
    expected: The first permitted read works and later refusal fails the export as access lost.
    negative: true
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#refuses
        the run made after it, re-reading the grants for that request
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#fails
        the export access_lost rather than printing a page of refusals
      - >-
        react-console:acceptance/reporting/playwright/journeys/print-and-export/RPT-ACC-0350.spec.ts#RPT-ACC-0350
      - TST-PFM-QRY-333
      - TST-PFM-QRY-111
    provenance: test
    source: >-
      services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#refuses
      the run made after it, re-reading the grants for that request
    category: failure
    binding_note: >-
      The cited suites contribute separate assertions. The complete combined example is not a single
      executable journey.
  - id: ATS-PFM-QRY-013-07
    title: Rendering bounds prevent unusable files
    level: api
    proves:
      - BR-CAP-PFM-QRY-013-07
    preconditions: 'Pages fail, fail to settle or exceed the configured page cap, and an Excel response is not a workbook.'
    steps: Run each controlled render case.
    expected: 'The corresponding render, timeout or page-limit failure is recorded without storage.'
    negative: true
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#fails
        a page that reported an error render_failed, with its reason made plain
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#fails
        a page that never settled timed_out, and still closes its browser
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#fails
        a PDF past its page limit too_many_pages
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#stores
        nothing for any of them
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#fails
        an answer that is not a workbook render_failed, storing nothing of it
      - >-
        react-console:acceptance/reporting/playwright/journeys/print-and-export/RPT-ACC-0353.spec.ts#RPT-ACC-0353
      - TST-PFM-QRY-333
      - TST-PFM-QRY-113
    provenance: test
    source: >-
      services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#fails
      a page that reported an error render_failed, with its reason made plain
    category: boundary
    binding_note: >-
      The cited suites contribute separate assertions. The complete combined example is not a single
      executable journey.
  - id: ATS-PFM-QRY-013-08
    title: Completed report files retain dated names and expiry
    level: api
    proves:
      - BR-CAP-PFM-QRY-013-08
    preconditions: A PDF rendering request is queued.
    steps: Complete rendering and inspect its file record.
    expected: The name uses report and workspace date and expiry is thirty days after completion.
    negative: false
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js#names
        the file for the report and the tenant’s date, as a PDF
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#keeps
        the file thirty days from its completion, as the bucket’s rule removes it
      - TST-PFM-QRY-334
      - TST-PFM-QRY-333
    provenance: test
    source: >-
      services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js#names
      the file for the report and the tenant’s date, as a PDF
    category: transition
    binding_note: >-
      The cited suites contribute separate assertions. The complete combined example is not a single
      executable journey.
  - id: ATS-PFM-QRY-013-09
    title: File availability is independent of report deletion
    level: browser
    proves:
      - BR-CAP-PFM-QRY-013-09
    preconditions: A report has one completed and one pending export.
    steps: 'Remove the report, download the completed export and process the pending request.'
    expected: The existing file downloads while the pending render ends as access lost.
    negative: false
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        react-console:acceptance/reporting/playwright/journeys/print-and-export/RPT-ACC-0349.spec.ts#RPT-ACC-0349
      - TST-PFM-QRY-110
    provenance: test
    source: >-
      react-console:acceptance/reporting/playwright/journeys/print-and-export/RPT-ACC-0349.spec.ts#RPT-ACC-0349
    category: interaction
  - id: ATS-PFM-QRY-013-10
    title: Rendering browser isolation rejects connections
    level: browser
    proves:
      - BR-CAP-PFM-QRY-013-10
    preconditions: A print shell is opened without a session and its page attempts a WebSocket.
    steps: Load the shell and inspect the intercepted connection.
    expected: The unauthenticated shell contains no private content and the connection is refused and recorded.
    negative: false
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/unit/services/rendering/api-interception.spec.ts#records a
        WebSocket the page opened as refused
      - >-
        react-console:acceptance/reporting/playwright/journeys/print-and-export/RPT-ACC-0351.spec.ts#RPT-ACC-0351
      - 'react-console:acceptance/reporting/playwright/journeys/adversarial/RPT-ACC-0494.spec.ts#RPT-ACC-0494'
      - TST-PFM-QRY-409
      - TST-PFM-QRY-112
      - TST-PFM-QRY-027
    provenance: test
    source: >-
      services-platform:modules/queries/tests/unit/services/rendering/api-interception.spec.ts#records a
      WebSocket the page opened as refused
    category: invariant
    binding_note: >-
      The cited suites contribute separate assertions. The complete combined example is not a single
      executable journey.
  - id: ATS-PFM-QRY-013-11
    title: Internal failures retry without exposing internals
    level: api
    proves:
      - BR-CAP-PFM-QRY-013-11
    preconditions: The renderer throws an internal failure.
    steps: Process an early attempt and its final receive.
    expected: Early work retries; the final failure uses a generic internal message.
    negative: true
    data_needs: Use the existing binding’s controlled fixture data.
    bound_to:
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#throws
        on an early receive, so the queue delivers the export again
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#records
        internal on the last receive, with the sentence that never says what went wrong
      - TST-PFM-QRY-333
    provenance: test
    source: >-
      services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#throws
      on an early receive, so the queue delivers the export again
    category: failure
  - id: ATS-PFM-QRY-013-12
    title: Deleting a report separates pending and completed files
    category: interaction
    level: api
    exercises:
      - CAP-PFM-QRY-011
      - CAP-PFM-QRY-013
    proves:
      - BR-CAP-PFM-QRY-011-12
      - BR-CAP-PFM-QRY-013-09
    preconditions: A report has one completed file and a second queued rendering request.
    steps: 'Delete the report, follow the completed download and process the queued request.'
    expected: The completed file remains available until expiry and the queued render fails for lost access.
    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/e2e/query-schedules.e2e.spec.js#pauses the schedule
        report_deleted, its report gone
      - 'services-platform:docs/queries/report-rendering.md#2. The export row'
  - id: ATS-PFM-QRY-013-13
    title: A dashboard render stops after source access is revoked
    category: interaction
    level: api
    exercises:
      - CAP-PFM-QRY-012
      - CAP-PFM-QRY-013
    proves:
      - BR-CAP-PFM-QRY-012-09
      - BR-CAP-PFM-QRY-013-06
    preconditions: A dashboard has two widgets and its requester loses one source permission between print-page requests.
    steps: >-
      Start rendering, complete a permitted source read, revoke access and let the next source request
      proceed.
    expected: The later refusal ends the export without a file containing partial data or a refusal message.
    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:docs/queries/reports.md#6. Dashboards'
      - >-
        services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js#fails
        the export access_lost rather than printing a page of refusals
  - id: ATS-PFM-QRY-013-14
    title: Report files use the shared file-access boundary
    category: interaction
    level: api
    exercises:
      - CAP-PFM-QRY-013
      - CAP-PFM-QRY-014
    proves:
      - BR-CAP-PFM-QRY-013-01
      - BR-CAP-PFM-QRY-014-07
    preconditions: A requester has report use but another reader lacks export ownership and schedule authority.
    steps: 'Render a table report, follow it as the requester and request the same export as the unrelated reader.'
    expected: The requester downloads the completed file and the unrelated reader receives not found.
    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/integration/services/rendering/report-exports.integration.spec.js#answers
        a colleague who may not see the private report 404, writing nothing
      - >-
        services-platform:modules/queries/tests/integration/services/exports/query-export-routes.integration.spec.js#answers
        404 to a colleague who did not ask for it, even once the file exists
  - id: ATS-PFM-QRY-013-15
    title: A report schedule renders the current presentation
    category: interaction
    level: api
    exercises:
      - CAP-PFM-QRY-013
      - CAP-PFM-QRY-015
    proves:
      - BR-CAP-PFM-QRY-013-04
      - BR-CAP-PFM-QRY-015-12
    preconditions: A table report has a PDF schedule and its layout changes after scheduling.
    steps: 'Run the schedule, inspect its export and remove the owner’s report-use grant before the next occurrence.'
    expected: >-
      The first occurrence uses the updated presentation; the next fails without a new file or delivery and
      pauses the schedule.
    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/rendering/render-report.integration.spec.js#fails
        a requester who may not use reports access_lost, saying so plainly
      - >-
        services-platform:modules/queries/tests/e2e/query-schedules.e2e.spec.js#refuses Excel for a dashboard
        (400 at options.format)
evidence:
  - 'Pinned reference: react-console:acceptance/reporting/playwright/journeys/adversarial/RPT-ACC-0494.spec.ts'
  - >-
    Pinned reference:
    react-console:acceptance/reporting/playwright/journeys/print-and-export/RPT-ACC-0349.spec.ts
  - >-
    Pinned reference:
    react-console:acceptance/reporting/playwright/journeys/print-and-export/RPT-ACC-0350.spec.ts
  - >-
    Pinned reference:
    react-console:acceptance/reporting/playwright/journeys/print-and-export/RPT-ACC-0351.spec.ts
  - >-
    Pinned reference:
    react-console:acceptance/reporting/playwright/journeys/print-and-export/RPT-ACC-0353.spec.ts
  - 'Pinned reference: services-platform:modules/queries/tests/e2e/read-tier.e2e.spec.js'
  - 'Pinned reference: services-platform:modules/queries/tests/e2e/report-exports.e2e.spec.js'
  - >-
    Pinned reference:
    services-platform:modules/queries/tests/integration/services/rendering/render-report.integration.spec.js
  - >-
    Pinned reference:
    services-platform:modules/queries/tests/integration/services/rendering/report-exports.integration.spec.js
  - 'Pinned reference: services-platform:modules/queries/tests/unit/services/rendering/api-interception.spec.ts'
coverage:
  rule: 'gap: FND-PFM-QRY-063'
  transition: covered
  validation: covered
  permission: covered
  edge: 'gap: FND-PFM-QRY-063'
  failure: covered
  boundary: covered
  concurrency: 'gap: FND-PFM-QRY-063'
  invariant: 'gap: FND-PFM-QRY-063'
  interaction: covered
coverage_findings:
  - FND-PFM-QRY-063
transition_obligations: []
unproved_rules: []
---

# Render a report for download: Capability Test Specification

## Coverage

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

## 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 |
|---|---|
| Journey dependency | `ATS-PFM-QRY-013-09` |
| `CAP-PFM-QRY-011` | `ATS-PFM-QRY-013-12` |
| `CAP-PFM-QRY-012` | `ATS-PFM-QRY-013-13` |
| `CAP-PFM-QRY-014` | `ATS-PFM-QRY-013-14` |
| `CAP-PFM-QRY-015` | `ATS-PFM-QRY-013-15` |

## 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.
