---
id: ATS-PFM-SEC-002
scope: CAP-PFM-SEC-002
product_area: platform
module: security
revision: 3
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-PFM-SEC-002-01
    title: Workspace reach across customer boundaries
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-01
    preconditions: Prepare two customers with a workspace each.
    steps: Read and list workspaces using one customer’s administrator.
    expected: The list contains only reachable workspaces; another customer’s default returns 404.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#lists no tenant of another
        customer, which is what the reach reduction means
      - TST-PFM-SEC-230
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#answers 404 for another
        customer's default tenant, so the route cannot be walked
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#lists no tenant of another
      customer, which is what the reach reduction means
    category: boundary
    test_references:
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#lists no tenant of another
        customer, which is what the reach reduction means
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#answers 404 for another
        customer's default tenant, so the route cannot be walked
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#lists no tenant of another
        customer, which is what the reach reduction means
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#lists no tenant of another
        customer, which is what the reach reduction means
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-002-02
    title: The HQ authority for status changes
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-02
    preconditions: Prepare an implementation workspace.
    steps: 'Attempt console patch and replacement status changes, then an HQ staff patch.'
    expected: Console changes fail with HQ guidance and leave status intact; the staff patch succeeds.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a customer
        administrator the same change on the console route, naming where it is made
      - TST-PFM-SEC-230
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-deletion-requests.e2e.spec.js#may not
        take it live through a replacement either
      - TST-PFM-SEC-225
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-deletion-requests.e2e.spec.js#lets Rhythm
        staff change the same status
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#answers 200 and the live
        status to the HQ patch
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a customer
      administrator the same change on the console route, naming where it is made
    category: permission
    test_references:
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a customer
        administrator the same change on the console route, naming where it is made
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-deletion-requests.e2e.spec.js#may not
        take it live through a replacement either
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-deletion-requests.e2e.spec.js#lets Rhythm
        staff change the same status
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#answers 200 and the live
        status to the HQ patch
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a customer
        administrator the same change on the console route, naming where it is made
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a customer
        administrator the same change on the console route, naming where it is made
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-002-03
    title: Lifecycle ownership on ordinary writes
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-03
      - INV-DOM-PFM-SEC-002-03
      - INV-DOM-PFM-SEC-002-04
    preconditions: Prepare an active workspace.
    steps: >-
      Send lifecycle values in a patch and replacement, then attempt a status prohibited by
      lifecycle constraints.
    expected: >-
      Client lifecycle values have no effect; the prohibited status fails without changing the
      record.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#leaves the lifecycle state
        where the server put it after such a patch
      - TST-PFM-SEC-230
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#refuses
        a status change the lifecycle forbids, by the rule the database holds
      - TST-PFM-SEC-253
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#leaves
        the tenant unchanged when it refuses that status change
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#leaves the lifecycle state
      where the server put it after such a patch
    category: invariant
    test_references:
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#leaves the lifecycle state
        where the server put it after such a patch
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#refuses
        a status change the lifecycle forbids, by the rule the database holds
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#leaves
        the tenant unchanged when it refuses that status change
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#leaves the lifecycle state
        where the server put it after such a patch
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#leaves the lifecycle state
        where the server put it after such a patch
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-002-04
    title: Accepted time-zone forms
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-04
      - INV-DOM-PFM-SEC-002-05
    preconditions: Prepare a workspace to create and edit.
    steps: 'Try an abbreviation, offset, Etc location and wrong case; also omit the zone.'
    expected: Invalid forms return 400 without storage changes; omission uses Eastern time.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a time zone given as
        an abbreviation as 400
      - TST-PFM-SEC-230
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a time zone given as
        a fixed offset as 400
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses an IANA zone spelled
        in another case as 400
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#answers the system default,
        Eastern
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#leaves the stored zone as
        the last accepted one
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a time zone given as
      an abbreviation as 400
    category: validation
    test_references:
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a time zone given as
        an abbreviation as 400
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a time zone given as
        a fixed offset as 400
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses an IANA zone spelled
        in another case as 400
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#answers the system default,
        Eastern
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#leaves the stored zone as
        the last accepted one
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a time zone given as
        an abbreviation as 400
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a time zone given as
        an abbreviation as 400
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-002-05
    title: Stable acronym suffixing
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-05
    preconditions: Prepare a workspace with an acronym.
    steps: Create it and save its name twice.
    expected: The saved name contains one acronym suffix after both updates.
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#suffixes
        it in the row, not only in the answer
      - TST-PFM-SEC-253
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#does
        not double an existing suffix on a later update
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#suffixes
      it in the row, not only in the answer
    category: rule
    test_references:
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#suffixes
        it in the row, not only in the answer
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#does
        not double an existing suffix on a later update
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#suffixes
        it in the row, not only in the answer
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#suffixes
        it in the row, not only in the answer
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-002-06
    title: Sandbox parent constraints
    level: unit
    proves:
      - BR-CAP-PFM-SEC-002-06
      - INV-DOM-PFM-SEC-002-02
    preconditions: Prepare a customer-type workspace and sandbox.
    steps: >-
      Try absent, wrong-type and cross-customer parents, nested sandboxes and a customer change on
      the parent.
    expected: Invalid relationships fail at the database; a same-customer pair succeeds.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/integration/db/tenants.table.integration.spec.js#refuses
        a sandbox that names no parent by tenants_sandbox_parent_check
      - TST-PFM-SEC-232
      - >-
        services-platform:modules/tenants/tests/integration/db/tenants.table.integration.spec.js#refuses
        a sandbox whose parent is not of type customer
      - >-
        services-platform:modules/tenants/tests/integration/db/tenants.table.integration.spec.js#refuses
        a sandbox of a sandbox, so a sandbox is never a parent
      - >-
        services-platform:modules/tenants/tests/integration/db/tenants.table.integration.spec.js#refuses
        moving a tenant that has sandboxes to another customer, which would split the pair
      - >-
        services-platform:modules/tenants/tests/integration/db/tenants.table.integration.spec.js#accepts
        a sandbox of a customer tenant of its own customer, the negative control
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/db/tenants.table.integration.spec.js#refuses
      a sandbox that names no parent by tenants_sandbox_parent_check
    category: invariant
    test_references:
      - >-
        services-platform:modules/tenants/tests/integration/db/tenants.table.integration.spec.js#refuses
        a sandbox that names no parent by tenants_sandbox_parent_check
      - >-
        services-platform:modules/tenants/tests/integration/db/tenants.table.integration.spec.js#refuses
        a sandbox whose parent is not of type customer
      - >-
        services-platform:modules/tenants/tests/integration/db/tenants.table.integration.spec.js#refuses
        a sandbox of a sandbox, so a sandbox is never a parent
      - >-
        services-platform:modules/tenants/tests/integration/db/tenants.table.integration.spec.js#refuses
        moving a tenant that has sandboxes to another customer, which would split the pair
      - >-
        services-platform:modules/tenants/tests/integration/db/tenants.table.integration.spec.js#accepts
        a sandbox of a customer tenant of its own customer, the negative control
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/db/tenants.table.integration.spec.js#refuses
        a sandbox that names no parent by tenants_sandbox_parent_check
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/db/tenants.table.integration.spec.js#refuses
        a sandbox that names no parent by tenants_sandbox_parent_check
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-002-07
    title: The dedicated commercial-account action
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-07
      - INV-DOM-PFM-SEC-002-06
    preconditions: Prepare a commercially linked workspace.
    steps: >-
      Attempt ordinary link edits and replacement omission; perform and repeat a versioned staff
      move, then clear the link.
    expected: >-
      Ordinary changes return 400; the move succeeds once and then returns 409; a customer
      administrator receives 403; moving requests licence synchronization, while clearing requests
      none.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a patch
        that moves the link as 400, even for Rhythm staff in their own editor
      - TST-PFM-SEC-227
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a
        replacement that simply drops the field, because omitting it would clear the link
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a second
        move at the version already written as 409
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses an
        administrator of the customer as 403, because this is a system route
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#asks for the
        company it moved the tenant to to be read from HubSpot
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#asks for nothing
        when the link is cleared, because there is no company to read
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a patch
      that moves the link as 400, even for Rhythm staff in their own editor
    category: permission
    test_references:
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a patch
        that moves the link as 400, even for Rhythm staff in their own editor
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a
        replacement that simply drops the field, because omitting it would clear the link
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a second
        move at the version already written as 409
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses an
        administrator of the customer as 403, because this is a system route
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#asks for the
        company it moved the tenant to to be read from HubSpot
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#asks for nothing
        when the link is cleared, because there is no company to read
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a patch
        that moves the link as 400, even for Rhythm staff in their own editor
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a patch
        that moves the link as 400, even for Rhythm staff in their own editor
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-002-08
    title: Version and lock refusals; add a valid clearing proof
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-08
    preconditions: Read a workspace at version n with a populated optional field.
    steps: >-
      Replace at n omitting that field, repeat at n, and replace an update-locked record; read back
      the current field spelling.
    expected: >-
      Stale and locked replacements fail. The proposed clearing check must assert the current stored
      field is absent or cleared, rather than inspect an obsolete property name.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to: []
    provenance: proposed
    source: FND-PFM-SEC-035
    category: concurrency
    test_references: []
    action_evidence:
      provenance: proposed
      source: FND-PFM-SEC-035
    assertion_evidence:
      provenance: proposed
      source: FND-PFM-SEC-035
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-002-09
    title: Workspace availability by route and caller
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-09
      - INV-DOM-PFM-SEC-002-07
    preconditions: 'Prepare disabled, provisioning, loading and deleting workspaces.'
    steps: >-
      Request ordinary routes as customer users and staff, HQ routes as staff, and an initial-import
      route during loading.
    expected: >-
      Ordinary blocked requests return 403 with the generic refusal; HQ staff pass subject to
      read-only deletion, and loading permits the authorized import route.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is refused
        403 in a tenant whose customer has been cut off
      - TST-PFM-SEC-223
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is refused
        403 in a tenant that is still being provisioned
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is refused
        403 in a tenant whose initial data import is open
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is refused
        the same way in a tenant being deleted, so the exemption is not a console route’s to grant
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#may not
        write to a tenant being deleted, which the same caller being served above is the premise for
      - >-
        services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#answers
        the rule for every combination of lifecycle state, status and caller
      - TST-PFM-SEC-266
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is refused
      403 in a tenant whose customer has been cut off
    category: boundary
    test_references:
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is refused
        403 in a tenant whose customer has been cut off
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is refused
        403 in a tenant that is still being provisioned
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is refused
        403 in a tenant whose initial data import is open
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is refused
        the same way in a tenant being deleted, so the exemption is not a console route’s to grant
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#may not
        write to a tenant being deleted, which the same caller being served above is the premise for
      - >-
        services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#answers
        the rule for every combination of lifecycle state, status and caller
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is refused
        403 in a tenant whose customer has been cut off
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is refused
        403 in a tenant whose customer has been cut off
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-002-10
    title: Direct deletion gives recovery guidance
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-11
    preconditions: Prepare an existing workspace.
    steps: Call its direct delete operation.
    expected: 'The operation returns 405, points to deletion requests and leaves the workspace unchanged.'
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#answers the gone status the
        error contract can express
      - TST-PFM-SEC-230
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#points the caller at the
        deletion request route
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#leaves the tenant exactly as
        it was, which is the point of refusing
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#answers the gone status the
      error contract can express
    category: transition
    test_references:
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#answers the gone status the
        error contract can express
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#points the caller at the
        deletion request route
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#leaves the tenant exactly as
        it was, which is the point of refusing
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#answers the gone status the
        error contract can express
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#answers the gone status the
        error contract can express
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-002-11
    title: 'HQ workspace search, filtering and pagination'
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-12
    preconditions: Prepare workspaces for several customers.
    steps: >-
      Search an identifier in different case, filter by type, follow a cursor and call as a customer
      administrator.
    expected: >-
      Search and filtering select the expected records, the cursor continues the list and the
      administrator receives 403.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenants.e2e.spec.js#finds a tenant by its id,
        the association's domain, whatever its case
      - TST-PFM-SEC-222
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenants.e2e.spec.js#answers only the tenants
        of the type asked for
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenants.e2e.spec.js#answers a cursor that
        resumes the list where the page stopped
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenants.e2e.spec.js#refuses an administrator
        of a customer, holding every key at that customer, as 403
      - >-
        services-platform:modules/tenants/tests/unit/aws/api/hq-tenant-list-mapper.spec.ts#is at
        most 100 tenants, whatever the limit asked for
      - TST-PFM-SEC-264
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/hq-tenants.e2e.spec.js#finds a tenant by its id,
      the association's domain, whatever its case
    category: boundary
    test_references:
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenants.e2e.spec.js#finds a tenant by its id,
        the association's domain, whatever its case
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenants.e2e.spec.js#answers only the tenants
        of the type asked for
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenants.e2e.spec.js#answers a cursor that
        resumes the list where the page stopped
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenants.e2e.spec.js#refuses an administrator
        of a customer, holding every key at that customer, as 403
      - >-
        services-platform:modules/tenants/tests/unit/aws/api/hq-tenant-list-mapper.spec.ts#is at
        most 100 tenants, whatever the limit asked for
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/hq-tenants.e2e.spec.js#finds a tenant by its id,
        the association's domain, whatever its case
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/hq-tenants.e2e.spec.js#finds a tenant by its id,
        the association's domain, whatever its case
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-002-12
    title: Private staff shortcuts and list limits
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-13
    preconditions: Prepare two staff identities.
    steps: 'Pin twenty-one workspaces, open eleven and compare the two identities’ lists.'
    expected: >-
      The extra pin fails; only ten recent entries remain, pins are preserved and lists do not
      disclose each other’s entries.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/staff-tenant-shortcuts.integration.spec.js#refuses
        the pin that would be one too many, naming the maximum
      - TST-PFM-SEC-243
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/staff-tenant-shortcuts.integration.spec.js#drops
        the oldest one it opened
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/staff-tenant-shortcuts.integration.spec.js#never
        drops a pinned tenant that has fallen out of the newest ones
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-shortcuts.e2e.spec.js#never answers
        the administrator the tenant the other person pinned
      - TST-PFM-SEC-221
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-shortcuts.e2e.spec.js#refuses an
        administrator of a customer reading the home page as 403, because these are system routes
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/persistence/staff-tenant-shortcuts.integration.spec.js#refuses
      the pin that would be one too many, naming the maximum
    category: edge
    test_references:
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/staff-tenant-shortcuts.integration.spec.js#refuses
        the pin that would be one too many, naming the maximum
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/staff-tenant-shortcuts.integration.spec.js#drops
        the oldest one it opened
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/staff-tenant-shortcuts.integration.spec.js#never
        drops a pinned tenant that has fallen out of the newest ones
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-shortcuts.e2e.spec.js#never answers
        the administrator the tenant the other person pinned
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-shortcuts.e2e.spec.js#refuses an
        administrator of a customer reading the home page as 403, because these are system routes
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/persistence/staff-tenant-shortcuts.integration.spec.js#refuses
        the pin that would be one too many, naming the maximum
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/persistence/staff-tenant-shortcuts.integration.spec.js#refuses
        the pin that would be one too many, naming the maximum
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-002-13
    title: Dedicated and shared sender information
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-14
    preconditions: Prepare one dedicated sender and one shared-sender workspace.
    steps: Read sender information as staff and as the customer administrator.
    expected: >-
      Staff receive DNS and verification details or a null shared-sender result; the administrator
      receives 403.
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-email-sender.e2e.spec.js#answers the DNS
        records the customer must publish, so a support person can read them out
      - TST-PFM-SEC-226
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-email-sender.e2e.spec.js#answers null
        rather than a record, which is how it says the shared sender
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-email-sender.e2e.spec.js#refuses an
        administrator of the tenant’s own customer as 403, because this is a system route
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-email-sender.e2e.spec.js#answers the DNS
      records the customer must publish, so a support person can read them out
    category: rule
    test_references:
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-email-sender.e2e.spec.js#answers the DNS
        records the customer must publish, so a support person can read them out
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-email-sender.e2e.spec.js#answers null
        rather than a record, which is how it says the shared sender
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-email-sender.e2e.spec.js#refuses an
        administrator of the tenant’s own customer as 403, because this is a system route
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenant-email-sender.e2e.spec.js#answers the DNS
        records the customer must publish, so a support person can read them out
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenant-email-sender.e2e.spec.js#answers the DNS
        records the customer must publish, so a support person can read them out
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-002-14
    title: The HQ edit sheet and disable confirmation
    level: browser
    proves:
      - AS-JNY-PFM-SEC-001-03
    preconditions: Prepare an HQ staff session and an existing workspace.
    steps: >-
      Edit the workspace name, save it, then attempt disabled status through the confirmation
      dialog.
    expected: >-
      The sheet omits an identifier editor, reflects the saved name and asks for confirmation before
      disabling; this mock test does not establish go-live behavior.
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        react-console:e2e/mock/hq-ops.mock.spec.ts#the edit sheet saves, has no identifier to
        change, and confirms before disabling the tenant
      - TST-PFM-SEC-023
    provenance: test
    source: >-
      react-console:e2e/mock/hq-ops.mock.spec.ts#the edit sheet saves, has no identifier to change,
      and confirms before disabling the tenant
    category: permission
    test_references:
      - >-
        react-console:e2e/mock/hq-ops.mock.spec.ts#the edit sheet saves, has no identifier to
        change, and confirms before disabling the tenant
    action_evidence:
      provenance: test
      source: >-
        react-console:e2e/mock/hq-ops.mock.spec.ts#the edit sheet saves, has no identifier to
        change, and confirms before disabling the tenant
    assertion_evidence:
      provenance: test
      source: >-
        react-console:e2e/mock/hq-ops.mock.spec.ts#the edit sheet saves, has no identifier to
        change, and confirms before disabling the tenant
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-002-15
    title: 'Workspace business status: implementation to live'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-02
    state_model: STATE-PFM-SEC-002
    transition:
      from: implementation
      to: live
      index: 0
    preconditions: >-
      Prepare a run-owned workspace business status in implementation state with the authority and
      inputs required by the cited transition.
    steps:
      - do: Save live status with the current version as authorized staff.
        expect: >-
          After the stated action, observe the workspace business status in live state. This case
          does not require an additional history event unless the transition explicitly defines one.
        provenance: proposed
        source:
          - >-
            services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#lets
            a sandbox tenant go live, the data-import check being recorded as debt
          - >-
            services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
            aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    expected: >-
      After the stated action, observe the workspace business status in live state. This case does
      not require an additional history event unless the transition explicitly defines one.
    negative: false
    data_needs: >-
      A disposable customer, workspace and named actor; a controllable clock where the transition
      depends on time.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#lets
        a sandbox tenant go live, the data-import check being recorded as debt
      - >-
        services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
        aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    guard_cases: >-
      The caller has workspace-update and status-management authority; loading is refused, but
      import completion is not checked.
    side_effects_to_verify:
      - Invalidate local availability
    transition_assertion:
      state: live
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#lets
          a sandbox tenant go live, the data-import check being recorded as debt
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#lets
          a sandbox tenant go live, the data-import check being recorded as debt
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#lets
          a sandbox tenant go live, the data-import check being recorded as debt
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-002-16
    title: 'Workspace business status: live to disabled'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-02
    state_model: STATE-PFM-SEC-002
    transition:
      from: live
      to: disabled
      index: 1
    preconditions: >-
      Prepare a run-owned workspace business status in live state with the authority and inputs
      required by the cited transition.
    steps:
      - do: Disable the live workspace using the dedicated staff edit.
        expect: >-
          After the stated action, observe the workspace business status in disabled state. This
          case does not require an additional history event unless the transition explicitly defines
          one.
        provenance: proposed
        source:
          - >-
            services-platform:modules/tenants/aws/api/tenants.routes.ts:patchHqTenant
            (requireStatusAuthority)
          - >-
            services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
            aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    expected: >-
      After the stated action, observe the workspace business status in disabled state. This case
      does not require an additional history event unless the transition explicitly defines one.
    negative: false
    data_needs: >-
      A disposable customer, workspace and named actor; a controllable clock where the transition
      depends on time.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-platform:modules/tenants/aws/api/tenants.routes.ts:patchHqTenant
        (requireStatusAuthority)
      - >-
        services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
        aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    guard_cases: A versioned staff edit passes status-management checks.
    side_effects_to_verify:
      - Ordinary availability stops within the process cache bound
    transition_assertion:
      state: disabled
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/aws/api/tenants.routes.ts:patchHqTenant
          (requireStatusAuthority)
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/aws/api/tenants.routes.ts:patchHqTenant
          (requireStatusAuthority)
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/aws/api/tenants.routes.ts:patchHqTenant
          (requireStatusAuthority)
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-002-17
    title: 'Workspace business status: implementation to disabled'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-02
    state_model: STATE-PFM-SEC-002
    transition:
      from: implementation
      to: disabled
      index: 2
    preconditions: >-
      Prepare a run-owned workspace business status in implementation state with the authority and
      inputs required by the cited transition.
    steps:
      - do: Disable the implementation workspace while no load is open.
        expect: >-
          After the stated action, observe the workspace business status in disabled state. This
          case does not require an additional history event unless the transition explicitly defines
          one.
        provenance: proposed
        source:
          - >-
            services-platform:modules/tenants/aws/api/tenants.routes.ts:patchHqTenant
            (requireStatusAuthority)
          - >-
            services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
            aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    expected: >-
      After the stated action, observe the workspace business status in disabled state. This case
      does not require an additional history event unless the transition explicitly defines one.
    negative: false
    data_needs: >-
      A disposable customer, workspace and named actor; a controllable clock where the transition
      depends on time.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-platform:modules/tenants/aws/api/tenants.routes.ts:patchHqTenant
        (requireStatusAuthority)
      - >-
        services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
        aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    guard_cases: Status-management checks pass and the workspace is not loading.
    side_effects_to_verify:
      - Block ordinary availability
    transition_assertion:
      state: disabled
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/aws/api/tenants.routes.ts:patchHqTenant
          (requireStatusAuthority)
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/aws/api/tenants.routes.ts:patchHqTenant
          (requireStatusAuthority)
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/aws/api/tenants.routes.ts:patchHqTenant
          (requireStatusAuthority)
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-002-18
    title: 'Workspace business status: disabled to live'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-02
    state_model: STATE-PFM-SEC-002
    transition:
      from: disabled
      to: live
      index: 3
    preconditions: >-
      Prepare a run-owned workspace business status in disabled state with the authority and inputs
      required by the cited transition.
    steps:
      - do: Save live status on the disabled workspace when no retirement is open.
        expect: >-
          After the stated action, observe the workspace business status in live state. This case
          does not require an additional history event unless the transition explicitly defines one.
        provenance: proposed
        source:
          - >-
            services-platform:modules/tenants/db/tenants.table.ts:tenants
            (tenants_deletion_pending_status_check)
          - >-
            services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
            aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    expected: >-
      After the stated action, observe the workspace business status in live state. This case does
      not require an additional history event unless the transition explicitly defines one.
    negative: false
    data_needs: >-
      A disposable customer, workspace and named actor; a controllable clock where the transition
      depends on time.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-platform:modules/tenants/db/tenants.table.ts:tenants
        (tenants_deletion_pending_status_check)
      - >-
        services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
        aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    guard_cases: Status-management checks pass and retirement is neither pending nor executing.
    side_effects_to_verify:
      - Allow ordinary availability when lifecycle is active
    transition_assertion:
      state: live
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/db/tenants.table.ts:tenants
          (tenants_deletion_pending_status_check)
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/db/tenants.table.ts:tenants
          (tenants_deletion_pending_status_check)
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/db/tenants.table.ts:tenants
          (tenants_deletion_pending_status_check)
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-002-19
    title: 'Workspace business status: disabled to implementation'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-02
    state_model: STATE-PFM-SEC-002
    transition:
      from: disabled
      to: implementation
      index: 4
    preconditions: >-
      Prepare a run-owned workspace business status in disabled state with the authority and inputs
      required by the cited transition.
    steps:
      - do: Save implementation status on the disabled workspace when no retirement is open.
        expect: >-
          After the stated action, observe the workspace business status in implementation state.
          This case does not require an additional history event unless the transition explicitly
          defines one.
        provenance: proposed
        source:
          - >-
            services-platform:modules/tenants/db/tenants.table.ts:tenants
            (tenants_deletion_pending_status_check)
          - >-
            services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
            aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    expected: >-
      After the stated action, observe the workspace business status in implementation state. This
      case does not require an additional history event unless the transition explicitly defines
      one.
    negative: false
    data_needs: >-
      A disposable customer, workspace and named actor; a controllable clock where the transition
      depends on time.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-platform:modules/tenants/db/tenants.table.ts:tenants
        (tenants_deletion_pending_status_check)
      - >-
        services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
        aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    guard_cases: Status-management checks pass and retirement is neither pending nor executing.
    side_effects_to_verify:
      - Allow ordinary availability when lifecycle is active
    transition_assertion:
      state: implementation
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/db/tenants.table.ts:tenants
          (tenants_deletion_pending_status_check)
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/db/tenants.table.ts:tenants
          (tenants_deletion_pending_status_check)
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/db/tenants.table.ts:tenants
          (tenants_deletion_pending_status_check)
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-002-20
    title: 'Workspace business status: live to implementation'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-02
    state_model: STATE-PFM-SEC-002
    transition:
      from: live
      to: implementation
      index: 5
    preconditions: >-
      Prepare a run-owned workspace business status in live state with the authority and inputs
      required by the cited transition.
    steps:
      - do: Save implementation status on the live workspace as authorized staff.
        expect: >-
          After the stated action, observe the workspace business status in implementation state.
          This case does not require an additional history event unless the transition explicitly
          defines one.
        provenance: proposed
        source:
          - 'services-platform:modules/tenants/db/tenants.table.ts:TENANT_STATUSES'
          - >-
            services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
            aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    expected: >-
      After the stated action, observe the workspace business status in implementation state. This
      case does not require an additional history event unless the transition explicitly defines
      one.
    negative: false
    data_needs: >-
      A disposable customer, workspace and named actor; a controllable clock where the transition
      depends on time.
    bound_to: []
    provenance: proposed
    source:
      - 'services-platform:modules/tenants/db/tenants.table.ts:TENANT_STATUSES'
      - >-
        services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
        aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    guard_cases: The caller has staff status-management authority.
    side_effects_to_verify: []
    transition_assertion:
      state: implementation
      provenance: proposed
      source:
        - 'services-platform:modules/tenants/db/tenants.table.ts:TENANT_STATUSES'
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    action_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/tenants/db/tenants.table.ts:TENANT_STATUSES'
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    assertion_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/tenants/db/tenants.table.ts:TENANT_STATUSES'
        - >-
          services-platform at ad3f6a65: modules/tenants/db/tenants.table.ts;
          aws/api/tenants.routes.ts, tenant-api-mapper.ts; services/access/tenant-availability.ts.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-002-21
    title: Maintain workspace information and operating status with establish and administer a customer
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-001-11
      - BR-CAP-PFM-SEC-002-01
    exercises:
      - CAP-PFM-SEC-002
      - CAP-PFM-SEC-001
    preconditions: A customer has one active workspace.
    steps: 'Try deleting the customer, then read the workspace and customer.'
    expected: Deletion is refused and both records retain their identities.
    negative: true
    data_needs: >-
      An isolated customer with two workspaces, ordinary and staff identities, and records owned by
      this run.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-platform:modules/customers/tests/e2e/customers.e2e.spec.js#refuses a customer that
        still has tenants as 409
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#lists no tenant of another
        customer, which is what the reach reduction means
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/customers/tests/e2e/customers.e2e.spec.js#refuses a customer
          that still has tenants as 409
        - >-
          services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#lists no tenant of another
          customer, which is what the reach reduction means
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/customers/tests/e2e/customers.e2e.spec.js#refuses a customer
          that still has tenants as 409
        - >-
          services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#lists no tenant of another
          customer, which is what the reach reduction means
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-002-22
    title: Maintain workspace information and operating status with prepare a workspace for customer use
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-09
      - BR-CAP-PFM-SEC-003-13
    exercises:
      - CAP-PFM-SEC-002
      - CAP-PFM-SEC-003
    preconditions: An active implementation workspace has an ordinary caller and an import operator.
    steps: >-
      Open an initial load, try ordinary work, then activate with a separate authorized staff
      identity.
    expected: >-
      Ordinary work is refused during loading and resumes after activation; implementation status
      remains unchanged.
    negative: true
    data_needs: >-
      An isolated customer with two workspaces, ordinary and staff identities, and records owned by
      this run.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-platform:modules/tenants/services/access/tenant-availability.ts:tenantAvailabilityOf
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses a live
        tenant, an initial import going only into an implementation tenant
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/services/access/tenant-availability.ts:tenantAvailabilityOf
        - >-
          services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses a live
          tenant, an initial import going only into an implementation tenant
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/services/access/tenant-availability.ts:tenantAvailabilityOf
        - >-
          services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses a live
          tenant, an initial import going only into an implementation tenant
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-002-23
    title: Maintain workspace information and operating status with manage a workspace retirement request
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-03
      - BR-CAP-PFM-SEC-004-07
    exercises:
      - CAP-PFM-SEC-002
      - CAP-PFM-SEC-004
    preconditions: A disabled active workspace is eligible for retirement.
    steps: 'Request retirement, try enabling the workspace, cancel before destruction, and read both axes.'
    expected: >-
      The enabling attempt fails; cancellation restores active lifecycle while business status
      remains disabled.
    negative: true
    data_needs: >-
      An isolated customer with two workspaces, ordinary and staff identities, and records owned by
      this run.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#ignores
        a lifecycle state a write input carries, rather than letting a client set the system axis
      - >-
        services-platform:modules/tenants/tests/integration/services/deletion/deletion-holds.integration.spec.js#leaves
        the tenant disabled: calling off a deletion restores nobody access
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#ignores
          a lifecycle state a write input carries, rather than letting a client set the system axis
        - >-
          services-platform:modules/tenants/tests/integration/services/deletion/deletion-holds.integration.spec.js#leaves
          the tenant disabled: calling off a deletion restores nobody access
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#ignores
          a lifecycle state a write input carries, rather than letting a client set the system axis
        - >-
          services-platform:modules/tenants/tests/integration/services/deletion/deletion-holds.integration.spec.js#leaves
          the tenant disabled: calling off a deletion restores nobody access
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-002-24
    title: Maintain workspace information and operating status with enforce access at request boundaries
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-09
      - BR-CAP-PFM-SEC-015-06
    exercises:
      - CAP-PFM-SEC-002
      - CAP-PFM-SEC-015
    preconditions: An ordinary caller has valid authority over an active workspace.
    steps: Disable the workspace and issue a new protected request after the availability cache expires.
    expected: The new request is refused even though the role assignment remains present.
    negative: true
    data_needs: >-
      An isolated customer with two workspaces, ordinary and staff identities, and records owned by
      this run.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-platform:modules/tenants/services/access/tenant-availability.ts:tenantAvailabilityOf
      - >-
        services-platform:modules/security/tests/unit/authorizer/authorize.spec.ts#returns a Deny
        for the whole route when no grant could apply anywhere
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/services/access/tenant-availability.ts:tenantAvailabilityOf
        - >-
          services-platform:modules/security/tests/unit/authorizer/authorize.spec.ts#returns a Deny
          for the whole route when no grant could apply anywhere
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/services/access/tenant-availability.ts:tenantAvailabilityOf
        - >-
          services-platform:modules/security/tests/unit/authorizer/authorize.spec.ts#returns a Deny
          for the whole route when no grant could apply anywhere
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
evidence:
  - >-
    Pinned services-platform references for the structured rows:
    modules/tenants/tests/e2e/hq-tenant-shortcuts.e2e.spec.js;
    modules/tenants/tests/e2e/hq-tenants.e2e.spec.js;
    modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js;
    modules/tenants/tests/e2e/tenant-deletion-requests.e2e.spec.js;
    modules/tenants/tests/e2e/tenant-email-sender.e2e.spec.js;
    modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js;
    modules/tenants/tests/e2e/tenants.e2e.spec.js;
    modules/tenants/tests/integration/db/tenants.table.integration.spec.js;
    modules/tenants/tests/integration/services/persistence/staff-tenant-shortcuts.integration.spec.js;
    modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js;
    modules/tenants/tests/unit/aws/api/hq-tenant-list-mapper.spec.ts;
    modules/tenants/tests/unit/services/access/tenant-availability.spec.js.
  - 'Pinned react-console references for the structured rows: e2e/mock/hq-ops.mock.spec.ts.'
  - >-
    Testing back-fill reviews the pinned suite assertions, related capabilities, domain invariants,
    state transitions and workflow failure boundaries. New unbound rows remain proposed.
coverage:
  rule: covered
  transition: covered
  validation: covered
  permission: covered
  edge: covered
  failure: 'gap: FND-PFM-SEC-059'
  boundary: covered
  concurrency: covered
  invariant: covered
  interaction: covered
coverage_notes:
  failure: No scenario isolates this category. The referenced finding retains the missing design proof.
invariant_proofs:
  - scenario: ATS-PFM-SEC-002-03
    proves:
      - INV-DOM-PFM-SEC-002-03
      - INV-DOM-PFM-SEC-002-04
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#leaves the lifecycle state
      where the server put it after such a patch
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
  - scenario: ATS-PFM-SEC-002-04
    proves:
      - INV-DOM-PFM-SEC-002-05
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a time zone given as
      an abbreviation as 400
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
  - scenario: ATS-PFM-SEC-002-06
    proves:
      - INV-DOM-PFM-SEC-002-02
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/db/tenants.table.integration.spec.js#refuses
      a sandbox that names no parent by tenants_sandbox_parent_check
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
  - scenario: ATS-PFM-SEC-002-07
    proves:
      - INV-DOM-PFM-SEC-002-06
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a patch
      that moves the link as 400, even for Rhythm staff in their own editor
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
  - scenario: ATS-PFM-SEC-002-09
    proves:
      - INV-DOM-PFM-SEC-002-07
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is refused
      403 in a tenant whose customer has been cut off
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
permission_proof_review:
  - key: platform.tenants.read
    scenario_candidates:
      - ATS-PFM-SEC-002-01
      - ATS-PFM-SEC-002-02
      - ATS-PFM-SEC-002-07
      - ATS-PFM-SEC-002-15
      - ATS-PFM-SEC-002-16
      - ATS-PFM-SEC-002-17
      - ATS-PFM-SEC-002-18
      - ATS-PFM-SEC-002-19
      - ATS-PFM-SEC-002-20
      - ATS-PFM-SEC-002-21
    qualification: >-
      These are candidate scenarios for the authority boundary, not an exhaustive allowed/refused
      matrix for this key. The finding retains combinations not established by the executable
      assertions.
    gap: FND-PFM-SEC-059
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-002-keep-a-workspace-s-details-status-and-commercial-link.md
  - key: platform.tenants.update
    scenario_candidates:
      - ATS-PFM-SEC-002-01
      - ATS-PFM-SEC-002-02
      - ATS-PFM-SEC-002-07
      - ATS-PFM-SEC-002-15
      - ATS-PFM-SEC-002-16
      - ATS-PFM-SEC-002-17
      - ATS-PFM-SEC-002-18
      - ATS-PFM-SEC-002-19
      - ATS-PFM-SEC-002-20
      - ATS-PFM-SEC-002-21
    qualification: >-
      These are candidate scenarios for the authority boundary, not an exhaustive allowed/refused
      matrix for this key. The finding retains combinations not established by the executable
      assertions.
    gap: FND-PFM-SEC-059
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-002-keep-a-workspace-s-details-status-and-commercial-link.md
  - key: platform.tenants.bulk
    scenario_candidates:
      - ATS-PFM-SEC-002-01
      - ATS-PFM-SEC-002-02
      - ATS-PFM-SEC-002-07
      - ATS-PFM-SEC-002-15
      - ATS-PFM-SEC-002-16
      - ATS-PFM-SEC-002-17
      - ATS-PFM-SEC-002-18
      - ATS-PFM-SEC-002-19
      - ATS-PFM-SEC-002-20
      - ATS-PFM-SEC-002-21
    qualification: >-
      These are candidate scenarios for the authority boundary, not an exhaustive allowed/refused
      matrix for this key. The finding retains combinations not established by the executable
      assertions.
    gap: FND-PFM-SEC-059
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-002-keep-a-workspace-s-details-status-and-commercial-link.md
  - key: platform.tenants.manage-status
    scenario_candidates:
      - ATS-PFM-SEC-002-01
      - ATS-PFM-SEC-002-02
      - ATS-PFM-SEC-002-07
      - ATS-PFM-SEC-002-15
      - ATS-PFM-SEC-002-16
      - ATS-PFM-SEC-002-17
      - ATS-PFM-SEC-002-18
      - ATS-PFM-SEC-002-19
      - ATS-PFM-SEC-002-20
      - ATS-PFM-SEC-002-21
    qualification: >-
      These are candidate scenarios for the authority boundary, not an exhaustive allowed/refused
      matrix for this key. The finding retains combinations not established by the executable
      assertions.
    gap: FND-PFM-SEC-059
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-002-keep-a-workspace-s-details-status-and-commercial-link.md
  - key: platform.tenants.manage-commercial-link
    scenario_candidates:
      - ATS-PFM-SEC-002-01
      - ATS-PFM-SEC-002-02
      - ATS-PFM-SEC-002-07
      - ATS-PFM-SEC-002-15
      - ATS-PFM-SEC-002-16
      - ATS-PFM-SEC-002-17
      - ATS-PFM-SEC-002-18
      - ATS-PFM-SEC-002-19
      - ATS-PFM-SEC-002-20
      - ATS-PFM-SEC-002-21
    qualification: >-
      These are candidate scenarios for the authority boundary, not an exhaustive allowed/refused
      matrix for this key. The finding retains combinations not established by the executable
      assertions.
    gap: FND-PFM-SEC-059
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-002-keep-a-workspace-s-details-status-and-commercial-link.md
  - key: hq.tenants.read
    scenario_candidates:
      - ATS-PFM-SEC-002-01
      - ATS-PFM-SEC-002-02
      - ATS-PFM-SEC-002-07
      - ATS-PFM-SEC-002-15
      - ATS-PFM-SEC-002-16
      - ATS-PFM-SEC-002-17
      - ATS-PFM-SEC-002-18
      - ATS-PFM-SEC-002-19
      - ATS-PFM-SEC-002-20
      - ATS-PFM-SEC-002-21
    qualification: >-
      These are candidate scenarios for the authority boundary, not an exhaustive allowed/refused
      matrix for this key. The finding retains combinations not established by the executable
      assertions.
    gap: FND-PFM-SEC-059
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-002-keep-a-workspace-s-details-status-and-commercial-link.md
  - key: hq.tenants.update
    scenario_candidates:
      - ATS-PFM-SEC-002-01
      - ATS-PFM-SEC-002-02
      - ATS-PFM-SEC-002-07
      - ATS-PFM-SEC-002-15
      - ATS-PFM-SEC-002-16
      - ATS-PFM-SEC-002-17
      - ATS-PFM-SEC-002-18
      - ATS-PFM-SEC-002-19
      - ATS-PFM-SEC-002-20
      - ATS-PFM-SEC-002-21
    qualification: >-
      These are candidate scenarios for the authority boundary, not an exhaustive allowed/refused
      matrix for this key. The finding retains combinations not established by the executable
      assertions.
    gap: FND-PFM-SEC-059
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-002-keep-a-workspace-s-details-status-and-commercial-link.md
examiner: codex
examined_at: '2026-10-23'
final_text: OpenAI
---
# Maintain workspace information and operating status: Capability Test Specification

## Coverage

| Required rule | Scenario or finding |
|---|---|
| `BR-CAP-PFM-SEC-002-01` | `ATS-PFM-SEC-002-01`, `ATS-PFM-SEC-002-21` |
| `BR-CAP-PFM-SEC-002-02` | `ATS-PFM-SEC-002-02`, `ATS-PFM-SEC-002-15`, `ATS-PFM-SEC-002-16`, `ATS-PFM-SEC-002-17`, `ATS-PFM-SEC-002-18`, `ATS-PFM-SEC-002-19`, `ATS-PFM-SEC-002-20` |
| `BR-CAP-PFM-SEC-002-03` | `ATS-PFM-SEC-002-03`, `ATS-PFM-SEC-002-23` |
| `BR-CAP-PFM-SEC-002-04` | `ATS-PFM-SEC-002-04` |
| `BR-CAP-PFM-SEC-002-05` | `ATS-PFM-SEC-002-05` |
| `BR-CAP-PFM-SEC-002-06` | `ATS-PFM-SEC-002-06` |
| `BR-CAP-PFM-SEC-002-07` | `ATS-PFM-SEC-002-07` |
| `BR-CAP-PFM-SEC-002-08` | `ATS-PFM-SEC-002-08` |
| `BR-CAP-PFM-SEC-002-09` | `ATS-PFM-SEC-002-09`, `ATS-PFM-SEC-002-22`, `ATS-PFM-SEC-002-24` |
| `BR-CAP-PFM-SEC-002-11` | `ATS-PFM-SEC-002-10` |
| `BR-CAP-PFM-SEC-002-12` | `ATS-PFM-SEC-002-11` |
| `BR-CAP-PFM-SEC-002-13` | `ATS-PFM-SEC-002-12` |

The category map records specified proof. A covered category can contain proposed scenarios; it does not mean the checks have run. The bindings identify individual executable contributions, while findings retain missing rules, permissions, transitions and assertions.

## Interactions With Related Capabilities

The interaction scenarios connect this capability to the related actions and workflow handoffs named in their proof references. Each case observes the outcome after the connected action changes records or available authority. A collection of separately bound checks does not establish an ordered feature journey.

Source revisions and assertion references are recorded in frontmatter. Steps and expected observations carry separate evidence annotations. Proposed checks remain distinct from executable test statements, and static review supplies no run result.
