---
id: ATS-PFM-SEC-005
scope: CAP-PFM-SEC-005
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-005-01
    title: Hashed storage and seven-day expiry
    level: api
    proves:
      - BR-CAP-PFM-SEC-005-01
      - INV-DOM-PFM-SEC-003-04
    preconditions: Prepare a new invitation.
    steps: 'Inspect storage, accept it and attempt an expired invitation.'
    expected: >-
      Storage holds the token hash, expiry is seven days after issuance and expired acceptance
      fails; activation is not repeated.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/unit/services/invitations/invite-user.spec.js#expires
        the invitation 7 days after the execution's clock, on the invitation and on the user
      - TST-PFM-SEC-210
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#records
        only the hash of the token it sent
      - TST-PFM-SEC-083
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#says
        the invitation expired
    provenance: test
    source: >-
      services-platform:modules/security/tests/unit/services/invitations/invite-user.spec.js#expires
      the invitation 7 days after the execution's clock, on the invitation and on the user
    category: invariant
    test_references:
      - >-
        services-platform:modules/security/tests/unit/services/invitations/invite-user.spec.js#expires
        the invitation 7 days after the execution's clock, on the invitation and on the user
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#records
        only the hash of the token it sent
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#says
        the invitation expired
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/unit/services/invitations/invite-user.spec.js#expires
        the invitation 7 days after the execution's clock, on the invitation and on the user
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/unit/services/invitations/invite-user.spec.js#expires
        the invitation 7 days after the execution's clock, on the invitation and on the user
    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-005-02
    title: The public invitation summary
    level: api
    proves:
      - BR-CAP-PFM-SEC-005-02
    preconditions: Prepare a usable invitation.
    steps: Fetch its summary without signing in.
    expected: 'Only the listed presentation fields are returned, with the address masked.'
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/unit/services/invitations/invitation-summary.spec.js#answers
        the first name, a masked e-mail, the expiry, the organization and the kind of account, and
        nothing else
      - TST-PFM-SEC-209
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#names
        the organization by its name and never by its id, which is what the page shows the person
      - TST-PFM-SEC-083
      - >-
        services-platform:modules/security/tests/unit/services/invitations/invitation-summary.spec.js#keeps
        the first letter of each side and the top-level domain of an ordinary address
    provenance: test
    source: >-
      services-platform:modules/security/tests/unit/services/invitations/invitation-summary.spec.js#answers
      the first name, a masked e-mail, the expiry, the organization and the kind of account, and
      nothing else
    category: rule
    test_references:
      - >-
        services-platform:modules/security/tests/unit/services/invitations/invitation-summary.spec.js#answers
        the first name, a masked e-mail, the expiry, the organization and the kind of account, and
        nothing else
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#names
        the organization by its name and never by its id, which is what the page shows the person
      - >-
        services-platform:modules/security/tests/unit/services/invitations/invitation-summary.spec.js#keeps
        the first letter of each side and the top-level domain of an ordinary address
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/unit/services/invitations/invitation-summary.spec.js#answers
        the first name, a masked e-mail, the expiry, the organization and the kind of account, and
        nothing else
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/unit/services/invitations/invitation-summary.spec.js#answers
        the first name, a masked e-mail, the expiry, the organization and the kind of account, and
        nothing else
    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-005-03
    title: Unusable-link refusals and accepted-link replay
    level: api
    proves:
      - BR-CAP-PFM-SEC-005-03
      - INV-DOM-PFM-SEC-003-04
    preconditions: 'Prepare malformed, unknown, expired, revoked, superseded and accepted links.'
    steps: >-
      Read summaries and attempt acceptance for each; include accepted links with active and
      inactive memberships.
    expected: >-
      Unusable links share the backend refusal text and expose no organization detail; reason codes
      select the appropriate screen. An accepted link succeeds again for an active membership and is
      refused after that membership becomes inactive.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#answers
        a malformed and an unknown token identically, without auditing a user nobody has identified
      - TST-PFM-SEC-205
      - >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#answers
        an expired, a revoked and a superseded token with the same sentence, and records which it
        was
      - >-
        services-platform:modules/security/tests/unit/services/invitations/invitation-summary.spec.js#reads
        no customer at all for a token it refuses, so a refusal discloses nothing
      - TST-PFM-SEC-209
      - >-
        services-platform:modules/security/tests/e2e/invitations.e2e.spec.js#refuses a malformed, an
        unknown, a revoked and a superseded token with one sentence and nothing more
      - TST-PFM-SEC-060
      - >-
        react-console:lib/auth/__tests__/invitations.test.ts#gives each of the design's problem
        codes its own refusal, so each gets its own screen
      - TST-PFM-SEC-037
    provenance: test
    source: >-
      services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#answers
      a malformed and an unknown token identically, without auditing a user nobody has identified
    category: edge
    test_references:
      - >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#answers
        a malformed and an unknown token identically, without auditing a user nobody has identified
      - >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#answers
        an expired, a revoked and a superseded token with the same sentence, and records which it
        was
      - >-
        services-platform:modules/security/tests/unit/services/invitations/invitation-summary.spec.js#reads
        no customer at all for a token it refuses, so a refusal discloses nothing
      - >-
        services-platform:modules/security/tests/e2e/invitations.e2e.spec.js#refuses a malformed, an
        unknown, a revoked and a superseded token with one sentence and nothing more
      - >-
        react-console:lib/auth/__tests__/invitations.test.ts#gives each of the design's problem
        codes its own refusal, so each gets its own screen
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#answers
        a malformed and an unknown token identically, without auditing a user nobody has identified
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#answers
        a malformed and an unknown token identically, without auditing a user nobody has identified
    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-005-04
    title: Activation after password validation
    level: api
    proves:
      - BR-CAP-PFM-SEC-005-04
    preconditions: Prepare an invited membership with a pending assignment.
    steps: 'Submit an unacceptable password, then an acceptable password.'
    expected: >-
      The refused password leaves the token unspent; the successful request activates membership and
      pending roles in one transaction.
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#sets
        the chosen password in Cognito, then accepts, activates and makes the pending roles real in
        one transaction
      - TST-PFM-SEC-205
      - >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#passes
        Cognito's refusal of the password through, and leaves the invitation unspent
      - >-
        services-platform:modules/security/tests/e2e/invitations.e2e.spec.js#accepts the e-mailed
        token with a password and makes the account active (the invite created the account before it
        sent the link)
      - TST-PFM-SEC-060
    provenance: test
    source: >-
      services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#sets
      the chosen password in Cognito, then accepts, activates and makes the pending roles real in
      one transaction
    category: transition
    test_references:
      - >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#sets
        the chosen password in Cognito, then accepts, activates and makes the pending roles real in
        one transaction
      - >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#passes
        Cognito's refusal of the password through, and leaves the invitation unspent
      - >-
        services-platform:modules/security/tests/e2e/invitations.e2e.spec.js#accepts the e-mailed
        token with a password and makes the account active (the invite created the account before it
        sent the link)
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#sets
        the chosen password in Cognito, then accepts, activates and makes the pending roles real in
        one transaction
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#sets
        the chosen password in Cognito, then accepts, activates and makes the pending roles real in
        one transaction
    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-005-05
    title: Acceptance replay leaves credentials untouched
    level: api
    proves:
      - BR-CAP-PFM-SEC-005-05
    preconditions: Prepare an accepted invitation whose membership remains active.
    steps: Submit the accepted link again.
    expected: 'The result says already accepted, membership stays active and no additional notice is sent.'
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#answers
        a reused token as the success it already was, without touching Cognito again
      - TST-PFM-SEC-205
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#leaves
        the account active after the repeated acceptance
      - TST-PFM-SEC-083
      - >-
        react-console:e2e/security/invitations.spec.ts#tells them their account is already set up if
        the spent link is opened again
      - TST-PFM-SEC-031
    provenance: test
    source: >-
      services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#answers
      a reused token as the success it already was, without touching Cognito again
    category: edge
    test_references:
      - >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#answers
        a reused token as the success it already was, without touching Cognito again
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#leaves
        the account active after the repeated acceptance
      - >-
        react-console:e2e/security/invitations.spec.ts#tells them their account is already set up if
        the spent link is opened again
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#answers
        a reused token as the success it already was, without touching Cognito again
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#answers
        a reused token as the success it already was, without touching Cognito 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-005-06
    title: Present inviter authority at acceptance
    level: api
    proves:
      - BR-CAP-PFM-SEC-005-06
    preconditions: Prepare an invitation and remove the inviter’s authority over its role.
    steps: 'Attempt acceptance, restore the authority and attempt again.'
    expected: >-
      The first attempt refuses neutrally and records its reason without activation or token use;
      the restored-authority attempt succeeds.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/integration/services/invitations/inviter-authority.integration.spec.js#refuses
        the acceptance once the administrator has lost the right, in the one sentence every bad link
        gets
      - TST-PFM-SEC-118
      - >-
        services-platform:modules/security/tests/integration/services/invitations/inviter-authority.integration.spec.js#activates
        nothing and spends no token, so the link still works if the authority comes back
      - >-
        services-platform:modules/security/tests/integration/services/invitations/inviter-authority.integration.spec.js#records
        the real reason in the trail, which the person pressing the button is not told
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/invitations/inviter-authority.integration.spec.js#refuses
      the acceptance once the administrator has lost the right, in the one sentence every bad link
      gets
    category: permission
    test_references:
      - >-
        services-platform:modules/security/tests/integration/services/invitations/inviter-authority.integration.spec.js#refuses
        the acceptance once the administrator has lost the right, in the one sentence every bad link
        gets
      - >-
        services-platform:modules/security/tests/integration/services/invitations/inviter-authority.integration.spec.js#activates
        nothing and spends no token, so the link still works if the authority comes back
      - >-
        services-platform:modules/security/tests/integration/services/invitations/inviter-authority.integration.spec.js#records
        the real reason in the trail, which the person pressing the button is not told
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/services/invitations/inviter-authority.integration.spec.js#refuses
        the acceptance once the administrator has lost the right, in the one sentence every bad link
        gets
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/services/invitations/inviter-authority.integration.spec.js#refuses
        the acceptance once the administrator has lost the right, in the one sentence every bad link
        gets
    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-005-07
    title: Google acceptance identity and replay protection
    level: api
    proves:
      - BR-CAP-PFM-SEC-005-07
    preconditions: Prepare an invited person and Google-link session.
    steps: >-
      Complete with another user’s bearer token, complete with the correct token and replay
      completion.
    expected: The wrong identity and replay fail; the correct identity activates once.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/unit/services/invitations/google-acceptance.spec.js#proves
        the invitation by its token, writes a link session as the invited person and answers its
        nonce as the state
      - TST-PFM-SEC-207
      - >-
        services-platform:modules/security/tests/unit/services/invitations/google-acceptance.spec.js#refuses
        a bearer token of another Cognito user, or one the pool does not verify (the nonce alone
        proves nothing)
      - >-
        services-platform:modules/security/tests/e2e/invitations.e2e.spec.js#begins with the token,
        refuses the completion of another Cognito user, completes once for the right one and refuses
        a replay
      - TST-PFM-SEC-060
    provenance: test
    source: >-
      services-platform:modules/security/tests/unit/services/invitations/google-acceptance.spec.js#proves
      the invitation by its token, writes a link session as the invited person and answers its nonce
      as the state
    category: validation
    test_references:
      - >-
        services-platform:modules/security/tests/unit/services/invitations/google-acceptance.spec.js#proves
        the invitation by its token, writes a link session as the invited person and answers its
        nonce as the state
      - >-
        services-platform:modules/security/tests/unit/services/invitations/google-acceptance.spec.js#refuses
        a bearer token of another Cognito user, or one the pool does not verify (the nonce alone
        proves nothing)
      - >-
        services-platform:modules/security/tests/e2e/invitations.e2e.spec.js#begins with the token,
        refuses the completion of another Cognito user, completes once for the right one and refuses
        a replay
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/unit/services/invitations/google-acceptance.spec.js#proves
        the invitation by its token, writes a link session as the invited person and answers its
        nonce as the state
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/unit/services/invitations/google-acceptance.spec.js#proves
        the invitation by its token, writes a link session as the invited person and answers its
        nonce as the state
    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-005-08
    title: Ordinary Google users cannot bypass invitation
    level: unit
    proves:
      - BR-CAP-PFM-SEC-005-08
    preconditions: >-
      Prepare a password account and an unknown person, neither eligible for founding-staff linking
      nor holding an acceptance session.
    steps: Attempt Google sign-in for each.
    expected: >-
      The sign-up trigger refuses account creation for both without revealing whether a membership
      exists.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to: []
    provenance: proposed
    source: 'services-platform:modules/security/services/provisioning/pre-sign-up.ts:authorizeSignUp'
    category: boundary
    test_references: []
    action_evidence:
      provenance: proposed
      source: 'services-platform:modules/security/services/provisioning/pre-sign-up.ts:authorizeSignUp'
    assertion_evidence:
      provenance: proposed
      source: 'services-platform:modules/security/services/provisioning/pre-sign-up.ts:authorizeSignUp'
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-005-09
    title: Public self-registration is unavailable
    level: browser
    proves:
      - BR-CAP-PFM-SEC-005-09
    preconditions: Use the deployed console and its sign-in pool.
    steps: 'Inspect sign-in links, request retired sign-up pages and attempt pool registration.'
    expected: 'No registration link exists, retired pages return 404 and pool registration is denied.'
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        react-console:e2e/dev/sign-in.dev.spec.ts#offers no sign-up link, and the retired routes
        answer 404
      - TST-PFM-SEC-018
      - 'react-console:e2e/dev/sign-in.dev.spec.ts#refuses Cognito''s own SignUp on the console client'
    provenance: test
    source: >-
      react-console:e2e/dev/sign-in.dev.spec.ts#offers no sign-up link, and the retired routes
      answer 404
    category: boundary
    test_references:
      - >-
        react-console:e2e/dev/sign-in.dev.spec.ts#offers no sign-up link, and the retired routes
        answer 404
      - 'react-console:e2e/dev/sign-in.dev.spec.ts#refuses Cognito''s own SignUp on the console client'
    action_evidence:
      provenance: test
      source: >-
        react-console:e2e/dev/sign-in.dev.spec.ts#offers no sign-up link, and the retired routes
        answer 404
    assertion_evidence:
      provenance: test
      source: >-
        react-console:e2e/dev/sign-in.dev.spec.ts#offers no sign-up link, and the retired routes
        answer 404
    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-005-10
    title: Acceptance in another user’s browser session
    level: browser
    proves:
      - BR-CAP-PFM-SEC-005-10
    preconditions: Sign in as an administrator and prepare an invitation for someone else.
    steps: Open the invitation in that browser.
    expected: The page blocks acceptance and offers to sign out the current user.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        react-console:e2e/dev/invitations.dev.spec.ts#refuses to accept an invitation while somebody
        else's console is on the screen
      - TST-PFM-SEC-013
      - >-
        react-console:lib/auth/__tests__/invitation-flow.test.ts#refuses to accept while another
        account is on screen, and offers to sign out
      - TST-PFM-SEC-036
    provenance: test
    source: >-
      react-console:e2e/dev/invitations.dev.spec.ts#refuses to accept an invitation while somebody
      else's console is on the screen
    category: boundary
    test_references:
      - >-
        react-console:e2e/dev/invitations.dev.spec.ts#refuses to accept an invitation while somebody
        else's console is on the screen
      - >-
        react-console:lib/auth/__tests__/invitation-flow.test.ts#refuses to accept while another
        account is on screen, and offers to sign out
    action_evidence:
      provenance: test
      source: >-
        react-console:e2e/dev/invitations.dev.spec.ts#refuses to accept an invitation while somebody
        else's console is on the screen
    assertion_evidence:
      provenance: test
      source: >-
        react-console:e2e/dev/invitations.dev.spec.ts#refuses to accept an invitation while somebody
        else's console is on the screen
    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-005-11
    title: Acceptance audit identity and secret exclusion
    level: api
    proves:
      - BR-CAP-PFM-SEC-005-11
    preconditions: Prepare a complete invitation lifecycle.
    steps: Inspect recorded events and captured log output.
    expected: >-
      Successful acceptance uses the joining person as actor; recorded material contains no raw
      token, token hash or password.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#records
        the person themselves as the actor of their own acceptance
      - TST-PFM-SEC-083
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#carries
        neither the raw token nor its hash anywhere in what it recorded
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#carries
        no password either, having been given one
      - >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#never
        writes the token or the password to a log line
      - TST-PFM-SEC-205
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#records
      the person themselves as the actor of their own acceptance
    category: invariant
    test_references:
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#records
        the person themselves as the actor of their own acceptance
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#carries
        neither the raw token nor its hash anywhere in what it recorded
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#carries
        no password either, having been given one
      - >-
        services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#never
        writes the token or the password to a log line
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#records
        the person themselves as the actor of their own acceptance
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#records
        the person themselves as the actor of their own acceptance
    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-005-12
    title: Reinvitation retains membership and pool identity
    level: api
    proves:
      - BR-CAP-PFM-SEC-005-12
    preconditions: Prepare a revoked member.
    steps: Invite the person again and accept that invitation.
    expected: The existing membership and pool account become enabled and active.
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#is
        invited back on the same row
      - TST-PFM-SEC-083
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#enables
        the same pool account at acceptance
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#leaves
        the pool account enabled and the person active, so they can sign in
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#is
      invited back on the same row
    category: transition
    test_references:
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#is
        invited back on the same row
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#enables
        the same pool account at acceptance
      - >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#leaves
        the pool account enabled and the person active, so they can sign in
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#is
        invited back on the same row
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js#is
        invited back on the same row
    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-005-13
    title: Invitation acceptance and console arrival
    level: browser
    proves:
      - AS-JNY-PFM-SEC-002-01
      - AS-JNY-PFM-SEC-002-02
    preconditions: Send an invitation through the Security screens.
    steps: Set a password through acceptance and sign in.
    expected: The new member reaches the console and no longer appears in the Invited filter.
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        react-console:e2e/security/invitations.spec.ts#lets them set a password and sign in, and
        clears them off the Invited filter
      - TST-PFM-SEC-031
      - >-
        react-console:e2e/dev/invitations.dev.spec.ts#shows who invited them, then sets their
        password and opens the console
      - TST-PFM-SEC-013
    provenance: test
    source: >-
      react-console:e2e/security/invitations.spec.ts#lets them set a password and sign in, and
      clears them off the Invited filter
    category: interaction
    test_references:
      - >-
        react-console:e2e/security/invitations.spec.ts#lets them set a password and sign in, and
        clears them off the Invited filter
      - >-
        react-console:e2e/dev/invitations.dev.spec.ts#shows who invited them, then sets their
        password and opens the console
    action_evidence:
      provenance: test
      source: >-
        react-console:e2e/security/invitations.spec.ts#lets them set a password and sign in, and
        clears them off the Invited filter
    assertion_evidence:
      provenance: test
      source: >-
        react-console:e2e/security/invitations.spec.ts#lets them set a password and sign in, and
        clears them off the Invited filter
    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-005-14
    title: 'Membership status: invited to active'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-005-04
    state_model: STATE-PFM-SEC-004
    transition:
      from: invited
      to: active
      index: 0
    preconditions: >-
      Prepare a run-owned membership status in invited state with the authority and inputs required
      by the cited transition.
    steps:
      - do: Accept with a valid password; repeat in a separate fixture through Google linking.
        expect: >-
          After the stated action, observe the membership status in active state. This case does not
          require an additional history event unless the transition explicitly defines one.
        provenance: proposed
        source:
          - 'services-platform:modules/security/services/invitations/accept-invitation.ts'
          - >-
            services-platform at ad3f6a65: modules/security/db/users.table.ts;
            services/invitations/accept-invitation.ts, activate-user.ts, invite-user.ts,
            revoke-user.ts, suspend-user.ts, resend-invitation.ts, user-deletion.ts;
            services/membership/lockout.ts, last-administrator.ts.
    expected: >-
      After the stated action, observe the membership status 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/security/services/invitations/accept-invitation.ts'
      - >-
        services-platform at ad3f6a65: modules/security/db/users.table.ts;
        services/invitations/accept-invitation.ts, activate-user.ts, invite-user.ts, revoke-user.ts,
        suspend-user.ts, resend-invitation.ts, user-deletion.ts; services/membership/lockout.ts,
        last-administrator.ts.
    guard_cases: >-
      The token is usable and the inviter still covers the pending grants, unless the
      founding-administrator exemption applies.
    side_effects_to_verify:
      - Activate pending assignments atomically
      - Prepare the sign-in credential before the activation transaction
      - Record lifecycle and security events with the accepting actor
    transition_assertion:
      state: active
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/invitations/accept-invitation.ts'
        - >-
          services-platform at ad3f6a65: modules/security/db/users.table.ts;
          services/invitations/accept-invitation.ts, activate-user.ts, invite-user.ts,
          revoke-user.ts, suspend-user.ts, resend-invitation.ts, user-deletion.ts;
          services/membership/lockout.ts, last-administrator.ts.
    action_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/invitations/accept-invitation.ts'
        - >-
          services-platform at ad3f6a65: modules/security/db/users.table.ts;
          services/invitations/accept-invitation.ts, activate-user.ts, invite-user.ts,
          revoke-user.ts, suspend-user.ts, resend-invitation.ts, user-deletion.ts;
          services/membership/lockout.ts, last-administrator.ts.
    assertion_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/invitations/accept-invitation.ts'
        - >-
          services-platform at ad3f6a65: modules/security/db/users.table.ts;
          services/invitations/accept-invitation.ts, activate-user.ts, invite-user.ts,
          revoke-user.ts, suspend-user.ts, resend-invitation.ts, user-deletion.ts;
          services/membership/lockout.ts, last-administrator.ts.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-005-15
    title: 'Invitation: live to accepted'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-005-04
    state_model: STATE-PFM-SEC-005
    transition:
      from: live
      to: accepted
      index: 1
    preconditions: >-
      Prepare a run-owned invitation in live state with the authority and inputs required by the
      cited transition.
    steps:
      - do: Accept the usable invitation and inspect membership and assignment activation together.
        expect: >-
          After the stated action, observe the invitation in accepted state. This case does not
          require an additional history event unless the transition explicitly defines one.
        provenance: proposed
        source:
          - 'services-platform:modules/security/services/persistence/invitations.ts:acceptInvitation'
          - >-
            services-platform at ad3f6a65: modules/security/db/user-invitations.table.ts;
            services/persistence/invitations.ts; services/invitations/invitation-lifetime.ts,
            resend-invitation.ts, accept-invitation.ts; services/provisioning/provision-user.ts.
    expected: >-
      After the stated action, observe the invitation in accepted 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/security/services/persistence/invitations.ts:acceptInvitation'
      - >-
        services-platform at ad3f6a65: modules/security/db/user-invitations.table.ts;
        services/persistence/invitations.ts; services/invitations/invitation-lifetime.ts,
        resend-invitation.ts, accept-invitation.ts; services/provisioning/provision-user.ts.
    guard_cases: >-
      The invitation is unexpired, unaccepted, unrevoked and not superseded; the conditional write
      must match.
    side_effects_to_verify:
      - Activate the membership and pending assignments
    transition_assertion:
      state: accepted
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/persistence/invitations.ts:acceptInvitation'
        - >-
          services-platform at ad3f6a65: modules/security/db/user-invitations.table.ts;
          services/persistence/invitations.ts; services/invitations/invitation-lifetime.ts,
          resend-invitation.ts, accept-invitation.ts; services/provisioning/provision-user.ts.
    action_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/persistence/invitations.ts:acceptInvitation'
        - >-
          services-platform at ad3f6a65: modules/security/db/user-invitations.table.ts;
          services/persistence/invitations.ts; services/invitations/invitation-lifetime.ts,
          resend-invitation.ts, accept-invitation.ts; services/provisioning/provision-user.ts.
    assertion_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/persistence/invitations.ts:acceptInvitation'
        - >-
          services-platform at ad3f6a65: modules/security/db/user-invitations.table.ts;
          services/persistence/invitations.ts; services/invitations/invitation-lifetime.ts,
          resend-invitation.ts, accept-invitation.ts; services/provisioning/provision-user.ts.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-005-16
    title: 'Invitation: live to expired'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-005-01
    state_model: STATE-PFM-SEC-005
    transition:
      from: live
      to: expired
      index: 2
    preconditions: >-
      Prepare a run-owned invitation in live state with the authority and inputs required by the
      cited transition.
    steps:
      - do: Advance a controllable clock to the seven-day deadline and attempt acceptance.
        expect: >-
          After the stated action, observe the invitation in expired state. This case does not
          require an additional history event unless the transition explicitly defines one.
        provenance: proposed
        source:
          - 'services-platform:modules/security/services/invitations/invitation-lifetime.ts'
          - >-
            services-platform at ad3f6a65: modules/security/db/user-invitations.table.ts;
            services/persistence/invitations.ts; services/invitations/invitation-lifetime.ts,
            resend-invitation.ts, accept-invitation.ts; services/provisioning/provision-user.ts.
    expected: >-
      After the stated action, observe the invitation in expired 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/security/services/invitations/invitation-lifetime.ts'
      - >-
        services-platform at ad3f6a65: modules/security/db/user-invitations.table.ts;
        services/persistence/invitations.ts; services/invitations/invitation-lifetime.ts,
        resend-invitation.ts, accept-invitation.ts; services/provisioning/provision-user.ts.
    guard_cases: Use-time evaluation checks the deadline; no expiry job is required.
    side_effects_to_verify:
      - Refuse the unusable token and require a replacement invitation
    transition_assertion:
      state: expired
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/invitations/invitation-lifetime.ts'
        - >-
          services-platform at ad3f6a65: modules/security/db/user-invitations.table.ts;
          services/persistence/invitations.ts; services/invitations/invitation-lifetime.ts,
          resend-invitation.ts, accept-invitation.ts; services/provisioning/provision-user.ts.
    action_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/invitations/invitation-lifetime.ts'
        - >-
          services-platform at ad3f6a65: modules/security/db/user-invitations.table.ts;
          services/persistence/invitations.ts; services/invitations/invitation-lifetime.ts,
          resend-invitation.ts, accept-invitation.ts; services/provisioning/provision-user.ts.
    assertion_evidence:
      provenance: proposed
      source:
        - 'services-platform:modules/security/services/invitations/invitation-lifetime.ts'
        - >-
          services-platform at ad3f6a65: modules/security/db/user-invitations.table.ts;
          services/persistence/invitations.ts; services/invitations/invitation-lifetime.ts,
          resend-invitation.ts, accept-invitation.ts; services/provisioning/provision-user.ts.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-005-17
    title: 'Role assignment: pending to live'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-005-04
    state_model: STATE-PFM-SEC-006
    transition:
      from: pending
      to: live
      index: 0
    preconditions: >-
      Prepare a run-owned role assignment in pending state with the authority and inputs required by
      the cited transition.
    steps:
      - do: Accept an invitation offering a current-window role and inspect effective access.
        expect: >-
          After the stated action, observe the role assignment in live state. This case does not
          require an additional history event unless the transition explicitly defines one.
        provenance: proposed
        source:
          - >-
            services-platform:modules/security/services/persistence/assignments.ts:activatePendingAssignments
          - >-
            services-platform at ad3f6a65: modules/security/db/security-assignments.table.ts;
            services/persistence/assignments.ts; services/membership/manage-assignments.ts;
            services/invitations/widening.ts.
    expected: >-
      After the stated action, observe the role assignment in live 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/security/services/persistence/assignments.ts:activatePendingAssignments
      - >-
        services-platform at ad3f6a65: modules/security/db/security-assignments.table.ts;
        services/persistence/assignments.ts; services/membership/manage-assignments.ts;
        services/invitations/widening.ts.
    guard_cases: 'Present inviter authority covers it, unless the invitation carries the explicit exemption.'
    side_effects_to_verify:
      - Record assignment and membership history
    transition_assertion:
      state: live
      provenance: proposed
      source:
        - >-
          services-platform:modules/security/services/persistence/assignments.ts:activatePendingAssignments
        - >-
          services-platform at ad3f6a65: modules/security/db/security-assignments.table.ts;
          services/persistence/assignments.ts; services/membership/manage-assignments.ts;
          services/invitations/widening.ts.
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/security/services/persistence/assignments.ts:activatePendingAssignments
        - >-
          services-platform at ad3f6a65: modules/security/db/security-assignments.table.ts;
          services/persistence/assignments.ts; services/membership/manage-assignments.ts;
          services/invitations/widening.ts.
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/security/services/persistence/assignments.ts:activatePendingAssignments
        - >-
          services-platform at ad3f6a65: modules/security/db/security-assignments.table.ts;
          services/persistence/assignments.ts; services/membership/manage-assignments.ts;
          services/invitations/widening.ts.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-005-18
    title: 'Role assignment: pending to scheduled'
    category: transition
    level: api
    proves:
      - BR-CAP-PFM-SEC-010-05
    state_model: STATE-PFM-SEC-006
    transition:
      from: pending
      to: scheduled
      index: 1
    preconditions: >-
      Prepare a run-owned role assignment in pending state with the authority and inputs required by
      the cited transition.
    steps:
      - do: Accept an invitation offering a role that begins tomorrow and inspect current access.
        expect: >-
          After the stated action, observe the role assignment in scheduled state. This case does
          not require an additional history event unless the transition explicitly defines one.
        provenance: proposed
        source:
          - >-
            services-platform:modules/security/services/persistence/assignments.ts:activatePendingAssignments
          - >-
            services-platform at ad3f6a65: modules/security/db/security-assignments.table.ts;
            services/persistence/assignments.ts; services/membership/manage-assignments.ts;
            services/invitations/widening.ts.
    expected: >-
      After the stated action, observe the role assignment in scheduled 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/security/services/persistence/assignments.ts:activatePendingAssignments
      - >-
        services-platform at ad3f6a65: modules/security/db/security-assignments.table.ts;
        services/persistence/assignments.ts; services/membership/manage-assignments.ts;
        services/invitations/widening.ts.
    guard_cases: Apply the same acceptance authority checks.
    side_effects_to_verify: []
    transition_assertion:
      state: scheduled
      provenance: proposed
      source:
        - >-
          services-platform:modules/security/services/persistence/assignments.ts:activatePendingAssignments
        - >-
          services-platform at ad3f6a65: modules/security/db/security-assignments.table.ts;
          services/persistence/assignments.ts; services/membership/manage-assignments.ts;
          services/invitations/widening.ts.
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/security/services/persistence/assignments.ts:activatePendingAssignments
        - >-
          services-platform at ad3f6a65: modules/security/db/security-assignments.table.ts;
          services/persistence/assignments.ts; services/membership/manage-assignments.ts;
          services/invitations/widening.ts.
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/security/services/persistence/assignments.ts:activatePendingAssignments
        - >-
          services-platform at ad3f6a65: modules/security/db/security-assignments.table.ts;
          services/persistence/assignments.ts; services/membership/manage-assignments.ts;
          services/invitations/widening.ts.
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-005-19
    title: Join through an invitation with use and recover a console sign-in
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-005-04
      - BR-CAP-PFM-SEC-006-02
    exercises:
      - CAP-PFM-SEC-005
      - CAP-PFM-SEC-006
    preconditions: An invited person has no console session.
    steps: Accept the invitation with a valid password and sign in to the protected destination.
    expected: >-
      The active account reaches the destination through a new session without another acceptance
      write.
    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/security/tests/unit/services/invitations/accept-invitation.spec.js#sets
        the chosen password in Cognito, then accepts, activates and makes the pending roles real in
        one transaction
      - >-
        react-console:e2e/dev/session.dev.spec.ts#sends a signed-out visitor to the login screen and
        back to the page they wanted
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#sets
          the chosen password in Cognito, then accepts, activates and makes the pending roles real
          in one transaction
        - >-
          react-console:e2e/dev/session.dev.spec.ts#sends a signed-out visitor to the login screen
          and back to the page they wanted
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#sets
          the chosen password in Cognito, then accepts, activates and makes the pending roles real
          in one transaction
        - >-
          react-console:e2e/dev/session.dev.spec.ts#sends a signed-out visitor to the login screen
          and back to the page they wanted
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-005-20
    title: Join through an invitation with assign roles within a controlled scope
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-005-04
      - BR-CAP-PFM-SEC-010-05
    exercises:
      - CAP-PFM-SEC-005
      - CAP-PFM-SEC-010
    preconditions: An invitation offers one current and one future role assignment.
    steps: >-
      Accept the invitation and inspect the assignments and current effective permission
      explanation.
    expected: >-
      The current assignment is effective; the future assignment stays scheduled and supplies no
      current permission.
    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/security/tests/unit/services/invitations/accept-invitation.spec.js#sets
        the chosen password in Cognito, then accepts, activates and makes the pending roles real in
        one transaction
      - >-
        services-platform:modules/security/tests/e2e/console-users.e2e.spec.js#answers a grant whose
        window opens tomorrow as scheduled, in the grant and in the list
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#sets
          the chosen password in Cognito, then accepts, activates and makes the pending roles real
          in one transaction
        - >-
          services-platform:modules/security/tests/e2e/console-users.e2e.spec.js#answers a grant
          whose window opens tomorrow as scheduled, in the grant and in the list
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#sets
          the chosen password in Cognito, then accepts, activates and makes the pending roles real
          in one transaction
        - >-
          services-platform:modules/security/tests/e2e/console-users.e2e.spec.js#answers a grant
          whose window opens tomorrow as scheduled, in the grant and in the list
    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/security/services/provisioning/pre-sign-up.ts;
    modules/security/tests/e2e/invitations.e2e.spec.js;
    modules/security/tests/integration/lifecycle/invitation/invitation-arc.integration.spec.js;
    modules/security/tests/integration/services/invitations/inviter-authority.integration.spec.js;
    modules/security/tests/unit/services/invitations/accept-invitation.spec.js;
    modules/security/tests/unit/services/invitations/google-acceptance.spec.js;
    modules/security/tests/unit/services/invitations/invitation-summary.spec.js;
    modules/security/tests/unit/services/invitations/invite-user.spec.js.
  - >-
    Pinned react-console references for the structured rows: e2e/dev/invitations.dev.spec.ts;
    e2e/dev/sign-in.dev.spec.ts; e2e/security/invitations.spec.ts;
    lib/auth/__tests__/invitation-flow.test.ts; lib/auth/__tests__/invitations.test.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: 'gap: FND-PFM-SEC-062'
  boundary: covered
  concurrency: 'gap: FND-PFM-SEC-062'
  invariant: covered
  interaction: covered
coverage_notes:
  failure: No scenario isolates this category. The referenced finding retains the missing design proof.
  concurrency: No scenario isolates this category. The referenced finding retains the missing design proof.
invariant_proofs:
  - scenario: ATS-PFM-SEC-005-01
    proves:
      - INV-DOM-PFM-SEC-003-04
    provenance: test
    source: >-
      services-platform:modules/security/tests/unit/services/invitations/invite-user.spec.js#expires
      the invitation 7 days after the execution's clock, on the invitation and on the user
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
  - scenario: ATS-PFM-SEC-005-03
    proves:
      - INV-DOM-PFM-SEC-003-04
    provenance: test
    source: >-
      services-platform:modules/security/tests/unit/services/invitations/accept-invitation.spec.js#answers
      a malformed and an unknown token identically, without auditing a user nobody has identified
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
permission_proof_review: []
examiner: codex
examined_at: '2026-10-23'
final_text: OpenAI
---
# Join through an invitation: Capability Test Specification

## Coverage

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

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.
