The admin History screen (ADMIN-SPEC 1g) had no API: the read
primitives existed (append-only completion-event reads, derived-state
missed logic) but nothing assembled them, so the admin PWA could not
render the event log or export it. Feature 13's export service was
superseded by the Admin PWA and remains unimplemented by design.
Add a Home-Assistant-free core history layer (core/history.py) that
owns every rule so the two routes cannot drift: one query over the
closed due-date range [start, end] for filter all (every completion
event) / reversals (uncompleted only) / missed (DERIVED past-due open
instances via the existing completion.list_missed_for_child rule --
never stored, never appended); strict ISO date and filter validation
raising ValueError naming filter/start/end; and a csv-module serializer
with a stable documented header (ADMIN-SPEC 5 event-row fields) so the
CSV export is the SAME filtered range as the query, through one
export_history_csv call. Admin routes GET /api/v1/admin/history and
/history.csv are thin adapters on the existing admin router (the one
require_admin dependency; no new auth check), mapping malformed input
to 422 and never 500. completion_events stays append-only: history
only reads.
Tests (tests/test_api_admin_history.py) drive the ASGI app as an admin
via the shared JWT harness: seeded completion + reversal + past-due
open instances prove each filter's rows, the CSV header/rows via
csv.reader, due-date range scoping, 403/401 refusals, and 422s for
unknown filter, non-strict dates and inverted ranges.
HA event triggers expose the payload as trigger.event.data, not
trigger.payload; fix the blueprint, its tests, and the README
examples, with a regression guard.
README gains the blueprint section: all four blueprints, their
inputs, the wiring table to the options-flow notification settings,
the celebration helper setup, event/sensor payload reference, and a
copy-pasteable example package. Tests assert every event trigger
references a real NestQuest event and no reminder is produced for an
absent child.
Child ids sharing a prefix no longer suppress each other (split and
compare entries for equality), and queued mode keeps a second child's
day-complete event from being dropped while the first notify runs.
Triggers on nestquest_child_day_complete (never a zero-quest day),
notifies with the payload's child name, and dedupes per child per
day via an input_text helper holding <child_id>:<today> entries
pruned to today — a re-cleared day does not re-fire, but a second
child clearing the same day still celebrates.
A missing or non-numeric remaining sensor reads as -1 in the
all-clear guard, so a degraded day reaches the parent instead of
looking like a clear day.
Defaults to 20:00 local — deliberately before the midnight missed
sweep, reading the same day's data. Every present child gets a
completion line; owed lines name still-open quests; absent children
are omitted; nothing sends when all clear unless opted in.