# Health Scoring Model

## Overview

Project health uses a **six-factor weighted model**. Scores are only computed when the project has sufficient evidence (backlog work items). Otherwise the project remains in **`initializing`** state.

---

## Initializing state

**When:**

- No sprint exists AND no backlog work items, OR
- No backlog work items (non-terminal projects)

**Returns:**

```json
{
  "status": "initializing",
  "score": null,
  "message": "Start planning work to generate project health metrics.",
  "ready": false
}
```

---

## Weighted components (when ready)

| # | Factor | Weight | Scoring logic |
|---|--------|--------|---------------|
| 1 | Sprint Delivery | **25%** | Active sprint done/total ratio; penalty if sprint overdue; fallback to last completed sprint |
| 2 | Velocity Trend | **15%** | `up`→100, `stable`→85, `down`→45; 75 if no closed sprints |
| 3 | Risks | **20%** | Start 100; -25 critical, -12 high (≥12), -5 other open risks |
| 4 | Dependencies | **15%** | 100 - (blocked_count × 20), min 15 |
| 5 | Milestones | **15%** | 100 - (overdue_count × 25), min 10 |
| 6 | Capacity | **10%** | Team overload + sprint capacity exceeded; min 25 |

### Composite score

```
health_score = round(
  sprint_delivery × 0.25 +
  velocity_trend × 0.15 +
  risks × 0.20 +
  dependencies × 0.15 +
  milestones × 0.15 +
  capacity × 0.10
)
```

---

## Health levels

| Score range | Level | UI label |
|-------------|-------|----------|
| 75 – 100 | `healthy` | Healthy |
| 60 – 74 | `attention` | Needs Attention |
| 0 – 59 | `critical` | At Risk |

---

## Alert eligibility

Notifications require:

1. `score` is not null  
2. `score < 60`  
3. At least one entry in `factors[]`

This prevents alerts on project creation, empty projects, or score-only degradation without evidence.

---

## Factor → human explanation map

| Factor | Executive dashboard message |
|--------|----------------------------|
| `sprint_delivery_behind` | Sprint delivery is behind plan |
| `velocity_declining` | Velocity trend is declining |
| `critical_risk` | Critical open risks present |
| `elevated_risk` | Elevated risk exposure |
| `blocked_dependency` | Blocked dependencies on critical path |
| `overdue_milestone` | One or more milestones are overdue |
| `capacity_overload` | Team capacity overloaded |
| `project_overdue` | Project is past its due date |

---

## Sprint health (separate engine)

Sprint board health is independent but feeds executive attention items and notifications.

| Score | Status |
|-------|--------|
| ≥ 80 | On track (`good`) |
| ≥ 60 | Warning |
| ≥ 40 | At risk |
| < 40 | Critical |

---

## Implementation

Primary class: `App\Modules\Projects\Services\ProjectHealthService`

Tests: `tests/Feature/Projects/ProjectHealthServiceTest.php`
