What's new
- Assignment dropdown interactions in
/inboxnow stay visually stable while operator data refreshes in the background. - Operators can now click an already-assigned operator to remove only that assignee (
remove_assignee) without collapsing additive multi-assignee behavior. - Assignment updates remain optimistic and immediate in the UI while persistence runs in the background queue.
Operator experience improvements
- Reduced post-click jank by preserving stable option ordering across cache-first and authoritative roster responses.
- Added explicit saved-state feedback (check indicator) and stronger inline error handling/retry flow.
- Improved delayed auto-close behavior so the menu closes only after pointer exit threshold, while preserving scroll/interaction flow.
- Auto-close now resets transient search state before reopen to avoid stale filter confusion.
API and data-layer hardening
- Added
remove_assigneeintent support in the assignment API route and database adapter exports. - Mapped expected assignment domain errors to clearer 4xx responses (
operator_not_workspace_member,conversation_not_found) instead of generic 500s. - Aligned operator workload/open-conversation counting to active inbox states (
open,waiting) and excluded archived rows.
Verification
pnpm --filter app exec vitest run app/api/conversations/[conversationId]/assign/route.test.tspnpm --filter app exec vitest run components/conversation-assign.test.tsxpnpm --filter database exec vitest run src/adapters/conversation-routing.test.tspnpm --filter app typecheckpnpm biome check --write apps/app/app/api/conversations/[conversationId]/assign/route.ts apps/app/app/api/conversations/[conversationId]/assign/route.test.ts apps/app/components/conversation-assign.tsx apps/app/components/conversation-assign.test.tsx packages/database/src/adapters/conversation-routing.ts packages/database/src/adapters/conversation-routing.test.ts packages/database/src/impl.ts packages/database/src/index.tspnpm release:hygiene