Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

fix: durable task completion + draft cleanup on every check-mark; coaching trigger manifest; sidebar projection typing

merged#2673CedarCopilot

CedarCopilot wants to merge 3 commits into staging from fix/dm-container-kind

Live on prod, no production signal yetTimeline and evidence
  1. Opened
    Sep 3, 2026, 12:41 PM
  2. Sep 4, 2026, 12:53 AM
  3. Merged
    Sep 4, 2026, 2:56 PM
  4. Live on prod
    Sep 4, 2026, 2:56 PM
  5. Observed 2 days
    Sep 4, 2026, 2:56 PM
  6. Pipelines steady after this deploy
    Sep 4, 2026, 2:56 PM
  7. Unobserved

    Live on prod, no production signal yet

    Sep 6, 2026, 11:47 PM

Behaviors Libra is checking

If the immediate completion write fails, the optimistic done state and pending-resolution mask are rolled back so the task remains visible and open instead of disappearing.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 6, 2026, 8:48 PM
Task completion is written to the server immediately instead of waiting for the undo toast to expire, so a reload, tab close, or crash cannot lose the user's check mark.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 6, 2026, 8:50 PM
A task remains hidden while its immediate completion request is in flight, even if an authoritative refetch still returns the task as todo.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 6, 2026, 9:48 PM
Undo reopens a completion through a durable status update that clears completedAt and reschedules the canceled agent run, while canceling pending draft cleanup and not recreating a draft that was already deleted.Inconclusivelow confidence

Verification reached its budget before a verdict.

prod, checked Sep 6, 2026, 9:48 PM
Deleting a task invalidates its conversation detail query so the Conversation Overview Due Tasks list cannot repopulate the deleted task from stale cached conversation data.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 6, 2026, 10:48 PM
If deferred Gmail draft cleanup fails after completion, the task remains completed and the cleanup error does not present as a task-completion failure.Inconclusivelow confidence

Unable to complete verification because the available telemetry queries returned no matching warning or task-operation spans, and source reads were blocked by the character budget.

prod, checked Sep 6, 2026, 10:48 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.

Three unrelated fixes, sharing a branch rather than a subject. The first two are the remaining Greptile findings from #2669, which merged before they landed; the third is the task-completion work below and can be reviewed on its own.

fix(coaching): the weekly cron was written down but never armed

seed-coaching-agent.ts wired a meeting trigger and a weekly cron into the playbook XML and saved it with a raw writeDocument. A PLAYBOOK.md is a compiled document , what the scheduler and router read is metadata.playbook_manifest, and a raw write updates the content while leaving that manifest untouched. The triggers were visible to anyone opening the playbook and invisible to everything that would act on them, with the script printing wired: and exiting zero. The seeding looked complete and the agent simply never ran.

Now routed through writeDocumentGuarded, which exists for exactly this and dispatches on the path, so it takes the user- or org-scoped playbook branch to match --level without being told which. The write returns a summary of what it armed, read off the manifest it just compiled; the script asserts the meeting trigger and the requested cron are both present and fails loudly otherwise, so a manifest that came back without them can't reproduce the same green-but-inert result.

fix(sidebar): the adapter asserted a projection it never receives

The sidebar cast the listConversations response through any, Record<string, unknown> and object on its way to HydratedConversation. That type describes the detail projection; the list ships strictly less. The casts asserted something untrue and switched off the only check that would have said so.

Removing them surfaced three real mismatches , a custom field arrives with no working-memory provenance, latestEvent is an overview event, and the conversation has no lastReviewedAt / conversationScope / overviewItems.

One was already live. buildHaystack searched latestEvent.emailEvent?.subject and latestEvent.summary; neither exists on an overview event, so both were always undefined and neither contributed a word to free-text search. Subject search still works , an email event's title is its subject (title: message.subject || '(No subject)') and title is what the list carries. The two dead branches are gone, and the test that covered them fabricated a detail-shaped event to pass, so it now uses the real shape.

SidebarConversation is inferred from the adapter rather than written out, so it is by construction whatever the projection produces and server-side drift lands as a compile error instead of a blank row. It is wider than HydratedConversation in the two places they differ, so the sidebar helpers still accept a detail conversation and nothing outside conversationsPage/ changes type.

I tried the alternative first , widening HydratedConversation itself , and backed it out: it produced 28 errors across 9 detail surfaces (10 in workingMemoryCard.tsx alone) that legitimately hold full entries and shouldn't have to guard.

fix(tasks): completion was lost on reload, and the check-mark never cleaned up its draft

Two defects on the task-completion path, reported independently by Zach (#cedar-concentrate: "I check them as done. I click refresh and then it appears again every time") and Mihir (#cedar-invoicebutler).

The completion write was lost if the page reloaded within 5s

optimisticCompleteTaskDelayed deferred the server write inside a setTimeout behind the undo toast. A reload, tab close or crash in that window took the timer down with the JS context: completeTask never fired, the in-memory mask did not survive either, and the row came back on the next fetch , with no completed_at and no server-side trace the user had ever closed it. Client-side navigation was fine; only a hard reload lost the write, which is exactly what Zach was doing.

The deferral was guarding a side effect that d

Show production surfaces and changed-file mapping

Production surfaces

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

Changed files → surfaces

  • apps/mail/modules/agentCanvas/hooks/use-agenda-task-sync.tsno production surface mapped
  • apps/mail/modules/conversations/components/nextSteps/TaskBlock.tsxno production surface mapped
  • apps/mail/modules/conversationsPage/components/ConversationsSidebarBody.tsxno production surface mapped
  • apps/mail/modules/conversationsPage/components/ConversationsSidebarRow.tsxno production surface mapped
  • apps/mail/modules/conversationsPage/hooks/use-conversations-sidebar-conversations.tsno production surface mapped
  • apps/mail/modules/conversationsPage/utils/filterConversationsByQuery.tsno production surface mapped
  • apps/mail/modules/conversationsPage/utils/groupSidebarConversations.tsno production surface mapped
  • apps/mail/modules/threads/conversation-inbox/ConversationTaskRow.tsxno production surface mapped
  • apps/mail/modules/userTasks/components/TaskExecutionList.tsxno production surface mapped
  • apps/mail/modules/userTasks/components/TaskKanbanBoard.tsxno production surface mapped
  • apps/mail/modules/userTasks/components/TaskListView.tsxno production surface mapped
  • apps/mail/modules/userTasks/hooks/use-optimistic-task-actions.tsno production surface mapped
  • apps/mail/modules/userTasks/lib/pending-task-resolutions.tsno production surface mapped
  • apps/mail/tests/modules/agentCanvas/invoke-task-flow.test.tsxno production surface mapped
  • apps/mail/tests/modules/conversationsPage/utils/filterConversationsByQuery.test.tsno production surface mapped
  • apps/mail/tests/modules/userTasks/completeTaskUndoWindow.test.tsxno production surface mapped
  • apps/server/src/scripts/seed-coaching-agent.tsno production surface mapped
  • apps/server/src/services/task-scheduling/__tests__/complete-task-draft-cleanup.test.tsno production surface mapped
  • apps/server/src/services/task-scheduling/execution.tsno production surface mapped
  • apps/server/src/services/user-tasks/__tests__/cleanup-draft-pointer.test.tsno production surface mapped
  • apps/server/src/services/user-tasks/tasks.tsno production surface mapped
  • apps/server/src/trpc/routes/__tests__/get-task-by-id-ticket-fields.test.tsno production surface mapped
  • apps/server/src/trpc/routes/__tests__/user-tasks-conversation-scope.test.tsno production surface mapped
  • apps/server/src/trpc/routes/__tests__/user-tasks-reopen-reschedules.test.tsno production surface mapped
  • apps/server/src/trpc/routes/__tests__/user-tasks-task-access.test.tsno production surface mapped
  • apps/server/src/trpc/routes/user-tasks.tsno production surface mapped