Extract the engines and business layer into core/ (task 510c1f78)

Move presence.py, materialize.py, completion.py, events.py, children.py,
quest_definitions.py, admin_allowlist.py and service_policy.py into
custom_components/nestquest/core/, leaving re-export shims at the
original paths so the integration keeps working unchanged.

core/events.py is refactored to PAYLOAD CONSTRUCTION ONLY: it builds
and returns (event_type, payload) tuples and never touches hass.bus or
hass.config. The HA-local 'today' the day-complete rule needs is now a
parameter (read from hass.config.time_zone by the integration shim).
The events.py shim retains fire_quest_completed/fire_quest_uncompleted,
wiring the returned events to hass.bus.async_fire so the four event
names and payload shapes stay identical (nestquest_quest_completed with
was_on_time, nestquest_quest_uncompleted, nestquest_child_day_complete
with quests_due/quests_completed, occurred_at strict UTC ISO-8601).

Update two test logger-name references (children now logs as
...core.children) and the materialize _now_stamp monkeypatch target
(now patches the core module the walk reads globals from).

1497 passed (baseline). No homeassistant import under core/, no
top-level core import under the integration, no repo-root core/.
This commit is contained in:
2026-09-21 14:52:58 -04:00
parent 1503774e85
commit 08cb31ce4c
18 changed files with 2726 additions and 2560 deletions
+2 -2
View File
@@ -141,7 +141,7 @@ def test_create_child_duplicate_name_allowed_and_warned(
async def _body(database):
first = await create_child(database, "Ada")
with caplog.at_level(
logging.WARNING, logger="custom_components.nestquest.children"
logging.WARNING, logger="custom_components.nestquest.core.children"
):
second = await create_child(database, " ADA ")
# Whitespace/case-normalised duplicate: allowed, both rows exist.
@@ -365,7 +365,7 @@ def test_create_child_concurrent_same_name_still_warns(tmp_path) -> None:
try:
await apply_migrations(database)
logger = logging.getLogger(
"custom_components.nestquest.children"
"custom_components.nestquest.core.children"
)
seen: list[logging.LogRecord] = []
+4 -1
View File
@@ -1475,7 +1475,7 @@ async def _collect_records(database, child_ids, start, end) -> set:
def test_materialize_end_to_end_six_rule_types(tmp_path, monkeypatch) -> None:
import custom_components.nestquest.materialize as materialize_module
import custom_components.nestquest.core.materialize as materialize_module
# Give each materialize run a DISTINCT batch stamp: production upserts
# rewrite generated_at on every re-run, so a shared pinned stamp would
@@ -1487,6 +1487,9 @@ def test_materialize_end_to_end_six_rule_types(tmp_path, monkeypatch) -> None:
stamps["n"] += 1
return f"2026-06-01T00:00:{stamps['n']:02d}+00:00"
# The materialize() walk reads ``_now_stamp`` from its OWN module
# globals (now the HA-free core package), so the patch must target
# the core module, not the re-export shim the integration imports.
monkeypatch.setattr(materialize_module, "_now_stamp", _distinct_stamp)
async def _body(database):