TenantAtlas/specs/176-backup-quality-truth/data-model.md
2026-04-07 13:38:16 +02:00

247 lines
12 KiB
Markdown

# 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<string> | 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<int|string> | Captured scope-tag identifiers |
| `scope_tag_names` | array<string> | 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<string> | 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<string> | `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<string> | 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<string> | 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<string> | 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<string> | 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.