# 02 — Target Selection Methodology and Selected Integrations ## 1. Data sources All data was collected during Milestone 1 (snapshot window: Home Assistant Core 2025.6.x; `home-assistant/core` `dev` branch; analytics and issue data as of the same window) from public sources: 1. **Popularity:** `analytics.home-assistant.io` — opt-in installation counts per integration. We use *rank bands* rather than raw counts in this document because raw counts drift weekly; bands are stable. Bands: **T1** = top 50 integrations by active installations, **T2** = 51–150, **T3** = 151–300. 2. **Issue volume:** open issues in `home-assistant/core` carrying the `integration: ` label, normalized by installation band (an integration with many users naturally accrues more issues; we care about *excess* issue pressure). Bands: **High** (top decile of label counts within its popularity band), **Med**, **Low**. 3. **Quality-scale state:** the `quality_scale` key in each integration's `manifest.json` plus, where present, the per-rule `quality_scale.yaml` status file (`done` / `todo` / `exempt` per rule). Integrations predating the 2024 revamp frequently have **no declared scale at all** ("legacy/unscored"), which in practice means Bronze-level gaps. 4. **Code-owner liveness:** whether listed CODEOWNERS have authored or reviewed activity in the integration within the last 12 months (categorized Active / Semi-active / Dormant). This feeds the engagement plan, not the score — we do not penalize dormant ownership, but it changes coordination strategy (doc 04 §3.3). ## 2. Scoring model Each candidate integration receives: ``` Impact I = 0.45·P + 0.35·V + 0.20·U Effort E = 0.40·G + 0.35·T + 0.25·H Score S = I / E (higher is better) ``` Where (each component normalized to 1–5): - **P — Popularity:** T1=5, T2=3, T3=1. - **V — Issue pressure:** High=5, Med=3, Low=1. - **U — User-pain class of the dominant gaps:** 5 if gaps include reauth / availability / setup-failure handling (users hit these constantly); 3 if mostly naming/diagnostics/translations; 1 if mostly internal (typing, code structure). - **G — Gap breadth:** count of unmet rules at-or-below the proposed target tier (1 = ≤4 rules, 3 = 5–9, 5 = ≥10). - **T — Test-suite condition:** 1 = modern fixture-based suite we can extend, 3 = partial suite, 5 = near-greenfield tests needed. - **H — Hardware/protocol complexity:** 1 = pure-HTTP/easily mocked, 3 = stateful protocol (websocket/UPnP) with existing mocks, 5 = binary/RF protocols or device zoos with poor mocks. We additionally apply two **hard filters** before scoring: - **F1 — No active in-flight rewrite:** integrations with an open, code-owner-led refactor branch/PR series are excluded (we'd collide). This filter removed several otherwise-attractive candidates during Milestone 1. - **F2 — Library viability:** the backing PyPI library must be maintained or vendorable-by-policy; integrations whose library is abandoned *and* whose rules would require deep library work are excluded. ## 3. Candidate pool Milestone 1 screened the ~120 integrations that are (a) T1/T2 popularity and (b) below Gold or unscored on the quality scale. After hard filters, 31 candidates were scored. The table below shows the top of the ranking; full scoring spreadsheet data is reproduced in Appendix A. ## 4. Scoring results (top 15 of 31) | Rank | Domain | P | V | U | I | G | T | H | E | **S** | Notes | |---|---|---|---|---|---|---|---|---|---|---|---| | 1 | `transmission` | 3 | 3 | 5 | 3.40 | 3 | 1 | 1 | 1.80 | **1.89** | Reauth + availability gaps; clean HTTP mocking | | 2 | `nut` | 3 | 3 | 3 | 3.00 | 3 | 1 | 1 | 1.80 | **1.67** | Unscored legacy; coordinator present; cheap Silver | | 3 | `denonavr` | 3 | 3 | 3 | 3.00 | 3 | 1 | 3 | 2.30 | **1.30** | Telnet/HTTP hybrid; good existing mocks | | 4 | `harmony` | 3 | 3 | 3 | 3.00 | 3 | 3 | 1 | 2.50 | **1.20** | Websocket lib; suite partial | | 5 | `samsungtv` | 5 | 5 | 5 | 5.00 | 3 | 3 | 5 | 3.50 | **1.43** | Huge user base; device-zoo risk priced in | | 6 | `broadlink` | 5 | 5 | 3 | 4.60 | 5 | 3 | 5 | 4.30 | **1.07** | Binary protocol; biggest gap breadth | | 7 | `kodi` | 3 | 3 | 3 | 3.00 | 3 | 3 | 3 | 3.00 | **1.00** | Websocket JSON-RPC; mocks exist | | 8 | `fritz` | 5 | 5 | 5 | 5.00 | 5 | 3 | 5 | 4.30 | **1.16** | Enormous EU install base; high issue pressure | | 9 | `dlna_dmr` | 3 | 3 | 3 | 3.00 | 3 | 3 | 3 | 3.00 | **1.00** | UPnP; async lib already (Platinum-cheap) | | 10 | `onvif` | 3 | 5 | 5 | 4.10 | 5 | 3 | 5 | 4.30 | **0.95** | Camera supportability pain → diagnostics high-value | | 11 | `yeelight` | 3 | 5 | 5 | 4.10 | 5 | 3 | 5 | 4.30 | **0.95** | Notorious availability log-spam; mDNS discovery rules | | 12 | `androidtv` | 5 | 5 | 3 | 4.60 | 5 | 5 | 5 | 4.75 | **0.97** | ADB complexity high but T1 popularity justifies | | 13 | `ping` | 5 | 1 | 1 | 2.80 | 1 | 1 | 1 | 1.00 | **2.80**¹ | Reserve: tiny gap breadth → little absolute impact | | 14 | `vlc_telnet` | 1 | 1 | 3 | 1.40 | 1 | 1 | 1 | 1.00 | **1.40** | Reserve | | 15 | `songpal` | 1 | 3 | 3 | 2.10 | 3 | 1 | 3 | 2.30 | **0.91** | Reserve | ¹ `ping` tops raw S because its effort is near-zero, but its absolute remaining gap (G=1, U=1) means little user-visible improvement; we therefore cap reserves to integrations whose *absolute* impact is small and use them only as substitutes. Selection = top 12 by S **subject to a minimum absolute impact I ≥ 3.0**, which is what demotes `ping`, `vlc_telnet`, `songpal` to reserve. ## 5. Selected primary targets and target tiers | # | Domain | Current scale (snapshot) | Target tier | Track weight | Audit file | |---|---|---|---|---|---| | 1 | `transmission` | Unscored (legacy) | **Silver** | Fast | `audits/transmission.md` | | 2 | `nut` | Unscored (legacy) | **Silver** | Fast | `audits/nut.md` | | 3 | `denonavr` | Unscored (legacy) | **Silver** | Fast | `audits/denonavr.md` | | 4 | `harmony` | Unscored (legacy) | **Silver** | Fast | `audits/harmony.md` | | 5 | `kodi` | Unscored (legacy) | **Silver** | Fast | `audits/kodi.md` | | 6 | `dlna_dmr` | Unscored (legacy) | **Silver** (+2 Platinum-cheap rules) | Fast | `audits/dlna_dmr.md` | | 7 | `samsungtv` | Unscored (legacy) | **Silver** | Heavy | `audits/samsungtv.md` | | 8 | `broadlink` | Unscored (legacy) | **Silver** | Heavy | `audits/broadlink.md` | | 9 | `fritz` | Unscored (legacy) | **Silver → Gold-partial** | Heavy | `audits/fritz.md` | | 10 | `onvif` | Unscored (legacy) | **Silver** | Heavy | `audits/onvif.md` | | 11 | `yeelight` | Unscored (legacy) | **Silver** | Heavy | `audits/yeelight.md` | | 12 | `androidtv` | Unscored (legacy) | **Bronze-complete → Silver** | Heavy | `audits/androidtv.md` | Target-tier rationale per integration lives in each audit's §1. We deliberately do **not** target Gold across the board: Gold's documentation rules (`docs-*` family) and `dynamic-devices`/`stale-devices` rules are best co-designed with code owners, so Gold items appear in the backlog only where the audit found them cheap and uncontroversial (notably `fritz` device lifecycle and `dlna_dmr` docs). ## 6. Reserve targets | Domain | Trigger to activate | Target tier | |---|---|---| | `ping` | Any primary track blocked per doc 04 §3.4 | Silver | | `vlc_telnet` | Two primary tracks blocked | Silver | | `songpal` | Three primary tracks blocked | Silver | Activation swaps the blocked track's *remaining* budget to the reserve; completed work on the blocked track is still submitted if rules with zero behavioral change remain (R1 mitigation). ## 7. Appendix A — full 31-candidate scoring data | Domain | P | V | U | G | T | H | I | E | S | Outcome | |---|---|---|---|---|---|---|---|---|---|---| | transmission | 3 | 3 | 5 | 3 | 1 | 1 | 3.40 | 1.80 | 1.89 | Selected | | nut | 3 | 3 | 3 | 3 | 1 | 1 | 3.00 | 1.80 | 1.67 | Selected | | samsungtv | 5 | 5 | 5 | 3 | 3 | 5 | 5.00 | 3.50 | 1.43 | Selected | | denonavr | 3 | 3 | 3 | 3 | 1 | 3 | 3.00 | 2.30 | 1.30 | Selected | | harmony | 3 | 3 | 3 | 3 | 3 | 1 | 3.00 | 2.50 | 1.20 | Selected | | fritz | 5 | 5 | 5 | 5 | 3 | 5 | 5.00 | 4.30 | 1.16 | Selected | | broadlink | 5 | 5 | 3 | 5 | 3 | 5 | 4.60 | 4.30 | 1.07 | Selected | | kodi | 3 | 3 | 3 | 3 | 3 | 3 | 3.00 | 3.00 | 1.00 | Selected | | dlna_dmr | 3 | 3 | 3 | 3 | 3 | 3 | 3.00 | 3.00 | 1.00 | Selected | | androidtv | 5 | 5 | 3 | 5 | 5 | 5 | 4.60 | 4.75 | 0.97 | Selected | | onvif | 3 | 5 | 5 | 5 | 3 | 5 | 4.10 | 4.30 | 0.95 | Selected | | yeelight | 3 | 5 | 5 | 5 | 3 | 5 | 4.10 | 4.30 | 0.95 | Selected | | ping | 5 | 1 | 1 | 1 | 1 | 1 | 2.80 | 1.00 | 2.80 | Reserve (I < 3.0) | | vlc_telnet | 1 | 1 | 3 | 1 | 1 | 1 | 1.40 | 1.00 | 1.40 | Reserve (I < 3.0) | | songpal | 1 | 3 | 3 | 3 | 1 | 3 | 2.10 | 2.30 | 0.91 | Reserve | | epson | 1 | 3 | 3 | 3 | 3 | 3 | 2.10 | 3.00 | 0.70 | Not selected | | panasonic_viera | 1 | 3 | 3 | 3 | 3 | 3 | 2.10 | 3.00 | 0.70 | Not selected | | directv | 1 | 1 | 1 | 1 | 1 | 3 | 1.20 | 1.50 | 0.80 | Not selected | | roomba | 3 | 3 | 3 | 3 | 3 | 5 | 3.00 | 3.50 | 0.86 | Not selected (H; MQTT-over-TLS device protocol) | | nmap_tracker | 3 | 3 | 1 | 3 | 3 | 5 | 2.60 | 3.50 | 0.74 | Not selected | | wake_on_lan | 3 | 1 | 1 | 1 | 1 | 1 | 2.00 | 1.00 | 2.00 | Not selected (I < 3.0, tiny gap) | | waze_travel_time | 3 | 3 | 1 | 1 | 1 | 1 | 2.60 | 1.00 | 2.60 | Not selected (I < 3.0) | | philips_js | 1 | 3 | 3 | 3 | 3 | 3 | 2.10 | 3.00 | 0.70 | Not selected | | onkyo | 3 | 3 | 3 | 5 | 5 | 3 | 3.00 | 4.45 | 0.67 | Excluded F1 (owner-led refactor in flight at snapshot) | | yamaha | 3 | 3 | 3 | 5 | 5 | 3 | 3.00 | 4.45 | 0.67 | Not selected (no config flow at all → near-rewrite) | | frontier_silicon | 1 | 1 | 3 | 3 | 3 | 3 | 1.40 | 3.00 | 0.47 | Not selected | | squeezebox | 1 | 3 | 3 | 3 | 3 | 3 | 2.10 | 3.00 | 0.70 | Not selected | | emulated_roku | 1 | 1 | 1 | 3 | 3 | 1 | 1.20 | 2.50 | 0.48 | Not selected | | icloud | 3 | 3 | 5 | 5 | 3 | 5 | 3.40 | 4.30 | 0.79 | Excluded F2 (library/API fragility) | | tuya | 5 | 5 | 5 | 5 | 5 | 5 | 5.00 | 5.00 | 1.00 | Excluded F1 (vendor-led work in flight at snapshot) | | zha | 5 | 5 | 3 | 3 | 3 | 5 | 4.60 | 3.50 | 1.31 | Excluded F1 (active core-team-owned subsystem) |