Commit Graph
19 Commits
Author SHA1 Message Date
overseer 536caf91e4 Fix review findings: first-refresh handling, stale runtime record, P3s
P1: the first-refresh error handling never fired against real Home
Assistant.  Real DataUpdateCoordinator.async_config_entry_first_refresh
converts ANY refresh failure into ConfigEntryNotReady (the original
exception survives only as __cause__), so `except NestQuestApiError`
could never match: the failure fell through to the outer except block,
unwound listeners, closed the DB and re-raised, and
async_forward_entry_setups never ran — no entities at all.  Two-sided
fix: _async_update_data now converts every typed NestQuestApiError
(unconfigured stub, transport failure, non-2xx) into
homeassistant.helpers.update_coordinator.UpdateFailed — the exception
HA's coordinator machinery records as a failed pass
(last_update_success=False, data=None) — and setup catches
ConfigEntryNotReady around the first refresh instead, so an unconfigured
API or failed fetch keeps setup alive with unavailable entities while
everything else still unwinds.  The conftest DataUpdateCoordinator
stand-in now reproduces HA's real contract (async_refresh records a
failure instead of raising; first_refresh wraps it in
ConfigEntryNotReady) and gains an UpdateFailed stand-in, so this class
of bug is caught by the suite — verified by reverting the catch, which
fails both unconfigured-API and failed-fetch tests.

P1: a stale hass.data[DOMAIN][entry.entry_id] survived a failed setup.
The runtime record registers in hass.data before the first refresh and
platform forward, but the except cleanup only cleared
entry.runtime_data; after any failure in that window a later unload
picked up the stale, already-torn-down record and re-invoked the
already-consumed update-listener remover (ValueError).  The except block
now also pops the hass.data entry, and
test_setup_failure_after_registration_shuts_coordinator_down (reworked
from the fiction-based first-refresh trigger: a failed first refresh is
tolerated setup, not an unwind) proves a failed setup followed by an
unload does not raise and leaves no residue.

P3: dropped the function-local re-import of NestQuestApiClient in
coordinator_client_from_entry (module-level import already covers it),
and the unused coordinator_client_from_entry alias in the conftest
fixture.

P3: test_due_today_payload_omits_missed_admin_equals_panel dropped the
missed-instance count assertions in the Feature 18 rewrite; restored
quests_completed_today == 0 / quests_remaining_today == 1 so the
missed-derivation + counts pairing stays verified (the counts arrive
precomputed and still roll the full day).
2026-09-23 06:26:29 -04:00
overseer ec7c8d4bc2 Coordinator polls the API snapshot and rebuilds the sensors' data
Feature 18: the shared coordinator's refresh pass now fetches
GET /api/v1/panel/snapshot through the NestQuestApiClient and
reconstructs the exact core dataclasses (NestQuestSnapshot,
ChildDaySnapshot, QuestInstanceView) the Feature 10 entities read, so
sensor.py and binary_sensor.py are untouched and every entity_id and
attribute payload keeps its shape.

Why: the integration becomes an API client of the NestQuest service
instead of a second reader of the SQLite file, and the panel cards and
the four blueprints keep working without changes.

- snapshot_from_api_payload maps the route's JSON back onto the
  dataclasses field by field (state 'completed' -> 'done' so
  instance_payload renders 'completed' again; counts, presence,
  next_present, overdue, on_time, completed_at pass through verbatim;
  due_date is stamped from today_iso, the only date the route serves).
- The panel payload omits missed instances (D-009), so
  admin_instances can no longer carry missed rows — the admin surface
  for missed quests is the PWA reading the API directly. Documented in
  the module docstring and pinned by tests.
- An unconfigured panel token (the shipped default) gets a typed-error
  stub instead of a construction crash: setup succeeds, the first
  refresh fails cleanly, entities come up unavailable and HA's retry
  cycle applies. Fetch failures log the typed error and mark the
  entities unavailable while data keeps its last good snapshot.
- The runtime record registers before the first refresh so the refresh
  path always finds the live entry state; the update interval and the
  serialized forced-refresh behaviour are unchanged.
- Tests: a fixture snapshot drives the coordinator (stub client, no
  network) asserting per-child values, household rollups, cycle day,
  and the exact instance payload shape, plus unconfigured and
  failed-fetch cases; DB-seeded tests ride a lazy local-snapshot
  client through the same JSON path.
2026-09-23 06:02:26 -04:00
dev_agent d78ef196d0 Feature 16: NestQuest API Service (#165)
Co-authored-by: dev_agent <17+dev_agent@code.cubecraftcreations.com>
Co-committed-by: dev_agent <17+dev_agent@code.cubecraftcreations.com>
2026-09-23 04:37:26 -04:00
dev_agent b3715ccdcd Replace HA config reads with an explicit settings object (task 4dd8f870)
Replace HA config reads with an explicit settings object (task 4dd8f870)
2026-09-21 15:55:18 -04:00
dev_agent 1503774e85 Extract the storage layer into core/ (bundled in the integration)
Extract the storage layer into core/ (bundled in the integration)
2026-09-21 14:48:01 -04:00
overseer edca25affa Add the Lit card toolchain and auto-register the Lovelace bundle 2026-09-20 10:08:38 -04:00
orchestrator-agent a9d8f1d225 Handle entity lifecycle for child add, deactivate, reactivate
The harness tracks entities per entry so a platform unload removes
exactly that entry's entities; lifecycle tests prove deactivated
children drop out on reload, reactivation restores the original
unique_ids, new children appear without disturbing existing ones,
and the restart equivalent restores live states.
2026-09-19 13:23:35 -04:00
orchestrator-agent fe38e5040e Fire the documented bus events from the completion service paths
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.
2026-09-19 12:01:05 -04:00
orchestrator-agent 00409a76db Add per-child daily count and percentage sensors
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.
2026-09-19 11:50:18 -04:00
orchestrator-agent 979eafc5a2 Add the shared NestQuest data update coordinator
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.
2026-09-19 11:41:12 -04:00
orchestrator-agent 37d7b7e6c3 Gate every NestQuest service behind the admin permission check
permission_gate wraps all registered services at registration time:
admin-only policy reads call.context.user_id against admin_allowlist
is_admin (fail closed on no context); complete_quest stays open.
2026-09-19 08:36:14 -04:00
orchestrator-agent 2d30f0ce77 Register canonical NestQuest HA services with schemas
Domain-global handlers for the ENTITIES-AND-SERVICES inventory plus
regenerate. No permission decorator yet.
2026-09-18 15:59:02 -04:00
overseer 5706d8b7a6 Startup backfill + regenerate service (Feature 07, task 7) (#81) 2026-09-17 15:42:10 -04:00
overseer be6367b600 Schedule the daily generation run at rollover (Feature 07, task 6) (#80) 2026-09-17 15:10:57 -04:00
Joshua King 068ace5693 Review fix: owner-account fallback seed for first setup
Review round 4 (Codex gpt-5.6-terra, HIGH): relying on the flow
context alone can leave first setup ownerless. seed_setup_admin gains
an owner_ids tier: when no persisted copy and no context user exist,
every HA owner account is seeded (owners can already do everything in
HA — no privilege escalation). __init__ resolves owners via
hass.auth.async_get_users on both setup paths; conftest's hass gains
the auth surface. Tests: owner fallback seeds only owners, context
user still wins over owners, owner_ids argument validation. Suite:
910 passed.
2026-09-15 17:22:39 -04:00
Joshua King d90c170460 Review fixes: persisted flow-user admin seed and real cv.multi_select
Review rounds 1-2 (Codex gpt-5.6-terra) found two HIGHs against real HA:
- entry.context is not a durable record — the config flow now persists
  the completing HA user into entry data (CONF_ADMIN_USER_IDS) and the
  seed precedence becomes: options copy (the current list) first, then
  the config flow's entry-data copy, then the context user as a last
  resort. Config-flow tests cover the persisted user and the
  context-free path; a seed-precedence test covers options > data.
- the hand-rolled closure could not serialize as an HA multi-select.
  The harness now mocks homeassistant.helpers.config_validation with a
  faithful multi_select, and the flow uses cv.multi_select exactly as
  real HA code does. Suite: 904 passed.
2026-09-15 17:13:32 -04:00
Joshua King 0d61ea2c88 Admin allowlist storage seeded with the setup user (Feature 03, task 4)
- 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.
2026-09-15 17:03:53 -04:00
orchestrator-agent 3e2860b2f1 Sync dev with main (release-merge backport) (#36) 2026-09-14 15:19:28 -04:00
dev_agent b854013f1a test: wire pytest test harness with standard hass fixture (#9) 2026-09-13 19:18:10 -04:00