TenantAtlas/specs/115-baseline-operability-alerts/data-model.md
ahmido fdfb781144 feat(115): baseline operability + alerts (#140)
Implements Spec 115 (Baseline Operability & Alert Integration).

Key changes
- Baseline compare: safe auto-close of stale baseline findings (gated on successful/complete compares)
- Baseline alerts: `baseline_high_drift` + `baseline_compare_failed` with dedupe/cooldown semantics
- Workspace settings: baseline severity mapping + minimum severity threshold + auto-close toggle
- Baseline Compare UX: shared stats layer + landing/widget consistency

Notes
- Livewire v4 / Filament v5 compatible.
- Destructive-like actions require confirmation (no new destructive actions added here).

Tests
- `vendor/bin/sail artisan test --compact tests/Feature/Baselines/ tests/Feature/Alerts/`

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #140
2026-03-01 02:26:47 +00:00

64 lines
2.8 KiB
Markdown

# Data Model — Baseline Operability & Alert Integration (Spec 115)
This spec extends existing models and introduces no new tables.
## Entities
### 1) Finding (existing: `App\Models\Finding`)
Baseline compare findings are a subset of drift findings.
Key fields used/extended by this feature:
- `workspace_id` (derived from tenant)
- `tenant_id`
- `finding_type` = `drift`
- `source` = `baseline.compare` (stable contract)
- `scope_key` = `baseline_profile:{baseline_profile_id}` (stable grouping)
- `fingerprint` (stable identifier; used for idempotent upsert + alert dedupe)
- `status` (lifecycle): `new`, `reopened`, other open states, and terminal states
- `reopened_at`, `resolved_at`, `resolved_reason`
- `severity` (`low|medium|high|critical`)
- `evidence_jsonb` (must include at least `change_type`)
- `current_operation_run_id` (the compare run that most recently observed the finding)
Lifecycle rules for baseline compare findings:
- New fingerprint → create finding with `status=new`.
- Existing finding in terminal state (at least `resolved`) observed again → set `status=reopened`, `reopened_at=now`, clear resolved fields.
- Existing open finding observed again → do not override workflow status.
- Stale open findings (not observed in a fully successful compare) → set `status=resolved`, `resolved_reason=no_longer_drifting`, `resolved_at=now`.
### 2) OperationRun (existing: `App\Models\OperationRun`)
Baseline compare runs are represented as:
- `type = baseline_compare`
- `tenant_id` required (tenant-scoped operation)
- `status/outcome` managed exclusively via `OperationRunService`
- `summary_counts` used for:
- completeness: `processed == total`
- safety: `failed == 0`
Baseline capture runs are represented as:
- `type = baseline_capture`
### 3) WorkspaceSetting (existing: `App\Models\WorkspaceSetting`)
New workspace keys (domain `baseline`):
- `baseline.severity_mapping` (json object)
- Keys MUST be exactly: `missing_policy`, `different_version`, `unexpected_policy`
- Values MUST be one of: `low|medium|high|critical`
- `baseline.alert_min_severity` (string)
- Allowed: `low|medium|high|critical`
- Default: `high`
- `baseline.auto_close_enabled` (bool)
- Default: `true`
Effective value rules:
- Consumers read via `SettingsResolver`, which merges system defaults with workspace overrides.
## Derived/Computed Values
- Baseline finding severity is computed at creation time from `baseline.severity_mapping[change_type]`.
- Baseline alert eligibility is computed at alert-evaluation time from:
- finding `source` + `status` + timestamps vs `windowStart`
- finding `severity` vs `baseline.alert_min_severity`
## Invariants
- `Finding.source = baseline.compare` MUST be stable and queryable.
- Auto-close MUST only execute if the compare run is complete (`processed==total`) and safe (`failed==0`) and `baseline.auto_close_enabled` is true.