---
id: WF-PFM-SEC-011
title: Grant and end staff entry to a customer workspace
trigger: Staff request or take permitted customer entry, a customer decides or gives entry, or an authorized
  actor ends a grant.
product_area: platform
module: security
revision: 1
status: draft
design_intent: confirmed
origin: 'services-platform:docs/hq/rhythm-hq-plan.md#D2, #D2b (K1, K1a, K1b, K2; Andrew 2026-10-11, reconfirmed
  2026-10-12)'
implementation_evidence: observed
inference: []
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
- CAP-PFM-SEC-017
- CAP-PFM-SEC-001
moves:
- STATE-PFM-SEC-007
- STATE-PFM-SEC-006
crosses:
- SVC-PFM-SEC-security
- SVC-PFM-SEC-tenants
- SVC-PFM-SEC-customers
idempotency: Sequential duplicate request checks return the held request or grant; emergency entry can reuse
  standing access. Active grants have target uniqueness, while concurrent requested-row exclusion remains unknown.
  Standing reconciliation preserves manually revoked grants.
concurrency: Grant decisions, matching assignments and history transact together under active-grant uniqueness.
  Requested-row creation uses a check-before-insert path without proved concurrent exclusion. Assignment validity
  governs fresh evaluation and grant expiry settles lazily; external notices and flushing follow commit.
hops:
- n: 1
  actor_or_service: Rhythm staff (request)
  action: Record a workspace request with customer role, reason, optional ticket and one-to-thirty-day duration,
    then notify administrators after commit.
  anchor: services-platform:modules/security/services/staff-access/request-tenant-access.ts
  seam: sync
  on_failure: Refuse duplicates or invalid target/role; log notification failure separately.
  left_inconsistent: A valid request can remain unknown to recipients if notification fails.
  observer: Grant lists, history and delivery logs show the request.
  provenance: observed
  source: services-platform:modules/security/services/staff-access/request-tenant-access.ts (header)
- n: 2
  actor_or_service: Customer administrator (decide or give)
  action: Approve for no longer than requested, decline with reason, or directly give permitted staff access;
    materialize assignments and notify afterward.
  anchor: services-platform:modules/security/services/staff-access/decide-tenant-access.ts
  seam: sync
  on_failure: Refuse missing customer-management authority or an already decided request.
  left_inconsistent: The committed decision can outlive a failed notice.
  observer: Customer grant lists and security history expose the decision.
  provenance: observed
  source: services-platform:modules/security/services/staff-access/decide-tenant-access.ts (header)
- n: 3
  actor_or_service: Rhythm Administrator (emergency)
  action: Create bounded emergency entry with the required reason and ticket, materialize its assignment and
    notify customer and staff security recipients.
  anchor: services-platform:modules/security/services/staff-access/open-emergency-access.ts
  seam: sync
  on_failure: Refuse missing emergency authority, duplicate targets or staff-only roles.
  left_inconsistent: Usable emergency access can exist before recipients are informed.
  observer: Customer history, grant lists and notification logs expose emergency entry.
  provenance: observed
  source: services-platform:modules/security/services/staff-access/open-emergency-access.ts (header)
- n: 4
  actor_or_service: Platform System (standing reconciliation)
  action: Reconcile eligible administrators’ customer-level standing access, replace covered narrower grants
    and preserve manual revocations.
  anchor: services-platform:modules/security/services/staff-access/ensure-standing-access.ts:ensureStandingAccess
  seam: sync
  on_failure: Best-effort deploy/provisioning reconciliation logs failures; ordinary transactional creation
    has its own failure boundary.
  left_inconsistent: Missing grants can remain until a later successful reconciliation; HQ customer creation
    omits immediate reconciliation.
  observer: Deployment logs and grant reads expose the gap.
  provenance: observed
  source: services-platform:modules/security/services/staff-access/ensure-standing-access.ts (header)
- n: 5
  actor_or_service: Anyone entitled (end early)
  action: End an allowed own, HQ-managed or customer-managed grant and its assignment atomically, then request
    flushing.
  anchor: services-platform:modules/security/services/staff-access/end-access-grant.ts
  seam: sync
  on_failure: HQ refuses standing-grant ending; access checks restrict other actors’ grant visibility.
  left_inconsistent: Earlier decisions and signed contexts can remain valid within their combined ninety-second
    bound.
  observer: Grant history and flush job state expose revocation.
  provenance: observed
  source: services-platform:modules/security/services/staff-access/end-access-grant.ts (header)
- n: 6
  actor_or_service: Authorizer and evaluator
  action: Use the materialized assignment for ordinary customer entry and apply workspace availability.
  anchor: services-platform:modules/security/authorizer/authorize.ts:authorize (step 10)
  seam: sync
  on_failure: Return refused deep links to HQ guidance and the permitted emergency-entry offer.
  left_inconsistent: No customer operation executes through a refused deep link.
  observer: Staff see entry guidance or the customer workspace.
  provenance: observed
  source: services-platform:modules/tenants/services/lifecycle/lifecycle-transitions.ts:isTenantEnterableByStaff
branches:
- Requester withdrawal closes the request as declined with the requester recorded as decider.
- Customer-level standing entry can reach the customer Security area under ordinary delegation and lockout
  checks.
waits:
- Approved entry is one to thirty days, seven by default; emergency entry lasts at most four hours, while standing
  entry has no scheduled end.
evidence:
- 'services-platform at ad3f6a65: modules/security/services/staff-access/*; db/staff-access-grants.table.ts;
  modules/customers/aws/api/customers.routes.ts (createCustomer and deleteCustomer hooks); modules/tenants/services/provisioning/provision-tenant-operations.ts:ensureFoundersStandingAccess.'
- 'react-console at baf6dae: components/security/rhythm-access/*; components/console/hq/emergency-access-dialog.tsx,
  staff-access-banner.tsx, staff/staff-access-grants-card.tsx.'
examined_at: '2026-10-23'
examiner: codex
controls: [TC-AVL-001, TC-AVL-004, TC-AVL-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-AZ-006, TC-CHG-001, TC-CHG-002, TC-CHG-003, TC-CHG-004, TC-CHG-005, TC-CHG-006, TC-CRY-001, TC-CRY-002, TC-CRY-003, TC-CRY-004, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-IAM-001, TC-IAM-002, TC-IAM-003, TC-IAM-004, TC-IAM-005, TC-IAM-006, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-MON-001, TC-MON-002, TC-MON-003, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-PRV-001, TC-PRV-002, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-VEN-001, TC-VEN-002, TC-VEN-003]
---

# Grant and end staff entry to a customer workspace

## What It Does

Staff customer entry uses ordinary scoped assignments backed by recorded grants. HQ system routes retain their separate staff-administration authority; they are not a substitute grant for ordinary customer work.

## The Flow

```mermaid
flowchart TD
    H1["Request staff entry"]
    H2["Decide or give entry"]
    H3["Open emergency entry"]
    H4["Reconcile standing access"]
    H5["End permitted grant"]
    H6["Enter customer workspace"]
    H1 -->|customer decision| H2
    H2 -->|approved or directly given| H6
    H3 --> H6
    H4 --> H6
    H6 -. permitted grant ending .-> H5
```

The diagram separates the relevant success, alternative and failure paths. The numbered hop rows retain the detailed authority checks, delegated work and retry limits.

## When Something Fails

Customer decisions, emergency entry and standing reconciliation have different actors and notice paths. The customer can revoke standing access, and deployment preserves that choice. Notification failure and cached authority remain separate from committed grant state.

Sequential duplicate request checks return the held request or grant; emergency entry can reuse standing access. Active grants have target uniqueness, while concurrent requested-row exclusion remains unknown. Standing reconciliation preserves manually revoked grants.

Grant decisions, matching assignments and history transact together under active-grant uniqueness. Requested-row creation uses a check-before-insert path without proved concurrent exclusion. Assignment validity governs fresh evaluation and grant expiry settles lazily; external notices and flushing follow commit.

## Open Design Questions

The recorded findings retain any stronger planning expectation, missing writer or unproved recovery path. Observed behavior does not approve those outstanding product choices.
