Skip to content

fix(homeassistant): notify every concurrent wait - #62

Merged
pedropombeiro merged 1 commit into
mainfrom
fix/notify-every-concurrent-wait
Aug 19, 2026
Merged

pedropombeiro merged 1 commit into
mainfrom
fix/notify-every-concurrent-wait

Conversation

@pedropombeiro

Copy link
Copy Markdown
Owner

Problem

Two curl permission requests arrived in quick succession, but only one notification was delivered. The one that arrived was approved correctly.

Not a delivery fault this time — the tracker never announced the second request.

Root cause

wait() suppressed onWaiting whenever the session was already waiting:

const wasWaiting = states.get(sessionID) === 'waiting';
states.set(sessionID, 'waiting');
if (!wasWaiting) await options.onWaiting?.(sessionID, detail);

So with per_A and per_B in flight, per_B got a tracked wait but no onWaiting — no webhook, no notification, no poll. Reproduced:

onBusy | onWaiting per_A | replied per_A
onWaiting events: [ "onWaiting per_A" ]

Worse than reported: per_B was never announced even after per_A was approved, since nothing re-announces pending waits. It stayed unanswerable until it timed out or was answered in the TUI.

The guard came from #44 to stop terminal plugins re-firing. Both current consumers are already idempotent, so it is not needed: tmux-indicator returns early when active, and terminal-progress writes an unchanged OSC sequence.

Fix

Fire onWaiting for each distinct wait. Dedupe by request ID (waits.has(id)) still applies.

Verification

Two distinct permissions now both notify:

onBusy | onWaiting per_A | onWaiting per_B | onBusy

Preserved invariants:

  • duplicate permission.asked for the same ID → 1 onWaiting
  • replying to per_A only → session stays waiting (per_B still pending)
  • replying to both → resumes exactly once

Real plugin, both permissions dispatched concurrently — no starvation despite onWaiting blocking for the poll duration:

HOOK +0.0s waiting id=per_A
HOOK +0.0s waiting id=per_B
REPLY +2.0s -> per_A {"response":"once"}

Both webhooks fire immediately and both polls run concurrently.

Regression suites all pass: the five tracker scenarios (including the single-webhook guarantee for tool questions), receiver, negative-path, webhook-failure, entity-read and config harnesses. terminal-progress emits the correct OSC sequence and tmux-indicator still sets/clears its flag exactly once. mise run typecheck, lint, build pass.

Note

Independent of the 0.7.5 webhook-delivery work. This one explains a missing notification when the webhook itself succeeded.

Two permission requests in quick succession produced only one
notification. The tracker suppressed onWaiting whenever the session was
already waiting, so the second request was tracked but never announced,
and the plugin never polled for it. It stayed unanswerable even after the
first was approved, because nothing announced it later either.

onWaiting now fires for each distinct wait. Deduplication by request ID
still applies, so a repeated event for the same ID notifies once, and the
session still resumes only when every wait has cleared.

Both other consumers are already idempotent: tmux-indicator returns early
when active, and terminal-progress writes an unchanged escape sequence.
@pedropombeiro
pedropombeiro merged commit 94f47d8 into main Aug 19, 2026
2 checks passed
@pedropombeiro
pedropombeiro deleted the fix/notify-every-concurrent-wait branch August 19, 2026 09:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant