Notify target (empty default, household fills their own service),
three strict HH:MM automation times (08:00/15:00/20:00 — the report
deliberately before the midnight sweep), and four independent enable
toggles, all leniently stored and round-tripped.
quest_completed and quest_uncompleted fire on actual transitions with
documented payloads; child_day_complete fires when a completion clears
the child's day; quest_missed is defined as Feature 11's contract.
Payloads documented in the README for automation authors.
all_done is on exactly when the child owed quests today and owes none
remaining (a zero-quest day stays off so celebrations never fire on
an empty day); present_today mirrors the presence engine's answer
for the HA-local date.
Four sensors per active child read the coordinator snapshot: quests
due today (carrying the panel payload that omits missed instances plus
the admin payload that includes them, D-009), completed, remaining, and
completion percentage (100 on a zero-quest day). Platform forwarding
wired through the harness's entity registry stand-ins.
One refresh pass builds the whole entity snapshot: active children,
today's instances with derived open/done/missed states, per-child
presence via the PresenceEngine (records converted to model objects),
rollup counts, and the custody cycle day. Interval configurable via
the new update_interval option, default five minutes.
- 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.
Per IMPLEMENTATION-ORDER.md 1.4: a quest_definition_windows table
(definition_id, window, due_time) declares which day windows a
definition spans, one row per definition+window via the composite
primary key; window is CHECK-constrained to morning/afternoon/evening.
- const.py: WINDOW_MORNING/AFTERNOON/EVENING, QUEST_WINDOWS canonical
order, WINDOW_CLOCK_RANGES with the documented boundaries and the
boundary-to-later-window rule documented for Feature 07.
- schema.py: windows DDL joins SCHEMA_V1_STATEMENTS; due_time is
caller-validated strict HH:MM (DAO layer), matching the date policy.
- migrations.py: migration 4 is a plain CREATE IF NOT EXISTS statement
list (no rebuild needed for a new table).
- dao_rules.py: QuestDefinitionsDao gains upsert_window (idempotent
per window, due_time refresh in place), list_windows (const order),
remove_window; _validate_time/_validate_window helpers.
- tests: windows DDL shape/constraints (CHECK matrix, duplicate,
unknown definition), DAO round-trips, const range shapes; leak
guards extended to the new table.