---
id: STATE-PFM-TNL-001
title: Workspace lifecycle
object: DOM-PFM-TNL-001
product_area: platform
module: tenant-lifecycle
revision: 1
status: draft
design_intent: confirmed
origin: services-platform:docs/tenants/tenant-lifecycle-plan.md#§2.2 Transitions (approved 2026-10-09); services-platform:docs/proposals/rhythm-data-job-engine-plan.md#§12.1
  (D5)
implementation_evidence: observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
states:
- name: provisioning
  meaning: Construction is underway; ordinary requests are unavailable.
- name: provisioning_failed
  meaning: Construction stopped and earlier resources remain available for recovery.
- name: active
  meaning: Construction has completed; ordinary access still depends on business standing.
- name: loading
  meaning: Initial import is open, admitting authorized data-job and staff system requests.
- name: deletion_pending
  meaning: Removal is requested but remains reversible; the workspace is disabled.
- name: deleting
  meaning: Removal has begun. Gated staff system requests are read-only, but HQ writes outside that gate remain
    possible.
transitions:
- from: provisioning
  to: active
  trigger: Provisioning reaches its activation task.
  guard: The workflow has checked participant readiness; the locked workspace permits activation.
  side_effects:
  - Record the first provisioning activation if absent.
  - Apply the requested business standing.
  - Enable always-available applications, then clear local availability facts.
  - Attempt founding staff access and development licences; log failures.
  - Attempt requester notification and the HQ alert.
  who: provisioning job
  provenance: observed
  source: services-platform:modules/tenants/services/persistence/tenants.ts:activateProvisionedTenant
- from: provisioning
  to: provisioning_failed
  trigger: A failed build is settled or stranded provisioning is repaired.
  guard: Only a workspace still provisioning is changed.
  side_effects:
  - Attempt the claimed requester notice and the keyed HQ failure alert.
  who: provisioning job, jobs reconciler, repair pass
  provenance: observed
  source: services-platform:modules/tenants/services/provisioning/provision-tenant-failure.ts:applyTenantProvisioningFailure
- from: provisioning_failed
  to: provisioning
  trigger: Staff invoke provisioning retry.
  guard: The workspace is failed-provisioning and has a prior attempt.
  side_effects:
  - Return the workspace to construction and clear its local availability cache.
  - Create a linked attempt in a separate commit, carrying completed steps.
  who: Rhythm staff with provisioning authority
  provenance: observed
  source: services-platform:modules/tenants/services/provisioning/submit-tenant-provisioning.ts:retryTenantProvisioning
- from: provisioning_failed
  to: deletion_pending
  trigger: Staff request removal of a failed build.
  guard: The workspace is disabled, unlocked, childless and unprotected; confirmation and open-request checks pass.
  side_effects:
  - Record the request, notice obligations and watcher.
  - Select the wait from disposable standing and recorded activation history.
  who: Rhythm staff with deletion-request authority
  provenance: observed
  source: services-platform:modules/tenants/services/deletion/request-deletion.ts:requestTenantDeletion
- from: active
  to: loading
  trigger: Staff open initial loading.
  guard: The locked workspace is active and in implementation standing.
  side_effects:
  - Record the operator, time and optional explanation.
  - Clear cached availability in the changing process.
  who: Rhythm staff with import authority
  provenance: observed
  source: services-platform:modules/tenants/services/persistence/tenants.ts:enterTenantLoading
- from: active
  to: deletion_pending
  trigger: Staff request workspace removal.
  guard: The workspace is disabled, unlocked, childless and unprotected; confirmation and open-request checks pass.
  side_effects:
  - Commit request, notices and watcher with pending-deletion lifecycle.
  who: Rhythm staff with deletion-request authority
  provenance: observed
  source: services-platform:modules/tenants/services/deletion/request-deletion.ts:requestTenantDeletion
- from: loading
  to: active
  trigger: Staff activate the imported workspace.
  guard: The workspace is loading; a repeated call succeeds for an active workspace with a load record.
  side_effects:
  - Change lifecycle to active while retaining business standing and load facts.
  - Clear local availability facts.
  who: Rhythm staff with go-live authority
  provenance: observed
  source: services-platform:modules/tenants/services/persistence/tenants.ts:activateLoadedTenant
- from: loading
  to: deletion_pending
  trigger: The successor table permits leaving loading for pending deletion.
  guard: 'No current request path satisfies this move: loading requires implementation and deletion requests require
    disabled active or failed-provisioning standing.'
  side_effects: []
  who: none today
  provenance: observed
  source: services-platform:modules/tenants/services/lifecycle/lifecycle-transitions.ts:SUCCESSORS
- from: deletion_pending
  to: active
  trigger: Staff cancel a reversible deletion.
  guard: The request is scheduled or held and its reviewed version matches.
  side_effects:
  - Record cancellation and its notice obligation.
  - Return lifecycle to active while keeping disabled business standing.
  who: Rhythm staff with cancel authority
  provenance: observed
  source: services-platform:modules/tenants/services/deletion/deletion-holds.ts:cancelTenantDeletion
- from: deletion_pending
  to: deleting
  trigger: The watcher passes irreversible-removal checks.
  guard: The locked request is scheduled, belongs to this watcher, is eligible, has satisfied gating notices, and
    still has a deletable workspace and authorized requester.
  side_effects:
  - Commit executing request, deleting workspace, notice obligation and purge job together.
  who: deletion schedule job
  provenance: observed
  source: services-platform:modules/tenants/services/deletion/begin-destruction.ts:beginTenantDestruction
- from: active
  to: deleting
  trigger: An operator reapplies ledger-recorded removal after restore.
  guard: The ledger confirms earlier completed removal; the restored workspace can begin in any lifecycle state.
  side_effects:
  - Force disabled and deleting standing.
  - Recover or create a removal request and start its purge without a new waiting decision.
  who: operator running the reapplication script
  provenance: observed
  source: services-platform:modules/tenants/services/persistence/tenants.ts:forceTenantDeletingAfterRestore
invalid:
- from: provisioning
  to: deleting
  why: The ordinary successor table rejects this move; restore reapplication is a separate exception.
- from: provisioning
  to: loading
  why: Loading requires construction to finish first.
- from: provisioning_failed
  to: active
  why: Recovery must return through construction before readiness can reopen the workspace.
- from: active
  to: provisioning
  why: Existing active lifecycle cannot restart construction through the successor table.
- from: loading
  to: provisioning
  why: Reset removes imported data without restarting construction.
- from: deletion_pending
  to: loading
  why: The ordinary table cannot enter loading while removal remains pending.
- from: deleting
  to: active
  why: Deleting has no ordinary successor; success removes the workspace and failure keeps deleting.
- from: deleting
  to: deletion_pending
  why: A removal already executing cannot return to its reversible wait.
concurrency: Lifecycle services lock and inspect the workspace row. The successor assertion accepts the same state,
  but a generic state write can still increment record version and modification facts. Availability caches in other
  processes can retain earlier facts for thirty seconds. HQ updates outside the workspace gate remain a separate
  write boundary.
invariants:
- INV-DOM-PFM-TNL-001-01
- INV-DOM-PFM-TNL-001-02
- INV-DOM-PFM-TNL-001-03
- INV-DOM-PFM-TNL-001-04
- INV-DOM-PFM-TNL-001-05
evidence:
- 'services-platform at ad3f6a65: modules/tenants/services/lifecycle/lifecycle-transitions.ts; services/persistence/tenants.ts;
  services/provisioning/*.ts; services/deletion/{request-deletion, deletion-holds, begin-destruction, reapply-deletions}.ts.'
---

# Workspace Lifecycle

## The Lifecycle

```mermaid
stateDiagram-v2
  [*] --> provisioning: provisioning request committed
  [*] --> active: created directly (development fixtures)
  provisioning --> active: every participant ready
  provisioning --> provisioning_failed: build settled failed
  provisioning_failed --> provisioning: staff retry
  provisioning_failed --> deletion_pending: deletion requested
  active --> loading: initial import opened
  loading --> active: load activated
  loading --> deletion_pending: allowed, unreachable today
  active --> deletion_pending: deletion requested
  deletion_pending --> active: deletion cancelled
  deletion_pending --> deleting: point of no return
  active --> deleting: restore reapplication
  deleting --> [*]: purge finalized, record removed
```

## Transitions Explained

Construction opens the workspace after readiness, or leaves it in failed-provisioning standing for staff recovery. A retry returns it to construction through a new linked attempt. Staff can open loading on an active implementation workspace and activate it afterward without changing business standing.

A removal request moves an eligible disabled workspace to pending deletion. Cancellation returns lifecycle to active but keeps the workspace disabled. Irreversible-removal checks commit deleting lifecycle with the purge job. Restore recovery is a separate forced move backed by the external ledger.

## What Cannot Happen

The ordinary successor table rejects skipped construction and reversed destruction. Restore reapplication is an exception that can force deleting from any restored state. Although loading can precede pending deletion in the table, the current deletion request cannot admit that combination.

## Concurrency and Timing

Lifecycle services lock and inspect the workspace row. The successor assertion accepts the same state, but a generic state write can still increment record version and modification facts. Availability caches in other processes can retain earlier facts for thirty seconds. HQ updates outside the workspace gate remain a separate write boundary.
