# Research: Tenant Registry Recovery Triage

## Decision 1: Use workspace-scoped batch posture maps from existing resolvers

- **Decision**: Build tenant-registry posture data from `TenantBackupHealthResolver::assessMany()` and `RestoreSafetyResolver::dashboardRecoveryEvidenceForTenants()` over the already scoped visible tenant set instead of resolving posture per row.
- **Rationale**: Both resolvers already provide the exact truth the registry needs and are already used together in `WorkspaceOverviewBuilder`. Reusing them keeps backup posture and recovery evidence aligned with existing workspace and tenant surfaces and avoids N+1 list rendering.
- **Alternatives considered**:
  - Per-row resolver calls inside table column closures: rejected because it creates predictable N+1 behavior and duplicates work between columns, filters, and sorting.
  - Reimplement posture logic in SQL joins or subqueries: rejected because it duplicates domain truth outside the existing resolver path and risks semantic drift.
  - Persist a tenant posture summary table: rejected because the spec explicitly forbids a second persisted truth.

## Decision 2: Preserve multi-tenant drilldown intent through exact query parameters on `/admin/tenants`

- **Decision**: Change workspace backup and recovery multi-tenant destinations to `/admin/tenants` with query parameters that encode exact posture selections and `triage_sort=worst_first`.
- **Rationale**: The codebase already uses query-string intent on list and page surfaces, and this approach preserves meaning directly in the URL without adding a new page, hidden state, or session-only transfer mechanism.
- **Alternatives considered**:
  - Keep `ChooseTenant` for multi-tenant drilldowns: rejected because it drops the recovery or backup cause and sends the operator back to manual tenant-by-tenant inspection.
  - Use only session state and no URL signal: rejected because it makes drilldown state invisible and harder to test.
  - Add a dedicated portfolio recovery page: rejected because it introduces a larger IA change than the current release needs.

## Decision 3: Use multi-select posture filters with exact state values

- **Decision**: Represent triage filters as exact state arrays rather than introducing `needs attention` or other pseudo-filter values.
- **Rationale**: The spec explicitly requires clear posture-based filtering and rejects semantically vague attention filters. Multi-select filters allow workspace backup drilldowns to preselect `absent`, `stale`, and `degraded`, and recovery drilldowns to preselect `weakened` and `unvalidated`, while keeping the filter chips themselves truthful.
- **Alternatives considered**:
  - Single-select filters plus an `attention` option: rejected because it hides the underlying state composition.
  - Custom tabs or page variants per posture family: rejected because they expand the surface model unnecessarily.
  - Hard-coded workspace-only registry variants: rejected because the registry should stay one canonical collection route.

## Decision 4: Keep the TenantResource list action surface contract intact

- **Decision**: Preserve full-row click as the one primary inspect model and keep at most one inline safe shortcut for fast next-step navigation.
- **Rationale**: `TenantResource` is already governed by the current action-surface contract and guard tests. The triage enhancement should be expressed through visible posture truth, filters, and ordering rather than additional row actions.
- **Alternatives considered**:
  - Add a dedicated View action: rejected because it duplicates the existing row-click inspect model.
  - Add multiple inline shortcuts to backup sets, restore runs, and dashboard: rejected because it would turn the registry into a crowded multi-action surface and violate the list hierarchy rules.

## Decision 5: Reuse existing recovery-readiness presentation semantics instead of inventing registry-local posture language

- **Decision**: Reuse or absorb the label, tone, and fallback-navigation semantics already present in `RecoveryReadiness` for `Backup posture` and `Recovery evidence` when the registry renders the same states.
- **Rationale**: The codebase already has one operator-facing composition that normalizes these exact states. Reusing that semantics avoids drift between dashboard and registry surfaces and keeps any new status-like rendering inside existing shared seams.
- **Alternatives considered**:
  - Local `match` statements inside `TenantResource`: rejected because they would create another page-local status language.
  - A new presentation framework or registry-specific presenter: rejected because there are only two concrete surfaces and the constitution prefers small extensions of existing seams over new frameworks.

## Decision 6: Use existing feature and guard tests as the primary acceptance harness

- **Decision**: Extend current workspace overview and tenant resource tests and add one focused registry triage test file instead of introducing a browser-first harness.
- **Rationale**: The repo already has precise seams for workspace summary metrics, drilldown continuity, tenant registry scope, and Filament table standards. Those seams are sufficient to prove truthfulness, scope safety, and ordering.
- **Alternatives considered**:
  - New browser tests: rejected because the relevant behaviors are already observable at the builder and Livewire list layers.
  - Manual-only QA: rejected because the spec explicitly requires regression-safe automated coverage.