# TV Power Coordination Task List (Server + Client)

## Goal
Prevent unintended TV power-off during adjacent events while enabling coordinated, server-driven power intent via MQTT with robust client-side fallback.

## Scope
- Server publishes explicit TV power intent and event-window context.
- Client executes HDMI-CEC power actions with timer-safe behavior.
- Client falls back to local schedule/end-time logic if server intent is missing or stale.
- Existing event playback behavior remains backward compatible.

## Ownership Proposal
- Server team: Scheduler integration, power-intent publisher, reliability semantics.
- Client team: MQTT handler, state machine, CEC execution, fallback and observability.

## Server PR-1 Pointer
- For the strict, agreed server-first implementation path, use:
  - `TV_POWER_SERVER_PR1_IMPLEMENTATION_CHECKLIST.md`
- Treat that checklist as the execution source of truth for Phase 1.

---

## 1. MQTT Contract (Shared Spec)

Phase-1 scope note:
- Group-level power intent is the only active server contract in Phase 1.
- Per-client power intent and client power state topics are deferred to Phase 2.

### 1.1 Topics
- Command/intent topic (retained):
  - infoscreen/groups/{group_id}/power/intent

Phase-2 (deferred):
- Optional per-client command/intent topic (retained):
  - infoscreen/{client_id}/power/intent
- Client state/ack topic:
  - infoscreen/{client_id}/power/state

### 1.2 QoS and retain
- intent topics: QoS 1, retained=true
- state topic: QoS 0 or 1 (recommend QoS 0 initially), retained=false (Phase 2)

### 1.3 Intent payload schema (v1)
```json
{
  "schema_version": "1.0",
  "intent_id": "uuid-or-monotonic-id",
  "group_id": 12,
  "desired_state": "on",
  "reason": "active_event",
  "issued_at": "2026-03-31T12:00:00Z",
  "expires_at": "2026-03-31T12:01:30Z",
  "poll_interval_sec": 15,
  "event_window_start": "2026-03-31T12:00:00Z",
  "event_window_end": "2026-03-31T13:00:00Z",
  "source": "scheduler"
}
```

### 1.4 State payload schema (client -> server)
Phase-2 (deferred).

```json
{
  "schema_version": "1.0",
  "intent_id": "last-applied-intent-id",
  "client_id": "...",
  "reported_at": "2026-03-31T12:00:01Z",
  "power": {
    "applied_state": "on",
    "source": "mqtt_intent|local_fallback",
    "result": "ok|skipped|error",
    "detail": "free text"
  }
}
```

### 1.5 Idempotency and ordering rules
- Client applies only newest valid intent by issued_at then intent_id tie-break.
- Duplicate intent_id must be ignored after first successful apply.
- Expired intents must not trigger new actions.
- Retained intent must be immediately usable after client reconnect.

### 1.6 Safety rules
- desired_state=on cancels any pending delayed-off timer before action.
- desired_state=off may schedule delayed-off, never immediate off during an active event window.
- If payload is malformed, client logs and ignores it.

---

## 2. Server Team Task List

### 2.1 Contract + scheduler mapping
- Finalize field names and UTC timestamp format with client team.
- Define when scheduler emits on/off intents for adjacent/overlapping events.
- Ensure contiguous events produce uninterrupted desired_state=on coverage.

### 2.2 Publisher implementation
- Add publisher for infoscreen/groups/{group_id}/power/intent.
- Support retained messages and QoS 1.
- Include expires_at based on scheduler poll interval (`max(3 x poll, 90s)`).
- Emit new intent_id only for semantic state transitions.

### 2.3 Reconnect and replay behavior
- On scheduler restart, republish current effective intent as retained.
- On event edits/cancellations, publish replacement retained intent.

### 2.4 Conflict policy
- Phase 1: not applicable (group-only intent).
- Phase 2: define precedence when both group and per-client intents exist.
- Recommended for Phase 2: per-client overrides group intent.

### 2.5 Monitoring and diagnostics
- Record publish attempts, broker ack results, and active retained payload.
- Add operational dashboard panels for intent age and last transition.

### 2.6 Server acceptance criteria
- Adjacent event windows do not produce off intent between events.
- Reconnect test: fresh client receives retained intent and powers correctly.
- Expired intent is never acted on by a conforming client.

---

## 3. Client Team Task List

### 3.1 MQTT subscription + parsing
- Phase 1: Subscribe to infoscreen/groups/{group_id}/power/intent.
- Phase 2 (optional): Subscribe to infoscreen/{client_id}/power/intent for per-device overrides.
- Parse schema_version=1.0 payload with strict validation.

### 3.2 Power state controller integration
- Add power-intent handler in display manager path that owns HDMI-CEC decisions.
- On desired_state=on:
  - cancel delayed-off timer
  - call CEC on only if needed
- On desired_state=off:
  - schedule delayed off using configured grace_seconds (or local default)
  - re-check active event before executing off

### 3.3 Fallback behavior (critical)
- If MQTT unreachable, intent missing, invalid, or expired:
  - fall back to existing local event-time logic
  - use event end as off trigger with existing delayed-off safety
- If local logic sees active event, enforce cancel of pending off timer.

### 3.4 Adjacent-event race hardening
- Guarantee pending off timer is canceled on any newly active event.
- Ensure event switch path never requests off while next event is active.
- Add explicit logging for timer create/cancel/fire with reason and event_id.

### 3.5 State publishing
- Publish apply results to infoscreen/{client_id}/power/state.
- Include source=mqtt_intent or local_fallback.
- Include last intent_id and result details for troubleshooting.

### 3.6 Config flags
- Add feature toggle:
  - POWER_CONTROL_MODE=local|mqtt|hybrid (recommend default: hybrid)
- hybrid behavior:
  - prefer valid mqtt intent
  - automatically fall back to local logic

### 3.7 Client acceptance criteria
- Adjacent events: no unintended off between two active windows.
- Broker outage during event: TV remains on via local fallback.
- Broker recovery: retained intent reconciles state without oscillation.
- Duplicate/old intents do not cause repeated CEC toggles.

---

## 4. Integration Test Matrix (Joint)

## 4.1 Happy paths
- Single event start -> on intent -> TV on.
- Event end -> off intent -> delayed off -> TV off.
- Adjacent events (end==start or small gap) -> uninterrupted TV on.

## 4.2 Failure paths
- Broker down before event start.
- Broker down during active event.
- Malformed retained intent at reconnect.
- Delayed off armed, then new event starts before timer fires.

## 4.3 Consistency checks
- Client state topic reflects actual applied source and result.
- Logs include intent_id correlation across server and client.

---

## 5. Rollout Plan

### Phase 1: Contract and feature flags
- Freeze schema and topic naming for group-only intent.
- Ship client support behind POWER_CONTROL_MODE=hybrid.

### Phase 2: Server publisher rollout
- Enable publishing for test group only.
- Verify retained and reconnect behavior.

### Phase 3: Production enablement
- Enable hybrid mode fleet-wide.
- Observe for 1 week: off-between-adjacent-events incidents must be zero.

### Phase 4: Optional tightening
- If metrics are stable, evaluate mqtt-first policy while retaining local safety fallback.

---

## 6. Definition of Done
- Shared MQTT contract approved by both teams.
- Server and client implementations merged with tests.
- Adjacent-event regression test added and passing.
- Operational runbook updated (topics, payloads, fallback behavior, troubleshooting).
- Production monitoring confirms no unintended mid-schedule TV power-off.
