TenantAtlas/specs/103-ia-scope-filter-semantics/research.md
Ahmed Darrazi 8b13d6f55f feat: refine tenant scope semantics
- Update OperateHub scope label copy (All tenants / Filtered by tenant)

- Fix Alerts KPI tenant resolution via activeEntitledTenant()

- Remove tenant indicator from manage lists

- Improve AlertRule form labels + sections

- UI polish: resource sections + tenant view widget layout + RBAC progressive disclosure

- Add/adjust Pest coverage
2026-02-21 01:00:31 +01:00

4.0 KiB
Raw Blame History

Research: 103 — IA Semantics: Scope vs Filter vs Targeting

Date: 2026-02-20
Status: Complete — No unknowns remain

R1 — OperateHubShell::scopeLabel() Is the Single Source of Truth

Decision: Update scopeLabel() in OperateHubShell to emit new copy.
Rationale: All Monitoring pages that display the tenant indicator call scopeLabel() (directly or via headerActions()). Updating this one method propagates the change to:

  • Operations index + run detail viewer
  • Alert Deliveries list
  • Alerts Overview page
  • Audit Log page

Current code (line 2433 of OperateHubShell.php):

public function scopeLabel(?Request $request = null): string
{
    $activeTenant = $this->activeEntitledTenant($request);
    if ($activeTenant instanceof Tenant) {
        return 'Scope: Tenant — '.$activeTenant->name;
    }
    return 'Scope: Workspace — all tenants';
}

New copy:

  • With tenant: "Filtered by tenant: {name}"
  • Without tenant: "All tenants"

Alternatives considered: Per-page label override — rejected because it would introduce duplication and risk drift.

R2 — AlertsKpiHeader Bugfix: Filament::getTenant() vs activeEntitledTenant()

Decision: Replace Filament::getTenant() with OperateHubShell::activeEntitledTenant(request()) in AlertsKpiHeader::deliveriesQueryForViewer().
Rationale: The current code at line 107 uses Filament::getTenant() which returns null when tenant-context is set via lastTenantId session fallback only. The indicator (via scopeLabel) uses activeEntitledTenant() which includes the fallback. This mismatch causes the indicator to say "filtered" while the KPIs show workspace-wide numbers.

Note: The AlertRule/AlertDestination count stats are workspace-owned and don't filter by tenant — this is correct and unchanged.

Alternatives considered: Making lastTenantId set Filament::setTenant() globally — rejected because it has broad side effects on Filament's tenant routing.

R3 — Manage Pages: Remove OperateHubShell Header Actions

Decision: Remove the ...app(OperateHubShell::class)->headerActions(...) spread from ListAlertRules::getHeaderActions() and ListAlertDestinations::getHeaderActions().
Rationale: These are workspace-owned Manage pages. The tenant indicator is semantically wrong because the data is not filtered by tenant. After removal, only the Create action remains in header actions.

Alternatives considered: Showing a different "Workspace configuration" indicator — rejected as unnecessary complexity.

R4 — AlertRule Form: Label + Section Changes

Decision: Update form labels in AlertRuleResource::form() and wrap fields in three Filament\Schemas\Components\Section groups.
Rationale:

  • "Tenant scope mode" → "Applies to tenants" (targeting semantics, not ownership)
  • "Tenant allowlist" → label removed from the current Allowlist option; becomes "Selected tenants"
  • Field option values: all → "All tenants", allowlist → "Selected tenants" (DB values unchanged)
  • Helper texts added per spec

Import verified: Filament v5 uses Filament\Schemas\Components\Section (confirmed in 11 existing files).

No persistence changes: The tenant_scope_mode column stores all/allowlist as before.

R5 — Existing Test Coverage

Decision: Update existing OperateHubShellTest assertions that check for old copy, and add new tests.

Existing tests that assert old copy (must be updated):

  • OperateHubShellTest: multiple assertSee('Scope: Workspace — all tenants') calls

New tests needed:

  • Monitoring indicator copy (with/without tenant)
  • KPI consistency bugfix (lastTenantId fallback)
  • Manage pages: no tenant indicator
  • AlertRule form: new labels

R6 — Section Import Path (Filament v5)

Decision: Use Filament\Schemas\Components\Section.
Rationale: Confirmed by grep across 11 existing Filament resource files in the codebase. This is the canonical v5 import.

Alternatives considered: Filament\Forms\Components\Section (v3/v4 path) — confirmed NOT used in this codebase.