---
id: ATS-PFM-SEC-003
scope: CAP-PFM-SEC-003
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-003-01
    title: Customer administrators cannot control setup
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-01
    preconditions: Prepare a signed customer-administrator context.
    steps: 'Attempt workspace creation, progress reading, retry and participant initialization.'
    expected: Each request fails and leaves the existing workspace intact.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#may not ask for
        a tenant at all
      - TST-PFM-SEC-229
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#may not watch
        the provisioning of their own tenant
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#may not
        provision their own tenant again
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#may not
        initialize a participant of their own tenant
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#leaves the
        tenant exactly as it was after all of those refusals
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#may not ask for a
      tenant at all
    category: permission
    test_references:
      - >-
        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#may not watch
        the provisioning of their own tenant
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#may not
        provision their own tenant again
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#may not
        initialize a participant of their own tenant
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#leaves the
        tenant exactly as it was after all of those refusals
    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_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-003-02
    title: Provisioning identifier validation
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-02
      - INV-DOM-PFM-SEC-002-01
    preconditions: Prepare an occupied identifier and a retired workspace identifier.
    steps: >-
      Request creation with missing, generated, adjacent-dot, reserved and occupied values, an
      obsolete domain field, and a new customer without an identifier.
    expected: >-
      Invalid or missing values return their 400 codes; occupation returns 409; the obsolete field
      is rejected.
    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 create that names
        no id as 400 tenant_id_required, naming id
      - TST-PFM-SEC-230
      - >-
        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#refuses an id another tenant
        has as 409 tenant_id_taken
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a create that sends
        domain as 400, naming the unknown property
      - >-
        services-platform:modules/tenants/tests/unit/aws/api/tenant-provisioning-mapper.spec.ts#refuses
        a new customer that names no id, naming new_customer.id
      - TST-PFM-SEC-265
    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
    test_references:
      - >-
        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#refuses an id another tenant
        has as 409 tenant_id_taken
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#refuses a create that sends
        domain as 400, naming the unknown property
      - >-
        services-platform:modules/tenants/tests/unit/aws/api/tenant-provisioning-mapper.spec.ts#refuses
        a new customer that names no id, naming new_customer.id
    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_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-003-03
    title: Submission replay and identifier collisions
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-03
      - INV-DOM-PFM-SEC-002-12
    preconditions: Choose a submission identity.
    steps: 'Submit twice, then use a different submission with the same workspace identifier.'
    expected: Replay returns the same workspace and job; the competing submission fails.
    negative: true
    data_needs: Use the records described in the setup.
    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-SEC-258
      - >-
        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
    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: concurrency
    test_references:
      - >-
        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
    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_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-003-04
    title: Readiness precedes activation
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-04
    preconditions: Register the participants used by the fixture.
    steps: Read the workspace during provisioning and after the job finishes.
    expected: >-
      It begins unavailable and becomes active with an activation timestamp after participant work
      and readiness checks.
    negative: false
    data_needs: Use the records described in the setup.
    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
      - TST-PFM-SEC-229
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#shows one step
        per participant, then the readiness check and the activation
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#records when the
        tenant became usable
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#asks
        every participant to confirm what it made before the tenant is opened
      - TST-PFM-SEC-258
    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
    test_references:
      - >-
        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#shows one step
        per participant, then the readiness check and the activation
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#records when the
        tenant became usable
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#asks
        every participant to confirm what it made before the tenant is opened
    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_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-003-05
    title: Failure retention and targeted retry
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-05
    preconditions: Configure one participant to fail on its first call.
    steps: 'Run provisioning, retry the failure and attempt retry after activation.'
    expected: >-
      Failure state and summary are retained; the retry finishes remaining work; retry from active
      state fails.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#leaves the
        tenant saying its provisioning failed, which is what makes it retryable
      - TST-PFM-SEC-229
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#leaves
        the tenant where an operator can see it, and does not open it
      - TST-PFM-SEC-258
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#does
        not repeat work the other macroservice completed before it lost the answer
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#refuses to
        provision a tenant again whose provisioning did not fail
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#leaves the tenant
      saying its provisioning failed, which is what makes it retryable
    category: failure
    test_references:
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#leaves the
        tenant saying its provisioning failed, which is what makes it retryable
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#leaves
        the tenant where an operator can see it, and does not open it
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#does
        not repeat work the other macroservice completed before it lost the answer
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#refuses to
        provision a tenant again whose provisioning did not fail
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#leaves the
        tenant saying its provisioning failed, which is what makes it retryable
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#leaves the
        tenant saying its provisioning failed, which is what makes it retryable
    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-003-06
    title: The first-administrator invitation ledger
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-06
    preconditions: Request a new customer and first administrator.
    steps: 'Run provisioning and replay its work, then provision for an existing customer.'
    expected: >-
      One invitation and ledger entry exist for the new customer; replay sends none and the
      existing-customer case sends none.
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#invites
        them once, and records the invitation in the ledger
      - TST-PFM-SEC-258
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#does
        not invite them a second time when the provisioning is run again
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#invites
        nobody when the request did not create the customer
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#invites
      them once, and records the invitation in the ledger
    category: interaction
    test_references:
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#invites
        them once, and records the invitation in the ledger
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#does
        not invite them a second time when the provisioning is run again
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#invites
        nobody when the request did not create the customer
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#invites
        them once, and records the invitation in the ledger
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#invites
        them once, and records the invitation in the ledger
    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-003-07
    title: Provisioning outcome notices are not duplicated
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-07
    preconditions: Prepare a requester with an e-mail address.
    steps: 'Finish successful and failed provisioning jobs, then replay their final tasks.'
    expected: >-
      Each outcome produces its requester notice and operations alert with the job link; completed
      notice delivery is not repeated.
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provisioning-notices.integration.spec.js#links
        to the job’s own page in Rhythm HQ, so the requester can read the steps
      - TST-PFM-SEC-259
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provisioning-notices.integration.spec.js#repeats
        the failure summary the job recorded, so the requester reads why
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provisioning-notices.integration.spec.js#sends
        nothing a second time when the activate task runs again
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning-alerts.e2e.spec.js#alerts
        once for the job, however often the task that ends it runs
      - TST-PFM-SEC-228
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning-alerts.e2e.spec.js#never
        fails the job: the tenant is active, the requester told, and nothing is alerted
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/provisioning-notices.integration.spec.js#links
      to the job’s own page in Rhythm HQ, so the requester can read the steps
    category: edge
    test_references:
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provisioning-notices.integration.spec.js#links
        to the job’s own page in Rhythm HQ, so the requester can read the steps
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provisioning-notices.integration.spec.js#repeats
        the failure summary the job recorded, so the requester reads why
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provisioning-notices.integration.spec.js#sends
        nothing a second time when the activate task runs again
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning-alerts.e2e.spec.js#alerts
        once for the job, however often the task that ends it runs
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning-alerts.e2e.spec.js#never
        fails the job: the tenant is active, the requester told, and nothing is alerted
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provisioning-notices.integration.spec.js#links
        to the job’s own page in Rhythm HQ, so the requester can read the steps
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/provisioning-notices.integration.spec.js#links
        to the job’s own page in Rhythm HQ, so the requester can read the steps
    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-003-08
    title: Sender validation is atomic with submission
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-08
    preconditions: Prepare an otherwise valid provisioning request.
    steps: >-
      Supply a domain strategy without a usable hostname, an address outside a supplied domain and a
      URL as the domain.
    expected: Validation names the relevant input and creates neither workspace nor sender identity.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#refuses
        an address outside the domain, because an identity proved for one domain may not send as
        another
      - TST-PFM-SEC-261
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#refuses
        a domain that is a URL rather than a hostname
      - >-
        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#proves
        the tenant’s id as the domain, the id being a hostname
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#refuses
      an address outside the domain, because an identity proved for one domain may not send as
      another
    category: validation
    test_references:
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#refuses
        an address outside the domain, because an identity proved for one domain may not send as
        another
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#refuses
        a domain that is a URL rather than a hostname
      - >-
        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#proves
        the tenant’s id as the domain, the id being a hostname
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#refuses
        an address outside the domain, because an identity proved for one domain may not send as
        another
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js#refuses
        an address outside the domain, because an identity proved for one domain may not send as
        another
    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-003-09
    title: Stranded provisioning repair is repeatable
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-11
    preconditions: Prepare a provisioning workspace whose job was reconciled as failed before starting.
    steps: Run repair twice alongside an actually running setup.
    expected: The stranded workspace becomes failed and is notified once; the running setup remains intact.
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/repair-stranded-provisioning.integration.spec.js#moves
        the stranded tenant to provisioning_failed, which makes it retryable and deletable again
      - TST-PFM-SEC-260
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/repair-stranded-provisioning.integration.spec.js#sends
        the requester nothing a second time
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/repair-stranded-provisioning.integration.spec.js#leaves
        a tenant whose provisioning is still running provisioning
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/repair-stranded-provisioning.integration.spec.js#moves
      the stranded tenant to provisioning_failed, which makes it retryable and deletable again
    category: failure
    test_references:
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/repair-stranded-provisioning.integration.spec.js#moves
        the stranded tenant to provisioning_failed, which makes it retryable and deletable again
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/repair-stranded-provisioning.integration.spec.js#sends
        the requester nothing a second time
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/repair-stranded-provisioning.integration.spec.js#leaves
        a tenant whose provisioning is still running provisioning
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/repair-stranded-provisioning.integration.spec.js#moves
        the stranded tenant to provisioning_failed, which makes it retryable and deletable again
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/repair-stranded-provisioning.integration.spec.js#moves
        the stranded tenant to provisioning_failed, which makes it retryable and deletable again
    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-003-10
    title: Initialization refuses unsafe targets
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-12
    preconditions: Prepare pending-deletion and deleting workspaces.
    steps: 'Initialize them, an unknown participant and a missing workspace.'
    expected: All attempts fail without changing workspace state.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/initialize-tenant.integration.spec.js#refuses
        a tenant whose deletion is pending
      - TST-PFM-SEC-255
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/initialize-tenant.integration.spec.js#refuses
        a tenant that is being deleted
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/initialize-tenant.integration.spec.js#refuses
        a participant that is not in the registry, and names the ones that are
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#refuses a
        participant nobody has heard of as 400
      - TST-PFM-SEC-229
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/integration/services/provisioning/initialize-tenant.integration.spec.js#refuses
      a tenant whose deletion is pending
    category: boundary
    test_references:
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/initialize-tenant.integration.spec.js#refuses
        a tenant whose deletion is pending
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/initialize-tenant.integration.spec.js#refuses
        a tenant that is being deleted
      - >-
        services-platform:modules/tenants/tests/integration/services/provisioning/initialize-tenant.integration.spec.js#refuses
        a participant that is not in the registry, and names the ones that are
      - >-
        services-platform:modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js#refuses a
        participant nobody has heard of as 400
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/initialize-tenant.integration.spec.js#refuses
        a tenant whose deletion is pending
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/integration/services/provisioning/initialize-tenant.integration.spec.js#refuses
        a tenant whose deletion is pending
    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-003-11
    title: Loading status and initiation information
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-13
      - INV-DOM-PFM-SEC-002-04
    preconditions: Prepare a live workspace and an implementation workspace.
    steps: Open initial loading for each.
    expected: >-
      Live status is refused and unchanged; implementation enters loading with the initiating
      person, time and reason.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        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
      - TST-PFM-SEC-220
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#left the live
        tenant exactly as it was, so the refusal did not half-happen
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#records who opened
        the load and why, which is what the row is evidence of
    provenance: test
    source: >-
      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
    category: transition
    test_references:
      - >-
        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
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#left the live
        tenant exactly as it was, so the refusal did not half-happen
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#records who opened
        the load and why, which is what the row is evidence of
    action_evidence:
      provenance: test
      source: >-
        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: test
      source: >-
        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: >-
      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-003-12
    title: Reset confirmation and participant support
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-14
      - INV-DOM-PFM-SEC-002-11
    preconditions: Prepare a loading workspace.
    steps: >-
      Try wrong confirmation, unsupported participant and concurrent reset, then run a supported
      reset.
    expected: >-
      Invalid requests leave the workspace intact; the successful reset removes imported records,
      retains configuration and leaves loading in place.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses a
        confirmation that is not the tenant’s own id, without saying what to type
      - TST-PFM-SEC-220
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#names every
        participant it could not reach, so an operator knows what to deploy
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses the second
        409, naming the reset that is running
      - >-
        services-platform:modules/tenants/tests/integration/services/reset/reset-tenant.integration.spec.js#keeps
        the tenant row itself, which is the whole point of a reset
      - TST-PFM-SEC-263
      - >-
        services-platform:modules/tenants/tests/integration/services/reset/reset-tenant.integration.spec.js#leaves
        the tenant loading, so the corrected package can be loaded at once
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses a
      confirmation that is not the tenant’s own id, without saying what to type
    category: validation
    test_references:
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses a
        confirmation that is not the tenant’s own id, without saying what to type
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#names every
        participant it could not reach, so an operator knows what to deploy
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses the second
        409, naming the reset that is running
      - >-
        services-platform:modules/tenants/tests/integration/services/reset/reset-tenant.integration.spec.js#keeps
        the tenant row itself, which is the whole point of a reset
      - >-
        services-platform:modules/tenants/tests/integration/services/reset/reset-tenant.integration.spec.js#leaves
        the tenant loading, so the corrected package can be loaded at once
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses a
        confirmation that is not the tenant’s own id, without saying what to type
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses a
        confirmation that is not the tenant’s own id, without saying what to type
    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-003-13
    title: Activation permission independently of import
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-15
    preconditions: 'Prepare a loaded workspace and callers with import-only, customer and activation authority.'
    steps: Request activation with each caller.
    expected: >-
      The first two receive refusals; activation authority succeeds while preserving business status
      and load initiation information.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses the staff
        member who ran the import, activation being the other key
      - TST-PFM-SEC-220
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#is served to a
        staff member holding hq.tenants.activate, returning the tenant to active
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#leaves the status
        where it was, going live being the separate decision
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses the staff
      member who ran the import, activation being the other key
    category: permission
    test_references:
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses the staff
        member who ran the import, activation being the other key
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#is served to a
        staff member holding hq.tenants.activate, returning the tenant to active
      - >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#leaves the status
        where it was, going live being the separate decision
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses the staff
        member who ran the import, activation being the other key
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses the staff
        member who ran the import, activation being the other key
    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-003-14
    title: The provisioning wizard and job handoff
    level: browser
    proves:
      - AS-JNY-PFM-SEC-001-01
      - AS-JNY-PFM-SEC-001-02
    preconditions: Start an HQ staff session.
    steps: >-
      Complete a new-customer provisioning form, submit it and follow the returned job; also submit
      a taken identifier.
    expected: 'The job page presents progress, and an occupied identifier appears as a field-related error.'
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - 'react-console:e2e/mock/hq-ops.mock.spec.ts#walks every step and lands on the job it started'
      - TST-PFM-SEC-023
      - >-
        react-console:e2e/mock/hq-ops.mock.spec.ts#puts Platform's refusal of a taken tenant ID on
        the Tenant ID
      - >-
        react-console:e2e/mock/hq-ops.mock.spec.ts#shows a failed job's reason and retries its
        provisioning
    provenance: test
    source: 'react-console:e2e/mock/hq-ops.mock.spec.ts#walks every step and lands on the job it started'
    category: rule
    test_references:
      - 'react-console:e2e/mock/hq-ops.mock.spec.ts#walks every step and lands on the job it started'
      - >-
        react-console:e2e/mock/hq-ops.mock.spec.ts#puts Platform's refusal of a taken tenant ID on
        the Tenant ID
      - >-
        react-console:e2e/mock/hq-ops.mock.spec.ts#shows a failed job's reason and retries its
        provisioning
    action_evidence:
      provenance: test
      source: 'react-console:e2e/mock/hq-ops.mock.spec.ts#walks every step and lands on the job it started'
    assertion_evidence:
      provenance: test
      source: 'react-console:e2e/mock/hq-ops.mock.spec.ts#walks every step and lands on the job it started'
    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-003-15
    title: 'Workspace lifecycle: provisioning to active'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-04
    state_model: STATE-PFM-SEC-001
    transition:
      from: provisioning
      to: active
      index: 0
    preconditions: >-
      Prepare a run-owned workspace lifecycle in provisioning state with the authority and inputs
      required by the cited transition.
    steps:
      - do: Finish all enabled participants and run the setup activation task.
        expect: >-
          After the stated action, observe the workspace lifecycle in active state. This case does
          not require an additional history event unless the transition explicitly defines one.
        provenance: proposed
        source:
          - >-
            services-platform:modules/tenants/services/persistence/tenants.ts:activateProvisionedTenant
          - >-
            services-platform at ad3f6a65:
            modules/tenants/services/lifecycle/lifecycle-transitions.ts;
            services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
            services/access/tenant-availability.ts; db/tenants.table.ts;
            docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    expected: >-
      After the stated action, observe the workspace lifecycle in active 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/services/persistence/tenants.ts:activateProvisionedTenant'
      - >-
        services-platform at ad3f6a65: modules/tenants/services/lifecycle/lifecycle-transitions.ts;
        services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
        services/access/tenant-availability.ts; db/tenants.table.ts;
        docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    guard_cases: The activation workflow is authoritative for this provisioning submission.
    side_effects_to_verify:
      - Apply the requested business status
      - Set first activation only when absent
      - Reconcile standing access for the workspace and customer
      - Claim and attempt completion notifications
      - Invalidate availability in the current process
    transition_assertion:
      state: active
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/services/persistence/tenants.ts:activateProvisionedTenant
        - >-
          services-platform at ad3f6a65:
          modules/tenants/services/lifecycle/lifecycle-transitions.ts;
          services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
          services/access/tenant-availability.ts; db/tenants.table.ts;
          docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/services/persistence/tenants.ts:activateProvisionedTenant
        - >-
          services-platform at ad3f6a65:
          modules/tenants/services/lifecycle/lifecycle-transitions.ts;
          services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
          services/access/tenant-availability.ts; db/tenants.table.ts;
          docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/services/persistence/tenants.ts:activateProvisionedTenant
        - >-
          services-platform at ad3f6a65:
          modules/tenants/services/lifecycle/lifecycle-transitions.ts;
          services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
          services/access/tenant-availability.ts; db/tenants.table.ts;
          docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-003-16
    title: 'Workspace lifecycle: provisioning to provisioning_failed'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-05
    state_model: STATE-PFM-SEC-001
    transition:
      from: provisioning
      to: provisioning_failed
      index: 1
    preconditions: >-
      Prepare a run-owned workspace lifecycle in provisioning state with the authority and inputs
      required by the cited transition.
    steps:
      - do: >-
          Fail an unfinished setup job and run its failure handler; repeat through stranded-job
          repair.
        expect: >-
          After the stated action, observe the workspace lifecycle in provisioning_failed state.
          This case does not require an additional history event unless the transition explicitly
          defines one.
        provenance: proposed
        source:
          - 'services-platform:modules/tenants/services/persistence/tenants.ts:failTenantProvisioning'
          - >-
            services-platform at ad3f6a65:
            modules/tenants/services/lifecycle/lifecycle-transitions.ts;
            services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
            services/access/tenant-availability.ts; db/tenants.table.ts;
            docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    expected: >-
      After the stated action, observe the workspace lifecycle in provisioning_failed 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/services/persistence/tenants.ts:failTenantProvisioning'
      - >-
        services-platform at ad3f6a65: modules/tenants/services/lifecycle/lifecycle-transitions.ts;
        services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
        services/access/tenant-availability.ts; db/tenants.table.ts;
        docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    guard_cases: Change only a workspace still in provisioning.
    side_effects_to_verify:
      - Claim and attempt failure notifications
      - Retain completed participant work
    transition_assertion:
      state: provisioning_failed
      provenance: proposed
      source:
        - 'services-platform:modules/tenants/services/persistence/tenants.ts:failTenantProvisioning'
        - >-
          services-platform at ad3f6a65:
          modules/tenants/services/lifecycle/lifecycle-transitions.ts;
          services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
          services/access/tenant-availability.ts; db/tenants.table.ts;
          docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    action_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/tenants/services/persistence/tenants.ts:failTenantProvisioning'
        - >-
          services-platform at ad3f6a65:
          modules/tenants/services/lifecycle/lifecycle-transitions.ts;
          services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
          services/access/tenant-availability.ts; db/tenants.table.ts;
          docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    assertion_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/tenants/services/persistence/tenants.ts:failTenantProvisioning'
        - >-
          services-platform at ad3f6a65:
          modules/tenants/services/lifecycle/lifecycle-transitions.ts;
          services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
          services/access/tenant-availability.ts; db/tenants.table.ts;
          docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-003-17
    title: 'Workspace lifecycle: provisioning_failed to provisioning'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-05
    state_model: STATE-PFM-SEC-001
    transition:
      from: provisioning_failed
      to: provisioning
      index: 2
    preconditions: >-
      Prepare a run-owned workspace lifecycle in provisioning_failed state with the authority and
      inputs required by the cited transition.
    steps:
      - do: Retry the failed setup using staff provisioning authority.
        expect: >-
          After the stated action, observe the workspace lifecycle in provisioning state. This case
          does not require an additional history event unless the transition explicitly defines one.
        provenance: proposed
        source:
          - >-
            services-platform:modules/tenants/services/provisioning/submit-tenant-provisioning.ts
            (Retrying)
          - >-
            services-platform at ad3f6a65:
            modules/tenants/services/lifecycle/lifecycle-transitions.ts;
            services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
            services/access/tenant-availability.ts; db/tenants.table.ts;
            docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    expected: >-
      After the stated action, observe the workspace lifecycle in provisioning 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/services/provisioning/submit-tenant-provisioning.ts
        (Retrying)
      - >-
        services-platform at ad3f6a65: modules/tenants/services/lifecycle/lifecycle-transitions.ts;
        services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
        services/access/tenant-availability.ts; db/tenants.table.ts;
        docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    guard_cases: The latest job failed and the caller has provisioning authority.
    side_effects_to_verify:
      - Create a retry job with completed steps carried forward
    transition_assertion:
      state: provisioning
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/services/provisioning/submit-tenant-provisioning.ts
          (Retrying)
        - >-
          services-platform at ad3f6a65:
          modules/tenants/services/lifecycle/lifecycle-transitions.ts;
          services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
          services/access/tenant-availability.ts; db/tenants.table.ts;
          docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/services/provisioning/submit-tenant-provisioning.ts
          (Retrying)
        - >-
          services-platform at ad3f6a65:
          modules/tenants/services/lifecycle/lifecycle-transitions.ts;
          services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
          services/access/tenant-availability.ts; db/tenants.table.ts;
          docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/services/provisioning/submit-tenant-provisioning.ts
          (Retrying)
        - >-
          services-platform at ad3f6a65:
          modules/tenants/services/lifecycle/lifecycle-transitions.ts;
          services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
          services/access/tenant-availability.ts; db/tenants.table.ts;
          docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-003-18
    title: 'Workspace lifecycle: active to loading'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-13
    state_model: STATE-PFM-SEC-001
    transition:
      from: active
      to: loading
      index: 4
    preconditions: >-
      Prepare a run-owned workspace lifecycle in active state with the authority and inputs required
      by the cited transition.
    steps:
      - do: Open an initial load as the import operator.
        expect: >-
          After the stated action, observe the workspace lifecycle in loading state. This case does
          not require an additional history event unless the transition explicitly defines one.
        provenance: proposed
        source:
          - 'services-platform:modules/tenants/services/persistence/tenants.ts:enterTenantLoading'
          - >-
            services-platform at ad3f6a65:
            modules/tenants/services/lifecycle/lifecycle-transitions.ts;
            services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
            services/access/tenant-availability.ts; db/tenants.table.ts;
            docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    expected: >-
      After the stated action, observe the workspace lifecycle in loading 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/services/persistence/tenants.ts:enterTenantLoading'
      - >-
        services-platform at ad3f6a65: modules/tenants/services/lifecycle/lifecycle-transitions.ts;
        services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
        services/access/tenant-availability.ts; db/tenants.table.ts;
        docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    guard_cases: The workspace is in implementation; an optional reason is limited to five hundred characters.
    side_effects_to_verify:
      - 'Retain opening actor, time and reason'
      - Invalidate local availability; other processes observe their cache bound
    transition_assertion:
      state: loading
      provenance: proposed
      source:
        - 'services-platform:modules/tenants/services/persistence/tenants.ts:enterTenantLoading'
        - >-
          services-platform at ad3f6a65:
          modules/tenants/services/lifecycle/lifecycle-transitions.ts;
          services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
          services/access/tenant-availability.ts; db/tenants.table.ts;
          docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    action_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/tenants/services/persistence/tenants.ts:enterTenantLoading'
        - >-
          services-platform at ad3f6a65:
          modules/tenants/services/lifecycle/lifecycle-transitions.ts;
          services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
          services/access/tenant-availability.ts; db/tenants.table.ts;
          docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    assertion_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/tenants/services/persistence/tenants.ts:enterTenantLoading'
        - >-
          services-platform at ad3f6a65:
          modules/tenants/services/lifecycle/lifecycle-transitions.ts;
          services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
          services/access/tenant-availability.ts; db/tenants.table.ts;
          docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-003-19
    title: 'Workspace lifecycle: loading to active'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-15
    state_model: STATE-PFM-SEC-001
    transition:
      from: loading
      to: active
      index: 5
    preconditions: >-
      Prepare a run-owned workspace lifecycle in loading state with the authority and inputs
      required by the cited transition.
    steps:
      - do: Activate the loaded workspace as a staff member holding activation authority.
        expect: >-
          After the stated action, observe the workspace lifecycle in active state. This case does
          not require an additional history event unless the transition explicitly defines one.
        provenance: proposed
        source:
          - 'services-platform:modules/tenants/services/persistence/tenants.ts:activateLoadedTenant'
          - >-
            services-platform at ad3f6a65:
            modules/tenants/services/lifecycle/lifecycle-transitions.ts;
            services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
            services/access/tenant-availability.ts; db/tenants.table.ts;
            docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    expected: >-
      After the stated action, observe the workspace lifecycle in active 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/services/persistence/tenants.ts:activateLoadedTenant'
      - >-
        services-platform at ad3f6a65: modules/tenants/services/lifecycle/lifecycle-transitions.ts;
        services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
        services/access/tenant-availability.ts; db/tenants.table.ts;
        docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    guard_cases: Lifecycle is loading and the caller has activation authority.
    side_effects_to_verify:
      - Preserve the existing first-activation timestamp
      - Preserve business status
      - Invalidate local availability
    transition_assertion:
      state: active
      provenance: proposed
      source:
        - 'services-platform:modules/tenants/services/persistence/tenants.ts:activateLoadedTenant'
        - >-
          services-platform at ad3f6a65:
          modules/tenants/services/lifecycle/lifecycle-transitions.ts;
          services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
          services/access/tenant-availability.ts; db/tenants.table.ts;
          docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    action_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/tenants/services/persistence/tenants.ts:activateLoadedTenant'
        - >-
          services-platform at ad3f6a65:
          modules/tenants/services/lifecycle/lifecycle-transitions.ts;
          services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
          services/access/tenant-availability.ts; db/tenants.table.ts;
          docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    assertion_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/tenants/services/persistence/tenants.ts:activateLoadedTenant'
        - >-
          services-platform at ad3f6a65:
          modules/tenants/services/lifecycle/lifecycle-transitions.ts;
          services/persistence/tenants.ts; services/provisioning/*; services/deletion/*;
          services/access/tenant-availability.ts; db/tenants.table.ts;
          docs/tenants/tenant-lifecycle-plan.md §2.2, §4, §5.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-003-20
    title: Prepare a workspace for customer use with establish and administer a customer
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-001-02
      - BR-CAP-PFM-SEC-003-03
    exercises:
      - CAP-PFM-SEC-003
      - CAP-PFM-SEC-001
    preconditions: A chosen customer and workspace identifier are unused.
    steps: >-
      Submit setup with a new customer, replay it, then try another submission with the same
      workspace identifier.
    expected: >-
      Replay returns the original customer, workspace and job; the competing submission creates
      none.
    negative: false
    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/services/persistence/customers.ts:requireCustomerId'
      - >-
        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
    action_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/customers/services/persistence/customers.ts:requireCustomerId'
        - >-
          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: proposed
      source:
        - 'services-platform:modules/customers/services/persistence/customers.ts:requireCustomerId'
        - >-
          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_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-003-21
    title: Prepare a workspace for customer use with maintain workspace information and operating status
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-002-09
      - BR-CAP-PFM-SEC-003-13
    exercises:
      - CAP-PFM-SEC-003
      - CAP-PFM-SEC-002
    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-003-22
    title: Prepare a workspace for customer use with manage a workspace retirement request
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-05
      - BR-CAP-PFM-SEC-004-02
    exercises:
      - CAP-PFM-SEC-003
      - CAP-PFM-SEC-004
    preconditions: A failed setup has a disabled workspace and completed participant work.
    steps: >-
      Request retirement instead of retrying setup, then attempt a setup retry against the pending
      retirement.
    expected: Retirement owns the lifecycle and setup cannot reactivate the workspace.
    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/provisioning/provision-tenant.integration.spec.js#does
        the missing work and not the finished work when it is provisioned again
      - >-
        services-platform:modules/tenants/tests/integration/services/deletion/request-deletion.integration.spec.js#refuses
        a tenant that is still live, because people must lose access first
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#does
          the missing work and not the finished work when it is provisioned again
        - >-
          services-platform:modules/tenants/tests/integration/services/deletion/request-deletion.integration.spec.js#refuses
          a tenant that is still live, because people must lose access first
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#does
          the missing work and not the finished work when it is provisioned again
        - >-
          services-platform:modules/tenants/tests/integration/services/deletion/request-deletion.integration.spec.js#refuses
          a tenant that is still live, because people must lose access first
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-003-23
    title: Prepare a workspace for customer use with offer and manage an invitation
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-06
      - BR-CAP-PFM-SEC-008-06
    exercises:
      - CAP-PFM-SEC-003
      - CAP-PFM-SEC-008
    preconditions: A new-customer setup specifies the first administrator.
    steps: >-
      Complete setup, replay its invitation step, and inspect the invitation and pending
      assignments.
    expected: >-
      One customer-wide administrator offer exists and pending assignments grant no access before
      acceptance.
    negative: false
    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/provisioning/provision-tenant.integration.spec.js#does
        not invite them a second time when the provisioning is run again
      - >-
        services-platform:modules/security/tests/unit/services/invitations/invite-user.spec.js#refuses
        a grant that reaches outside the wall the user is being created in, before a user exists
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#does
          not invite them a second time when the provisioning is run again
        - >-
          services-platform:modules/security/tests/unit/services/invitations/invite-user.spec.js#refuses
          a grant that reaches outside the wall the user is being created in, before a user exists
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#does
          not invite them a second time when the provisioning is run again
        - >-
          services-platform:modules/security/tests/unit/services/invitations/invite-user.spec.js#refuses
          a grant that reaches outside the wall the user is being created in, before a user exists
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-003-24
    title: Prepare a workspace for customer use with control staff access to customer workspaces
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-003-04
      - BR-CAP-PFM-SEC-017-08
    exercises:
      - CAP-PFM-SEC-003
      - CAP-PFM-SEC-017
    preconditions: An eligible Rhythm Administrator exists before a new customer workspace is provisioned.
    steps: 'Finish provisioning, read standing access, and enter the workspace with a fresh context.'
    expected: >-
      Standing access and its assignment agree on the new customer and allow the intended customer
      entry.
    negative: false
    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/provisioning/provision-tenant.integration.spec.js#asks
        every participant to confirm what it made before the tenant is opened
      - >-
        services-platform:modules/security/tests/integration/services/staff-access/rhythm-administrator-standing-access.integration.spec.js#gives
        each Rhythm Administrator one active customer-level standing grant in every customer but
        Rhythm’s own
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#asks
          every participant to confirm what it made before the tenant is opened
        - >-
          services-platform:modules/security/tests/integration/services/staff-access/rhythm-administrator-standing-access.integration.spec.js#gives
          each Rhythm Administrator one active customer-level standing grant in every customer but
          Rhythm’s own
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js#asks
          every participant to confirm what it made before the tenant is opened
        - >-
          services-platform:modules/security/tests/integration/services/staff-access/rhythm-administrator-standing-access.integration.spec.js#gives
          each Rhythm Administrator one active customer-level standing grant in every customer but
          Rhythm’s own
    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-loading.e2e.spec.js;
    modules/tenants/tests/e2e/tenant-provisioning-alerts.e2e.spec.js;
    modules/tenants/tests/e2e/tenant-provisioning.e2e.spec.js;
    modules/tenants/tests/e2e/tenants.e2e.spec.js;
    modules/tenants/tests/integration/services/provisioning/initialize-tenant.integration.spec.js;
    modules/tenants/tests/integration/services/provisioning/provision-tenant.integration.spec.js;
    modules/tenants/tests/integration/services/provisioning/provisioning-notices.integration.spec.js;
    modules/tenants/tests/integration/services/provisioning/repair-stranded-provisioning.integration.spec.js;
    modules/tenants/tests/integration/services/provisioning/tenant-email-strategy.integration.spec.js;
    modules/tenants/tests/integration/services/reset/reset-tenant.integration.spec.js;
    modules/tenants/tests/unit/aws/api/tenant-provisioning-mapper.spec.ts.
  - '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: covered
  boundary: covered
  concurrency: covered
  invariant: 'gap: FND-PFM-SEC-060'
  interaction: covered
coverage_notes:
  invariant: No scenario isolates this category. The referenced finding retains the missing design proof.
invariant_proofs:
  - scenario: ATS-PFM-SEC-003-02
    proves:
      - INV-DOM-PFM-SEC-002-01
    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
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
  - scenario: ATS-PFM-SEC-003-03
    proves:
      - INV-DOM-PFM-SEC-002-12
    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
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
  - scenario: ATS-PFM-SEC-003-11
    proves:
      - INV-DOM-PFM-SEC-002-04
    provenance: test
    source: >-
      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
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
  - scenario: ATS-PFM-SEC-003-12
    proves:
      - INV-DOM-PFM-SEC-002-11
    provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/hq-tenant-loading.e2e.spec.js#refuses a
      confirmation that is not the tenant’s own id, without saying what to type
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
permission_proof_review:
  - key: hq.tenants.provision
    scenario_candidates:
      - ATS-PFM-SEC-003-01
      - ATS-PFM-SEC-003-13
      - ATS-PFM-SEC-003-19
    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-060
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-003-provision-a-workspace-and-bring-it-into-service.md
  - key: hq.tenants.read
    scenario_candidates:
      - ATS-PFM-SEC-003-01
      - ATS-PFM-SEC-003-13
      - ATS-PFM-SEC-003-19
    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-060
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-003-provision-a-workspace-and-bring-it-into-service.md
  - key: hq.tenants.activate
    scenario_candidates:
      - ATS-PFM-SEC-003-01
      - ATS-PFM-SEC-003-13
      - ATS-PFM-SEC-003-19
    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-060
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-003-provision-a-workspace-and-bring-it-into-service.md
  - key: hq.data-runs.manage
    scenario_candidates:
      - ATS-PFM-SEC-003-01
      - ATS-PFM-SEC-003-13
      - ATS-PFM-SEC-003-19
    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-060
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-003-provision-a-workspace-and-bring-it-into-service.md
examiner: codex
examined_at: '2026-10-23'
final_text: OpenAI
---
# Prepare a workspace for customer use: Capability Test Specification

## Coverage

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

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.
