## Summary - add a dedicated Recovery Readiness dashboard widget for backup posture and recovery evidence - group Needs Attention items by domain and elevate the recovery call-to-action - align restore-run and recovery posture tests with the extracted widget and continuity flows - include the related spec artifacts for 184-dashboard-recovery-honesty ## Verification - `cd /Users/ahmeddarrazi/Documents/projects/TenantAtlas/apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - `cd /Users/ahmeddarrazi/Documents/projects/TenantAtlas/apps/platform && ./vendor/bin/sail artisan test --compact --filter="DashboardKpisWidget|DashboardRecoveryPosture|TenantDashboardDbOnly|TenantpilotSeedBackupHealthBrowserFixtureCommand|NeedsAttentionWidget"` - browser smoke verified on the calm, unvalidated, and weakened dashboard states ## Notes - Livewire v4.0+ compliant with Filament v5 - no panel provider changes; Laravel 11+ provider registration remains in `bootstrap/providers.php` - Recovery Readiness stays within the existing tenant dashboard asset strategy; no new Filament asset registration required Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #215
273 lines
24 KiB
Markdown
273 lines
24 KiB
Markdown
# Implementation Plan: Dashboard Recovery Posture Honesty
|
||
|
||
**Branch**: `184-dashboard-recovery-honesty` | **Date**: 2026-04-08 | **Spec**: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/184-dashboard-recovery-honesty/spec.md`
|
||
**Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/184-dashboard-recovery-honesty/spec.md`
|
||
|
||
## Summary
|
||
|
||
Harden the tenant dashboard so healthy backup inputs never read as validated recovery posture by default. The implementation will keep backup health and restore evidence as separate truths, reuse the existing backup positive-claim boundary and per-run `RestoreResultAttention` semantics, add an honest recovery-evidence summary to the tenant dashboard KPI and attention surfaces, and route no-history or weak-history signals into canonical restore-run list or detail drilldowns using the repo’s existing continuity-banner pattern. The slice stays read-only, introduces no new persistence, enum, provider, asset, or recovery-confidence engine, and limits code changes to existing dashboard widgets, existing restore-run list or detail surfaces, and focused Pest coverage.
|
||
|
||
## Technical Context
|
||
|
||
**Language/Version**: PHP 8.4, Laravel 12, Blade, Filament v5, Livewire v4
|
||
**Primary Dependencies**: Filament v5 widgets and resources, Livewire v4, Pest v4, existing `TenantDashboard`, `DashboardKpis`, `NeedsAttention`, `TenantBackupHealthResolver`, `TenantBackupHealthAssessment`, `RestoreRunResource`, `RestoreSafetyResolver`, `RestoreResultAttention`, `OperationRunLinks`, and existing RBAC helpers
|
||
**Storage**: PostgreSQL with existing tenant-owned `backup_sets`, `restore_runs`, and linked `operation_runs`; no schema change planned
|
||
**Testing**: Pest feature tests, Livewire widget or page tests, and narrow unit coverage for restore-history derivation, all run through Sail
|
||
**Target Platform**: Laravel web application in Sail locally and containerized Linux deployment in staging and production
|
||
**Project Type**: Laravel monolith web application rooted at `apps/platform`
|
||
**Performance Goals**: Keep tenant dashboard rendering DB-only, avoid external calls at render time, cap recovery-evidence derivation to the most recent 10 tenant-scoped restore-run candidates with only the required relations eager-loaded, and preserve the existing restore-run list scanability without N+1 row lookups
|
||
**Constraints**: No new persisted recovery-confidence field or table, no new recovery-proven signal, no new Graph calls, no new panel or provider registration, no new global-search behavior, no RBAC drift, no summary claim stronger than the evidence visible to the current user, and no new Filament asset registration
|
||
**Scale/Scope**: One tenant dashboard page, two existing dashboard widgets, one restore-run list continuity seam, one restore-run detail reuse seam, one internal dashboard surface contract, and focused unit plus feature regression coverage
|
||
|
||
## Constitution Check
|
||
|
||
*GATE: Passed before Phase 0 research. Re-checked after Phase 1 design and still passing.*
|
||
|
||
| Principle | Status | Notes |
|
||
|-----------|--------|-------|
|
||
| Inventory-first | Pass | Existing backup and restore artifacts remain the only evidence sources; no ownership model changes |
|
||
| Read/write separation | Pass | This slice is read-only summary hardening; no new mutation or remote work is introduced |
|
||
| Graph contract path | Pass | No Graph calls, contract-registry changes, or provider changes are required |
|
||
| Deterministic capabilities | Pass | Existing capability registry, policies, and `UiEnforcement` remain authoritative |
|
||
| RBAC-UX planes and 404 vs 403 | Pass | Tenant dashboard and restore-run surfaces remain in `/admin/t/{tenant}/...`; non-members stay 404; in-scope members retain existing capability semantics |
|
||
| Workspace isolation | Pass | No workspace-scope broadening is planned; workspace overview remains unchanged in this slice |
|
||
| Tenant isolation | Pass | All evidence and drilldowns stay tenant-owned and tenant-scoped |
|
||
| Destructive confirmation standard | Pass | No new destructive dashboard actions are added; existing restore-run destructive actions remain confirmed and server-authorized |
|
||
| Global search safety | Pass | No new globally searchable resource or search behavior is introduced; existing resources retain their current view-page-backed search safety |
|
||
| Run observability / Ops-UX | Pass | No new `OperationRun`, background work, notification surface, or lifecycle transition is added |
|
||
| Data minimization | Pass | The slice reuses existing backup and restore metadata and keeps diagnostics on existing restore surfaces |
|
||
| Proportionality (PROP-001) | Pass | The design extends existing widgets, list pages, and restore-safety seams instead of adding a new recovery-confidence subsystem |
|
||
| No premature abstraction (ABSTR-001) | Pass | No new registry, interface, or orchestration layer is planned; at most a narrow extension of existing restore-safety seams or local widget derivation is needed |
|
||
| Persisted truth (PERSIST-001) | Pass | Recovery posture remains derived at render time; no new stored truth is introduced |
|
||
| Behavioral state (STATE-001) | Pass | `unvalidated`, `weakened`, and `no_recent_issues_visible` stay derived UI semantics, not new persisted domain state |
|
||
| UI semantics (UI-SEM-001) | Pass | Recovery honesty is rendered directly on existing widgets and restore surfaces; no new presenter framework is planned |
|
||
| Badge semantics (BADGE-001) | Pass | Existing badge catalogs remain authoritative; if restore attention appears on the list, it will reuse existing restore status and attention semantics rather than page-local mappings |
|
||
| Filament-native UI (UI-FIL-001) | Pass | Existing `StatsOverviewWidget`, dashboard section view, Filament links, badges, and restore-run resource tables remain the primary seams |
|
||
| UI Action Surface Contract | Pass | No new inspect model or destructive placement is introduced; restore-run list retains clickable-row inspect and grouped mutations |
|
||
| UX-001 / HDR-001 | Pass | The dashboard keeps its existing widget layout; no new record headers or form layout changes are introduced |
|
||
| Filament v5 / Livewire v4 compliance | Pass | The plan stays inside current Filament v5 and Livewire v4 surface patterns |
|
||
| Provider registration location | Pass | No provider change is needed; existing Laravel 11+ registration remains in `bootstrap/providers.php` |
|
||
| Global-search rule for changed resources | Pass | No change to searchable resource registration; `RestoreRunResource` already has detail pages and this slice touches no search-specific behavior |
|
||
| Asset strategy | Pass | No new assets are planned; deployment continues to include `cd apps/platform && php artisan filament:assets` unchanged |
|
||
|
||
## Phase 0 Research
|
||
|
||
Research outcomes are captured in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/184-dashboard-recovery-honesty/research.md`.
|
||
|
||
Key decisions:
|
||
|
||
- Keep the implementation scoped to tenant dashboard and restore-history confirmation surfaces; do not expand `WorkspaceOverviewBuilder` in this slice because the workspace overview does not currently restate backup or recovery posture.
|
||
- Reuse `TenantBackupHealthAssessment::positiveClaimBoundary` as the canonical backup-health boundary on summary surfaces instead of inventing new copy.
|
||
- Treat only non-dry-run, non-preview, executed restore runs as relevant restore history for overview confidence language.
|
||
- Reuse `RestoreSafetyResolver::resultAttentionForRun(...)` as the sole authority for failed, partial, completed-with-follow-up, and completed-without-follow-up semantics.
|
||
- Prefer canonical restore-run list drilldowns with a continuity reason banner when no specific run exists or when a direct detail link would be fragile; use restore-run detail only when a recent problematic run exists and is accessible.
|
||
- Keep summary language cautious under RBAC restrictions: if deeper restore evidence cannot be opened, the summary may disable or fall back on the action but must not upgrade the claim.
|
||
- Reuse the existing backup-health list continuity pattern (`backup_health_reason`) for restore-history continuity rather than adding a new UI shell or route family.
|
||
- Extend existing dashboard, restore-run, and restore-attention tests instead of creating a new browser-level harness.
|
||
|
||
## Phase 1 Design
|
||
|
||
Design artifacts are created under `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/184-dashboard-recovery-honesty/`:
|
||
|
||
- `research.md`: implementation decisions, constraints, and alternatives for recovery-posture honesty
|
||
- `data-model.md`: existing evidence models and the derived overview recovery-posture projection
|
||
- `contracts/dashboard-recovery-posture.openapi.yaml`: internal reference contract for tenant dashboard and restore-history drilldown surfaces
|
||
- `quickstart.md`: focused validation workflow for honest dashboard recovery posture
|
||
|
||
Design decisions:
|
||
|
||
- Keep backup health and recovery evidence separate on the dashboard: backup posture remains the backup-input truth; a dedicated recovery-evidence summary or equivalent dashboard qualifier carries the restore-history truth.
|
||
- Suppress all-clear semantics when relevant restore history is absent by making no-history its own derived overview condition rather than folding it into healthy backup posture.
|
||
- Use existing per-run `RestoreResultAttention` output to decide whether recent restore history weakens confidence; do not duplicate that logic with raw status checks in widgets.
|
||
- Add restore-history continuity to `ListRestoreRuns` via a query-string reason and subheading pattern analogous to `ListBackupSets` and `ListBackupSchedules`.
|
||
- Make restore-run list rows more self-confirming by surfacing result-attention summary in a default-visible column or equivalent default-visible fact.
|
||
- Reuse existing `ViewRestoreRun` result-attention presentation for detailed drilldown confirmation instead of building a new recovery detail page.
|
||
- Leave workspace overview unchanged in this spec to avoid introducing a second summary surface with partially duplicated semantics; verify instead that no new contradiction is introduced.
|
||
|
||
## Project Structure
|
||
|
||
### Documentation (this feature)
|
||
|
||
```text
|
||
specs/184-dashboard-recovery-honesty/
|
||
├── spec.md
|
||
├── plan.md
|
||
├── research.md
|
||
├── data-model.md
|
||
├── quickstart.md
|
||
├── contracts/
|
||
│ └── dashboard-recovery-posture.openapi.yaml
|
||
├── checklists/
|
||
│ └── requirements.md
|
||
└── tasks.md
|
||
```
|
||
|
||
### Source Code (repository root)
|
||
|
||
```text
|
||
apps/platform/
|
||
├── app/
|
||
│ ├── Filament/
|
||
│ │ ├── Pages/
|
||
│ │ │ └── TenantDashboard.php
|
||
│ │ ├── Widgets/
|
||
│ │ │ └── Dashboard/
|
||
│ │ │ ├── DashboardKpis.php
|
||
│ │ │ └── NeedsAttention.php
|
||
│ │ └── Resources/
|
||
│ │ ├── RestoreRunResource.php
|
||
│ │ └── RestoreRunResource/
|
||
│ │ └── Pages/
|
||
│ │ ├── ListRestoreRuns.php
|
||
│ │ └── ViewRestoreRun.php
|
||
│ ├── Models/
|
||
│ │ ├── BackupSet.php
|
||
│ │ ├── RestoreRun.php
|
||
│ │ └── OperationRun.php
|
||
│ └── Support/
|
||
│ ├── BackupHealth/
|
||
│ │ ├── TenantBackupHealthAssessment.php
|
||
│ │ └── TenantBackupHealthResolver.php
|
||
│ ├── RestoreSafety/
|
||
│ │ ├── RestoreResultAttention.php
|
||
│ │ └── RestoreSafetyResolver.php
|
||
│ └── OperationRunLinks.php
|
||
├── resources/views/
|
||
│ └── filament/widgets/dashboard/
|
||
│ └── needs-attention.blade.php
|
||
└── tests/
|
||
├── Feature/
|
||
│ ├── Filament/
|
||
│ │ ├── DashboardKpisWidgetTest.php
|
||
│ │ ├── NeedsAttentionWidgetTest.php
|
||
│ │ ├── RestoreResultAttentionSurfaceTest.php
|
||
│ │ ├── RestoreRunUiEnforcementTest.php
|
||
│ │ ├── DashboardRecoveryPosturePerformanceTest.php
|
||
│ │ └── RestoreRunListContinuityTest.php
|
||
│ └── Rbac/
|
||
│ └── DashboardRecoveryPostureVisibilityTest.php
|
||
└── Unit/
|
||
└── Support/
|
||
└── RestoreSafety/
|
||
└── RestoreResultAttentionTest.php
|
||
```
|
||
|
||
**Structure Decision**: Standard Laravel monolith inside `apps/platform`. The implementation stays inside existing dashboard widgets, existing restore-run resources or pages, existing restore-safety support classes, and existing test directories. No new root folders, no new panel providers, and no new cross-cutting framework are planned.
|
||
|
||
## Implementation Strategy
|
||
|
||
### Phase A — Derive Relevant Restore History Without A New Engine
|
||
|
||
**Goal**: Decide whether restore evidence is absent, weakened, or merely non-proving by reusing existing restore-safety truth and a minimal tenant-scoped history query.
|
||
|
||
| Step | File | Change |
|
||
|------|------|--------|
|
||
| A.1 | `apps/platform/app/Support/RestoreSafety/RestoreSafetyResolver.php` or co-located dashboard widget methods | Add the minimal tenant-scoped query seam needed to determine relevant restore history, capped to the 10 most recent restore-run candidates and eager-loading only the relations required for the latest relevant visible executed run and its applicable `RestoreResultAttention`, without introducing a new persistent recovery-confidence model |
|
||
| A.2 | Existing dashboard widgets only | Keep derived state local and lightweight: no new persisted field, no new enum, and no cross-domain recovery framework; if shared logic is unavoidable, keep it inside the existing restore-safety support namespace or a narrow local helper |
|
||
| A.3 | `apps/platform/tests/Unit/Support/RestoreSafety/RestoreResultAttentionTest.php` and a focused new unit test if needed | Cover preview-only exclusion, no-history detection, latest-run precedence, and weak-history precedence over older calmer history |
|
||
|
||
### Phase B — Surface Honest Recovery Language On The KPI Strip
|
||
|
||
**Goal**: Make the tenant dashboard scan distinguish backup-input health from recovery evidence in the first glance.
|
||
|
||
| Step | File | Change |
|
||
|------|------|--------|
|
||
| B.1 | `apps/platform/app/Filament/Widgets/Dashboard/DashboardKpis.php` | Keep the existing `Backup posture` stat as backup-input truth and append the visible backup claim boundary where the summary could otherwise sound stronger than the evidence |
|
||
| B.2 | `apps/platform/app/Filament/Widgets/Dashboard/DashboardKpis.php` | Add a recovery-evidence stat or equivalent adjacent summary signal that expresses `unvalidated`, `weakened`, or `no_recent_issues_visible` without ever claiming recovery proof |
|
||
| B.3 | `apps/platform/app/Filament/Widgets/Dashboard/DashboardKpis.php` | Route KPI drilldowns to canonical restore-run list or detail surfaces, with disabled or fallback behavior when a more specific drilldown is unavailable or inappropriate |
|
||
|
||
### Phase C — Integrate Recovery Honesty Into Needs Attention And Healthy Checks
|
||
|
||
**Goal**: Ensure healthy backup posture does not collapse into a quiet all-clear when restore evidence is missing or concerning.
|
||
|
||
| Step | File | Change |
|
||
|------|------|--------|
|
||
| C.1 | `apps/platform/app/Filament/Widgets/Dashboard/NeedsAttention.php` | Add a recovery-family attention item for `no relevant restore history` that explains why confidence is unvalidated and points to restore history |
|
||
| C.2 | `apps/platform/app/Filament/Widgets/Dashboard/NeedsAttention.php` | Add a recovery-family attention item for recent `failed`, `partial`, or `completed_with_follow_up` restore evidence using existing `RestoreResultAttention` semantics |
|
||
| C.3 | `apps/platform/app/Filament/Widgets/Dashboard/NeedsAttention.php` | Add a healthy-check entry for `no recent restore issues visible` that still preserves the non-proof boundary, and prevent healthy backup messaging from becoming an unqualified all-clear |
|
||
| C.4 | `apps/platform/resources/views/filament/widgets/dashboard/needs-attention.blade.php` only if needed | Reuse the existing attention and healthy-check rendering shape; only adjust the lead copy if the current calm sentence would still overclaim once recovery checks are present |
|
||
|
||
### Phase D — Restore History Drillthrough Continuity
|
||
|
||
**Goal**: Make every summary link land on a restore-history surface that confirms the same truth the dashboard just stated.
|
||
|
||
| Step | File | Change |
|
||
|------|------|--------|
|
||
| D.1 | `apps/platform/app/Filament/Resources/RestoreRunResource/Pages/ListRestoreRuns.php` | Add `backup_health_reason`-style continuity support with a `recovery_posture_reason` subheading so `no history` and list-fallback links remain self-explanatory |
|
||
| D.2 | `apps/platform/app/Filament/Resources/RestoreRunResource.php` | Add a default-visible result-attention summary column or equivalent row fact derived through `RestoreSafetyResolver::resultAttentionForRun(...)` so the restore-run list immediately confirms failed, partial, and follow-up states |
|
||
| D.3 | `apps/platform/app/Filament/Resources/RestoreRunResource/Pages/ViewRestoreRun.php` | Reuse the existing result-attention section as the canonical detail confirmation surface; add only lightweight context copy if a dashboard-linked reason is not already obvious |
|
||
| D.4 | `apps/platform/app/Support/OperationRunLinks.php` and widget link builders only if needed | Keep canonical list and detail routing intact; prefer list fallback when a direct run link is brittle, unavailable, or semantically weaker than the restore-history list context |
|
||
|
||
### Phase E — Regression Protection And Focused Verification
|
||
|
||
**Goal**: Lock the honesty boundary into automated tests without widening the feature into a larger recovery-confidence program.
|
||
|
||
| Step | File | Change |
|
||
|------|------|--------|
|
||
| E.1 | `apps/platform/tests/Feature/Filament/DashboardKpisWidgetTest.php` | Cover healthy backups with no relevant restore history, claim-boundary visibility on the KPI strip, and recovery-evidence summary behavior |
|
||
| E.2 | `apps/platform/tests/Feature/Filament/NeedsAttentionWidgetTest.php` | Cover no-history attention, failed or partial or follow-up escalation, healthy-check fallback, and non-overclaim behavior |
|
||
| E.3 | `apps/platform/tests/Feature/Filament/RestoreRunListContinuityTest.php` | Add continuity coverage for `recovery_posture_reason` list drilldowns, especially `no_history` fallback and weak-history fallback |
|
||
| E.4 | `apps/platform/tests/Feature/Filament/RestoreResultAttentionSurfaceTest.php` | Confirm dashboard drilldowns land on restore surfaces that show the same result-attention reason and claim boundary |
|
||
| E.5 | `apps/platform/tests/Feature/Rbac/DashboardRecoveryPostureVisibilityTest.php` and `apps/platform/tests/Feature/Filament/RestoreRunUiEnforcementTest.php` | Prove readonly members still see cautious summary truth, in-scope members lacking restore-history view receive 403 on drillthrough while the dashboard stays truthful, and non-members still receive 404 behavior |
|
||
| E.6 | `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` and focused Pest runs | Required formatting and targeted verification before implementation is considered complete |
|
||
|
||
## Key Design Decisions
|
||
|
||
### D-001 — No Relevant Restore History Is Derived From Executed Runs Only
|
||
|
||
Preview-only, dry-run, draft, scoped, checked, and previewed restore records already carry a boundary that they do not prove execution. The overview should therefore treat them as insufficient evidence rather than as calming history.
|
||
|
||
### D-002 — Backup Health And Recovery Evidence Stay Orthogonal
|
||
|
||
`TenantBackupHealthAssessment` remains the source of backup-input truth. Recovery honesty is a second derived summary that references restore history without changing what backup health means.
|
||
|
||
### D-003 — Existing Claim Boundaries Stay Canonical
|
||
|
||
The backup positive-claim boundary already exists in `TenantBackupHealthAssessment`, and per-run restore claim boundaries already exist in `RestoreResultAttention`. The plan reuses those boundaries instead of inventing a second copy system.
|
||
|
||
### D-004 — Continuity Uses Existing List-Subheading Patterns
|
||
|
||
The repo already uses query-string continuity copy on list pages (`backup_health_reason`) to explain why a dashboard drillthrough landed on a list instead of a detail page. Restore history will use the same pattern rather than a new shell, modal, or route family.
|
||
|
||
### D-005 — Workspace Overview Stays Unchanged In This Slice
|
||
|
||
Current workspace overview logic surfaces governance, compare, findings, alerts, and operations, but not backup or recovery posture. Not changing it is the smallest way to avoid introducing contradictory portfolio-level semantics in this spec.
|
||
|
||
### D-006 — Readonly Users Can Still Validate The Claim Boundary
|
||
|
||
Existing tests show readonly tenant members can open restore-run history while mutations stay disabled. The plan uses that existing view-rights shape to preserve honesty for lower-capability operators without widening restore permissions.
|
||
|
||
## Risk Assessment
|
||
|
||
| Risk | Impact | Likelihood | Mitigation |
|
||
|------|--------|------------|------------|
|
||
| Relevant restore history is misclassified because preview-only or dry-run records are counted as real evidence | High | Medium | Add explicit derivation tests for preview-only exclusion and executed-run selection |
|
||
| Dashboard widgets drift semantically because backup health and restore evidence are derived in two different ways | High | Medium | Centralize the minimal history-selection logic in one existing seam or prove the local duplication is identical through tests |
|
||
| Restore-run list drilldowns do not visibly confirm `completed_with_follow_up` or other weak-history reasons | High | Medium | Add a default-visible result-attention fact on list rows and a continuity subheading on fallback list views |
|
||
| RBAC-restricted users see calmer summary language because a direct restore detail link is unavailable | High | Low | Keep summary claims independent from link availability and add readonly visibility regression coverage |
|
||
| Dashboard render cost grows due to extra restore-history queries | Medium | Medium | Cap candidate selection to the latest 10 restore runs, eager-load only the required relations in that query, and keep workspace overview out of scope in this slice |
|
||
|
||
## Test Strategy
|
||
|
||
- Extend the existing dashboard widget tests first instead of creating a new browser-driven harness.
|
||
- Add unit coverage for the relevant restore-history selection and weak-history precedence if a shared restore-safety query seam is introduced.
|
||
- Add feature coverage proving that healthy backup posture plus no relevant restore history never yields an all-clear on the dashboard.
|
||
- Add feature coverage proving that failed, partial, and follow-up restore outcomes become overview-visible attention states.
|
||
- Add continuity tests for dashboard-to-restore-history drilldowns, including list fallback and detail confirmation.
|
||
- Add RBAC regression tests proving readonly members still see cautious truth while non-members remain 404 and restore mutations stay disabled.
|
||
- Add query-shape regression coverage proving recovery-evidence derivation stays capped to the latest 10 candidate restore runs and does not introduce N+1 queries on the dashboard or restore-run list surfaces.
|
||
- Keep all tests Livewire v4 compatible and run the smallest affected subset through Sail before asking for a broader suite run.
|
||
|
||
## Complexity Tracking
|
||
|
||
No constitution violations are currently justified. The plan deliberately avoids new persistence, new enums, new registries, and new page shells. Any shared derivation added during implementation must stay narrower than a new recovery-confidence subsystem and remain inside existing restore-safety or dashboard seams.
|
||
|
||
## Proportionality Review
|
||
|
||
- **Current operator problem**: Operators can currently read healthy backup summaries as stronger recovery assurance than the product can actually prove when restore history is absent or weak.
|
||
- **Existing structure is insufficient because**: The backup-health boundary and the per-run restore-result truth already exist, but the tenant dashboard does not currently connect them or preserve the same explanation on drilldown.
|
||
- **Narrowest correct implementation**: Extend existing dashboard widgets, existing restore-run list/detail seams, and existing restore-safety truth rather than adding a new recovery-confidence model or page.
|
||
- **Ownership cost created**: Additional widget copy, a narrow restore-history derivation path, one list continuity seam, and focused unit plus feature tests.
|
||
- **Alternative intentionally rejected**: A full recovery-confidence engine, persisted posture state, new enum family, or standalone recovery page were rejected because they add broader truth and maintenance cost than this honesty slice needs.
|
||
- **Release truth**: Current-release truth hardening.
|