# Specification: Full Review — Critical Fixes

**Track ID:** review-critical_20260318
**Type:** Refactor
**Created:** 2026-03-18
**Status:** Draft

## Summary

Address all Critical (P0) findings and small-effort High (P1) findings from the comprehensive code review. These are quick wins with high correctness and safety impact — CI release gates, code bugs, protocol violations, and asyncio anti-patterns.

## Context

The comprehensive code review identified 6 Critical and 15 High findings across code quality, CI/CD, architecture, and best practices. This track covers the subset that can be fixed with small effort: single-file changes, one-line fixes, import corrections, and CI YAML edits.

## Acceptance Criteria

- [ ] CI release gate requires `test` matrix to pass (not skipped) before publishing to PyPI
- [ ] CI release gate requires `generated-files` check to pass before publishing to PyPI
- [ ] `multizone.py` duplicated state update block removed (single update per call)
- [ ] `MultiZoneEffect.direction` setter produces exactly 8 parameters (not 9)
- [ ] `animator.py` uses `allocate_source()` instead of `random.randint(1, ...)`
- [ ] `discover_mdns()` return type corrected to `AsyncGenerator[Device, None]`
- [ ] `_discover_with_packet` uses `get_packet_class()` O(1) lookup instead of `dir()` scan
- [ ] `time.time()` replaced with `time.monotonic()` for all elapsed-time measurements in discovery
- [ ] `error_received` logs UDP errors instead of silently swallowing them
- [ ] Exception re-raise uses `raise ... from e` to preserve traceback chain
- [ ] `__import__("time").time()` anti-pattern eliminated across device layer
- [ ] Unbounded `asyncio.Queue` in UDP transport replaced with bounded queue (`maxsize=1000`)
- [ ] `pypa/gh-action-pypi-publish` action pinned to full commit SHA
- [ ] All quality gates pass: ruff format, ruff check, pyright, pytest

## Dependencies

- None — all fixes are isolated to individual files

## Out of Scope

- Animation pipeline performance optimizations (→ review-perf_20260318)
- Documentation content fixes (→ review-docs_20260318)
- New tests for coverage gaps (→ review-tests_20260318)
- Pyright strict mode upgrade
- Ruff rule set expansion

## Technical Notes

### CI/CD fixes (`ci.yml`)

- **CICD-H1**: `test` job has `if: github.event_name == 'pull_request'` so it skips on main-branch push. Release `if:` treats `needs.test.result == 'skipped'` as valid. Add the test job to run on main push OR tighten the release condition to require `needs.test.result == 'success'`.
- **CICD-H2**: `generated-files` is in `needs:` but not in `if:` expression. Add `needs.generated-files.result == 'success'` to the release `if:`.
- **CICD-M2**: `pypa/gh-action-pypi-publish@release/v1` is the only action not pinned to a SHA. Pin it.

### Code fixes

- **CQ-C1**: `multizone.py` lines 364-368 and 461-465 are exact duplicates of the preceding 5-line block. Delete the duplicates.
- **CQ-M3**: `multizone.py:130` direction setter: `[0, int(value), 0, 0, 0, 0, 0, 0, 0]` → `[0, int(value), 0, 0, 0, 0, 0, 0]`
- **CQ-M9 / SEC-L1**: `animator.py:121` replace `random.randint(1, 0xFFFFFFFF)` with `allocate_source()` from `lifx.network.utils`
- **AR-M2 / D-H1**: `api.py:802` return type `AsyncGenerator[Light, None]` → `AsyncGenerator[Device, None]`
- **CQ-H2 / PERF-M1**: `discovery.py:309-324` replace `dir()` loop with `get_packet_class(header.pkt_type)` (already imported in `connection.py`)
- **BP-M2 / PERF-L5**: `discovery.py` replace 16 `time.time()` timeout calls with `time.monotonic()`
- **CQ-M8 / SEC-L2**: `transport.py:39-42` add `_LOGGER.warning(...)` to `error_received`
- **CQ-M7**: `light.py:1029-1032` add `from e` to exception re-raises
- **CQ-H1**: Remove `__import__("time").time()` across `base.py`, `multizone.py`, `light.py`
- **SEC-M1 / AR-L2**: `transport.py:28` add `maxsize=1000` to `asyncio.Queue()` + drop-on-full in `datagram_received`

---

_Generated by Conductor. Review and edit as needed._
