Skip to content

[Improve] Surface routing failures instead of silently showing the picker - #1120

Merged
mrubens merged 3 commits into
developfrom
improve/loud-routing-fallback
Aug 5, 2026
Merged

[Improve] Surface routing failures instead of silently showing the picker#1120
mrubens merged 3 commits into
developfrom
improve/loud-routing-fallback

Conversation

@mrubens

@mrubens mrubens commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Problem

When the router's LLM call fails for infrastructure reasons (inference provider outage, key limit, timeout), the failure was invisible everywhere a human might look:

  • The fallback reason was dropped in the Slack start path, so users just got the manual workspace picker with no explanation — indistinguishable from an ambiguous request.
  • The router debug channel showed Why this route: (none) because fallback decisions carry reason, not reasoning, and nobody passed it through.
  • Only the server logs contained the actual error.

During a recent provider-key outage this made routing look "broken" with no user-facing signal about why, and the deploy that happened around the same time was a red herring.

Changes

  1. Typed failure cause. Fallback decisions now carry cause: 'exception' | 'model_decision' (RoutingFallbackCause). Catch blocks mark exception; "router ran but declined to pick" paths mark model_decision. The [LLM Router] Routing fallback log lines include cause=.

  2. User-visible warning on the picker. When the cause is an exception, the Slack manual picker now shows a notice that automatic routing is temporarily unavailable and an admin should check the deployment's inference provider. Wired through both entry paths: the mention flow (showTaskConfiguration, including its catch block) and channel auto-start (startAutoRoutedSlackTaskshowManualPickerForAutoRouteFallback). Raw provider errors are deliberately kept out of user threads since they can contain key identifiers; ambiguity-driven fallbacks still show the plain picker.

  3. Debug channel gets the real reason. New postRouterFallbackDebugMessage fires at fallback time on every fallback, posting source, message, cause, and the full failure reason to the configured router debug destination (Slack blocks + plain-text variants for Discord/Telegram/Teams). Previously nothing was posted at fallback time at all.

Tests

  • router-service.test.ts: exception fallback now asserts cause: 'exception'
  • show-task-configuration.test.ts: picker warning + fallback diagnostics for exception fallbacks; plain picker for model-decided fallbacks; notice passthrough with skipRouting
  • auto-route-fallback.test.ts: warning passthrough for exception cause, none for model decisions

pnpm lint, pnpm check-types, pnpm knip, and the full @roomote/slack suite pass.

Follow-up (not in this PR)

Treating repeated non-task inference failures as provider health (web-app banner, Slack warning text) so this whole class of outage self-diagnoses across surfaces beyond routing.

…cker

Routing fallbacks caused by infrastructure errors (provider outages, key
limits) were indistinguishable from the router legitimately declining to
pick a workspace: the reason string was dropped, users just saw the manual
picker, and the router debug channel showed "(none)".

- Add RoutingFallbackCause ('exception' | 'model_decision') to fallback
  decisions and set it at every construction site; include cause= in the
  routing fallback logs
- Show a routing-unavailable warning above the Slack manual picker when the
  fallback came from an exception (both the mention flow and channel
  auto-start), keeping raw provider errors out of user threads
- Post a router-fallback diagnostic to the configured router debug channel
  at fallback time, including the full failure reason
@roomote-community

roomote-community Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

No new code issues found. See task

  • packages/slack/src/block-kit.ts:1082 The new exception notice is assigned by a catch that also covers Slack context setup, not just routeTask. For example, a failed getChannelName call now tells users to check the inference provider and logs it as a routing infrastructure failure even though the LLM was never called. Limit this warning/cause to the router invocation or classify setup failures separately.

Reviewed f548e7

mrubens added 2 commits August 5, 2026 11:12
Slack context setup failures (thread fetch, channel lookup) in the outer
catch no longer claim the routing infrastructure is down; only a thrown
router invocation maps to cause 'exception'.
@mrubens
mrubens merged commit 7d829a2 into develop Aug 5, 2026
18 checks passed
@mrubens
mrubens deleted the improve/loud-routing-fallback branch August 5, 2026 15:31
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