---
id: STATE-PFM-SEC-007
title: Staff access grant
object: DOM-PFM-SEC-003
product_area: platform
module: security
revision: 1
status: draft
design_intent: confirmed
origin: services-platform:docs/hq/rhythm-hq-plan.md#D2 (option A, K1, K1a, K1b, K2; Andrew 2026-10-11 and 2026-10-12)
implementation_evidence: observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
states:
- name: requested
  meaning: A staff access request awaits a customer decision and grants no entry.
  provenance: observed
  source: 'services-platform at ad3f6a65: modules/security/db/staff-access-grants.table.ts; services/staff-access/*;
    docs/hq/rhythm-hq-plan.md §D2.'
- name: active
  meaning: The materialized assignment can grant entry within the approved validity interval.
  provenance: observed
  source: services-platform:modules/security/services/staff-access/decide-tenant-access.ts
- name: declined
  meaning: The customer declined or the requester withdrew; the decision closes the request.
  provenance: observed
  source: services-platform:modules/security/services/staff-access/request-tenant-access.ts:withdrawAccessRequest
- name: expired
  meaning: The grant’s window ended; a later read persists the interpreted expiry.
  provenance: observed
  source: services-platform:modules/security/services/persistence/staff-access-grants.ts:settleExpiredStaffAccessGrants
- name: revoked
  meaning: Access was ended early. Manual revocation of standing access survives reconciliation.
  provenance: observed
  source: services-platform:modules/security/services/staff-access/end-access-grant.ts
transitions:
- from: requested
  to: active
  trigger: A customer administrator approves the staff request.
  guard: The caller can manage staff access; duration cannot exceed the requested duration or thirty days.
  side_effects:
  - Create the scoped role assignment with matching validity
  - Record customer security history and send the decision notice after commit
  who: Customer Administrator
  provenance: observed
  source: services-platform:modules/security/services/staff-access/decide-tenant-access.ts
- from: requested
  to: declined
  trigger: The customer declines or the requester withdraws.
  guard: The request is still awaiting a decision.
  side_effects:
  - Retain the reason and identify the withdrawing requester as decider
  who: Customer Administrator or the requesting staff member
  provenance: observed
  source: services-platform:modules/security/services/staff-access/request-tenant-access.ts:withdrawAccessRequest
- from: active
  to: expired
  trigger: The grant’s end is reached.
  guard: Evaluation already excludes the expired assignment; a read settles the grant state.
  side_effects: []
  who: nobody (clock), settled on read
  provenance: observed
  source: services-platform:modules/security/services/persistence/staff-access-grants.ts:settleExpiredStaffAccessGrants
- from: active
  to: revoked
  trigger: The customer, staff member, authorized HQ administrator or reconciliation ends the grant.
  guard: HQ end-access operations exclude standing grants; customer administration may revoke them.
  side_effects:
  - Revoke the assignment and record security history atomically
  - Request a post-commit flush and send the revocation notice
  who: Customer Administrator, Rhythm staff, or Platform System
  provenance: observed
  source: services-platform:modules/security/services/staff-access/end-access-grant.ts
invalid:
- from: revoked
  to: active
  why: A manual standing-access revocation remains final for that target through reconciliation.
  provenance: observed
  source: 'services-platform at ad3f6a65: modules/security/db/staff-access-grants.table.ts; services/staff-access/*;
    docs/hq/rhythm-hq-plan.md §D2.'
- from: declined
  to: active
  why: A closed decision cannot be approved later; the staff member submits another request.
  provenance: observed
  source: 'services-platform at ad3f6a65: modules/security/db/staff-access-grants.table.ts; services/staff-access/*;
    docs/hq/rhythm-hq-plan.md §D2.'
- from: requested
  to: expired
  why: Requested rows store the requested window but expiry settlement only updates active grants. An undecided
    request is not automatically expired by that path.
  provenance: observed
  source: 'services-platform at ad3f6a65: modules/security/db/staff-access-grants.table.ts; services/staff-access/*;
    docs/hq/rhythm-hq-plan.md §D2.'
concurrency: Active-grant unique indexes protect workspace and customer targets. Request submission checks
  for existing requested work before insertion but does not prove concurrent request exclusion. Materialization
  and grant writes share a transaction, and matching-grant database integrity protects cross-customer assignments.
  Evaluation enforces validity; expiry settlement applies to active grants only.
invariants:
- INV-DOM-PFM-SEC-003-17
- INV-DOM-PFM-SEC-003-18
- INV-DOM-PFM-SEC-003-19
evidence:
- 'services-platform at ad3f6a65: modules/security/db/staff-access-grants.table.ts; services/staff-access/*;
  docs/hq/rhythm-hq-plan.md §D2.'
examined_at: '2026-10-23'
examiner: codex
---

# Staff access grant

## The Lifecycle

```mermaid
stateDiagram-v2
    state "Requested" as requested
    state "Active" as active
    state "Declined" as declined
    state "Expired" as expired
    state "Revoked" as revoked
    requested --> active
    requested --> declined
    active --> expired
    active --> revoked
```

The diagram summarizes the observed transition rows; declared edges without an observed writer remain outside the operational graph.

## Transitions Explained

The state rows describe requested and granted customer entry. Emergency and standing creation can begin directly in active state through their own capabilities; they do not imply customer approval of a requested row.

Expiry is enforced by assignment validity and settled lazily on reads. Revocation records the actor and preserves the customer’s ability to end standing access.

## What Cannot Happen

A manual standing-access revocation remains final for that target through reconciliation.

A closed decision cannot be approved later; the staff member submits another request.

Requested rows store the requested window but expiry settlement only updates active grants. An undecided request is not automatically expired by that path.

## Concurrency and Timing

Active-grant unique indexes protect workspace and customer targets. Request submission checks for existing requested work before insertion but does not prove concurrent request exclusion. Materialization and grant writes share a transaction, and matching-grant database integrity protects cross-customer assignments. Evaluation enforces validity; expiry settlement applies to active grants only.
