Report when remaining counts are unavailable, not all-clear

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.
This commit is contained in:
2026-09-19 14:47:37 -04:00
parent d2f9c50930
commit b913772007
2 changed files with 48 additions and 4 deletions
@@ -66,8 +66,10 @@ conditions:
- condition: template
value_template: "{{ send_report | bool }}"
# Skip an all-clear day unless the household opted into
# send-even-when-clear: the guard is false when no present child
# has any quests remaining today.
# send-even-when-clear: the guard is false only when every present
# child has a usable remaining count of zero. A MISSING or
# non-numeric remaining sensor reads as -1 and counts as open —
# a degraded state must reach the parent, not look like all-clear.
- condition: template
value_template: |
{%- set ns = namespace(any_open=false) -%}
@@ -79,7 +81,7 @@ conditions:
| selectattr('attributes.child_id', 'eq', due.attributes.child_id)
| map(attribute='state')
| list -%}
{%- if remaining_values and (remaining_values | first | int) > 0 -%}
{%- if not remaining_values or (remaining_values | first | int(-1)) != 0 -%}
{%- set ns.any_open = true -%}
{%- endif -%}
{%- endif -%}
+42
View File
@@ -294,3 +294,45 @@ def test_end_of_day_report_never_hard_codes_notify_target() -> None:
"the input description should show a placeholder example"
)
assert single_action(bp)["action"] == BlueprintInput("notify_target")
def test_end_of_day_report_guard_true_when_remaining_unavailable() -> None:
"""A present child whose remaining sensor is missing or reads
'unavailable' must NOT look like all-clear: the degraded state
reaches the parent (Codex review regression)."""
states = make_states(
sensors=[
TemplateState(
"sensor.nestquest_alice_quests_due_today",
"3",
{"child_name": "Alice", "child_id": 1, "present": True},
),
TemplateState(
"sensor.nestquest_alice_quests_remaining_today",
"unavailable",
{"child_id": 1},
),
],
)
rendered = render(
clear_guard(end_of_day_report()),
states=states,
send_even_when_clear=False,
)
assert rendered.strip() == "True"
# A missing remaining sensor entirely: also report-worthy.
states_missing = make_states(
sensors=[
TemplateState(
"sensor.nestquest_alice_quests_due_today",
"3",
{"child_name": "Alice", "child_id": 1, "present": True},
),
],
)
rendered_missing = render(
clear_guard(end_of_day_report()),
states=states_missing,
send_even_when_clear=False,
)
assert rendered_missing.strip() == "True"