feat(home-assistant): voice can lock the front door, never unlock it - #1795
Conversation
|
Claude finished @johnae's task —— View job Review: voice can lock the front door, never unlock it
Nice change overall — removing the lock from the tool surface and replacing it with a lock‑only script plus a human‑readable status sensor is the right shape, and the reasoning is captured in comments and docs where it belongs. Notes below, roughly in order of how much they matter. Nothing here is a blocker; no Correctness1. The door contact is trusted only when it says If that binary sensor is {% set door = states('binary_sensor.192_168_20_143_door_sensor') %}
{% if door == 'on' %}öppen
{% elif door != 'off' %}{{ 'låst' if lock == 'locked' else 'olåst' }}, vet inte om den är stängd
{% elif lock == 'locked' %}stängd och låst
...An 2. The contact's entity id is DHCP-derived — If the Nuki ever gets a different lease or re-announces itself over MQTT discovery, that entity id changes, the template silently falls into case 1 above, and nothing fails loudly. Worth renaming the entity in the registry to something stable ( 3. The script reports success even when the lock never locked —
{variables.svar = "{{ {'ytterdörren': states('sensor.ytterdorren'), 'låst': is_state('lock.varmdogatan', 'locked')} }}";}(Locking a door that is standing open is exactly the case where Nuki jams, and that's a realistic voice request.) 4. Small timing dependency: 5. The exposure question (the actual safety boundary)The guarantee "voice cannot unlock" lives entirely in Also worth a sentence in the doc on what "not exposed" means here: the lock is still fully reachable from the HA UI, the app and automations — this is a voice-surface restriction, not a permission. The HA patch
Minor
TestsThe manual matrix in the description (12/12 status, 10/10 regressions, refusals never actuating the lock) is the right kind of evidence for this, and stating that locking itself was untested by voice is honest. The branches that are hard to reach naturally — |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XfYTVcQVjCevVeoJofu8FF
d614eb8 to
4cc5f1b
Compare
|
Claude finished @johnae's task —— View job Review: voice can lock the front door, never unlock it
The shape of this is right: take the lock off the tool surface, hand voice a one-way script, and give the model words instead of Correctness1. The door contact is only trusted when it says {% if is_state('binary_sensor.192_168_20_143_door_sensor', 'on') %}öppen
{% elif lock == 'locked' %}stängd och låst
{% set door = states('binary_sensor.192_168_20_143_door_sensor') %}
{% if door == 'on' %}öppen
{% elif door != 'off' %}{{ 'låst' if lock == 'locked' else 'olåst' }}, vet inte om den är stängd
{% elif lock == 'locked' %}stängd och låst2. An open door hides the lock state entirely — When the contact is {variables.svar = "{{ {'ytterdörren': states('sensor.ytterdorren'), 'låst': is_state('lock.varmdogatan', 'locked')} }}";}
3. The contact's entity id is DHCP-derived — A new lease or a re-announced MQTT discovery renames that entity, the template silently falls into case 1, and nothing fails loudly. Renaming it in the registry to something stable ( 4. 20 s of wait inside a voice tool call — The wait happens while the pipeline holds the turn, so a slow or jammed lock means a long silence before the reply. Nuki locks in a few seconds; ~8 s would still cover the normal case and fail faster. Correction to my earlier review: I wrote that a retry during the wait "raises already running and hands the LLM an error". That was wrong — 5. Small ordering assumption: The exposure boundaryThe "voice cannot unlock" guarantee lives entirely in One prompt gap: the prompt ( The HA patch
Minor
TestsThe manual matrix (12/12 status, 10/10 regressions, refusals never actuating the lock) is the right evidence for a change like this, and saying plainly that locking was not tested by voice is honest. The states that are hard to reach naturally — View job • branch |
With
lock.varmdogatanexposed to Assist, voice could unlock the front door.Voice doesn't identify the speaker: a guest, someone outside a window, or a
video on the TV counts as the user. "Lås" is also one misheard word away from
"lås upp". Locking from anywhere is worth keeping, so:
unlatch buttons were not exposed before this change either.
Lås ytterdörrenis a new script that only callslock.lock, thenreports the resulting state.
sensor.ytterdorrenreports one of "öppen", "stängd men olåst" or"stängd och låst". It combines the lock state with the door contact sensor.
With the contact sensor's raw
off, the model had answered that the doorwas open. The raw sensor is now hidden.
nameandarea. Gemma writes"name": ["Ytterdörren"], copying the listform that
domainallows. Validation then fails, and the model repeats thecall until it gives up with no answer. A prompt rule against it did not
help. The patch uses
overrideAttrs, becauseoverridePythonAttrsdropsthe
.overridethat the NixOS module relies on.Tested with the kitchen Voice PE's device context, checking the lock state
after every request:
app or the keypad, and the lock was never actuated.
where the previous version answered "står öppen" to a locked door.
patched build.
Locking itself was not tested by voice, since that would turn the lock.
🤖 Generated with Claude Code
https://claude.ai/code/session_01XfYTVcQVjCevVeoJofu8FF