Continues narrowing SamsungEntityDescription accesses to the correct
subclass and asserting Optional write_fn/match_fn/exists_fn fields are
set before calling them, per the pattern established in the previous
commit.
Adds [tool.ruff] and [tool.ty] config to pyproject.toml with a curated
ruff rule set (E, F, W, I, UP, B, C4, SIM, RUF, ASYNC, LOG, G, PIE, RET,
PERF, N), pins ruff/ty in requirements-dev.txt, reformats the whole tree
with `ruff format`, and fixes the pre-existing lint and type-check debt
those tools surfaced so both run clean.
Production-code type fixes include: HA's ConfigFlowResult vs. the
generic FlowResult in config_flow.py, narrowing BoundEntity.desc to its
platform-specific subclass (SelectDesc/NumberDesc/SensorDesc/etc.) via
cast() instead of an unchecked annotation, converting HA device_class
strings to their proper enum types, a resolve_registry callback typed
as `object` instead of `DeviceRegistry | None`, and a couple of other
narrow correctness fixes (CA key type validation, an index-out-of-bounds
false positive from an empty-tuple fallback, a bool/dict argument swap).
Test-file fixes are mechanical: narrowing SamsungEntityDescription to
the correct subclass via isinstance()/cast() before accessing
subclass-only fields, and asserting Optional write_fn/unit_fn fields
are set before calling them.
DA_DF_TP1_21_COMMON reports a plain {setBuzzerSound, supportedFinishSound}
buzzersound resource -- the same shape laundry.BUZZER_SOUND already
handles for washers/dryers -- but it was unbound because the air_dresser
registry never included that capability. Add it, and lock the board in
with a scrubbed fixture, golden, and capability tests.
The reporter's actual complaint (course cycles showing as raw codes) is
a labelling gap, not a coverage one: this board's course table has no
code->name mapping anywhere in the dump, same as issue #162's board, so
there's nothing to bind here -- it needs a reporter to identify the
codes before they can be named in translations.