TenantAtlas/specs/176-backup-quality-truth/research.md
ahmido e840007127 feat: add backup quality truth surfaces (#211)
## Summary
- add a shared backup-quality resolver and summary model for backup sets, backup items, policy versions, and restore selection
- surface backup-quality truth across Filament backup-set, policy-version, and restore-wizard entry points
- add focused Pest coverage and the full Spec Kit artifact set for spec 176

## Testing
- focused backup-quality verification and integrated-browser smoke coverage were completed during implementation
- degraded browser smoke path was validated with temporary seeded records and then cleaned up again
- the workspace already has a prior `vendor/bin/sail artisan test --compact` run exiting non-zero; that full-suite failure was not reworked as part of this PR

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #211
2026-04-07 11:39:40 +00:00

6.9 KiB

Research: Backup Quality Truth Surfaces

Decision 1: Derive backup quality from existing backup and version metadata instead of creating a persisted backup-health model

  • Decision: Build backup quality from the metadata already present on BackupItem and PolicyVersion, then aggregate backup-set truth from those per-item facts. Do not add a new table, column, or stored backup-health projection.
  • Rationale: The current data model already records the core quality signals this feature needs: metadata-only source markers, assignment fetch failures, orphaned assignments, warnings, scope-tag context, and integrity notes. The product problem is weak surfacing, not missing persistence.
  • Alternatives considered:
    • Persist a backup_quality or backup_health table. Rejected because it would create a second source of truth for information that is already derivable.
    • Add materialized quality fields to backup_sets or policy_versions. Rejected because the feature does not need independent lifecycle state.

Decision 2: Keep capture lifecycle and backup quality as separate truths on every affected surface

  • Decision: Render capture lifecycle (completed, partial, failed, archived) independently from backup quality (metadata-only present, assignment issues present, degraded-count summary, or no degradations detected).
  • Rationale: Operators currently overread completed as good backup. The feature must stop that conflation without erasing the lifecycle truth that the system already tracks.
  • Alternatives considered:
    • Blend quality into one stronger status badge. Rejected because that would collapse two different truths into one ambiguous state.
    • Treat completed plus degraded counts as a new status family. Rejected because it would introduce new state where derived summary is sufficient.

Decision 3: Reuse the central snapshot-mode badge and shared badge infrastructure instead of page-local mapping

  • Decision: Use the existing BadgeDomain::PolicySnapshotMode and PolicySnapshotModeBadge semantics for full versus metadata only. Any new quality chips or labels should stay inside shared badge or copy seams rather than page-local match statements.
  • Rationale: The codebase already centralizes status-like badge semantics, and Filament v5 tables or schema text badges can render those shared specs directly. This keeps backup quality aligned with BADGE-001 and avoids a second vocabulary for snapshot completeness.
  • Alternatives considered:
    • Add local badge mapping per surface. Rejected because it would drift from the central badge catalog.
    • Introduce a generic trust score badge. Rejected because the spec explicitly avoids a new scoring engine.

Decision 4: Use existing Filament tables, infolists, enterprise-detail sections, and checkbox-list descriptions instead of a new UI shell

  • Decision: Implement the feature inside BackupSetResource, BackupItemsRelationManager, PolicyVersionResource, and RestoreRunResource using the current Filament table columns, infolist sections, enterprise-detail builder, and wizard descriptions.
  • Rationale: Filament v5 already supports badge columns, summary-first view content, relation-manager tables, and descriptive checkbox list options. The repository also already uses enterpriseDetailPage() for backup-set detail and schema-driven wizard steps for restore selection.
  • Alternatives considered:
    • Build a dedicated backup-health dashboard. Rejected because it is explicitly out of scope.
    • Add a custom client-side wizard overlay. Rejected because the needed truth is server-driven and fits existing Filament seams.

Decision 5: Surface backup-set and item quality in restore selection before risk checks, but keep restore safety as a separate authority

  • Decision: Enrich restore wizard step 1 backup-set labels or helper copy and step 2 item descriptions with input-quality truth before preview or risk checks run. Do not block degraded selections at this stage unless existing restore safety already blocks them later.
  • Rationale: Operators need early warning before the risk-check stage, but this spec is about backup quality, not execution safety. The restore-safety layer already owns blocker and preview-only semantics.
  • Alternatives considered:
    • Leave degraded truth exclusively to restore risk checks. Rejected because it preserves the current late-discovery trust failure.
    • Prevent selecting degraded inputs in step 1 or step 2. Rejected because the spec requires truthful surfacing, not a new restore policy.

Decision 6: Preserve truth visibility for TENANT_VIEW users even when restore actions remain unavailable

  • Decision: Quality truth remains visible on backup-set and policy-version surfaces for users who can view tenant backup or version records, even if they cannot create restore runs or use maintenance actions.
  • Rationale: Missing restore permission must not make degraded inputs appear calmer or cleaner. Authorization can suppress mutation, but it must not suppress source-of-truth visibility.
  • Alternatives considered:
    • Couple quality sections to restore permissions. Rejected because it would falsify the operator surface.
    • Rely on disabled restore actions as the quality indicator for lower-privilege users. Rejected because disabled actions are not an adequate explanation of input quality.

Decision 7: Use unknown quality only when existing metadata cannot justify a stronger claim

  • Decision: Emit unknown quality only when the record lacks authoritative metadata for snapshot completeness or assignment-quality interpretation. Absence of an error is not enough to call an item or version full if the record never captured the relevant quality signal.
  • Rationale: Defaulting to unknown too often would hide real degradations, while defaulting to full from silence would overstate confidence. This feature needs a narrow, evidence-based fallback.
  • Alternatives considered:
    • Default all older records to unknown. Rejected because many records already carry usable source metadata.
    • Infer full whenever metadata_only is absent. Rejected because silence is not always proof of completeness.

Decision 8: Extend the existing Pest and Livewire test surface rather than introducing a browser-first harness

  • Decision: Add focused unit coverage for backup-quality derivation and extend existing backup, version, restore-selection, and RBAC feature tests for UI truth. Keep the current Pest and Livewire patterns as the main verification path.
  • Rationale: The affected behavior is server-driven list, detail, and wizard state, which the current test suite already covers well. The repo also already has restore and RBAC tests that should remain authoritative.
  • Alternatives considered:
    • Rely only on manual validation. Rejected because the feature is specifically about preventing subtle trust regressions.
    • Introduce a large browser-only test pack. Rejected because the most important assertions are deterministic server-side state and rendered truth.