Completion Notifications: last_active_session_key routing (Issue #603)
Execution brief
- Goal (SMART): Persist
last_active_session_keyper(tenant_id, agent_id, workspace_id)and, when a WorkItem transitions todone|blocked|failed, emit the corresponding WorkBoard WS event and enqueue an outbound completion notification routed to the last active session key (fallbackcreated_from_session_key), with idempotent delivery. - Non-goals: Full presence-based routing, multi-connector rollout beyond existing channel plumbing, new UI surfaces; changing auth defaults or existing policy semantics.
- Constraints: Node 24 / pnpm workspace; strict TypeScript + ESM
.jsimport specifiers; channel sends must remain policy/approval gated and deduped. - Plan: (1) Add unit tests for routing + idempotency. (2) Implement a small WorkBoard notifier that resolves the route from durable state and enqueues a single channel outbox message with a stable dedupe key, honoring policy + approvals. (3) Update Telegram inbound to upsert
work_scope_activity. (4) Addwork.item.failedWS event and emit it on failed transitions. (5) Runpnpm test && pnpm typecheck && pnpm lint. - Risks & rollback: Risk of misrouting when no durable channel route exists; mitigate by only sending when a recent
channel_inboxrow exists for the resolved session key. Roll back by reverting the notifier + schema changes.
Design
Durable last-active routing
- Source of truth for last-active is the WorkBoard persistence table
work_scope_activity:- Primary key:
(tenant_id, agent_id, workspace_id) - Values:
last_active_session_key,updated_at_ms
- Primary key:
- Update rule:
- On inbound interactive channel activity (Telegram): upsert
work_scope_activityfor the agent/workspace with the inbound session key used for that message.
- On inbound interactive channel activity (Telegram): upsert
Completion notification routing
When a WorkItem transitions to done|blocked|failed:
- Resolve
target_session_key:- Prefer
work_scope_activity.last_active_session_key - Fallback to
work_items.created_from_session_key
- Prefer
- Resolve a concrete channel destination (best-effort, durable):
- Look up the newest
channel_inboxrow forkey = target_session_key - If none exists, do not enqueue a channel send (Desktop WS clients still receive WorkBoard WS events).
- Look up the newest
- Enqueue one outbound message into
channel_outbox:inbox_id: from the resolvedchannel_inboxrow (for policy overrides + FK integrity)source/thread_id: from the resolvedchannel_inboxrowdedupe_key: stable per transition (e.g.work.notify:<work_item_id>:<status>:<updated_at>)chunk_index:0parse_mode: unset (plain text)
- Policy + approvals:
- Evaluate
PolicyService.evaluateConnectorActionfor the resolved connector/thread. - If
require_approval, create an approval and setapproval_idon the outbox row. - If
deny(and policy is enforcing), skip enqueue.
- Evaluate
WorkBoard WS events
- Continue emitting existing WorkBoard WS events for
blockedanddone. - Add explicit
work.item.failedWS event and emit it when a WorkItem transitions tofailed.