# Health Assessment API

Module: `citadel_operator.k3s.health`

## HealthState

```python
class HealthState(Enum):
    HEALTHY = "healthy"
    WARNING = "warning"
    ERROR = "error"
    TERMINAL = "terminal"
```

### State Determination

| State | Condition |
|-------|-----------|
| TERMINAL | Not ready AND unschedulable |
| ERROR | Not ready (any), OR 2+ pressure conditions, OR failed custom probes |
| WARNING | 1 pressure condition, OR age > 80% of max_age_hours |
| HEALTHY | Default |

States are evaluated top-down; the first match wins.

## NodeCondition

Frozen dataclass representing a single evaluated condition.

```python
@dataclass(frozen=True)
class NodeCondition:
    condition_type: str    # e.g., "Ready", "DiskPressure"
    status: str            # "True", "False", "Unknown"
    healthy: bool          # Whether this condition is healthy
    message: str           # Human-readable description
```

## NodeHealthReport

Frozen dataclass representing a comprehensive health assessment.

```python
@dataclass(frozen=True)
class NodeHealthReport:
    node_name: str
    state: HealthState
    conditions: list[NodeCondition]
    age_hours: float
    max_age_hours: float
    age_exceeded: bool
    custom_probe_report: CustomProbeReport | None = None
    entity_health: list[EntityHealth] | None = None
```

### Properties

| Property | Type | Description |
|----------|------|-------------|
| `needs_termination` | `bool` | Age exceeded OR terminal OR failed custom probes |
| `has_failed_custom_probes` | `bool` | Any custom probes exceeded failure threshold |
| `failed_custom_probes` | `list[ProbeResult]` | List of failed custom probe results |
| `unhealthy_entities` | `list[EntityHealth]` | Entities with health ratio < 1.0 |

## HealthChecker

### Constructor

```python
HealthChecker(max_age_hours: float = 48.0)
```

### Methods

| Method | Signature | Description |
|--------|-----------|-------------|
| `check` | `(node, custom_probe_report=None, entity_health=None) -> NodeHealthReport` | Single node assessment |
| `check_all` | `(nodes, custom_probe_reports=None, entity_health_by_node=None) -> list[NodeHealthReport]` | Batch assessment |

### Usage

```python
from citadel_operator import NodeManager, HealthChecker

nm = NodeManager()
hc = HealthChecker(max_age_hours=48)

nodes = nm.list_nodes()
reports = hc.check_all(nodes)

for report in reports:
    print(f"{report.node_name}: {report.state.value}")
    if report.needs_termination:
        print(f"  -> Needs termination (age_exceeded={report.age_exceeded})")
    for condition in report.conditions:
        if not condition.healthy:
            print(f"  -> {condition.condition_type}: {condition.message}")
```
