The HA integration is now purely a client of the NestQuest API service
(Feature 18): the API owns the SQLite file, the migrations, and every
business rule, so keeping a second copy of that ownership inside the
integration meant two sources of truth for household state, dead
wiring (the startup backfill, the day-rollover materialization and
sweep listeners, the corrupt-DB handling, the admin-allowlist seeding)
and settings keys nothing consumes any more.
Removed the integration's re-export/DB shim modules (db, store,
migrations, schema, the five DAOs, completion, children,
quest_definitions, admin_allowlist, presence, presence_management,
materialize, recurrence, events, sweep); the bundled domain package at
custom_components/nestquest/core/ is untouched and remains the single
home of those engines. Setup now builds only the API client, the
snapshot coordinator, and the SSE subscription, registers the one
complete_quest proxy, and forwards the platforms. The options flow
keeps only the keys the client itself consumes (API base URL + panel
token, update interval, staleness, panel idle timeout); the horizon,
rollover, notification and admin-allowlist settings moved out with the
database (the API's settings store owns horizon/rollover, and the
automations take their behaviour from blueprint inputs). The
integration-plane tests now script the panel route's payloads and SSE
frames instead of seeding a local database; the core-plane tests keep
their coverage with imports pointed at core directly.
- admin_allowlist.py: list_admin_ids / set_admin_ids (atomic sync of
the allowlist inside one transaction under the connection lock;
refuses empty targets so the last admin can never be removed and
the allowlist can never be emptied — fail closed) and
seed_setup_admin (seeds ONLY an empty allowlist: stored entry-data
copy first — disaster recovery for a lost database — else the HA
user who completed the config flow from the entry context;
non-empty lists are never resurrected).
- __init__.py: both setup paths (first setup and the reopened-record
path) seed after migrations; a failed seed closes the database and
re-raises through the existing error handling.
- options_flow.py: the admin picker is a multi-select of EXISTING HA
users (hass.auth.async_get_users), defaulted to the current
database allowlist, membership-checked at the schema level and
backed up on the raw-input path; empty selections are refused
(no_admins), unknown ids rejected (invalid_admin); the selection is
applied to the DB when the runtime record is reachable and always
stored on the entry as the recovery copy. Submissions without the
key (legacy raw payloads) keep the three-key behaviour untouched.
- const.CONF_ADMIN_USER_IDS; strings + translations for the field and
the two errors; conftest entries gain a context dict (HA's entry
context carries the flow user).
- Tests: 20 allowlist business tests (round-trips, refusal matrix,
seed precedence and narrowed-list persistence), 5 picker flow tests,
3 setup-seeding lifecycle tests. Suite: 901 passed.