# Server Handoff: TV Power Coordination

## Purpose
Implement server-side MQTT power intent publishing so clients can keep TVs on across adjacent events and power off safely after schedules end.

## Source of Truth
- Shared full plan: TV_POWER_COORDINATION_TASKLIST.md

## Scope (Server Team)
- Scheduler-to-intent mapping
- MQTT publishing semantics (retain, QoS, expiry)
- Conflict handling (group vs client)
- Observability for intent lifecycle

## MQTT Contract (Server Responsibilities)

### Topics
- Primary (per-client): infoscreen/{client_id}/power/intent
- Optional (group-level): infoscreen/groups/{group_id}/power/intent

### Delivery Semantics
- QoS: 1
- retained: true
- Always publish UTC timestamps (ISO 8601 with Z)

### Intent Payload (v1)
```json
{
  "schema_version": "1.0",
  "intent_id": "uuid-or-monotonic-id",
  "issued_at": "2026-03-31T12:00:00Z",
  "expires_at": "2026-03-31T12:10:00Z",
  "target": {
    "client_id": "optional-if-group-topic",
    "group_id": "optional"
  },
  "power": {
    "desired_state": "on",
    "reason": "event_window_active",
    "grace_seconds": 30
  },
  "event_window": {
    "start": "2026-03-31T12:00:00Z",
    "end": "2026-03-31T13:00:00Z"
  }
}
```

## Required Behavior

### Adjacent/Overlapping Events
- Never publish an intermediate off intent when windows are contiguous/overlapping.
- Maintain continuous desired_state=on coverage across adjacent windows.

### Reconnect/Restart
- On scheduler restart, republish effective retained intent.
- On event edits/cancellations, replace retained intent with a fresh intent_id.

### Conflict Policy
- If both group and client intent exist: per-client overrides group.

### Expiry Safety
- expires_at must be set for every intent.
- Server should avoid publishing already-expired intents.

## Implementation Tasks
1. Add scheduler mapping layer that computes effective desired_state per client timeline.
2. Add intent publisher with retained QoS1 delivery.
3. Generate unique intent_id for each semantic transition.
4. Emit issued_at/expires_at and event_window consistently in UTC.
5. Add group-vs-client precedence logic.
6. Add logs/metrics for publish success, retained payload age, and transition count.
7. Add integration tests for adjacent events and reconnect replay.

## Acceptance Criteria
1. Adjacent events do not create OFF gap intents.
2. Fresh client receives retained intent after reconnect and gets correct desired state.
3. Intent payloads are schema-valid, UTC-formatted, and include expiry.
4. Publish logs and metrics allow intent timeline reconstruction.

## Operational Notes
- Keep intent publishing idempotent and deterministic.
- Preserve backward compatibility while clients run in hybrid mode.
