# 05 — Global Acceptance Criteria & Definition of Done **Status:** Final for Milestone 2 **Applies to:** Every work item in the program backlog (doc 06). Per-item criteria in doc 06 are *additive* to this document; nothing here may be waived per-item without an explicit `waiver:` note in the backlog entry approved by the program lead and recorded with rationale. --- ## 1. Structure Acceptance criteria are layered: 1. **Universal DoD (§2)** — applies to every PR, no exceptions. 2. **Category DoD (§3)** — applies per work-item category (tests, typing, diagnostics, flows, naming, refactors, library work, docs). 3. **Per-item criteria** — in doc 06, expressed as testable statements. 4. **Per-integration tier gate (§4)** — applies to the final PR of each integration's series. An item is **Done** only when all four layers pass *and* the PR is merged into `home-assistant/core` `dev` (or the relevant upstream library's default branch, for `upstream-first` items). "Approved but unmerged" is not Done; "merged then reverted" reopens the item. --- ## 2. Universal Definition of Done (every PR) ### 2.1 Code quality gates (mechanically verifiable) - [ ] CI fully green: `hassfest`, `ruff` (lint + format), `mypy` for the touched component if it is in (or being added to) `.strict-typing`, pytest for the component, and translation checks. - [ ] No new `# type: ignore`, `# noqa`, or `pylint: disable` comments unless each carries a one-line justification comment and was accepted by the reviewer. - [ ] No blocking I/O introduced into the event loop; any sync library calls wrapped in `async_add_executor_job` (or library-provided async API used). - [ ] No protocol/business logic added to the component that belongs in the dependency library (ADR alignment per doc 04 §2). - [ ] All user-facing strings live in `strings.json`; **no other language files are hand-edited** (translations flow through Lokalise). Placeholders use the documented `{name}` syntax and every placeholder referenced in code exists in strings. - [ ] `manifest.json` untouched unless the item explicitly changes it; any `requirements` bump references a published release on PyPI with a changelog link in the PR description. - [ ] No new entities, services, or options beyond the item's stated scope. ### 2.2 Test gates - [ ] Component test suite passes locally and in CI with **zero new warnings** promoted from the component (`pytest -W error::DeprecationWarning` discipline where the suite enforces it). - [ ] New/changed code paths are covered: program-wide floor of **95% line coverage on files touched by the PR**, and **100% on any `config_flow.py`** touched (matching the quality-scale `config-flow-test-coverage` rule). - [ ] Tests use connection mocking/fixtures only — no network, no timing-sensitive sleeps (use `freezegun`/`async_fire_time_changed` patterns already standard in the test suite). - [ ] Where snapshot testing (`syrupy`) is the established pattern for the platform under test, snapshots are added/updated and the diff is explained in the PR description. ### 2.3 Process gates (per doc 04) - [ ] PR conforms to sizing rules (doc 04 §4.1) and series order (§4.2), or carries reviewer pre-approval for the deviation. - [ ] PR description complete per doc 04 §4.3, including quality-scale rule keys and series linkage. - [ ] Code owner was review-requested; veto-window / owner-response rules respected. - [ ] Paired `home-assistant.io` documentation PR opened and cross-linked **iff** user-facing behavior, options, or setup steps changed. - [ ] If user-visible behavior changed: draft release-notes blurb included; if breaking: full breaking-change protocol satisfied (doc 04 §4.4). - [ ] Program status page updated within 48h of open/merge. ### 2.4 Quality-scale bookkeeping - [ ] If the PR completes a quality-scale rule, `quality_scale.yaml` for the domain is updated in that PR (rule key flipped to `done`, or `exempt` with the required comment), keeping the file truthful at every commit on `dev`. --- ## 3. Category Definitions of Done ### 3.1 Test scaffolding & coverage items Done when: - Fixtures represent realistic device payloads (captured or faithfully constructed from protocol docs), checked in under `tests/components//fixtures/` and loaded via `load_fixture`/JSON helpers per house style. - A `conftest.py` provides reusable `mock_config_entry` and mocked-client fixtures so subsequent PRs in the series add tests without re-plumbing. - Config-flow tests cover: happy path, each declared error (`cannot_connect`, `invalid_auth`, `unknown` as applicable), duplicate-entry abort (`already_configured`), and every discovery source declared in the manifest (zeroconf/ssdp/dhcp/usb as applicable), including discovery-update-of-existing-entry paths. - Setup/unload tests cover: successful setup, `ConfigEntryNotReady` on connection failure, `ConfigEntryAuthFailed` on auth failure (where auth exists), and clean unload (no lingering timers/listeners — test asserts via `hass.data` cleanliness and no `lingering timer` test-teardown errors). ### 3.2 Typing items Done when: - All functions in the component have complete parameter and return annotations; `runtime_data` (or `hass.data`) access is typed via a typed `ConfigEntry` alias where the modern pattern applies. - The domain is added to `.strict-typing` and `mypy` passes in strict mode for it in CI. - No semantic changes whatsoever (diff is annotations, imports, and the strict-typing registration only). ### 3.3 Diagnostics items Done when: - `diagnostics.py` implements config-entry diagnostics (and device diagnostics where per-device data is meaningful). - Output includes: redacted config-entry data/options, coordinator/runtime data snapshot, and library/device version info available without extra I/O. - **Redaction is exhaustive**: credentials, tokens, MACs, serials, lat/long, hostnames-as-secrets — via `async_redact_data` with a reviewed `TO_REDACT` list; a test asserts redaction of every sensitive key present in fixtures. - A snapshot test pins the diagnostics shape. ### 3.4 Reauth / reconfigure flow items Done when: - Auth failures at setup raise `ConfigEntryAuthFailed`; auth failures at runtime (coordinator update or service call) trigger the same path, starting reauth exactly once (no repair-issue spam, no duplicate flows). - Reauth flow re-validates credentials against the device/service, updates the existing entry in place (`async_update_reload_and_abort` pattern), and aborts with `reauth_successful`. - Reconfigure flow (where in scope) prevents account/device identity switching (asserts unique_id match) and aborts with `reconfigure_successful`. - 100% test coverage on the new flow steps, including the wrong-account/wrong-device rejection paths. ### 3.5 Entity-naming / device-info items Done when: - `has_entity_name = True` adopted across the integration's entities; the main feature of a device uses `_attr_name = None`; auxiliary entities use translated names via `translation_key` (no hard-coded English names in code where translations are the rule). - Device registry entries carry correct `identifiers`/`connections`, `manufacturer`, `model`, `sw_version` where obtainable, and `via_device` for hub topologies. - **No existing entity unique_ids change.** If achieving correct naming would require unique_id changes, the item escalates to Lane B breaking-change protocol or is descoped — silent unique_id churn is an automatic acceptance failure. - Snapshot tests pin entity names, entity_ids (for pre-existing entries), and device info; PR description states expected user-visible name changes explicitly. ### 3.6 Coordinator / runtime-data refactors Done when: - Polling consolidated into `DataUpdateCoordinator` (or documented push/`CALLBACK` architecture) with correct `update_interval`, `UpdateFailed` mapping, and availability propagation to entities (`available` reflects coordinator success). - `entry.runtime_data` typed pattern adopted; `hass.data[DOMAIN]` usage removed for this integration. - Behavior-neutrality demonstrated: pre-existing tests pass unmodified except for mechanical fixture/plumbing updates, and snapshots (where present) are byte-identical. ### 3.7 Upstream-library items (`upstream-first`) Done when: - The change is merged in the upstream library with tests, **released** on PyPI, and the version bump PR in core passes the full component suite against the new version. - The core PR contains only the bump plus the minimal adaptation; library feature adoption is a separate follow-on item. - If upstream is unresponsive for 45 days, the item converts to `blocked-upstream` status with a written fallback decision (drop, fork-discussion-with-core, or wait) — *silently vendoring code into core is never the fallback.* ### 3.8 Documentation items Done when: - `home-assistant.io` page updated to match shipped behavior: prerequisites, all options, troubleshooting section for the failure modes our flows surface, and removal of stale YAML examples for anything migrated. - Docs PR merged in the same release window as the core PR it pairs with (coordinate with docs reviewers if the core PR merges close to a release cut). --- ## 4. Per-Integration Tier Gate (final PR of each series) The integration's uplift is **Done** when: - [ ] Every rule required for the target tier is `done` or legitimately `exempt` (with comment) in `quality_scale.yaml`, and the tier claim is updated. - [ ] Every backlog item for the integration in doc 06 is `merged`, `owner-declined`, `parked-no-review`, or `descoped` — with no item left in an ambiguous state, and declined/parked items annotated. - [ ] The full component test suite passes with overall component coverage at or above the level recorded in the integration's audit *plus* the per-file floors of §2.2. - [ ] One full release cycle (beta + stable) has shipped containing the series' last behavioral PR with **zero open regressions** attributed to the series. - [ ] Exit summary posted on the uplift proposal issue: rules completed, rules exempted and why, follow-ups handed off, and the §8 (doc 04) sustainability watch window start date. --- ## 5. Verification & Sign-off Protocol For every item, sign-off requires three independent checks recorded on the program status page: | Check | Performed by | Evidence | |---|---|---| | **Mechanical** | CI | Green run link on the merged commit | | **Functional** | Program peer (not the author) | Checklist from the relevant §3 category, executed against the merged code; for hardware-dependent integrations, executed against fixtures plus, where a program member owns the device, a real-device smoke test noted as such | | **Community** | HA reviewer + code owner | The merge itself, plus absence of post-merge objections within 14 days | Hardware reality check: many of the 12 targets (e.g., `broadlink`, `onvif`, `harmony`, `samsungtv`) cannot be fully validated without devices. The program maintains a **device matrix** (who owns what) on the status page; items touching device behavior on hardware nobody in the program owns are flagged `needs-device-tester` in doc 06 and must recruit a community tester on the PR before the behavioral parts merge. Test-only and typing-only items are exempt from this flag. --- ## 6. Non-Goals Restated as Acceptance Boundaries To prevent scope creep, the following are **automatic review-rejection criteria** inside the program (even if an HA reviewer would accept them): - New features, entities, or services not present in the audit gap list — file them as ordinary feature requests instead. - Rewrites of working code for style preference alone. - Dependency *swaps* (replacing the integration's library) — out of program scope entirely; raise with the code owner as a separate discussion if an audit found the library unmaintained. - Any change to integrations outside the 12 targets, except trivial shared-helper fixes explicitly required by an in-scope item and approved by the program lead.