UX-08 2c: short refusals, error texts and option texts
Validator refusals name the setting by its label and key, say what is wrong and what to change, and keep the rejected value and limit. Option names and descriptions are short in en and nl; citations moved to DOCS "For installers" and the test_translations citation check now pins the instruction on the tab and the record in DOCS. No rule, key, schema, default or exit code changed. Allowlist 167 -> 43 (log lines only). 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
e1d0970b23
commit
2c516a032c
@@ -1629,7 +1629,7 @@ check("⚠️ AC 5: two inverters naming the SAME setpoint_entity are REFUSED. "
|
||||
"life of this add-on because the schema had exactly one such key; this "
|
||||
"is the first configuration in which it is expressible, and it is the "
|
||||
"first time that guarantee has had to be a check",
|
||||
_why(_p_same, "one actuator") and _why(_p_same, "number.sp_a"))
|
||||
_why(_p_same, "point at the same inverter entity") and _why(_p_same, "number.sp_a"))
|
||||
check("...and case-folded, so the hazard cannot be smuggled past on "
|
||||
"NUMBER.SP_A versus number.sp_a - which is exactly how it would be "
|
||||
"written by someone copying an entity id out of the HA UI",
|
||||
@@ -1653,7 +1653,7 @@ check("a flat setpoint_entity left set BESIDE a declared roster is refused. It "
|
||||
"names an actuator the roster does not, so nothing would ever write it - "
|
||||
"a site running quietly smaller than its own configuration, which is the "
|
||||
"'silently a different config' outcome this card ranks below a refusal",
|
||||
_why(_p_flat, "AND an inverters list"))
|
||||
_why(_p_flat, "but the “Inverter list” (inverters) has"))
|
||||
_p_dup = validate_startup_config(_opts(setpoint_entity="", inverters=[
|
||||
dict(name="twin", setpoint_entity="number.sp_a", max_w=A_RATING),
|
||||
dict(name="twin", setpoint_entity="number.sp_b",
|
||||
@@ -1666,13 +1666,14 @@ for _what, _bad, _needle in (
|
||||
("with no name at all",
|
||||
dict(setpoint_entity="number.sp_b", max_w=3000), "has no name"),
|
||||
("this controller cannot command",
|
||||
dict(name="inverter-b", max_w=3000), "has no setpoint_entity"),
|
||||
dict(name="inverter-b", max_w=3000),
|
||||
"has no “Inverter setpoint entity” (setpoint_entity)"),
|
||||
("with no rating",
|
||||
dict(name="inverter-b", setpoint_entity="number.sp_b"),
|
||||
"no usable max_w"),
|
||||
"no usable “Inverter rating” (max_w)"),
|
||||
("whose rating is not a number",
|
||||
dict(name="inverter-b", setpoint_entity="number.sp_b", max_w="lots"),
|
||||
"no usable max_w")):
|
||||
"no usable “Inverter rating” (max_w)")):
|
||||
check(f"an entry {_what} is refused, and the refusal says which entry and "
|
||||
f"which key ({_needle!r}) rather than that something is wrong",
|
||||
_why(validate_startup_config(_opts(setpoint_entity="",
|
||||
@@ -1680,7 +1681,7 @@ for _what, _bad, _needle in (
|
||||
check("`inverters` that is not a list at all is refused with the shape it "
|
||||
"should have been, rather than crashing inside build_roster()",
|
||||
_why(validate_startup_config(_opts(inverters="number.sp_b")),
|
||||
"must be a\nLIST".replace("\n", " ")))
|
||||
"(inverters) is str 'number.sp_b', not a list"))
|
||||
|
||||
# --- the permissive readers INSIDE validate.py --------------------------------
|
||||
# ⚠️ RUN BOTH WAYS, WHICH IS MUTATION.md's RULE. A check that only asserts the
|
||||
@@ -1738,8 +1739,8 @@ check("the fixture actually desynchronises the two lists, or the two checks "
|
||||
check("⚠️ RULE 5 NAMES THE UNIT THE NUMBER CAME OFF. The weakest cap is "
|
||||
"inverter-c's 1000 W; it sits at caps index 1, and `_unit_label(opts, 1)` "
|
||||
"is inverter-B. The refusal says inverter-c",
|
||||
_why(_p_skew, "max_w (inverter-c) is 1000 W")
|
||||
and not _why(_p_skew, "max_w (inverter-b) is 1000 W"))
|
||||
_why(_p_skew, "(max_w) for inverter-c is 1000 W")
|
||||
and not _why(_p_skew, "(max_w) for inverter-b is 1000 W"))
|
||||
# ⚠️ MAINT-05 MOVED RULE 6's SUBJECT, AND THIS CHECK MOVED WITH IT. It used to
|
||||
# assert the refusal named inverter-b, because rule 6 graded the FIRST entry
|
||||
# with a usable cap - `Controller.maint_unit` was `inverters[0]` and the shaping
|
||||
@@ -1753,15 +1754,15 @@ check("⚠️ RULE 6 TOO, AND SINCE MAINT-05 IT IS THE WEAKEST PACK IT NAMES. "
|
||||
"inverter-c's 1000 W sits at caps index 1, and `_unit_label(opts, 1)` is "
|
||||
"inverter-B - so a caps index leaking into a roster index would say "
|
||||
"inverter-b here. The refusal says inverter-c, with inverter-c's number",
|
||||
_why(_p_skew, "maintenance_charge_w is 3000 W but max_w (inverter-c) is "
|
||||
"1000 W")
|
||||
and not _why(_p_skew, "maintenance_charge_w is 3000 W but max_w "
|
||||
"(inverter-b)"))
|
||||
_why(_p_skew, "(maintenance_charge_w) is 3000 W, but the “Inverter rating” (max_w) for "
|
||||
"inverter-c is 1000 W")
|
||||
and not _why(_p_skew, "(maintenance_charge_w) is 3000 W, but the “Inverter rating” (max_w) for "
|
||||
"inverter-b"))
|
||||
check("...and it is no longer graded against the FIRST usable cap at all, which "
|
||||
"is the behaviour change MAINT-05 makes here: inverter-b's 2000 W was the "
|
||||
"pre-card answer and appears nowhere in the maintenance refusal now",
|
||||
not _why(_p_skew, "maintenance_charge_w is 3000 W but max_w "
|
||||
"(inverter-b) is 2000 W"))
|
||||
not _why(_p_skew, "(maintenance_charge_w) is 3000 W, but the “Inverter rating” (max_w) for "
|
||||
"inverter-b is 2000 W"))
|
||||
check("...and the counterfactual, so this is not a check that would pass on a "
|
||||
"validator that named nothing: the OLD expressions still evaluate, on "
|
||||
"this same config, to the wrong names",
|
||||
@@ -1784,7 +1785,7 @@ check("⚠️ A READER THAT SILENTLY PINNED INVERTER #1, IN main.py. run_control
|
||||
"unit's max_w was graded against the device it is written to, and the "
|
||||
"skip was silent. The per-unit form catches B against B's own ESPHome",
|
||||
len(_p_rng) == 1 and _why(_p_rng, "inverter-b")
|
||||
and _why(_p_rng, "THE DEVICE WINS"))
|
||||
and _why(_p_rng, "Lower this inverter's rating to"))
|
||||
check("...and it says INVERTER-B, not 'the setpoint device' - a site with "
|
||||
"three inverters and one bad rating needs to be told which one",
|
||||
_why(_p_rng, "number.sp_b") and not _why(_p_rng, "inverter-a"))
|
||||
|
||||
Reference in New Issue
Block a user