UX-08 phase 2a: short, plain notifications, and a ratchet for the rest
Every HA notification the add-on raises now has a title of at most 5 everyday words and a one-sentence body; a red alarm may use three so no action is lost. The texts live in app/messages.py, the rule in STYLE.md, and the detail that moved out in DOCS.md "Notifications", which each body links to. No notification_id, trigger or cadence changed. test_messages.py enforces the rule on every notification, fails any notification worded outside app/messages.py, and ratchets the kinds not yet rewritten (rows, banners, refusals, logs, options) through a shrinking allowlist of 200. Six tests re-pinned from prose to meaning. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
2503de124e
commit
50ccea3dd7
@@ -85,6 +85,7 @@ from pathlib import Path
|
||||
|
||||
import aiohttp
|
||||
|
||||
from app import messages
|
||||
from app.control import Tuning, compute
|
||||
from app.freeze import (
|
||||
RAIL_FRAC, FreezeWatchdog, FreezeWatchdogConfig, looks_frozen,
|
||||
@@ -773,7 +774,7 @@ def _is_freeze_note(d):
|
||||
calls itself frozen, which would be a confusable alarm on its own account.
|
||||
"""
|
||||
return (d.get("notification_id") == FREEZE_NOTE_ID
|
||||
or "frozen" in str(d.get("title", "")).lower())
|
||||
or d.get("title") == messages.T_METER_FROZEN)
|
||||
|
||||
|
||||
def notes_of(hass):
|
||||
@@ -788,7 +789,7 @@ def notes_by_text_of(hass):
|
||||
both would be true by construction.
|
||||
"""
|
||||
return [d for d in all_notes_of(hass)
|
||||
if "frozen" in str(d.get("title", "")).lower()]
|
||||
if d.get("title") == messages.T_METER_FROZEN]
|
||||
|
||||
|
||||
def wired(unchanged_s, grid, cycles=60, dev=(-5000.0, 5000.0), **over):
|
||||
@@ -858,7 +859,7 @@ check("...with a fixed notification_id so repeats replace, not stack",
|
||||
[d.get("notification_id") for d in notes_by_text_of(hass_f)]
|
||||
== [FREEZE_NOTE_ID])
|
||||
check("...and it says the controller is still running",
|
||||
bool(notes) and "STILL RUNNING" in notes[0]["message"])
|
||||
bool(notes) and "Control is still running" in notes[0]["message"])
|
||||
check("the status page carries a failed row saying so",
|
||||
len(frozen_rows) == 1 and not frozen_rows[0]["ok"] and not frozen_rows[0]["warn"])
|
||||
check("the event log names it", any("METER FROZEN" in e for e in ctl_f.events))
|
||||
@@ -1180,11 +1181,16 @@ check("...and at or above the device rail, which is why it must",
|
||||
check("THE ALARM FIRES through the real cycle() - the rating reaches the "
|
||||
"predicate from the controller, not just from a unit call",
|
||||
len(_n20) == 1 and _c20.freeze_wd.active)
|
||||
check("...and the notification the operator gets quotes the capped rail, "
|
||||
"not the max_w one",
|
||||
# UX-08: the notification no longer quotes a rail at all (the reader's action
|
||||
# is "check the meter"), so it cannot quote the wrong one; the capped rail is
|
||||
# still what the reason - the log line and the status row - carries.
|
||||
check("...and the notification the operator gets names no max_w rail, and the "
|
||||
"reason behind it quotes the capped rail",
|
||||
bool(_n20)
|
||||
and f"{rail_w(LIVE_INSTALL_MAX_W):.0f} W"
|
||||
not in str(_n20[0].get("message", ""))
|
||||
and f"{rail_w(LIVE_INSTALL_MAX_W, dev_min=-4700.0, dev_max=4700.0):.0f} W"
|
||||
in str(_n20[0].get("message", "")))
|
||||
in _c20.freeze_wd.reason)
|
||||
# p1_enabled is what a homewizard_local install has - set by hand here for the
|
||||
# same reason part 4 sets it, see freeze_rows().
|
||||
_c20.p1_enabled = True
|
||||
|
||||
Reference in New Issue
Block a user