Trello UX-09 (P2). Fixes from the UX-08 phase 2a post-merge test, plus the scope added by the 2b review.
1. Details link
Finding (from HA source, not guessed):
HA 2026.2 added the built-in app panel: core af83fa809a "Add app panel (#157554)", frontend #28245 "Add apps panel as built-in panel". Its add-on pages are /config/app/<slug>/documentation (src/panels/config/apps/ha-config-app-dashboard.ts).
HA 2026.5 stopped registering the hassio panel. homeassistant/components/hassio/__init__.py still has frontend_url_path="hassio" at tag 2026.4.0 and no longer has it from 2026.5.0 on. So /hassio/addon/<slug>/documentation is a 404 on 2026.5+ (TEST-23 saw this on 2026.9.1).
HA 2026.1 and older have only /hassio/addon/<slug>/....
/_my_redirect/supervisor_addon?addon=<slug> works on both, but it opens the Info tab: new → /config/app/<slug>/info (ha-panel-my.ts), old → /hassio/addon?addon= (hassio-my-redirect.ts, frontend 20260107.0). No path reaches the Documentation tab on both.
Fix: at start the add-on reads its slug (GET /addons/self/info) and the HA version (GET /info). Both are on the Supervisor's bypass list for an add-on's own token. It builds /config/app/<slug>/documentation, or /hassio/addon/... for HA < 2026.2. An unknown version gets the new path. The hostname is still the fallback for the slug, which fixes the TEST-23 case where the hostname was a container id. There are no heading anchors, so the line still names the section plainly. test_messages.py pins the full line, the version table and the fallbacks.
2. Shadow mode
output_clamp(), row_power_too_high() and peak_saturated() take shadow=. main.py passes self.shadow. test_messages.py covers both modes on the texts, and test_clamp.py covers both modes through check_output_clamp() and checks(). The id, severity and cadence are the same in both modes.
3. Term mapping (one term per concept)
Concept
Texts and DOCS say
Setting label (en)
who decides / what it does
the add-on / control (rows: Control: …)
– (was "controller")
peak_soc_floor
peak reserve
Peak reserve (%) (was "Peak guard will not discharge below (%)"; nl "Piekreserve (%)")
“Solar production entity” (was "single sensor setting")
Solar production entity (W) (was "PV …")
pv_entities
“Solar production entities, per inverter”
Solar production entities, per inverter (W)
pv_invert_entities
“Reversed-sign solar entities” (was "reversed-sign list")
Reversed-sign solar entities
meter_source
“Where the meter reading comes from” (was "meter source")
unchanged
meter_entity
“Grid power entity” (was "grid power sensor")
unchanged
discharge
draw the battery down / give power
–
failsafe latch
safety stop
–
"Controller" became "the add-on" (who decides) and "control" (what it does). The reader sees "the add-on" in HA, "start control" was already in use, and "controller" was easy to confuse with the control board. The glossary is in STYLE.md §4. Option descriptions are phase 2c and were not changed, so some still say "PV".
3b. Shouting
The shadow banner is now messages.banner_shadow(). The inverter link notes are now row_no_setpoint, row_not_controllable and row_commands_refused. All are sampled, so test_messages.py checks them. The liveness row colour now comes from is_live() instead of matching "NOT COMMANDABLE" in the text. The colours are the same as before.
Before / after
Power request too high (shadow): "The controller asked for 3 607 W, above the inverter rating, and sent 2 000 W instead. Control is still running. …" → "The add-on asked for 3 607 W, above the “Inverter rating” setting, and would have sent 2 000 W instead. Shadow mode is on, so the inverter stays at 0 W. This is a software fault, so please report it to your installer."
Battery is not keeping up: "The battery cannot give what the controller asks, which is normal for a moment but needs a check if it keeps happening." → "The battery does less than asked, which is normal briefly, but if this keeps happening, check that it is on and not empty or full."
Load too high for battery (live): "… This is not a fault: the load is bigger than the inverter." → "… This is not a fault: the load is more than the battery can supply." (In shadow mode: "The add-on would ask the battery for all it can give, … Shadow mode is on, so the battery gives nothing and this month's peak may rise. …")
Battery stopped limiting the peak: "Switch off large loads, or lower the peak reserve if the battery allows it. … normal home use can still discharge the battery below it, down to its cut-out level." → "Switch off large loads, or lower the peak reserve. … normal home use can still draw the battery below it, down to the battery cut-out level."
Shadow banner: "SHADOW MODE - the battery is NOT being controlled. … ⚠️ A FAILSAFE LATCH IS STILL UP (inverter-a sign watchdog) and it will still be up when shadow mode is turned off." → "Shadow mode, battery not controlled. A safety stop stays on, see below." (warn: "Shadow mode: the battery is not controlled. Inverters stay at 0 W.")
Inverter notes: "inverter-b: NOT COMMANDABLE - every write rejected for 45 s (limit 30 s)" → "inverter-b cannot be controlled. Every command was refused for 45 seconds, limit 30 seconds." and "inverter-b: NO SETPOINT ENTITY - this controller cannot command it, …" → "inverter-b: “Setpoint entity” is not set, so every inverter stays at 0 W"
Also: "Controller: last ran 2 seconds ago" → "Control: last ran 2 seconds ago"; "so add it to the reversed-sign list" → "add it to “Reversed-sign solar entities”"; "Peak guard: off, it needs a meter source instead of the grid power sensor" → "Peak guard: off, set “Where the meter reading comes from” to anything but off".
4. DOCS
"Notifications" and "Status page" are now written for home owners. Each ends in a "For installers" part, which holds the ids, the SAFETY cards, the option keys, integrator and capaciteitstarief. The notification headings are unchanged, so every Details line still finds its section.
5. Safety
No id, severity, colour, cadence or trigger changed. The latch names left the red shadow banner (12 words cannot carry them). Each latch still has its own red row, which names it and says how it clears, and test_clamp.py now pins that. The choices are recorded in DECISIONS/UX-08-short-notifications.md under "UX-09".
6. Allowlist
168 → 167: the pv_entities option name now fits 6 words. The cap equals the length.
Left for later (not in this card): the "Shadow mode" row of the values table (shadow.words(), "ON THIS CYCLE WOULD HAVE COMMANDED") and the SAFETY-37 stale note still shout. They are not on the ratchet.
Not deployed. The live link check is for the post-merge test on TEST-23 with a Supervisor-style hostname.
Trello UX-09 (P2). Fixes from the UX-08 phase 2a post-merge test, plus the scope added by the 2b review.
## 1. Details link
**Finding (from HA source, not guessed):**
- HA **2026.2** added the built-in `app` panel: core `af83fa809a` "Add app panel (#157554)", frontend #28245 "Add apps panel as built-in panel". Its add-on pages are `/config/app/<slug>/documentation` (`src/panels/config/apps/ha-config-app-dashboard.ts`).
- HA **2026.5** stopped registering the `hassio` panel. `homeassistant/components/hassio/__init__.py` still has `frontend_url_path="hassio"` at tag 2026.4.0 and no longer has it from 2026.5.0 on. So `/hassio/addon/<slug>/documentation` is a 404 on 2026.5+ (TEST-23 saw this on 2026.9.1).
- HA **2026.1 and older** have only `/hassio/addon/<slug>/...`.
- `/_my_redirect/supervisor_addon?addon=<slug>` works on both, but it opens the Info tab: new → `/config/app/<slug>/info` (ha-panel-my.ts), old → `/hassio/addon?addon=` (hassio-my-redirect.ts, frontend 20260107.0). No path reaches the Documentation tab on both.
**Fix:** at start the add-on reads its slug (`GET /addons/self/info`) and the HA version (`GET /info`). Both are on the Supervisor's bypass list for an add-on's own token. It builds `/config/app/<slug>/documentation`, or `/hassio/addon/...` for HA < 2026.2. An unknown version gets the new path. The hostname is still the fallback for the slug, which fixes the TEST-23 case where the hostname was a container id. There are no heading anchors, so the line still names the section plainly. `test_messages.py` pins the full line, the version table and the fallbacks.
## 2. Shadow mode
`output_clamp()`, `row_power_too_high()` and `peak_saturated()` take `shadow=`. `main.py` passes `self.shadow`. `test_messages.py` covers both modes on the texts, and `test_clamp.py` covers both modes through `check_output_clamp()` and `checks()`. The id, severity and cadence are the same in both modes.
## 3. Term mapping (one term per concept)
| Concept | Texts and DOCS say | Setting label (en) |
|---|---|---|
| who decides / what it does | the add-on / control (rows: `Control: …`) | – (was "controller") |
| `peak_soc_floor` | peak reserve | **Peak reserve (%)** (was "Peak guard will not discharge below (%)"; nl "Piekreserve (%)") |
| `bms_soc_floor` | battery cut-out level | Battery cut-out level (%) (unchanged) |
| `max_w` | “Inverter rating” setting | Inverter rating (W) (unchanged) |
| `soc_entity` | battery level / “Battery level entity” | **Battery level entity (%)** (was "Battery charge level …") |
| `pv_entity` | “Solar production entity” (was "single sensor setting") | **Solar production entity (W)** (was "PV …") |
| `pv_entities` | “Solar production entities, per inverter” | **Solar production entities, per inverter (W)** |
| `pv_invert_entities` | “Reversed-sign solar entities” (was "reversed-sign list") | **Reversed-sign solar entities** |
| `meter_source` | “Where the meter reading comes from” (was "meter source") | unchanged |
| `meter_entity` | “Grid power entity” (was "grid power sensor") | unchanged |
| discharge | draw the battery down / give power | – |
| failsafe latch | safety stop | – |
"Controller" became "the add-on" (who decides) and "control" (what it does). The reader sees "the add-on" in HA, "start control" was already in use, and "controller" was easy to confuse with the control board. The glossary is in STYLE.md §4. Option **descriptions** are phase 2c and were not changed, so some still say "PV".
## 3b. Shouting
The shadow banner is now `messages.banner_shadow()`. The inverter link notes are now `row_no_setpoint`, `row_not_controllable` and `row_commands_refused`. All are sampled, so `test_messages.py` checks them. The liveness row colour now comes from `is_live()` instead of matching "NOT COMMANDABLE" in the text. The colours are the same as before.
## Before / after
1. **Power request too high (shadow):** "The controller asked for 3 607 W, above the inverter rating, and sent 2 000 W instead. Control is still running. …" → "The add-on asked for 3 607 W, above the “Inverter rating” setting, and would have sent 2 000 W instead. Shadow mode is on, so the inverter stays at 0 W. This is a software fault, so please report it to your installer."
2. **Battery is not keeping up:** "The battery cannot give what the controller asks, which is normal for a moment but needs a check if it keeps happening." → "The battery does less than asked, which is normal briefly, but if this keeps happening, check that it is on and not empty or full."
3. **Load too high for battery (live):** "… This is not a fault: the load is bigger than the inverter." → "… This is not a fault: the load is more than the battery can supply." (In shadow mode: "The add-on would ask the battery for all it can give, … Shadow mode is on, so the battery gives nothing and this month's peak may rise. …")
4. **Battery stopped limiting the peak:** "Switch off large loads, or lower the peak reserve if the battery allows it. … normal home use can still discharge the battery below it, down to its cut-out level." → "Switch off large loads, or lower the peak reserve. … normal home use can still draw the battery below it, down to the battery cut-out level."
5. **Shadow banner:** "SHADOW MODE - the battery is NOT being controlled. … ⚠️ A FAILSAFE LATCH IS STILL UP (inverter-a sign watchdog) and it will still be up when shadow mode is turned off." → "Shadow mode, battery not controlled. A safety stop stays on, see below." (warn: "Shadow mode: the battery is not controlled. Inverters stay at 0 W.")
6. **Inverter notes:** "inverter-b: NOT COMMANDABLE - every write rejected for 45 s (limit 30 s)" → "inverter-b cannot be controlled. Every command was refused for 45 seconds, limit 30 seconds." and "inverter-b: NO SETPOINT ENTITY - this controller cannot command it, …" → "inverter-b: “Setpoint entity” is not set, so every inverter stays at 0 W"
Also: "Controller: last ran 2 seconds ago" → "Control: last ran 2 seconds ago"; "so add it to the reversed-sign list" → "add it to “Reversed-sign solar entities”"; "Peak guard: off, it needs a meter source instead of the grid power sensor" → "Peak guard: off, set “Where the meter reading comes from” to anything but off".
## 4. DOCS
"Notifications" and "Status page" are now written for home owners. Each ends in a "For installers" part, which holds the ids, the SAFETY cards, the option keys, integrator and capaciteitstarief. The notification headings are unchanged, so every Details line still finds its section.
## 5. Safety
No id, severity, colour, cadence or trigger changed. The latch names left the red shadow banner (12 words cannot carry them). Each latch still has its own red row, which names it and says how it clears, and `test_clamp.py` now pins that. The choices are recorded in `DECISIONS/UX-08-short-notifications.md` under "UX-09".
## 6. Allowlist
168 → 167: the `pv_entities` option name now fits 6 words. The cap equals the length.
**Left for later (not in this card):** the "Shadow mode" row of the values table (`shadow.words()`, "ON THIS CYCLE WOULD HAVE COMMANDED") and the SAFETY-37 stale note still shout. They are not on the ratchet.
Not deployed. The live link check is for the post-merge test on TEST-23 with a Supervisor-style hostname.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p
- Details link: /config/app/<slug>/documentation on HA 2026.2+ (the old
/hassio/addon path is a 404 from 2026.5), /hassio/addon on 2026.1 and
older. Slug from GET /addons/self/info, version from GET /info, hostname
as fallback.
- Shadow mode: the over-rating alarm and row say what would have been sent,
the peak alarm no longer says the battery is giving all it can.
- "controller" -> "the add-on" / "control". Settings named by their labels;
four labels changed to match (Peak reserve, Battery level entity, Solar
production ..., Reversed-sign solar entities).
- Shadow banner and inverter link notes moved to messages.py and checked.
- DOCS Notifications and Status page rewritten for home owners, with a
"For installers" part each. Allowlist 168 -> 167.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p
Startup calls: one blocking point. The rest checks out. /addons/self/info and /info are on the Supervisor's api_bypass for the add-on's own token (see selfconfig.py header; config.yaml also sets hassio_api: true). Any failure is caught and logged at INFO, and the path falls back to the hostname. A shim 404 (non-JSON body, or a JSON error body without data) gives None. But the two calls run one after the other with timeout=10 each, awaited before the startup gate. A hung Supervisor delays control start by up to 20 s. Fix: ask both together with a 3 s budget, pinned by a test.
Labels: keys and schema are unchanged, and there is no fr.yaml. en/nl are consistent and test_translations passes. No old label text is left in the code, DOCS or UI. "Peak reserve" is consistent. OK.
Shadow: every "sent" path (output_clamp in all three shapes, row_power_too_high) and peak_saturated have a shadow variant, and tests cover both modes. Gap: in shadow mode only the per-inverter direction latch is pinned to keep its own red row. shadow_latches() also names the circulating and site-direction latches. Fix: add shadow checks for both to test_watchdog.py.
Readability:
row_not_controllable says "…refused for 45 s, limit 30 s." "Limit 30 s" is terse jargon for a home owner. Proposed: "It refused every command for 45 s, so control leaves it out."
loop_bound says "does less than asked, which is normal briefly". Proposed: "The battery gives less than asked, which is normal for a moment, but if it lasts, check it is on and not empty or full." (≤25 words.)
The red shadow banner opens with "Shadow mode," but the amber one opens with "Shadow mode:". Make them the same.
Safety: ids, severities, cadence and triggers are unchanged against release/1.0. The main.py diff touches only payloads and the liveness colour. is_live() is False only in the reject-past-limit branch that printed "NOT COMMANDABLE", so red/amber is unchanged. OK.
DOCS: the home-owner parts are plain and free of card ids. Keys and SAFETY-nn are only under "For installers". OK.
2026.2 cutoff: spot-checked. core #157554 "Add app panel" and frontend #28245 "Add apps panel as built-in panel" were both merged on 2026-01-19, so they ship in 2026.2. OK.
I'm pushing the fixes for 1, 3 and 4.
**Review (UX-09), head 00e3ee9**
1. **Startup calls: one blocking point.** The rest checks out. `/addons/self/info` and `/info` are on the Supervisor's `api_bypass` for the add-on's own token (see selfconfig.py header; `config.yaml` also sets `hassio_api: true`). Any failure is caught and logged at INFO, and the path falls back to the hostname. A shim 404 (non-JSON body, or a JSON error body without `data`) gives None. But the two calls run **one after the other with `timeout=10` each, awaited before the startup gate**. A hung Supervisor delays control start by up to 20 s. **Fix:** ask both together with a 3 s budget, pinned by a test.
2. **Labels:** keys and schema are unchanged, and there is no fr.yaml. en/nl are consistent and test_translations passes. No old label text is left in the code, DOCS or UI. "Peak reserve" is consistent. OK.
3. **Shadow:** every "sent" path (`output_clamp` in all three shapes, `row_power_too_high`) and `peak_saturated` have a shadow variant, and tests cover both modes. **Gap:** in shadow mode only the per-inverter direction latch is pinned to keep its own red row. `shadow_latches()` also names the circulating and site-direction latches. **Fix:** add shadow checks for both to test_watchdog.py.
4. **Readability:**
- `row_not_controllable` says "…refused for 45 s, limit 30 s." "Limit 30 s" is terse jargon for a home owner. Proposed: "It refused every command for 45 s, so control leaves it out."
- `loop_bound` says "does less than asked, which is normal briefly". Proposed: "The battery gives less than asked, which is normal for a moment, but if it lasts, check it is on and not empty or full." (≤25 words.)
- The red shadow banner opens with "Shadow mode," but the amber one opens with "Shadow mode:". Make them the same.
5. **Safety:** ids, severities, cadence and triggers are unchanged against release/1.0. The main.py diff touches only payloads and the liveness colour. `is_live()` is False only in the reject-past-limit branch that printed "NOT COMMANDABLE", so red/amber is unchanged. OK.
6. **DOCS:** the home-owner parts are plain and free of card ids. Keys and SAFETY-nn are only under "For installers". OK.
7. **2026.2 cutoff:** spot-checked. core #157554 "Add app panel" and frontend #28245 "Add apps panel as built-in panel" were both merged on 2026-01-19, so they ship in 2026.2. OK.
I'm pushing the fixes for 1, 3 and 4.
The Supervisor questions for the Details link are asked together with a
3 s budget instead of one after the other at 10 s each, so a hung
Supervisor cannot hold control start for 20 s. In shadow mode the
circulating and site-direction latches are pinned to keep their own red
row that says how they clear. Plainer inverter and battery wording.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review fixes pushed: 63dee6d (verified with ls-remote)
docs_link_facts() now asks both questions together with asyncio.gather, each with DOCS_LINK_TIMEOUT_S = 3, so the worst case is about 3 s instead of 20 s. It still fails quietly at INFO. test_messages pins the timeout at ≤ 3 s.
test_watchdog.py: in shadow mode the circulating latch and the site-direction latch each turn the banner red with "safety stop". Their own red row stays and says "Only starting control clears this". The per-inverter direction latch was already pinned in test_clamp.py.
row_not_controllable now reads "name cannot be controlled. It refused every command for 45 s, so control leaves it out." loop_bound now reads "The battery gives less than asked, which is normal for a moment, but if it lasts, check it is on and not empty or full."
The red shadow banner now starts with "Shadow mode:", like the amber one.
The full suite passes locally (36 files, without hwsim). Waiting for CI.
**Review fixes pushed: 63dee6d** (verified with ls-remote)
1. `docs_link_facts()` now asks both questions together with `asyncio.gather`, each with `DOCS_LINK_TIMEOUT_S = 3`, so the worst case is about 3 s instead of 20 s. It still fails quietly at INFO. test_messages pins the timeout at ≤ 3 s.
3. test_watchdog.py: in shadow mode the circulating latch and the site-direction latch each turn the banner red with "safety stop". Their own red row stays and says "Only starting control clears this". The per-inverter direction latch was already pinned in test_clamp.py.
4. `row_not_controllable` now reads "*name* cannot be controlled. It refused every command for 45 s, so control leaves it out."
`loop_bound` now reads "The battery gives less than asked, which is normal for a moment, but if it lasts, check it is on and not empty or full."
The red shadow banner now starts with "Shadow mode:", like the amber one.
The full suite passes locally (36 files, without hwsim). Waiting for CI.
admin
merged commit e1d0970b23 into release/1.02026-09-27 04:54:42 +02:00
All points fixed. CI was green on 63dee6d (checks/unit and infra-pin). Merged with head_commit_id pinned. release/1.0 is now e1d0970 (verified with ls-remote), and the post-merge infra-pin / fresh is green. Follow-up for the TEST-23 re-test: check the link with a Supervisor-style hostname and with the shim's /addons/self/info.
All points fixed. CI was green on 63dee6d (checks/unit and infra-pin). Merged with head_commit_id pinned. release/1.0 is now e1d0970 (verified with ls-remote), and the post-merge infra-pin / fresh is green. Follow-up for the TEST-23 re-test: check the link with a Supervisor-style hostname and with the shim's /addons/self/info.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Trello UX-09 (P2). Fixes from the UX-08 phase 2a post-merge test, plus the scope added by the 2b review.
1. Details link
Finding (from HA source, not guessed):
apppanel: coreaf83fa809a"Add app panel (#157554)", frontend #28245 "Add apps panel as built-in panel". Its add-on pages are/config/app/<slug>/documentation(src/panels/config/apps/ha-config-app-dashboard.ts).hassiopanel.homeassistant/components/hassio/__init__.pystill hasfrontend_url_path="hassio"at tag 2026.4.0 and no longer has it from 2026.5.0 on. So/hassio/addon/<slug>/documentationis a 404 on 2026.5+ (TEST-23 saw this on 2026.9.1)./hassio/addon/<slug>/..../_my_redirect/supervisor_addon?addon=<slug>works on both, but it opens the Info tab: new →/config/app/<slug>/info(ha-panel-my.ts), old →/hassio/addon?addon=(hassio-my-redirect.ts, frontend 20260107.0). No path reaches the Documentation tab on both.Fix: at start the add-on reads its slug (
GET /addons/self/info) and the HA version (GET /info). Both are on the Supervisor's bypass list for an add-on's own token. It builds/config/app/<slug>/documentation, or/hassio/addon/...for HA < 2026.2. An unknown version gets the new path. The hostname is still the fallback for the slug, which fixes the TEST-23 case where the hostname was a container id. There are no heading anchors, so the line still names the section plainly.test_messages.pypins the full line, the version table and the fallbacks.2. Shadow mode
output_clamp(),row_power_too_high()andpeak_saturated()takeshadow=.main.pypassesself.shadow.test_messages.pycovers both modes on the texts, andtest_clamp.pycovers both modes throughcheck_output_clamp()andchecks(). The id, severity and cadence are the same in both modes.3. Term mapping (one term per concept)
Control: …)peak_soc_floorbms_soc_floormax_wsoc_entitypv_entitypv_entitiespv_invert_entitiesmeter_sourcemeter_entity"Controller" became "the add-on" (who decides) and "control" (what it does). The reader sees "the add-on" in HA, "start control" was already in use, and "controller" was easy to confuse with the control board. The glossary is in STYLE.md §4. Option descriptions are phase 2c and were not changed, so some still say "PV".
3b. Shouting
The shadow banner is now
messages.banner_shadow(). The inverter link notes are nowrow_no_setpoint,row_not_controllableandrow_commands_refused. All are sampled, sotest_messages.pychecks them. The liveness row colour now comes fromis_live()instead of matching "NOT COMMANDABLE" in the text. The colours are the same as before.Before / after
Also: "Controller: last ran 2 seconds ago" → "Control: last ran 2 seconds ago"; "so add it to the reversed-sign list" → "add it to “Reversed-sign solar entities”"; "Peak guard: off, it needs a meter source instead of the grid power sensor" → "Peak guard: off, set “Where the meter reading comes from” to anything but off".
4. DOCS
"Notifications" and "Status page" are now written for home owners. Each ends in a "For installers" part, which holds the ids, the SAFETY cards, the option keys, integrator and capaciteitstarief. The notification headings are unchanged, so every Details line still finds its section.
5. Safety
No id, severity, colour, cadence or trigger changed. The latch names left the red shadow banner (12 words cannot carry them). Each latch still has its own red row, which names it and says how it clears, and
test_clamp.pynow pins that. The choices are recorded inDECISIONS/UX-08-short-notifications.mdunder "UX-09".6. Allowlist
168 → 167: the
pv_entitiesoption name now fits 6 words. The cap equals the length.Left for later (not in this card): the "Shadow mode" row of the values table (
shadow.words(), "ON THIS CYCLE WOULD HAVE COMMANDED") and the SAFETY-37 stale note still shout. They are not on the ratchet.Not deployed. The live link check is for the post-merge test on TEST-23 with a Supervisor-style hostname.
🤖 Generated with Claude Code
https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p
Review (UX-09), head
00e3ee9/addons/self/infoand/infoare on the Supervisor'sapi_bypassfor the add-on's own token (see selfconfig.py header;config.yamlalso setshassio_api: true). Any failure is caught and logged at INFO, and the path falls back to the hostname. A shim 404 (non-JSON body, or a JSON error body withoutdata) gives None. But the two calls run one after the other withtimeout=10each, awaited before the startup gate. A hung Supervisor delays control start by up to 20 s. Fix: ask both together with a 3 s budget, pinned by a test.output_clampin all three shapes,row_power_too_high) andpeak_saturatedhave a shadow variant, and tests cover both modes. Gap: in shadow mode only the per-inverter direction latch is pinned to keep its own red row.shadow_latches()also names the circulating and site-direction latches. Fix: add shadow checks for both to test_watchdog.py.row_not_controllablesays "…refused for 45 s, limit 30 s." "Limit 30 s" is terse jargon for a home owner. Proposed: "It refused every command for 45 s, so control leaves it out."loop_boundsays "does less than asked, which is normal briefly". Proposed: "The battery gives less than asked, which is normal for a moment, but if it lasts, check it is on and not empty or full." (≤25 words.)is_live()is False only in the reject-past-limit branch that printed "NOT COMMANDABLE", so red/amber is unchanged. OK.I'm pushing the fixes for 1, 3 and 4.
Review fixes pushed:
63dee6d(verified with ls-remote)docs_link_facts()now asks both questions together withasyncio.gather, each withDOCS_LINK_TIMEOUT_S = 3, so the worst case is about 3 s instead of 20 s. It still fails quietly at INFO. test_messages pins the timeout at ≤ 3 s.row_not_controllablenow reads "name cannot be controlled. It refused every command for 45 s, so control leaves it out."loop_boundnow reads "The battery gives less than asked, which is normal for a moment, but if it lasts, check it is on and not empty or full."The red shadow banner now starts with "Shadow mode:", like the amber one.
The full suite passes locally (36 files, without hwsim). Waiting for CI.
All points fixed. CI was green on
63dee6d(checks/unit and infra-pin). Merged with head_commit_id pinned. release/1.0 is nowe1d0970(verified with ls-remote), and the post-merge infra-pin / fresh is green. Follow-up for the TEST-23 re-test: check the link with a Supervisor-style hostname and with the shim's /addons/self/info.