---
id: CAP-PFM-TNL-006
title: Preserve valid workspace lifecycle states
feature: FEAT-PFM-TNL-02
product_area: platform
module: tenant-lifecycle
revision: 2
status: draft
product_intent: proposed
implementation_evidence: observed
supersedes: []
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
intent_sources:
  - 'services-platform:docs/tenants/tenant-lifecycle-plan.md#§2.2'
  - 'services-platform:docs/proposals/rhythm-data-job-engine-plan.md#§21.3 D5'
purpose: >-
  Lifecycle workflows maintain a state that follows allowed transitions and
  agrees with the workspace’s business mode.
outcomes:
  - Client inputs cannot replace system lifecycle facts.
  - Lifecycle transitions accept only permitted paths and harmless repeats.
  - Loading and deletion retain their required business statuses.
concepts:
  - CON-PFM-TNL-001
actors:
  - ACT-PFM-012
  - ACT-PFM-004
surfaces:
  - api
  - job
preconditions: []
postconditions: []
permissions:
  - key: platform.tenants.manage-status
    where_checked: api
    scope: global
rules:
  - id: BR-CAP-PFM-TNL-006-01
    proved_by: [ATS-PFM-TNL-006-01]
    statement: >-
      Client writes discard lifecycle state and first-activation time; lifecycle
      workflows control those values.
    kind: invariant
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    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
    origin: >-
      services-platform:docs/tenants/tenant-lifecycle-plan.md#§2.2 No API sets
      lifecycle_state directly (approved)
  - id: BR-CAP-PFM-TNL-006-02
    proved_by: [ATS-PFM-TNL-006-02, TST-PFM-TNL-096]
    statement: >-
      Allowed lifecycle moves connect provisioning to active or failed, failed
      to provisioning or deletion pending, active to loading or deletion
      pending, loading to active or deletion pending, and deletion pending to
      active or deleting; deleting has no successor.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/unit/services/lifecycle/lifecycle-transitions.spec.js#refuses
      deleting, so nothing can skip the waiting period by writing the state
    origin: >-
      services-platform:docs/tenants/tenant-lifecycle-plan.md#§2.2 Transitions
      (approved);
      services-platform:docs/proposals/rhythm-data-job-engine-plan.md#§12.1 (D5)
  - id: BR-CAP-PFM-TNL-006-03
    proved_by: [ATS-PFM-TNL-006-03, TST-PFM-TNL-096]
    statement: >-
      Repeating the current lifecycle state succeeds without a transition or
      further state change.
    kind: invariant
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/unit/services/lifecycle/lifecycle-transitions.spec.js#allows
      deleting to deleting, so a retried purge step is idempotent
    origin: 'services-platform:docs/tenants/tenant-lifecycle-plan.md#§2.2 (approved)'
  - id: BR-CAP-PFM-TNL-006-04
    proved_by: [ATS-PFM-TNL-006-04, ATS-PFM-TNL-006-07, TST-PFM-TNL-077]
    statement: >-
      Database checks require disabled status during pending deletion and
      destruction, and implementation status during loading.
    kind: invariant
    enforced_at:
      - database
    must_prove: true
    provenance: test
    source: >-
      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
    origin: >-
      services-platform:docs/tenants/tenant-lifecycle-plan.md#§2.2 (approved);
      services-platform:docs/proposals/rhythm-data-job-engine-plan.md#§21.4
      (Andrew, 2026-10-11)
  - id: BR-CAP-PFM-TNL-006-05
    proved_by: [ATS-PFM-TNL-006-05, TST-PFM-TNL-052]
    statement: >-
      Business-status changes belong to authorized Rhythm staff; customer
      administrators may correct ordinary workspace details but cannot change
      that status.
    kind: permission
    enforced_at:
      - api
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-deletion-requests.e2e.spec.js#may
      not disable it, because cutting an association off is a staff act
    origin: >-
      services-platform:docs/tenants/tenant-lifecycle-plan.md#§2.2 Who can
      change status (approved)
  - id: BR-CAP-PFM-TNL-006-06
    proved_by: []
    statement: >-
      Direct fixture creation outside a provisioning submission defaults the
      workspace to active lifecycle.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: false
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#answers
      the lifecycle state of a tenant created ready to use
    origin: none
  - id: BR-CAP-PFM-TNL-006-07
    proved_by: [ATS-PFM-TNL-006-06, TST-PFM-TNL-077]
    statement: >-
      Disposable workspaces are a testing convention and their creation is
      rejected in Production.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#refuses
      a disposable tenant in Production, where no such tenant exists
    origin: >-
      services-platform:docs/tenants/tenant-lifecycle-plan.md#§5.3 Disposable
      test tenants (approved)
scenarios:
  - id: SC-CAP-PFM-TNL-006-01
    given: A disabled workspace awaits deletion.
    when: A write attempts to make its status live while leaving deletion pending.
    then: The database rejects the inconsistent axes.
    provenance: test
    source: >-
      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
edge_cases: []
constraints: []
depends_on: []
related:
  - CAP-PFM-TNL-002
  - CAP-PFM-TNL-005
  - CAP-PFM-TNL-011
  - CAP-PFM-TNL-013
  - CAP-PFM-TNL-014
  - CAP-PFM-TNL-016
journeys: []
open_questions:
  - OQ-PFM-TNL-003
evidence:
  - >-
    Inspected source:
    services-platform:docs/tenants/tenant-lifecycle-plan.md#§2.2
  - >-
    Inspected source:
    services-platform:docs/proposals/rhythm-data-job-engine-plan.md#§21.3 D5
  - >-
    Inspected 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
  - >-
    Inspected source:
    services-platform:docs/tenants/tenant-lifecycle-plan.md#§2.2 No API sets
    lifecycle_state directly (approved)
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/unit/services/lifecycle/lifecycle-transitions.spec.js#refuses
    deleting, so nothing can skip the waiting period by writing the state
  - >-
    Inspected source:
    services-platform:docs/tenants/tenant-lifecycle-plan.md#§2.2 Transitions
    (approved);
    services-platform:docs/proposals/rhythm-data-job-engine-plan.md#§12.1 (D5)
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/unit/services/lifecycle/lifecycle-transitions.spec.js#allows
    deleting to deleting, so a retried purge step is idempotent
  - >-
    Inspected source:
    services-platform:docs/tenants/tenant-lifecycle-plan.md#§2.2 (approved)
  - >-
    Inspected source:
    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
  - >-
    Inspected source:
    services-platform:docs/tenants/tenant-lifecycle-plan.md#§2.2 (approved);
    services-platform:docs/proposals/rhythm-data-job-engine-plan.md#§21.4
    (Andrew, 2026-10-11)
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/e2e/tenant-deletion-requests.e2e.spec.js#may
    not disable it, because cutting an association off is a staff act
  - >-
    Inspected source:
    services-platform:docs/tenants/tenant-lifecycle-plan.md#§2.2 Who can change
    status (approved)
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#answers the
    lifecycle state of a tenant created ready to use
  - >-
    Inspected source:
    services-platform:modules/tenants/tests/integration/services/persistence/tenants.integration.spec.js#refuses
    a disposable tenant in Production, where no such tenant exists
  - >-
    Inspected source:
    services-platform:docs/tenants/tenant-lifecycle-plan.md#§5.3 Disposable test
    tenants (approved)
controls: [TC-AVL-001, TC-AVL-004, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-DAT-001, TC-DAT-003, TC-DAT-004, TC-DAT-006, TC-IAM-001, TC-IAM-003, TC-IAM-006, TC-LOG-001, TC-LOG-004, TC-LOG-005, TC-MON-001, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-VEN-001, TC-VEN-002, TC-VEN-003]
exercised_by: [FAS-PFM-TNL-02-01, FAS-PFM-TNL-02-02, FAS-PFM-TNL-02-03, FAS-PFM-TNL-02-04, FAS-PFM-TNL-02-05]
suites: [TST-PFM-TNL-052, TST-PFM-TNL-077, TST-PFM-TNL-096]
---

# Preserve valid workspace lifecycle states

## Purpose

Lifecycle workflows maintain a state that follows allowed transitions and agrees with the workspace’s business mode.

## How It Works

Staff see lifecycle separately from business status. A client editing ordinary workspace fields cannot write the lifecycle axis or first activation time. Construction, loading, activation and deletion workflows make those changes. The transition policy limits each move and accepts a repeat of the current state. Database checks keep loading tied to implementation mode. The same checks keep pending or executing deletion tied to disabled status. Staff must cancel deletion before separately re-enabling the workspace. Disposable fixtures use a testing convention that is refused in Production.

## Relationships

- Open a workspace after its applications are ready: Its readiness and activation finish workspace construction.
- Apply workspace availability consistently: Its access decision determines when callers can use the workspace.
- Control the initial import and subsequent opening: Its loading period and activation decision control initial import availability.
- Schedule deliberate workspace deletion: The capabilities share the workspace’s recorded lifecycle decision.
- Pause or cancel deletion while preservation remains possible: The capabilities share the workspace’s recorded lifecycle decision.
- Revalidate the irreversible deletion decision: The capabilities share the workspace’s recorded lifecycle decision.
