# Data Model: Workspace Recovery Posture Visibility ## Existing Source Truth Models ### TenantBackupHealthAssessment Existing derived tenant-level backup-input assessment from `TenantBackupHealthResolver`. | Field | Type | Meaning | |------|------|---------| | `tenantId` | integer | Tenant scope for the assessment | | `posture` | string | `absent`, `stale`, `degraded`, or `healthy` backup-input posture | | `primaryReason` | string nullable | Why the current backup posture is not calmly healthy | | `headline` | string | Operator-facing headline for the backup truth | | `supportingMessage` | string nullable | Supporting backup-health explanation | | `healthyClaimAllowed` | boolean | Whether a positive backup-health statement is allowed | | `primaryActionTarget` | action target nullable | Canonical tenant-local backup follow-up target | | `positiveClaimBoundary` | string | Canonical statement that backup health reflects backup inputs only and does not prove restore success | ### Dashboard Recovery Evidence Projection Existing tenant-level recovery-evidence projection from `RestoreSafetyResolver::dashboardRecoveryEvidence()`. | Field | Type | Meaning | |------|------|---------| | `backup_posture` | string | Current tenant backup posture carried through for bounded recovery copy | | `overview_state` | string | `unvalidated`, `weakened`, or `no_recent_issues_visible` | | `headline` | string | Operator-facing headline for tenant recovery evidence | | `summary` | string | Supporting explanation of the current evidence state | | `claim_boundary` | string | Text that prevents the summary from becoming a recovery-proof claim | | `latest_relevant_restore_run_id` | integer nullable | Most relevant executed restore run for continuity | | `latest_relevant_attention_state` | string nullable | Existing `RestoreResultAttention` state for the relevant run | | `reason` | string | Reason key such as `no_history`, `failed`, `partial`, `completed_with_follow_up`, or `no_recent_issues_visible` | ### Existing Workspace Overview Output Contracts `WorkspaceOverviewBuilder` already emits derived `summary_metrics`, `attention_items`, and `calmness` for `/admin`. | Projection | Existing role | |-----------|---------------| | `summary_metrics` | Workspace scan strip for scope, governance, activity, and alerts | | `attention_items` | Bounded, prioritized tenant- or workspace-bound triage list | | `calmness` | Honest empty-state and “nothing urgent” contract for the visible workspace slice | ## New Derived Projections For Spec 185 Spec 185 adds **derived** workspace projections only. No migration or persisted model is introduced. ### VisibleWorkspaceTenantRecoveryContext Per-visible-tenant context carried inside `WorkspaceOverviewBuilder` before widget rendering. | Field | Type | Persisted | Meaning | |------|------|-----------|---------| | `tenantId` | integer | no | Visible tenant identity | | `tenantLabel` | string | no | Tenant name shown on workspace surfaces | | `tenantRouteKey` | string | no | Tenant route identity for drillthrough | | `backupHealthPosture` | string | no | Existing tenant backup-health posture | | `backupHealthReason` | string nullable | no | Existing tenant backup-health primary reason | | `backupHealthHeadline` | string | no | Backup-health headline for workspace reason text | | `backupHealthSummary` | string nullable | no | Supporting backup-health explanation | | `backupHealthBoundary` | string | no | Backup-input claim boundary inherited from tenant truth | | `recoveryEvidenceState` | string | no | Existing tenant recovery-evidence overview state | | `recoveryEvidenceReason` | string | no | Existing tenant recovery-evidence reason key | | `recoveryEvidenceHeadline` | string | no | Recovery-evidence headline for workspace reason text | | `recoveryEvidenceSummary` | string | no | Supporting recovery-evidence explanation | | `recoveryEvidenceBoundary` | string | no | Recovery claim boundary inherited from tenant truth | | `latestRelevantRestoreRunId` | integer nullable | no | Latest relevant restore run for continuity if needed later | | `hasBackupAttention` | boolean | no | True when backup posture is `absent`, `stale`, or `degraded` | | `hasRecoveryAttention` | boolean | no | True when recovery evidence is `weakened` or `unvalidated` | | `workspacePrimaryDestination` | destination | no | Primary tenant-dashboard drillthrough payload | ### WorkspaceRecoverySummaryMetric Derived stat-strip metric for cross-tenant recovery and backup visibility. | Field | Type | Persisted | Meaning | |------|------|-----------|---------| | `key` | string | no | `backup_attention_tenants` or `recovery_attention_tenants` | | `label` | string | no | Operator-facing metric label | | `value` | integer | no | Count of visible tenants needing follow-up in that family | | `category` | string | no | Distinct metric category such as `backup_health` or `recovery_evidence` | | `description` | string | no | Bounded explanation of what the count means | | `destination` | destination nullable | no | `tenant_dashboard` when exactly one visible tenant is affected, otherwise `choose_tenant` | ### WorkspaceRecoveryAttentionItem Derived workspace triage item for one visible tenant backup or recovery weakness. | Field | Type | Persisted | Meaning | |------|------|-----------|---------| | `key` | string | no | Stable item key such as `tenant_backup_absent` or `tenant_recovery_weakened` | | `family` | string | no | `backup_health` or `recovery_evidence` | | `urgency` | string | no | Relative severity tier used inside workspace ordering | | `tenant_id` | integer | no | Visible tenant identity | | `tenant_label` | string | no | Visible tenant label | | `title` | string | no | Bounded item title | | `body` | string | no | Short reason text explaining the weakness | | `supporting_message` | string nullable | no | Optional claim boundary or supplemental follow-up explanation | | `badge` | string | no | Family badge label | | `badge_color` | string | no | Existing shared tone mapping | | `reason_context` | object | no | `{ family, state, reason }` payload for tests and future continuity | | `destination` | destination | no | Primary tenant-dashboard drillthrough or safe disabled state | ### WorkspaceRecoveryCalmnessContract Derived calmness state with explicit domain coverage. | Field | Type | Persisted | Meaning | |------|------|-----------|---------| | `is_calm` | boolean | no | True only when covered domains are quiet for visible tenants | | `checked_domains` | list | no | Must now include `backup_health` and `recovery_evidence` | | `title` | string | no | Calm or non-calm summary title | | `body` | string | no | Bounded explanation that names the covered domains | | `next_action` | destination | no | Tenant dashboard, choose-tenant, switch-workspace, or existing workspace action target | ## Derived State Rules ### Backup Attention Eligibility | Backup posture | Workspace backup attention? | Notes | |---------------|-----------------------------|-------| | `absent` | yes | Highest backup-health severity | | `stale` | yes | Middle backup-health severity | | `degraded` | yes | Lowest backup-health severity that still needs attention | | `healthy` | no | Schedule follow-up may still exist at tenant level, but Spec 185 counts only non-healthy backup posture for workspace backup attention | ### Recovery Attention Eligibility | Recovery state | Workspace recovery attention? | Notes | |---------------|-------------------------------|-------| | `weakened` | yes | Highest recovery-evidence severity | | `unvalidated` | yes | Lower than `weakened`, but still attention-worthy | | `no_recent_issues_visible` | no | Calm recovery evidence still carries a non-proof boundary and must not become a problem item | ### Attention Ordering Consequences | Derived family | Internal order | |---------------|----------------| | `backup_health` | `absent` → `stale` → `degraded` | | `recovery_evidence` | `weakened` → `unvalidated` | Cross-family ordering remains integrated into the existing workspace priority model. The new families must rank above activity-only operations and alerts while preserving the current governance-first intent of the queue. ## Invariants - All new workspace recovery and backup projections are derived at render time and are not persisted. - All counts and items are computed only from visible tenants in the active workspace scope. - Backup health and recovery evidence remain separate fields and separate families in every derived workspace structure. - Any calm workspace statement is bounded to visible tenants and covered domains only. - The tenant dashboard is the canonical destination for new workspace backup or recovery items; deeper tenant backup-set or restore-run pages remain secondary follow-up surfaces. - No derived workspace projection may claim recovery proof or restore guarantee. ## Relationships | Source | Relationship | Target | Use in this spec | |------|--------------|--------|------------------| | Tenant | has one derived | `TenantBackupHealthAssessment` | Source of backup posture for workspace aggregation | | Tenant | has one derived | dashboard recovery evidence projection | Source of recovery-evidence state for workspace aggregation | | Workspace overview | derives many | `VisibleWorkspaceTenantRecoveryContext` | Per-tenant visible context used by stats, attention, and calmness | | Workspace overview | derives many | `WorkspaceRecoverySummaryMetric` | Separate backup and recovery portfolio counts | | Workspace overview | derives many | `WorkspaceRecoveryAttentionItem` | Prioritized tenant-level triage items | | Workspace overview | derives one | `WorkspaceRecoveryCalmnessContract` | Honest calmness and checked-domain statement | ## No Persistence Changes Spec 185 introduces no new table, no new column, no new materialized view, no new cache artifact, and no migration. All new structures are transient builder- or widget-level projections over existing tenant truth.