CedarCopilot wants to merge 4 commits into staging from fix/recommended-todo-duplicate-tasks
Not deployed
Libra has no production signal for this change yet because it has not deployed. Libra checks hourly for 3 days after each deploy.
strategist creates status: 'recommended' tasks (soft proposals); next-steps creates status: 'todo' tasks (real, committed follow-ups). Both can independently conclude the same real-world action is needed, producing two rows for one commitment , traced concretely to a case where strategist proposed "Confirm MSA signed status with Octavio" as a recommendation, and 6 days later next-steps independently created a todo saying "Confirm MSA is signed...", with no cross-check ever catching it.
Promotion direction (explicit, one-way): recommendations promote UP into todos , never the reverse. A recommendation must never demote real, committed work, and seeing an existing recommendation must only change how a genuinely-owed action is satisfied (promote vs. create fresh) , never a reason to skip creating it.
createTaskTool's duplicate-awareness gate to also see open recommended rows and to run when creating a recommendation, not just a todo (it used to skip entirely for status === 'recommended').acceptRecommendation route into a shared promoteRecommendationToTodo() in services/user-tasks/tasks.ts, called by both the user's own Accept button and the tool's automatic promotion, so the two paths can never drift apart.taskId handoff (so a chained tool in the same turn, e.g. save-draft, attaches to the right task) and the interactive taskCreated stream event. Both are now applied on promotion too, with a dedicated test.A prior agent in this worktree had already built most of this (the gate widening, the promote path, the extracted promoteRecommendationToTodo) but stalled mid-edit. Picking it up: found the promotedRecommendation output field was set at the call site but never added to CreateTaskOutputSchema (added it); found the promotion success path skipped the taskId handoff + stream event that a fresh insert gets (added both, per thermo-review); updated createTaskTool.recommendation-cap.test.ts's fixtures for the gate's extra openTodos query, which now also runs ahead of the ยง3.05 cap check when creating a recommendation; added createTaskTool.recommendation-promotion.test.ts covering the promote path, the recommendation-vs-todo block, and both guardrail cases (an ambiguous recommendation stack, and a promotion that races and fails) never silently dropping owed work.
pnpm --filter @zero/server run types , cleanpnpm exec vitest run src/mastra/tools/task/__tests__/ , 218 passed, 2 skipped (unrelated)pnpm exec vitest run on the touched trpc-route / db-sort-order test files , all passpnpm dlx oxlint@1.78.0 --deny-warnings , cleanpnpm deps:check , no dependency violations (services layer stays clean of Mastra imports)git diff origin/staging , one ๐ก found (missing taskId handoff + stream event on promotion) and fixed; a couple of ๐ข nits noted as deliberate/out-of-scope (promotion doesn't rewrite taskActionData/threadId/notes, matching acceptRecommendation's existing narrow semantics; promoteRecommendationToTodo opens its own DB connection rather than reusing the caller's)๐ค Generated with Claude Code
Libra has not measured any production surfaces for this change yet.