---
id: ATS-PFM-TNL-001
scope: CAP-PFM-TNL-001
product_area: platform
module: tenant-lifecycle
revision: 3
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
  services-committees: 36129c24daeaadcdb339218c38cdeaff9861359d
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  services-submissions: 64236c19be89579ef5897aad7de3925ed3ce03bf
  services-websites: 5fc6823c69d5e6f208c21dba8c0eb3132f8bdc4c
  services-marketing: d071a159fe9782bb71ff246d5c67d5bbfe07fbfa
  rhythm-v2-docs: d318a948692343e2f0a7ecc2e11c50db179a8c95
scenarios:
  - id: ATS-PFM-TNL-001-01
    title: Customer authority cannot provision
    level: api
    proves:
      - BR-CAP-PFM-TNL-001-01
    preconditions: A working workspace has a customer administrator.
    steps: Submit a creation request with that identity.
    expected: The request is refused without recording a workspace or build job.
    negative: true
    data_needs: >-
      Use the run-owned records and caller contexts created by the cited tests; use their provider and clock
      seams only where declared.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#may not ask for a tenant
        at all
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#leaves the tenant exactly
        as it was after all of those refusals
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#refuses an anonymous call
        as 401
      - TST-PFM-TNL-056
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#may not ask for a tenant at
      all
    category: permission
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#may not ask for a tenant
        at all
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#may not ask for a tenant
        at all
    binding_note: >-
      All cited checks for this scenario occur in the registered file. The link establishes inspected
      executable source rather than a passing run.
  - id: ATS-PFM-TNL-001-02
    title: Identifiers are validated and normalized
    level: api
    proves:
      - BR-CAP-PFM-TNL-001-02
    preconditions: 'Creation requests exercise missing, generated-looking, reserved and mixed-case identifiers.'
    steps: Submit each identifier variant.
    expected: Invalid variants identify the rejected field; valid mixed-case input is stored lowercase.
    negative: true
    data_needs: >-
      Use the run-owned records and caller contexts created by the cited tests; use their provider and clock
      seams only where declared.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a create that names no id as
        400 tenant_id_required, naming id
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a UUID-shaped id as 400
        tenant_id_invalid, nothing generating ids any more
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a reserved id as 400
        tenant_id_reserved
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#stores an id normalized, trimmed and
        lowercase
      - TST-PFM-TNL-057
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a create that names no id as 400
      tenant_id_required, naming id
    category: validation
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a create that names no id as
        400 tenant_id_required, naming id
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a create that names no id as
        400 tenant_id_required, naming id
    binding_note: >-
      All cited checks for this scenario occur in the registered file. The link establishes inspected
      executable source rather than a passing run.
  - id: ATS-PFM-TNL-001-03
    title: Submission replay retains identity
    level: api
    proves:
      - BR-CAP-PFM-TNL-001-03
    preconditions: The original submission has been accepted.
    steps: Resubmit its identical payload and submission identity.
    expected: Both responses refer to one workspace and one build job.
    negative: false
    data_needs: >-
      Use the run-owned records and caller contexts created by the cited tests; use their provider and clock
      seams only where declared.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#answers
        the same tenant and the same job when the same submission is sent twice
      - TST-PFM-TNL-082
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#answers
      the same tenant and the same job when the same submission is sent twice
    category: invariant
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#answers
        the same tenant and the same job when the same submission is sent twice
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#answers
        the same tenant and the same job when the same submission is sent twice
    binding_note: >-
      All cited checks for this scenario occur in the registered file. The link establishes inspected
      executable source rather than a passing run.
  - id: ATS-PFM-TNL-001-04
    title: Identifier collision preserves the original
    level: api
    proves:
      - BR-CAP-PFM-TNL-001-04
    preconditions: A workspace already holds the chosen identifier.
    steps: Submit a new request with that identifier.
    expected: Creation reports the collision without modifying the existing record.
    negative: true
    data_needs: >-
      Use the run-owned records and caller contexts created by the cited tests; use their provider and clock
      seams only where declared.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#refuses
        a different submission that names a tenant id somebody already has
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses an id another tenant has as
        409 tenant_id_taken
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#refuses
      a different submission that names a tenant id somebody already has
    category: validation
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#refuses
        a different submission that names a tenant id somebody already has
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#refuses
        a different submission that names a tenant id somebody already has
    binding_note: >-
      The original test-title references contribute separate assertions from several files. No suite receives
      an implements link for the complete combined scenario; a full executable mapping remains
      FND-PFM-TNL-084.
    binding_gap: FND-PFM-TNL-084
  - id: ATS-PFM-TNL-001-05
    title: Sender refusal rolls back creation
    level: api
    proves:
      - BR-CAP-PFM-TNL-001-05
    preconditions: A request includes an invalid sender choice.
    steps: Submit the whole workspace request.
    expected: 'The refusal retains no new customer, workspace, job or provider resource.'
    negative: true
    data_needs: >-
      Use the run-owned records and caller contexts created by the cited tests; use their provider and clock
      seams only where declared.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#creates
        no tenant at all when the strategy is refused: the request is rejected whole
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#creates
        nothing in SES when the strategy is refused
      - TST-PFM-TNL-085
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#creates
      no tenant at all when the strategy is refused: the request is rejected whole
    category: invariant
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#creates
        no tenant at all when the strategy is refused: the request is rejected whole
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#creates
        no tenant at all when the strategy is refused: the request is rejected whole
    binding_note: >-
      All cited checks for this scenario occur in the registered file. The link establishes inspected
      executable source rather than a passing run.
  - id: ATS-PFM-TNL-001-06
    title: Request acceptance precedes readiness
    level: api
    proves:
      - BR-CAP-PFM-TNL-001-06
    preconditions: A new workspace request is ready to submit.
    steps: Inspect the returned workspace before and after running its build.
    expected: It begins provisioning and becomes active with a recorded opening time.
    negative: false
    data_needs: >-
      Use the run-owned records and caller contexts created by the cited tests; use their provider and clock
      seams only where declared.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#answers a tenant that is
        not usable yet, because the work has only been asked for
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#leaves the tenant usable
        once the job has run
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#records when the tenant
        became usable
      - TST-PFM-TNL-056
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#answers a tenant that is not
      usable yet, because the work has only been asked for
    category: transition
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#answers a tenant that is
        not usable yet, because the work has only been asked for
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#answers a tenant that is
        not usable yet, because the work has only been asked for
    binding_note: >-
      All cited checks for this scenario occur in the registered file. The link establishes inspected
      executable source rather than a passing run.
  - id: ATS-PFM-TNL-001-07
    title: Execution-start failure preserves the request
    level: api
    proves:
      - BR-CAP-PFM-TNL-001-07
    preconditions: The job starter is configured to fail.
    steps: Submit the provisioning request.
    expected: The response returns the committed workspace and pending job without an execution handle.
    negative: false
    data_needs: >-
      Use the run-owned records and caller contexts created by the cited tests; use their provider and clock
      seams only where declared.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#answers
        the tenant it created and the job it submitted, as a successful request does
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#leaves
        the job pending and without a handle, which is what the reconciler settles
      - TST-PFM-TNL-082
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#answers
      the tenant it created and the job it submitted, as a successful request does
    category: failure
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#answers
        the tenant it created and the job it submitted, as a successful request does
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#answers
        the tenant it created and the job it submitted, as a successful request does
    binding_note: >-
      All cited checks for this scenario occur in the registered file. The link establishes inspected
      executable source rather than a passing run.
  - id: ATS-PFM-TNL-001-08
    title: Provisioning distinguishes inherited and explicitly cleared company links
    category: rule
    level: api
    proves:
      - BR-CAP-PFM-TNL-001-10
    preconditions: The existing customer has a commercial company link; the provisioning caller is authorized staff.
    steps: >-
      Create one workspace without a company field, another with an explicit company and a third with an
      explicitly cleared company.
    expected: >-
      The three workspaces respectively inherit the customer company, use the supplied company and retain no
      company link.
    negative: false
    data_needs: Use separate run-owned target and comparison workspace records created by the cited suite.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-hubspot-link.integration.spec.js#takes
        the customer\u2019s company when the request says nothing about one
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-hubspot-link.integration.spec.js#stores
        the company the request names, in place of the customer\u2019s
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-hubspot-link.integration.spec.js#links
        a tenant to no company when the request says so explicitly, though the customer has one
      - TST-PFM-TNL-086
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/tenant-hubspot-link.integration.spec.js#takes
      the customer\u2019s company when the request says nothing about one;
      services-platform:modules/tenants/tests/integration/services/provisioning/tenant-hubspot-link.integration.spec.js#stores
      the company the request names, in place of the customer\u2019s;
      services-platform:modules/tenants/tests/integration/services/provisioning/tenant-hubspot-link.integration.spec.js#links
      a tenant to no company when the request says so explicitly, though the customer has one
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-hubspot-link.integration.spec.js#takes
        the customer\u2019s company when the request says nothing about one;
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-hubspot-link.integration.spec.js#stores
        the company the request names, in place of the customer\u2019s;
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-hubspot-link.integration.spec.js#links
        a tenant to no company when the request says so explicitly, though the customer has one
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-hubspot-link.integration.spec.js#takes
        the customer\u2019s company when the request says nothing about one;
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-hubspot-link.integration.spec.js#stores
        the company the request names, in place of the customer\u2019s;
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-hubspot-link.integration.spec.js#links
        a tenant to no company when the request says so explicitly, though the customer has one
    binding_note: >-
      All cited checks for this scenario occur in the registered file. The link establishes inspected
      executable source rather than a passing run.
  - id: ATS-PFM-TNL-001-09
    title: Accepted construction changes access only after readiness
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-TNL-001-06
    interacts_with:
      - CAP-PFM-TNL-002
      - CAP-PFM-TNL-003
      - CAP-PFM-TNL-005
    preconditions: A new customer workspace is requested and one remote readiness check reports a missing resource.
    steps: >-
      Submit the request, run construction through the failing readiness check, inspect ordinary access,
      repair the resource and retry.
    expected: >-
      The accepted identity remains the same; access stays closed on failure and opens only after the repaired
      attempt succeeds.
    negative: true
    data_needs: >-
      Create a separate run-owned workspace for each decision branch and an unaffected comparison workspace.
      Use a controlled clock, paused task or injected fault at the boundary named in the scenario.
    bound_to: []
    provenance: proposed
    source: >-
      rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-001-ask-for-a-new-workspace-and-have-every-application-build-it.md;
      rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-002-open-a-new-workspace-only-when-every-application-reports-it.md;
      rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-003-follow-a-provisioning-retry-it-and-hear-how-it-ended.md;
      rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-005-keep-people-and-background-work-out-of-a-workspace-that-is.md
    action_evidence:
      provenance: proposed
      source: >-
        rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-001-ask-for-a-new-workspace-and-have-every-application-build-it.md;
        rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-002-open-a-new-workspace-only-when-every-application-reports-it.md;
        rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-003-follow-a-provisioning-retry-it-and-hear-how-it-ended.md;
        rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-005-keep-people-and-background-work-out-of-a-workspace-that-is.md
    assertion_evidence:
      provenance: proposed
      source: >-
        rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-001-ask-for-a-new-workspace-and-have-every-application-build-it.md;
        rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-002-open-a-new-workspace-only-when-every-application-reports-it.md;
        rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-003-follow-a-provisioning-retry-it-and-hear-how-it-ended.md;
        rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-005-keep-people-and-background-work-out-of-a-workspace-that-is.md
evidence:
  - >-
    services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#may not ask for a tenant at
    all
  - >-
    services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a create that names no id as 400
    tenant_id_required, naming id
  - >-
    services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#answers
    the same tenant and the same job when the same submission is sent twice
  - >-
    services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#refuses
    a different submission that names a tenant id somebody already has
  - >-
    services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#creates
    no tenant at all when the strategy is refused: the request is rejected whole
  - >-
    services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#answers a tenant that is not
    usable yet, because the work has only been asked for
  - >-
    services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#answers
    the tenant it created and the job it submitted, as a successful request does
  - >-
    services-platform:modules/tenants/tests/integration/services/provisioning/tenant-hubspot-link.integration.spec.js#takes
    the customer\u2019s company when the request says nothing about one;
    services-platform:modules/tenants/tests/integration/services/provisioning/tenant-hubspot-link.integration.spec.js#stores
    the company the request names, in place of the customer\u2019s;
    services-platform:modules/tenants/tests/integration/services/provisioning/tenant-hubspot-link.integration.spec.js#links
    a tenant to no company when the request says so explicitly, though the customer has one
  - >-
    rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-001-ask-for-a-new-workspace-and-have-every-application-build-it.md;
    rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-002-open-a-new-workspace-only-when-every-application-reports-it.md;
    rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-003-follow-a-provisioning-retry-it-and-hear-how-it-ended.md;
    rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-005-keep-people-and-background-work-out-of-a-workspace-that-is.md
coverage:
  rule: 'gap: FND-PFM-TNL-066'
  transition: 'gap: FND-PFM-TNL-066'
  validation: covered
  permission: covered
  edge: 'gap: FND-PFM-TNL-066'
  failure: covered
  boundary: 'gap: FND-PFM-TNL-066'
  concurrency: 'gap: FND-PFM-TNL-066'
  invariant: covered
  interaction: 'gap: FND-PFM-TNL-066'
coverage_notes:
  transition: >-
    The listed scenarios sample lifecycle changes. Complete transition, guard and side-effect proof is still
    owed for the state models named in the coverage finding.
  interaction: >-
    The added interaction is proposed. Related capabilities not included in that scenario remain named in the
    coverage finding.
transition_obligations:
  - state_model: STATE-PFM-TNL-001
    transition_n: 1
    coverage: 'gap: FND-PFM-TNL-066'
    provenance: observed
    source: 'services-platform:modules/tenants/services/persistence/tenants.ts:activateProvisionedTenant'
  - state_model: STATE-PFM-TNL-001
    transition_n: 2
    coverage: 'gap: FND-PFM-TNL-066'
    provenance: observed
    source: >-
      services-platform:modules/tenants/services/provisioning/provision-tenant-failure.ts:applyTenantProvisioningFailure
  - state_model: STATE-PFM-TNL-001
    transition_n: 3
    coverage: 'gap: FND-PFM-TNL-066'
    provenance: observed
    source: >-
      services-platform:modules/tenants/services/provisioning/submit-tenant-provisioning.ts:retryTenantProvisioning
  - state_model: STATE-PFM-TNL-001
    transition_n: 4
    coverage: 'gap: FND-PFM-TNL-066'
    provenance: observed
    source: 'services-platform:modules/tenants/services/deletion/request-deletion.ts:requestTenantDeletion'
  - state_model: STATE-PFM-TNL-001
    transition_n: 5
    coverage: 'gap: FND-PFM-TNL-066'
    provenance: observed
    source: 'services-platform:modules/tenants/services/persistence/tenants.ts:enterTenantLoading'
  - state_model: STATE-PFM-TNL-001
    transition_n: 6
    coverage: 'gap: FND-PFM-TNL-066'
    provenance: observed
    source: 'services-platform:modules/tenants/services/deletion/request-deletion.ts:requestTenantDeletion'
  - state_model: STATE-PFM-TNL-001
    transition_n: 7
    coverage: 'gap: FND-PFM-TNL-066'
    provenance: observed
    source: 'services-platform:modules/tenants/services/persistence/tenants.ts:activateLoadedTenant'
  - state_model: STATE-PFM-TNL-001
    transition_n: 8
    coverage: 'gap: FND-PFM-TNL-066'
    provenance: observed
    source: 'services-platform:modules/tenants/services/lifecycle/lifecycle-transitions.ts:SUCCESSORS'
  - state_model: STATE-PFM-TNL-001
    transition_n: 9
    coverage: 'gap: FND-PFM-TNL-066'
    provenance: observed
    source: 'services-platform:modules/tenants/services/deletion/deletion-holds.ts:cancelTenantDeletion'
  - state_model: STATE-PFM-TNL-001
    transition_n: 10
    coverage: 'gap: FND-PFM-TNL-066'
    provenance: observed
    source: 'services-platform:modules/tenants/services/deletion/begin-destruction.ts:beginTenantDestruction'
  - state_model: STATE-PFM-TNL-001
    transition_n: 11
    coverage: 'gap: FND-PFM-TNL-066'
    provenance: observed
    source: 'services-platform:modules/tenants/services/persistence/tenants.ts:forceTenantDeletingAfterRestore'
  - state_model: STATE-PFM-TNL-002
    transition_n: 1
    coverage: 'gap: FND-PFM-TNL-066'
    provenance: observed
    source: >-
      services-platform:modules/tenants/services/provisioning/provision-tenant-operations.ts:tenantProvisioningOperations
  - state_model: STATE-PFM-TNL-002
    transition_n: 2
    coverage: 'gap: FND-PFM-TNL-066'
    provenance: documented
    source: 'services-platform:docs/jobs.md#§2 step 8'
  - state_model: STATE-PFM-TNL-002
    transition_n: 3
    coverage: 'gap: FND-PFM-TNL-066'
    provenance: observed
    source: >-
      services-platform:modules/tenants/services/provisioning/provision-tenant-operations.ts:tenantProvisioningOperations
  - state_model: STATE-PFM-TNL-002
    transition_n: 4
    coverage: 'gap: FND-PFM-TNL-066'
    provenance: observed
    source: >-
      services-platform:modules/tenants/services/provisioning/provision-tenant-workflow.ts:tenantProvisioningWorkflow
permission_obligations:
  - key: hq.tenants.provision
    where_checked: api
    scenario_examples:
      - ATS-PFM-TNL-001-01
    coverage: 'gap: FND-PFM-TNL-066'
    note: 'Examples do not establish the complete key-by-key grant, revoked-grant and staff-context matrix.'
    provenance: documented
    source: >-
      rhythm-v2-docs:specs/platform/tenant-lifecycle/planning/capabilities/CAP-PFM-TNL-001-ask-for-a-new-workspace-and-have-every-application-build-it.md
evidence_note: >-
  The test-specific convention lists an Evidence body section, but the corpus checker rejects it. Sources and
  verification limits remain in frontmatter so this artifact conforms without changing the checker.
---
# Request a complete customer workspace: Capability Test Specification

## Coverage

The category map separates defined scenarios from missing proof. A covered category has a scenario; a binding records inspected test assertions and carries no execution result. State-model completeness and untested interactions remain explicit gaps.

| Rule | Proved by |
|---|---|
| `BR-CAP-PFM-TNL-001-01` | `ATS-PFM-TNL-001-01` |
| `BR-CAP-PFM-TNL-001-02` | `ATS-PFM-TNL-001-02` |
| `BR-CAP-PFM-TNL-001-03` | `ATS-PFM-TNL-001-03` |
| `BR-CAP-PFM-TNL-001-04` | `ATS-PFM-TNL-001-04` |
| `BR-CAP-PFM-TNL-001-05` | `ATS-PFM-TNL-001-05` |
| `BR-CAP-PFM-TNL-001-06` | `ATS-PFM-TNL-001-06`, `ATS-PFM-TNL-001-09` |
| `BR-CAP-PFM-TNL-001-07` | `ATS-PFM-TNL-001-07` |
| `BR-CAP-PFM-TNL-001-08` | No scenario: `FND-PFM-TNL-066` |
| `BR-CAP-PFM-TNL-001-10` | `ATS-PFM-TNL-001-08` |

## Interactions With Related Capabilities

Accepted construction changes access only after readiness. The combined scenario sets up the stated boundary, changes the upstream condition and observes its effect on the dependent outcome. Its steps and assertions are proposed; component tests do not establish this combined execution.

| Related capability | Combined coverage |
|---|---|
| `CAP-PFM-TNL-002` | `ATS-PFM-TNL-001-09` (proposed) |
| `CAP-PFM-TNL-003` | `ATS-PFM-TNL-001-09` (proposed) |
| `CAP-PFM-TNL-004` | Gap: `FND-PFM-TNL-066` |
| `CAP-PFM-TNL-018` | Gap: `FND-PFM-TNL-066` |
