---
id: ATS-PFM-TNL-005
scope: CAP-PFM-TNL-005
product_area: platform
module: tenant-lifecycle
revision: 2
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
scenarios:
  - id: ATS-PFM-TNL-005-01
    title: Closed workspaces share the unavailable response
    level: api
    proves:
      - BR-CAP-PFM-TNL-005-01
    preconditions: >-
      Platform and CRM fixtures cover active, disabled, provisioning and
      deleting workspaces.
    steps: Call ordinary workspace routes as a customer user.
    expected: >-
      Only the active enabled fixture is admitted; closed fixtures use the
      unavailable response.
    negative: true
    data_needs: >-
      Use the workspace, caller and collaborator fixtures declared by the bound
      tests.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is
        served a tenant-scoped route in an active tenant (the premise every
        refusal below is read against)
      - >-
        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 destruction has begun
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is
        told only that the tenant is not available
      - >-
        services-crm:modules/tenant-lifecycle/tests/e2e/tenant-availability.e2e.spec.js#is
        refused 403 TenantUnavailable in the disabled tenant
      - >-
        services-crm:modules/tenant-lifecycle/tests/e2e/tenant-availability.e2e.spec.js#is
        refused 403 TenantUnavailable in a tenant still being provisioned
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is
      served a tenant-scoped route in an active tenant (the premise every
      refusal below is read against)
  - id: ATS-PFM-TNL-005-02
    title: System staff access has its own boundary
    level: api
    proves:
      - BR-CAP-PFM-TNL-005-02
    preconditions: The workspace is disabled.
    steps: Call system and console routes using the corresponding staff contexts.
    expected: >-
      The system exception admits authorized staff while console context
      receives no exception.
    negative: false
    data_needs: >-
      Use the workspace, caller and collaborator fixtures declared by the bound
      tests.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is
        past the gate in a tenant its own customer could not reach, because
        staff reach every tenant
      - >-
        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
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is
      past the gate in a tenant its own customer could not reach, because staff
      reach every tenant
  - id: ATS-PFM-TNL-005-03
    title: Destruction limits staff to reads
    level: api
    proves:
      - BR-CAP-PFM-TNL-005-03
    preconditions: The workspace is deleting.
    steps: Issue staff read and write requests.
    expected: Read is admitted and mutation is refused.
    negative: true
    data_needs: >-
      Use the workspace, caller and collaborator fixtures declared by the bound
      tests.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#is
        reads only for staff once destruction has begun, so support can still
        inspect it
      - >-
        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
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#is
      reads only for staff once destruction has begun, so support can still
      inspect it
  - id: ATS-PFM-TNL-005-04
    title: Loading preserves route and staff exceptions
    level: api
    proves:
      - BR-CAP-PFM-TNL-005-04
    preconditions: The workspace is loading.
    steps: >-
      Call an ordinary customer route, a data-job route and an authorized staff
      system route.
    expected: >-
      Ordinary customer use is refused while data jobs and the staff exception
      remain admitted.
    negative: true
    data_needs: >-
      Use the workspace, caller and collaborator fixtures declared by the bound
      tests.
    bound_to:
      - >-
        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
        past the gate in a tenant whose initial data import is open, which is
        what lets the import run at all
      - >-
        services-crm:modules/tenant-lifecycle/tests/e2e/tenant-availability.e2e.spec.js#is
        served the submission of a bulk contact job, which is what the import is
        made of
      - >-
        services-crm:modules/tenant-lifecycle/tests/e2e/tenant-availability.e2e.spec.js#is
        refused the contact list 403 TenantUnavailable, because nothing but the
        import may touch the tenant
      - >-
        services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#serves
        the upload protocol, which is what the load is made of
      - >-
        services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#serves
        staff, who reach every tenant on a system route
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is
      refused 403 in a tenant whose initial data import is open
  - id: ATS-PFM-TNL-005-05
    title: Absence refuses every caller
    level: unit
    proves:
      - BR-CAP-PFM-TNL-005-05
    preconditions: The requested workspace does not exist.
    steps: Evaluate availability for staff and customer identities.
    expected: Both answers are unavailable.
    negative: true
    data_needs: >-
      Use the workspace, caller and collaborator fixtures declared by the bound
      tests.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#is
        unavailable to everybody when there is no such tenant
      - >-
        services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#is
        unavailable to staff too when there is no such tenant
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#is
      unavailable to everybody when there is no such tenant
  - id: ATS-PFM-TNL-005-06
    title: Cache expiry prompts a fresh lifecycle read
    level: unit
    proves:
      - BR-CAP-PFM-TNL-005-06
    preconditions: A process has cached lifecycle facts.
    steps: 'Read before expiry, at expiry and after explicit invalidation.'
    expected: >-
      Fresh entries are reused; expired or forgotten entries cause another
      database read.
    negative: false
    data_needs: >-
      Use the workspace, caller and collaborator fixtures declared by the bound
      tests.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#still
        answers from the cache one millisecond before the window closes
      - >-
        services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#reads
        again once the window has closed
      - >-
        services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#reads
        a forgotten tenant again at once, which is how the process that changed
        it stays right
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#still
      answers from the cache one millisecond before the window closes
  - id: ATS-PFM-TNL-005-07
    title: Background enumeration selects operational records
    level: api
    proves:
      - BR-CAP-PFM-TNL-005-07
    preconditions: Fixtures cover lifecycle states and disabled business status.
    steps: List Platform’s operational workspaces.
    expected: 'The result contains only active, non-disabled workspaces.'
    negative: false
    data_needs: >-
      Use the workspace, caller and collaborator fixtures declared by the bound
      tests.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.queries.integration.spec.js#answers
        no tenant that is still provisioning
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.queries.integration.spec.js#answers
        no tenant whose provisioning failed
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.queries.integration.spec.js#answers
        no tenant awaiting deletion
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.queries.integration.spec.js#answers
        no tenant being deleted
      - >-
        services-platform:modules/tenants/tests/integration/services/persistence/tenants.queries.integration.spec.js#answers
        no disabled tenant, active though its lifecycle is
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/persistence/tenants.queries.integration.spec.js#answers
      no tenant that is still provisioning
  - id: ATS-PFM-TNL-005-08
    title: Opening changes ordinary availability
    level: api
    proves:
      - AS-JNY-PFM-TNL-001-01
    preconditions: The construction journey includes a before-and-after gate fixture.
    steps: Read ordinary availability around activation.
    expected: >-
      Provisioning refuses customer access and active enabled lifecycle admits
      it.
    negative: false
    data_needs: >-
      Use the workspace, caller and collaborator fixtures declared by the bound
      tests.
    bound_to:
      - >-
        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-provisioning.e2e.spec.js#leaves
        the tenant usable once the job has run
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is
      refused 403 in a tenant that is still being provisioned
  - id: ATS-PFM-TNL-005-09
    title: Loading journey retains its staff exception
    level: api
    proves:
      - AS-JNY-PFM-TNL-003-03
    preconditions: The import journey’s workspace is loading.
    steps: 'Exercise ordinary customer, data-job and staff system access.'
    expected: >-
      Customer routes close except for data-job work and staff system access
      remains possible.
    negative: false
    data_needs: >-
      Use the workspace, caller and collaborator fixtures declared by the bound
      tests.
    bound_to:
      - >-
        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-crm:modules/tenant-lifecycle/tests/e2e/tenant-availability.e2e.spec.js#is
        refused the contact list 403 TenantUnavailable, because nothing but the
        import may touch the tenant
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is
      refused 403 in a tenant whose initial data import is open
evidence:
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is
    served a tenant-scoped route in an active tenant (the premise every refusal
    below is read against)
  - >-
    Inspected 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
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is
    refused 403 in a tenant that is still being provisioned
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is
    refused 403 in a tenant whose destruction has begun
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is
    told only that the tenant is not available
  - >-
    Inspected source:
    services-crm:modules/tenant-lifecycle/tests/e2e/tenant-availability.e2e.spec.js#is
    refused 403 TenantUnavailable in the disabled tenant
  - >-
    Inspected source:
    services-crm:modules/tenant-lifecycle/tests/e2e/tenant-availability.e2e.spec.js#is
    refused 403 TenantUnavailable in a tenant still being provisioned
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is
    past the gate in a tenant its own customer could not reach, because staff
    reach every tenant
  - >-
    Inspected source:
    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
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#is
    reads only for staff once destruction has begun, so support can still
    inspect it
  - >-
    Inspected source:
    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
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is
    refused 403 in a tenant whose initial data import is open
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/e2e/tenant-availability-gate.e2e.spec.js#is
    past the gate in a tenant whose initial data import is open, which is what
    lets the import run at all
  - >-
    Inspected source:
    services-crm:modules/tenant-lifecycle/tests/e2e/tenant-availability.e2e.spec.js#is
    served the submission of a bulk contact job, which is what the import is
    made of
  - >-
    Inspected source:
    services-crm:modules/tenant-lifecycle/tests/e2e/tenant-availability.e2e.spec.js#is
    refused the contact list 403 TenantUnavailable, because nothing but the
    import may touch the tenant
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#serves
    the upload protocol, which is what the load is made of
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#serves
    staff, who reach every tenant on a system route
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#is
    unavailable to everybody when there is no such tenant
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#is
    unavailable to staff too when there is no such tenant
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#still
    answers from the cache one millisecond before the window closes
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#reads
    again once the window has closed
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/unit/services/access/tenant-availability.spec.js#reads
    a forgotten tenant again at once, which is how the process that changed it
    stays right
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/integration/services/persistence/tenants.queries.integration.spec.js#answers
    no tenant that is still provisioning
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/integration/services/persistence/tenants.queries.integration.spec.js#answers
    no tenant whose provisioning failed
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/integration/services/persistence/tenants.queries.integration.spec.js#answers
    no tenant awaiting deletion
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/integration/services/persistence/tenants.queries.integration.spec.js#answers
    no tenant being deleted
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/integration/services/persistence/tenants.queries.integration.spec.js#answers
    no disabled tenant, active though its lifecycle is
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#leaves
    the tenant usable once the job has run
---

# Apply workspace availability consistently: Acceptance Test Set

## Coverage

| Rule | Proved by |
|---|---|
| `BR-CAP-PFM-TNL-005-01` | `ATS-PFM-TNL-005-01` |
| `BR-CAP-PFM-TNL-005-02` | `ATS-PFM-TNL-005-02` |
| `BR-CAP-PFM-TNL-005-03` | `ATS-PFM-TNL-005-03` |
| `BR-CAP-PFM-TNL-005-04` | `ATS-PFM-TNL-005-04` |
| `BR-CAP-PFM-TNL-005-05` | `ATS-PFM-TNL-005-05` |
| `BR-CAP-PFM-TNL-005-06` | `ATS-PFM-TNL-005-06` |
| `BR-CAP-PFM-TNL-005-07` | `ATS-PFM-TNL-005-07` |
