6.5 KiB
TV Power Coordination Canary Validation Checklist (Phase 1)
Manual verification checklist for Phase-1 server-side group-level power-intent publishing before production rollout.
Preconditions
- Scheduler running with
POWER_INTENT_PUBLISH_ENABLED=true - One canary group selected for testing (example: group_id=1)
- Mosquitto broker running and accessible
- Database with seeded test data (canary group with events)
Validation Scenarios
1. Baseline Payload Structure
Goal: Retained topic shows correct Phase-1 contract.
Instructions:
- Subscribe to
infoscreen/groups/1/power/intent(canary group, QoS 1) - Verify received payload contains:
schema_version: "v1"group_id: 1desired_state: "on"or"off"(string)reason: "active_event"or"no_active_event"(string)intent_id: "<uuid>"(not empty, valid UUID v4 format)issued_at: "2026-03-31T14:22:15Z"(ISO 8601 with Z suffix)expires_at: "2026-03-31T14:24:00Z"(ISO 8601 with Z suffix, always > issued_at)poll_interval_sec: 30(integer, matches scheduler poll interval)
Pass criteria: All fields present, correct types and formats, no extra/malformed fields.
2. Event Start Transition
Goal: ON intent published immediately when event becomes active.
Instructions:
- Create an event for canary group starting 2 minutes from now
- Wait for event start time
- Check retained topic immediately after event start
- Verify
desired_state: "on"andreason: "active_event" - Note the
intent_idvalue
Pass criteria:
desired_state: "on"appears within 30 seconds of event start- No OFF in between (if a prior OFF existed)
3. Event End Transition
Goal: OFF intent published when last active event ends.
Instructions:
- In setup from Scenario 2, wait for the event to end (< 5 min duration)
- Check retained topic after end time
- Verify
desired_state: "off"andreason: "no_active_event"
Pass criteria:
desired_state: "off"appears within 30 seconds of event end- New
intent_idgenerated (different from Scenario 2)
4. Adjacent Events (No OFF Blip)
Goal: When one event ends and next starts immediately after, no OFF is published.
Instructions:
- Create two consecutive events for canary group, each 3 minutes:
- Event A: 14:00-14:03
- Event B: 14:03-14:06
- Watch retained topic through both event boundaries
- Capture all
desired_statechanges
Pass criteria:
desired_state: "on"throughout both events- No OFF at 14:03 (boundary between them)
- One or two transitions total (transition at A start only, or at A start + semantic change reasons)
5. Heartbeat Republish (Unchanged Intent)
Goal: Intent republishes each poll cycle with same intent_id if state unchanged.
Instructions:
- Create a long-duration event (15+ minutes) for canary group
- Subscribe to power intent topic
- Capture timestamps and intent_ids for 3 consecutive poll cycles (90 seconds with default 30s polls)
- Verify:
- Payload received at T, T+30s, T+60s
- Same
intent_idacross all three - Different
issued_attimestamps (should increment by ~30s)
Pass criteria:
- At least 3 payloads received within ~90 seconds
- Same
intent_idfor all - Each
issued_atis later than previous - Each
expires_atis 90 seconds after itsissued_at
6. Scheduler Restart (Immediate Republish)
Goal: On scheduler process start, immediate published active intent.
Instructions:
- Create and start an event for canary group (duration ≥ 5 minutes)
- Wait for event to be active
- Kill and restart scheduler process
- Check retained topic within 5 seconds after restart
- Verify
desired_state: "on"andreason: "active_event"
Pass criteria:
- Correct ON intent retained within 5 seconds of restart
- No OFF published during restart/reconnect
7. Broker Reconnection (Retained Recovery)
Goal: On MQTT reconnect, scheduler republishes cached intents.
Instructions:
- Create and start an event for canary group
- Subscribe to power intent topic
- Note the current
intent_idand payload - Restart Mosquitto broker (simulates network interruption)
- Verify retained topic is immediately republished after reconnect
Pass criteria:
- Correct ON intent reappears on retained topic within 5 seconds of broker restart
- Same
intent_id(no new transition UUID) - Publish metrics show
retained_republish_totalincremented
8. Feature Flag Disable
Goal: No power-intent publishes when feature disabled.
Instructions:
- Set
POWER_INTENT_PUBLISH_ENABLED=falsein scheduler env - Restart scheduler
- Create and start a new event for canary group
- Subscribe to power intent topic
- Wait 90 seconds
Pass criteria:
- No messages on
infoscreen/groups/1/power/intent - Scheduler logs show no
event=power_intent_publish*lines
9. Scheduler Logs Inspection
Goal: Logs contain structured fields for observability.
Instructions:
- Run canary with one active event
- Collect scheduler logs for 60 seconds
- Filter for
event=power_intent_publishlines
Pass criteria:
- Each log line contains:
group_id,desired_state,reason,intent_id,issued_at,expires_at,transition_publish,heartbeat_publish,topic,qos,retained - No malformed JSON in payloads
- Error logs (if any) are specific and actionable
10. Expiry Validation
Goal: Payloads never published with expires_at <= issued_at.
Instructions:
- Capture power-intent payloads for 120+ seconds
- Parse
issued_atandexpires_atfor each - Verify
expires_at > issued_atfor all
Pass criteria:
- All 100% of payloads have valid expiry window
- Typical delta is 90 seconds (min expiry)
Summary Report Template
After running all scenarios, capture:
Canary Validation Report
Date: [date]
Scheduler version: [git commit hash]
Test group ID: [id]
Environment: [dev/test/prod]
Scenario Results:
1. Baseline Payload: ✓/✗ [notes]
2. Event Start: ✓/✗ [notes]
3. Event End: ✓/✗ [notes]
4. Adjacent Events: ✓/✗ [notes]
5. Heartbeat Republish: ✓/✗ [notes]
6. Restart: ✓/✗ [notes]
7. Broker Reconnect: ✓/✗ [notes]
8. Feature Flag: ✓/✗ [notes]
9. Logs: ✓/✗ [notes]
10. Expiry Validation: ✓/✗ [notes]
Overall: [Ready for production / Blockers found]
Issues: [list if any]
Rollout Gate
Power-intent Phase 1 is ready for production rollout only when:
- All 10 scenarios pass
- Zero unintended OFF between adjacent events
- All log fields present and correct
- Feature flag default remains
false - Transition latency <= 30 seconds nominal case