# Data Model — Drift Golden Master Cutover (Spec 119) This spec extends existing models and introduces no new tables. ## Entities ### 1) Finding (existing: `App\Models\Finding`) Baseline Compare drift findings are tenant-owned rows in `findings`. Key fields used/extended by this feature: - `workspace_id` (derived from tenant; required) - `tenant_id` (required) - `finding_type = drift` (required) - `source = baseline.compare` (mandatory contract post-cutover) - `scope_key` (baseline compare grouping key; stable across re-runs) - `fingerprint` + `recurrence_key` (stable identity for idempotent upsert and lifecycle) - `severity` (`low|medium|high|critical`) - `status` (lifecycle): `new`, `reopened`, other open states, terminal states - `evidence_fidelity` (string): `content|meta|mixed` - `evidence_jsonb` (JSONB): enriched evidence contract (see below) - `current_operation_run_id` (the Baseline Compare `OperationRun` that observed the finding) - `baseline_operation_run_id` (unused for Baseline Compare drift; legacy run-to-run drift used it) #### Evidence contract (`findings.evidence_jsonb`) Minimum required keys for diff-UX compatibility: - `change_type` (string): `missing_policy|unexpected_policy|different_version` - `policy_type` (string) - `subject_key` (string) - `summary.kind` (string): `policy_snapshot|policy_assignments|policy_scope_tags` - `baseline.policy_version_id` (int|null) - `current.policy_version_id` (int|null) - `baseline.hash` / `current.hash` (string; may be empty for missing/unexpected) - `baseline.provenance` / `current.provenance` (object; fidelity/source/observed_at/observed_operation_run_id) - `fidelity` (string): `content|meta|mixed` - `provenance` (object): `baseline_profile_id`, `baseline_snapshot_id`, `compare_operation_run_id`, and `inventory_sync_run_id` when applicable Invariant: - `different_version` requires both policy version ids to render a detailed diff. - `missing_policy` may render a detailed diff with only `baseline.policy_version_id`. - `unexpected_policy` may render a detailed diff with only `current.policy_version_id`. - If the required policy version reference(s) for the finding’s change type are missing, the UI must treat the finding as “diff unavailable”. ### 2) OperationRun (existing: `App\Models\OperationRun`) Baseline Compare runs: - `type = baseline_compare` - `tenant_id` is required (tenant-scoped operation) - `status/outcome` transitions are service-owned (must go through `OperationRunService`) - `context.baseline_profile_id` and `context.baseline_snapshot_id` identify the compare baseline inputs - `context.baseline_compare.*` contains coverage + evidence gap breakdowns (read-only reporting) Baseline Capture runs: - `type = baseline_capture` - `context.baseline_profile_id` and `context.source_tenant_id` identify the capture inputs - `context.baseline_capture.inventory_sync_run_id` records which completed Inventory Sync bounded subject selection when one existed - `context.baseline_capture.gaps.*` remains the canonical reporting block for snapshot-capture ambiguity or evidence issues Legacy run-to-run drift generation runs: - `type = drift_generate_findings` (no longer created post-cutover; existing rows may remain historical) ### 3) BaselineProfile / BaselineSnapshot / BaselineSnapshotItem (existing) Workspace-owned baseline objects: - Baseline Profile (`baseline_profiles`) defines scope + capture mode and points to `active_snapshot_id`. - Baseline Snapshot (`baseline_snapshots`) is immutable and stores `summary_jsonb`. - Baseline Snapshot Items (`baseline_snapshot_items`) store: - `baseline_hash` (string) - `meta_jsonb.evidence` provenance fields (fidelity/source/observed_at), intentionally without tenant-owned identifiers (e.g., no `policy_version_id`). ### 4) PolicyVersion (existing: `App\Models\PolicyVersion`) Tenant-owned immutable policy snapshots used for: - Content hashing/normalization for Baseline Compare evidence - Rendering diffs in Findings detail view when both baseline/current policy version references exist Relevant fields: - `id` - `tenant_id` - `policy_id` (ties versions to a tenant policy) - `capture_purpose` (e.g., `baseline_capture`, `baseline_compare`) - `operation_run_id` (which run captured it) - `captured_at` - `snapshot`, `assignments`, `scope_tags` (JSON/arrays) ## Derived/Computed Values - `evidence_jsonb.fidelity` should align with (or be derived from) the per-finding `evidence_fidelity` column. - `summary.kind` may be set conservatively (e.g., `policy_snapshot`) when dimension-level detection is not available. ## Invariants - Post-cutover drift findings must be queryable as: `finding_type = drift AND source = baseline.compare`. - Legacy drift findings are deleted by a one-time migration using: `finding_type = drift AND (source IS NULL OR source <> 'baseline.compare')`.