Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

fix(review-dispatch): force next-steps/drafter through run-subagent, exclude crm-updater/strategist from review

merged#2734CedarCopilot

CedarCopilot wants to merge 3 commits into staging from worktree-delegated-dispatch-forcer

Live on prod, no production signal yetTimeline and evidence
  1. Opened
    Sep 8, 2026, 2:26 PM
  2. Sep 8, 2026, 3:28 PM
  3. Merged
    Sep 8, 2026, 3:34 PM
  4. Live on prod
    Sep 8, 2026, 3:34 PM
  5. Observed 3 days
    Sep 8, 2026, 3:34 PM
  6. Pipelines steady after this deploy
    Sep 8, 2026, 3:34 PM
  7. Unobserved

    Live on prod, no production signal yet

    Sep 11, 2026, 3:06 PM

Behaviors Libra is checking

Routed review refs receive conversation/ref-specific child execution rows parented to the sweep run so their task, draft, and other tool actions cannot attach to another conversation sharing the sweep.Inconclusivelow confidence

Verification reached its 130s outer budget before the verifier returned. Libra is keeping this intent verifying until the next check.

prod, checked Sep 11, 2026, 12:23 PM
Eligible user-level drafter refs in conversation review now use run-subagent's dedicated drafter executor rather than a separate direct executor implementation.Inconclusivelow confidence

Verification reached its 120s wall-clock budget before a tied verdict. Libra is keeping this intent verifying until the next check.

prod, checked Sep 11, 2026, 12:25 PM
Review drafter dispatches now report dedicated dispatch status and child run ID through run-subagent rather than returning the direct executor's free-text output payload.Inconclusivelow confidence

Verification reached its 130s outer budget before the verifier returned. Libra is keeping this intent verifying until the next check.

prod, checked Sep 11, 2026, 1:04 PM
Conversation review excludes crm-updater and strategist from the candidate set and dispatches them never, even when a playbook registers them or the classifier names them, while other trigger modes remain unchanged.Inconclusivelow confidence

Verification reached its 120s wall-clock budget before a tied verdict. Libra is keeping this intent verifying until the next check.

prod, checked Sep 11, 2026, 1:06 PM
Eligible conversation-review dispatches now route the user-level next-steps subagent through run-subagent and its curated NEXT_STEPS_TASKS_TOOLS allowlist instead of the unrestricted automation-agent path.Inconclusivelow confidence

Verification reached its 130s outer budget before the verifier returned. Libra is keeping this intent verifying until the next check.

prod, checked Sep 11, 2026, 2:04 PM
Org-scoped documents named drafter or next-steps remain on the generic path as the org-authored ref instead of being intercepted by the user-level reserved-name handlers.Inconclusivehigh confidence

Since 2026-09-08T22:34:24Z, CloudWatch shows 0 invocations for @org/subagents/drafter and 0 for @org/subagents/next-steps, and OTEL shows 0 spans carrying either exact org-scoped ref. Therefore there is no positive runtime evidence that the intended org-document generic path.

prod, checked Sep 11, 2026, 2:05 PM

Libra has verdicts on 0 of 8 tracked behaviors on prod; 8 are still being checked. Libra checks hourly for 3 days after each deploy.

Summary

Daily-agenda's review sweep dispatched next-steps/crm-updater/strategist via runAgent directly , the generic, unrestricted automation path , instead of the real run-subagent tool, which is the only place in the codebase that correctly routes these system agents to their dedicated, curated-allowlist dispatch tools. That's how a next-steps review run ended up with modify-calendar-event in its toolset and sent a real calendar invite to external attendees with no approval step (Pax/Trey account, 2026-09-08).

Full design/investigation: apps/server/docs/design/delegated-dispatch-forcer.md (added in this PR).

  • next-steps and drafter now dispatch through the real run-subagent tool from the review path, exactly as the on-event orchestrator already does , no more bespoke re-implementation (runDrafterRef deleted, replaced by a generic runNamedSubagentViaTool).
  • crm-updater and strategist are excluded from conversation review entirely (REVIEW_EXCLUDED_SUBAGENT_NAMES), per explicit product decision , filtered out of the triage candidate list before the classifier ever sees them. Their dedicated tools hard-require a live event a review never has, so they can't yet be routed the same way next-steps/drafter are; rather than leave them running unrestricted until that's built, they simply don't run on review at all. This is a real functionality loss, not just a security tightening , the morning sweep stops producing crm-updater's field syncs and strategist's MEDDPICC/strategy output for reviewed deals until they're migrated. Measured exposure this closes immediately: crm-updater called save-draft from review 9 times and strategist 34 times in one 7-day sample, under the same unrestricted toolset (REVIEW_DRAFT_HANDOFF_DENIED_TOOLS's own comment).
  • Self-caught during thermo-review and fixed in a follow-up commit: the first pass silently dropped the inner sub-execution id (agentSubRunId/executorRunId) that agenda-run-telemetry.ts needs to correctly attribute tool calls , reproducing the exact bug class the deleted runDrafterRef's own fallback logic existed to prevent. Now forwarded through both run-subagent and updateNextStepsAndTasksTool's output schemas.

Explicitly deferred, not this PR (see design doc): migrating crm-updater/strategist onto run-subagent (needs a no-live-event review mode built into each , real tool-logic work); a runAgent-level reserved-name guard (considered and rejected as unsafe in its naive form , it would break legitimate org-level-ref and no-parentRunId-sentinel fallthrough; needs its own scoping pass); migrating run-single-subagent.ts (the subagent-runner CLI, a third confirmed instance of the same bug class); gating calendar in agent-scope.ts's TOOL_ACTIONS (calendar is currently ungatable by connection scope for anything on the generic path at all).

Known gap, flagged by Libra on every commit in this branch

No test coverage was added , there is no existing test scaffolding for runPlaybookSectionExecution's dispatch loop or runSubagentTool.ts to extend, so this would be new test infrastructure, not a quick addition. Verified instead via pnpm --filter @zero/server run types, pnpm run deps:check, and oxlint --deny-warnings on every touched file (all clean) plus manual tracing of every claim in the design doc (execution-row parenting, org-level/no-parentRunId fallthrough, telemetry attribution). Libra's separate "could dispatch more than once" advisory is not a new risk from this change , the existing canRunExecutor/REVIEW_SKIP_IF_RUN_WITHIN_HOURS dedupe machinery is untouched by every commit here.

Test plan

  • pnpm --filter @zero/server run types , clean
  • pnpm run deps:check , 0 violations (confirms the lazy await import() pattern is correct)
  • pnpm dlx oxlint@1.78.0 --deny-warnings on every touched file , clean
  • Manual trace of agentSubRunId/executorRunId propagation,
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/docs/design/delegated-dispatch-forcer.mdno production surface mapped
  • apps/server/src/mastra/tools/agenda/__tests__/reviewConversationFanOut.test.tsno production surface mapped
  • apps/server/src/mastra/tools/event-execution/runSubagentTool.tsno production surface mapped
  • apps/server/src/mastra/tools/subagent-tool-allowlists.tsno production surface mapped
  • apps/server/src/mastra/tools/task/updateNextStepsAndTasksTool.tsno production surface mapped
  • apps/server/src/services/playbook/__tests__/drafter-review-dispatch.test.tsno production surface mapped
  • apps/server/src/services/playbook/__tests__/drafter-seed.test.tsno production surface mapped
  • apps/server/src/services/playbook/playbook-execution-triggers.tsno production surface mapped