Files
kandev/docs/decisions/2026-07-24-semantic-notification-events.md
T

77 lines
3.7 KiB
Markdown

# Semantic notification events come from domain occurrences
**Status:** accepted
**Date:** 2026-07-24
**Area:** backend, frontend, desktop
## Context
The session lifecycle uses `WAITING_FOR_INPUT` for several operationally
different situations: startup readiness, the idle state after a normal turn,
and an actual clarification request. The notification service subscribed to
that state transition and translated every occurrence into “needs your input.”
Its once-per-session delivery key compounded the problem: a startup or ordinary
turn notification could consume the key before the agent asked a real question.
The product now exposes ordinary turn completion and explicit clarification as
independently selectable notification events. Their occurrence boundaries must
remain stable even if the orchestrator's lifecycle states change.
## Decision
User-facing notifications will be sourced from semantic domain events, not
inferred from generic session lifecycle state.
- `session.turn_finished` is derived from the durable completion of a specific
agent turn and uses the turn ID as its occurrence identity.
- `session.clarification_requested` is derived from Kandev's structured
agent-authored clarification-request message and uses the shared
pending/request ID as its occurrence identity. Task and session identity are
required.
- `system.update_available` is derived from the release poller's durable cached
version and uses the release version/tag as its occurrence identity. It is
install-wide and has no task or session identity.
- Notification idempotency is keyed by provider, semantic event type, and
occurrence identity. The task-session ID remains recorded for routing and
audit but is not the deduplication boundary.
- `session.waiting_for_input` is retired as an emitted notification event.
Existing subscriptions migrate to clarification requests only.
- Local WebSocket and desktop notifications preserve the semantic event type
and occurrence identity rather than collapsing both cases back into a
waiting-state action.
- New-release delivery uses the same provider subscriptions, delivery history,
and retry semantics as other notifications. It does not maintain a parallel
update-only preference or de-duplication store.
The user-visible contract is defined by
[Semantic Notifications](../specs/platform/notifications.md).
## Consequences
- Startup and ordinary idle transitions cannot claim that the agent needs an
answer.
- Users can opt into every completed turn without coupling that choice to
clarification alerts.
- More than one turn or clarification in a session can notify, while replaying
one domain occurrence remains idempotent.
- Notification persistence requires an occurrence identifier and a replayable
migration from the legacy session-scoped unique key.
- New notification-producing features must identify a semantic domain
occurrence and stable occurrence ID instead of subscribing to a convenient
lifecycle state.
## Alternatives Considered
1. **Keep `WAITING_FOR_INPUT` and inspect the previous state.** Rejected because
the same transition still represents both normal completion and
clarification, and lifecycle changes would silently alter user-facing
semantics.
2. **Rename the existing notification to “turn ended.”** Rejected because it
would still fail to distinguish an explicit question and would preserve the
once-per-session suppression bug.
3. **Send both messages from every waiting transition.** Rejected because it
would create notifications for events that did not happen and prevent users
from selecting the two intents independently.
4. **Deduplicate only in memory.** Rejected because replay and process restart
require durable idempotency.