# 2026-03-22 — Data model refactor: structured issues + metric alerts

## What changed

### Issue model restructured
- `Issue.description` split into structured fields: `source` (where: LAN/ISP/network), `name` (short problem name), `cause` (probable cause)
- Dropped `Issue.message` property — notification now uses `name` directly
- Dropped `Issue.value` and `IssueRecord.last_value` — metric numbers only live in the Details section now
- `IssueRecord` updated to carry `source`, `cause`, `name`

### New MetricAlert model
- `MetricAlert(host, metric, severity)` flags specific probe metrics as out of range
- `CheckResult` now carries `alerts` alongside `issues`
- `diagnosis.analyze()` returns `(issues, alerts)` tuple
- This fills the gap where probe results didn't know if their values were problematic — that knowledge now flows from diagnosis to the UI

### UI changes
- "Why?" section shows structured columns: `source | name (cause) | (count, timing)`
- Metric values (value field) removed from "Why?" — they belong in Details
- Details section highlights bad values in red/yellow using MetricAlerts
- Internet details stay as a single aggregate line (not per-target)

### Notifications
- Only fire in watch mode (>1 check), not on single-shot runs

## Open questions
- Should `source` be an enum instead of a free string?
- May want DNS and VPN as sources eventually — not needed yet
