version: 1
feature: 135-canonical-tenant-context-resolution
title: Canonical Tenant Context Resolution Matrix
type: internal-behavior-contract

canonical_rules:
  tenant_panel:
    source_of_truth: Filament::getTenant()
    fallback_behavior: none
    notes:
      - Tenant-panel-native routes keep panel semantics.
      - Remembered admin tenant state must not override tenant-panel context.
  workspace_admin:
    source_of_truth: App\Support\OperateHub\OperateHubShell::activeEntitledTenant
    priority_order:
      - entitled_filament_tenant
      - entitled_remembered_workspace_tenant
      - none
    no_context_outcome_by_surface:
      operations_monitoring_index: workspace_scoped_all_tenants_state_with_no_tenant_default_filter_and_no_tenant_only_kpis
      tenantless_operation_run_detail: render_only_if_workspace_scope_and_tenant_entitlement_still_pass_otherwise_not_found
      admin_entra_group_list_and_view: not_found
      admin_entra_group_global_search: no_results_for_tenant_owned_records

request_states:
  remembered_only:
    filament_tenant: null
    remembered_tenant: entitled
    resolved_source: remembered
  filament_only:
    filament_tenant: entitled
    remembered_tenant: null
    resolved_source: filament
  conflict:
    filament_tenant: entitled
    remembered_tenant: entitled_and_different
    resolved_source: filament
  no_context:
    filament_tenant: null_or_not_entitled
    remembered_tenant: null_or_not_entitled
    resolved_source: none

surfaces:
  - name: operations_monitoring_index
    route: /admin/operations
    panel: admin
    expectations:
      - header_scope_label_matches_resolved_tenant
      - kpi_cards_match_resolved_tenant
      - table_query_matches_resolved_tenant
      - filter_defaults_match_resolved_tenant
      - no_context_renders_workspace_scoped_all_tenants_state
      - no_context_clears_tenant_default_filters
      - no_context_hides_tenant_only_kpi_behavior

  - name: tenantless_operation_run_detail
    route: /admin/operations/{run}
    panel: admin
    expectations:
      - authorization_uses_workspace_and_tenant_entitlement
      - detail_visibility_is_not_broader_than_index_scope
      - navigation_labels_use_same_resolved_tenant_as_admin_shell
      - no_context_renders_only_when_workspace_scope_and_tenant_entitlement_still_pass
      - no_context_otherwise_returns_not_found

  - name: operation_run_filters
    route: /admin/operations with persisted table filters
    panel: admin
    expectations:
      - tenant_filter_options_do_not_exceed_list_scope
      - tenant_filter_default_uses_resolved_tenant
      - persisted_tenant_sensitive_values_are_revalidated_per_request

  - name: entra_group_list_and_view
    route: /admin/.../groups and /admin/.../groups/{record}
    panel: mixed
    expectations:
      - tenant_panel_routes_use_panel_native_tenant
      - admin_sensitive_access_paths_use_explicit_scope_rule
      - direct_record_resolution_matches_list_scope
      - admin_no_context_returns_not_found
      - out_of_scope_access_returns_not_found

  - name: entra_group_global_search
    route: global-search
    panel: mixed
    expectations:
      - search_results_follow_same_scope_as_list_and_detail
      - non_members_receive_no_hints
      - admin_no_context_returns_no_tenant_owned_results
      - resource_search_is_disabled_if_scope_parity_cannot_be_guaranteed

  - name: alert_delivery_reference_pattern
    route: /admin/alert-deliveries
    panel: admin
    expectations:
      - existing_admin_query_and_filter_alignment_is_preserved
      - resource_remains_non_regression_reference

authorization_contract:
  non_member_or_out_of_scope:
    response: not_found
  member_missing_capability:
    response: forbidden

guardrail:
  purpose: prevent_new_admin_panel_raw_panel_native_tenant_reads
  forbidden_patterns:
    - Filament::getTenant()
    - Tenant::current()
  enforced_in:
    - app/Filament/Pages/Monitoring
    - app/Filament/Pages/Operations
    - app/Filament/Resources
    - app/Filament/Widgets/Operations
  allowed_exceptions:
    - app/Filament/Pages/ChooseTenant.php
    - app/Http/Controllers/SelectTenantController.php
    - app/Support/Middleware/EnsureFilamentTenantSelected.php
    - app/Filament/Resources/EntraGroupResource.php
