# Data Model: Backup Quality Truth Surfaces ## Overview This feature does not add or change a top-level persisted domain entity. It introduces a tighter derived backup-quality model around the existing tenant-owned backup, version, and restore-selection surfaces. The central design task is to make existing backup truth visible without changing: - `BackupSet`, `BackupItem`, or `PolicyVersion` ownership - existing backup or restore route identity - existing restore-safety, preview, and execution authority - existing audit and RBAC responsibilities - the no-new-table boundary of this feature ## Existing Persistent Entities ### 1. BackupSet - Purpose: Tenant-owned backup collection that records lifecycle state and groups captured backup items. - Existing persistent fields used by this feature: - `id` - `tenant_id` - `name` - `status` - `item_count` - `metadata` - `created_by` - `completed_at` - `created_at` - Existing relationships used by this feature: - `tenant` - `items` - `restoreRuns` #### Proposed nested metadata additions None. Backup-set quality is derived from related backup items and existing set facts. No new backup-set status or metadata field is required. ### 2. BackupItem - Purpose: Tenant-owned captured recovery input for one backed-up policy or foundation record. - Existing persistent fields used by this feature: - `id` - `tenant_id` - `backup_set_id` - `policy_id` - `policy_version_id` - `policy_identifier` - `policy_type` - `platform` - `payload` - `assignments` - `metadata` - `captured_at` - Existing relationships used by this feature: - `tenant` - `backupSet` - `policy` - `policyVersion` #### Existing metadata signals used by this feature | Key | Type | Meaning | |---|---|---| | `source` | string or null | Primary source marker; may be `metadata_only` | | `snapshot_source` | string or null | Copied source marker from a linked policy version when a backup item is created from a version | | `warnings` | array | Warning messages; may include metadata-only fallback wording | | `assignments_fetch_failed` | boolean | Assignment capture failed for this item | | `assignment_capture_reason` | string or null | Informational reason such as `separate_role_assignments`; not all reasons are degradations | | `has_orphaned_assignments` | boolean | One or more resolved assignment targets were orphaned | | `assignment_count` | integer or null | Captured assignment count | | `scope_tag_ids` | array | Captured scope-tag identifiers | | `scope_tag_names` | array | Captured scope-tag names | | `integrity_warning` | string or null | Existing integrity or redaction warning copied into the backup item | | `protected_paths_count` | integer or null | Count of protected or redacted paths copied from the policy version context | ### 3. PolicyVersion - Purpose: Tenant-owned immutable version record for a policy snapshot. - Existing persistent fields used by this feature: - `id` - `tenant_id` - `policy_id` - `version_number` - `snapshot` - `metadata` - `assignments` - `scope_tags` - `secret_fingerprints` - `redaction_version` - `captured_at` - `capture_purpose` - Existing relationships used by this feature: - `tenant` - `policy` - `operationRun` #### Existing metadata signals used by this feature | Key | Type | Meaning | |---|---|---| | `source` | string or null | Snapshot source marker; `metadata_only` is the primary degraded completeness signal | | `warnings` | array | Snapshot warnings; may include metadata-only fallback language | | `assignments_fetch_failed` | boolean | Assignment capture failed during version capture | | `assignments_fetch_error` | string or null | Human-readable assignment capture error | | `assignments_fetch_error_code` | int or string or null | Technical assignment capture error code | | `has_orphaned_assignments` | boolean | One or more captured assignment targets were orphaned | | `capture_source` | string or null | Existing capture context such as `version_capture` | #### Related persisted integrity context used by this feature | Field | Type | Meaning | |---|---|---| | `secret_fingerprints` | array | Existing redaction context used to expose integrity notes on version-derived restore inputs | | `redaction_version` | integer | Existing redaction version for operator diagnostics | | `scope_tags` | array | Existing scope-tag context surfaced alongside quality truth where useful | ### 4. Restore selection context - Purpose: Existing wizard state that lets operators choose a backup set and optional backup-item subset before running risk checks. - Existing state used by this feature: - `backup_set_id` - `scope_mode` - `backup_item_ids` - `group_mapping` - `is_dry_run` No new persisted restore-selection state is planned. This feature only enriches the current rendered option models. ## Derived Models ### 1. SnapshotCompletenessFact Derived completeness truth shared by backup items and policy versions. | Field | Type | Source | Notes | |---|---|---|---| | `mode` | string | metadata-derived | `full`, `metadata_only`, or `unknown` | | `sourceSignal` | string or null | `metadata.source` or `metadata.snapshot_source` | Authoritative direct signal when present | | `warningEvidence` | list | `metadata.warnings` | Secondary fallback signal | | `badgeState` | string | derived | Routes to the existing `PolicySnapshotModeBadge` state | Rules: - `metadata_only` when `source` or `snapshot_source` equals `metadata_only`, or when warning evidence clearly states metadata-only capture. - `full` only when there is no metadata-only evidence and the record contains enough captured payload context to justify a complete-snapshot claim. - `unknown` only when existing metadata cannot prove either `full` or `metadata_only`. ### 2. AssignmentCaptureFact Derived assignment-quality truth for backup items and policy versions. | Field | Type | Source | Notes | |---|---|---|---| | `fetchFailed` | boolean | `assignments_fetch_failed` | Primary degraded assignment signal | | `captureReason` | string or null | `assignment_capture_reason` | Informational reason; not always degraded | | `orphanedAssignments` | boolean | `has_orphaned_assignments` | Secondary degraded signal | | `assignmentCount` | integer or null | `assignment_count` or `assignments` length | Informational support data | | `issuePresent` | boolean | derived | True when fetch failed or orphaned targets exist | Rules: - `assignment_capture_reason = separate_role_assignments` is informative and must not be misread as a failure on its own. - `fetchFailed = true` is a degraded quality signal. - `orphanedAssignments = true` is a degraded quality signal even if fetch succeeded. ### 3. BackupItemQualityFact Default item-level backup-quality model for backup items. | Field | Type | Source | Notes | |---|---|---|---| | `backupItemId` | integer | record id | Identity | | `snapshotCompleteness` | `SnapshotCompletenessFact` | derived | Primary completeness truth | | `assignmentCapture` | `AssignmentCaptureFact` | derived | Assignment quality truth | | `integrityWarning` | string or null | `metadata.integrity_warning` | Existing integrity signal | | `degradationFamilies` | list | derived | Examples: `metadata_only`, `assignment_capture_issue`, `orphaned_assignments`, `integrity_warning`, `unknown_quality` | | `hasDegradations` | boolean | derived | True when one or more degradation families apply | | `summaryMessage` | string | derived | Concise operator-facing truth | | `nextAction` | string | derived | Primary next step such as inspect detail or continue with caution | ### 4. BackupSetQualitySummary Aggregate backup-quality truth for one backup set. | Field | Type | Source | Notes | |---|---|---|---| | `backupSetId` | integer | record id | Identity | | `totalItems` | integer | `item_count` or related count | Informational total | | `degradedItemCount` | integer | aggregated item facts | Number of degraded items | | `metadataOnlyCount` | integer | aggregated item facts | Count of metadata-only items | | `assignmentIssueCount` | integer | aggregated item facts | Count of assignment capture failures | | `orphanedAssignmentCount` | integer | aggregated item facts | Count of orphaned-assignment signals | | `integrityWarningCount` | integer | aggregated item facts | Count of integrity warnings carried into backup items | | `unknownQualityCount` | integer | aggregated item facts | Count of items whose quality is truly unknown | | `degradationFamilies` | list | derived | Set-level union of degradation families | | `summaryMessage` | string | derived | Compact summary for list and detail | | `nextAction` | string | derived | Open detail, inspect degraded items, prefer stronger version, or continue with caution | | `positiveClaimBoundary` | string | derived | Explains that quality does not equal safe restore or tenant recoverability | Rules: - Aggregate counts are computed from related `BackupItemQualityFact` values, never from `BackupSet.status`. - `completed but degraded` remains a display combination of lifecycle plus quality summary, not a new persisted backup-set status. ### 5. PolicyVersionQualityFact Version-level backup-quality truth for policy versions. | Field | Type | Source | Notes | |---|---|---|---| | `policyVersionId` | integer | record id | Identity | | `snapshotCompleteness` | `SnapshotCompletenessFact` | derived from version metadata | Primary completeness truth | | `assignmentCapture` | `AssignmentCaptureFact` | derived from version metadata and assignments | Assignment quality truth | | `integrityWarning` | string or null | derived from existing redaction or integrity context | Existing warning already present in current restore and version flows | | `degradationFamilies` | list | derived | Same family as backup items where applicable | | `hasDegradations` | boolean | derived | True when one or more degradation families apply | | `summaryMessage` | string | derived | Concise operator-facing truth | | `nextAction` | string | derived | Prefer stronger version, inspect raw settings, or continue to restore with caution | ### 6. RestoreSelectionQualityHint Selection-stage quality model for restore wizard step 1 and step 2. | Field | Type | Source | Notes | |---|---|---|---| | `targetType` | string | derived | `backup_set` or `backup_item` | | `targetId` | integer | selected record id | Identity | | `summaryMessage` | string | derived | Early warning before risk checks | | `degradationFamilies` | list | derived | Carries through set-level or item-level truth | | `nextAction` | string | derived | Inspect detail or continue with caution | | `positiveClaimBoundary` | string | derived | Explicitly states that input quality is not restore safety | Rules: - Step 1 uses `BackupSetQualitySummary` facts. - Step 2 uses `BackupItemQualityFact` facts. - Neither step may claim `safe to restore`, `restore ready`, or `tenant recoverable`. ## Validation Rules - Never derive backup quality from `BackupSet.status`, `PolicyVersion` action availability, or restore gating alone. - `assignments_fetch_failed` and `has_orphaned_assignments` are distinct signals and must be surfaced separately where the UI can support it. - `assignment_capture_reason` is explanatory metadata, not automatically a degraded state. - `unknown quality` is permitted only when current metadata cannot justify `full` or `metadata_only` and cannot justify an assignment-quality claim. - `TENANT_VIEW` visibility for backup-quality truth must remain independent from `TENANT_MANAGE` restore capability. - Restore selection hints must explicitly preserve the claim boundary that backup quality is not restore safety.