---
id: WF-PFM-CSH-008
title: Open a page from its address
trigger: 'A person opens workspace work from navigation, reference, bookmark or history.'
product_area: platform
module: console-shell
revision: 1
status: draft
design_intent: confirmed
origin: >-
  services-platform:docs/proposals/application-access-and-entitlements.md#6.4
  Console integration, item 2 (built and accepted by Andrew 2026-10-15);
  react-console:docs/url-architecture.md#3. Workspaces (decided by Andrew
  2026-10-14; final acceptance 2026-10-15)
implementation_evidence: observed
source_sha:
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
implements:
  - CAP-PFM-CSH-009
  - CAP-PFM-CSH-015
  - CAP-PFM-CSH-018
moves:
  - STATE-PFM-CSH-002
crosses:
  - SVC-PFM-CSH-console-shell
inference: []
idempotency: >-
  Local gate evaluation repeats over current inputs; workspace entry can cause
  Security reads and bookkeeping.
concurrency: >-
  Current entitlements determine local decisions, which recompute after
  application replacement.
hops:
  - 'n': 1
    actor_or_service: console (record reference)
    action: >-
      For record references, construct a workspace-bound destination only when
      the helper can resolve a built, permitted noun without a required parent.
    anchor: 'react-console:lib/console/record-types.ts:recordHref, recordDestination'
    seam: sync
    on_failure: >-
      Withhold a link when the helper cannot resolve a destination; an unknown
      noun passed to a route builder throws.
    left_inconsistent: An unresolved or unpermitted reference remains unlinked text.
    observer: Person through linked or unlinked record text.
    provenance: test
    source: >-
      react-console:lib/console/__tests__/record-destination.test.ts#answers
      null for a child noun, whose URL needs a parent id
  - 'n': 2
    actor_or_service: console (workspace entry)
    action: >-
      Resolve the workspace requested by the address before rendering its
      content.
    anchor: 'react-console:components/console/tenant-id-gate.tsx:TenantIdGate'
    seam: sync
    on_failure: Display the workspace-entry refusal state.
    left_inconsistent: Previous context can remain while requested workspace content is withheld.
    observer: Person through entry presentation.
    provenance: observed
    source: 'react-console:components/console/tenant-id-gate.tsx:TenantIdGate'
  - 'n': 3
    actor_or_service: console (application route gate)
    action: >-
      Classify the settled path with the domain registry and show unavailable
      when its application is absent.
    anchor: >-
      react-console:components/console/application-route-gate.tsx:ApplicationRouteGate
    seam: sync
    on_failure: Show application unavailable without a supplied reason.
    left_inconsistent: The explanation can lack the underlying availability reason.
    observer: Person through application refusal.
    provenance: observed
    source: >-
      react-console:components/console/application-route-gate.tsx:ApplicationRouteGate
  - 'n': 4
    actor_or_service: console (page guard)
    action: >-
      Check the page’s explicit or permission-derived application candidates,
      then require any declared permission.
    anchor: >-
      react-console:lib/authz/guard.tsx:RequirePermission;
      lib/console/application-guard.ts:applicationGuardDecision
    seam: sync
    on_failure: Show application unavailable or the page’s Access Denied state.
    left_inconsistent: Guard success does not authorize any later service request.
    observer: Person through page guard presentation.
    provenance: test
    source: >-
      react-console:lib/console/application-guard.test.ts#says the application
      is not available, not that access was denied
  - 'n': 5
    actor_or_service: console (planned-page catch-all)
    action: >-
      Resolve a registered catch-all destination to its guarded placeholder,
      otherwise report not found.
    anchor: >-
      react-console:app/(console)/console/[tenantId]/[...slug]/page.tsx:ModulePage
    seam: sync
    on_failure: Return not found when no registry item matches.
    left_inconsistent: A placeholder is not a built working page.
    observer: Person through placeholder or not found.
    provenance: observed
    source: >-
      react-console:app/(console)/console/[tenantId]/[...slug]/page.tsx:ModulePage
  - 'n': 6
    actor_or_service: owning service
    action: >-
      Let the owning service authorize page requests independently and report
      application-coded refusals to the refresh listener.
    anchor: >-
      react-console:lib/security-context/application-refusal.ts:reportApplicationRefusal
    seam: sync
    on_failure: >-
      The page owns request-error handling, and recognized application refusals
      also request refresh.
    left_inconsistent: >-
      The failed business request is not compensated by refreshing the
      application list.
    observer: Person through page request handling.
    provenance: documented
    source: >-
      services-platform:docs/proposals/application-access-and-entitlements.md#5.3
      Tenant isolation, caching and staleness
branches:
  - >-
    Paths outside the domain registry may still receive application checks from
    page permissions.
waits: []
evidence:
  - >-
    react-console at baf6dae:
    components/console/{application-route-gate,application-unavailable,tenant-id-gate}.tsx;
    lib/authz/guard.tsx;
    lib/console/{application-guard,record-types,domains}.ts;
    app/(console)/console/[tenantId]/[...slug]/page.tsx.
controls: [TC-AVL-001, TC-AVL-004, TC-AVL-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-CRY-001, TC-CRY-002, TC-CRY-003, TC-CRY-004, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-MON-001, 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]
---
# Open a page from its address

## What It Does

Direct arrival first resolves the address workspace, then checks a recognized application path, then applies the page’s own guard. Record-reference helpers can withhold links when the destination is unavailable or requires a parent.

## The Flow

```mermaid
sequenceDiagram
  participant C as Workspace gate
  participant S as Page guard
  Note over C: direct address
  C->>S: settled workspace and application
  S-->>C: permission result
  Note over C: page requests independently authorized by service
```

## When Something Fails

Application refusal and permission refusal have separate states. Missing availability reasons leave the former explanation generic. Pages outside the route registry rely on their own guards, which may still infer application requirements from permission keys. Services evaluate each request independently, and an application-coded refusal triggers refresh.

## Open Design Questions

Availability explanations should use reasons the caller is allowed to see. Customer record-reference fallback currently checks general read authority without the type’s own scope.
