Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

fix(slack): recover userId when Mastra's context loses it mid-run

closed#2678CedarCopilot

CedarCopilot wants to merge 1 commit into staging from fix/manufact-live-slack-userid

Not deployedTimeline and evidence
  1. Opened
    Sep 3, 2026, 5:27 PM
  2. Sep 3, 2026, 5:41 PM
  3. Merged, live on staging, live on prod, observed
    Pending
  4. Not deployed

    Not deployed

    Pending

Libra has no production signal for this change yet because it has not deployed. Libra checks hourly for 3 days after each deploy.

Summary

  • ManuFact's stripe-payment-watcher cron subagent failed 6 consecutive runs (2026-09-01 through 09-03) with search-live-slack/read-live-slack-thread returning "Missing userId in request context", while other tool calls (list-slack-channels, notify-user) in the same run read userId correctly off the same request context.
  • Traced into the installed @mastra/core@1.0.0-beta.19: CoreToolBuilder.createExecute builds each tool call's context as options.requestContext ?? new RequestContext() (dist/chunk-43VR5ZNS.js:183) , if Mastra's own context is ever falsy for a given call, it silently substitutes a brand-new, empty context instead of erroring. Nothing in Cedar's code can see or prevent that substitution from inside a tool's execute.
  • Both tools now fall back to getAgentRunScope() , the existing AsyncLocalStorage scope runAutomationInProcess already opens around every agent-bearing automation run (agent-run-scope.ts), which Mastra cannot swap out from under a running call. That scope already proves it survives into a tool's execute and beyond (it's used for write-document → writeFileAsYjs → recordHistoryAsync attribution, four layers deeper than what this needs), so this extends it with userId rather than adding a second ambient mechanism.
  • Logs (agent.liveSlackTool.userIdRecoveredFromAgentRunScope) whenever the fallback actually fires, so a recurrence is visible instead of silently invisible the way the original incident was.

An earlier version of this fix introduced a parallel, duplicate AsyncLocalStorage module instead of extending agent-run-scope.ts; a thermo-review pass caught the duplication and this is the folded-in version , see the review conversation for the full trace.

Test plan

  • pnpm --filter @zero/server exec vitest run src/mastra/tools/slack/__tests__/liveSlackTools.test.ts , 13/13 pass, including new cases for the agent-run-scope fallback (recover + still-fails-with-nothing)
  • pnpm --filter @zero/server exec vitest run src/mastra/tools/slack/__tests__/slackTool.test.ts , 19/19 pass, no regression on the external MCP dispatch layer
  • pnpm --filter @zero/server exec vitest run src/services/aop/__tests__/automations-service.test.ts src/services/aop/__tests__/automation-agent.test.ts , 29/29 pass, no regression
  • pnpm --filter @zero/server run types (tsc --noEmit) , clean
  • pnpm deps:check , clean, no dependency-direction violations
  • Confirm on Pietro's next scheduled stripe-payment-watcher run (06:00/14:00 UTC) that the fallback log fires and the sync succeeds

šŸ¤– Generated with Claude Code

https://claude.ai/code/session_01X1GCXeLkxf7NjFAfiTytbA

Greptile Summary

The PR adds an AsyncLocalStorage-backed userId fallback for two live-Slack tools when Mastra supplies an empty request context.

  • Extends AgentRunScope with the automation user's identity.
  • Centralizes direct-context and ambient-scope resolution with fallback logging.
  • Adds recovery and missing-identity tests for Slack search and thread reads.
  • Leaves an existing test constructor incompatible with the newly required scope shape.

Confidence Score: 4/5

The fallback behavior appears appropriately scoped, but the missing userId in an existing AgentRunScope test constructor should be fixed before merging because it breaks test typechecking.

The production automation path carries one consistent user identity into both Mastra context and AsyncLocalStorage, while the widened required interface leaves an included test object incompatible with AgentRunScope.

Files Needing Attention: apps/server/src/services/agent-action-queue/agent-run-scope.ts, apps/server/src/services/agent-memory/tests/memory-store.test.ts, apps/server/src/mastra/tools/slack/resolve-live-slack-user-id.ts

Important Files Changed

FilenameOverview
apps/server/s
Show production surfaces and changed-file mapping

Production surfaces

Libra has not measured any production surfaces for this change yet.

Changed files → surfaces

  • apps/server/src/mastra/tools/slack/__tests__/liveSlackTools.test.tsno production surface mapped
  • apps/server/src/mastra/tools/slack/readLiveSlackThreadTool.tsno production surface mapped
  • apps/server/src/mastra/tools/slack/resolve-live-slack-user-id.tsno production surface mapped
  • apps/server/src/mastra/tools/slack/searchLiveSlackTool.tsno production surface mapped
  • apps/server/src/services/agent-action-queue/agent-run-scope.tsno production surface mapped
  • apps/server/src/services/aop/automations.tsno production surface mapped