Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

feat(calendar): cancel obsolete tasks when a linked calendar event syncs

merged#2856CedarCopilot

CedarCopilot wants to merge 2 commits into staging from feat/jev-calendar-task-obsolescence-gate

Live on prod, 0 of 1 surfaces working, 1 day leftTimeline and evidence
  1. Opened
    Sep 21, 2026, 5:26 AM
  2. Sep 21, 2026, 5:44 AM
  3. Merged
    Sep 21, 2026, 6:14 AM
  4. Live on prod
    Sep 21, 2026, 6:14 AM
  5. Observed 0 hours, 1 surface, 0 requests
    Sep 21, 2026, 6:14 AM
  6. Watching

    Live on prod, 0 of 1 surfaces working, 1 day left

    Sep 21, 2026, 6:14 AM
  7. Pipelines steady after this deploy
    Sep 21, 2026, 6:14 AM

Behaviors Libra is checking

When a linked calendar event is cancelled, the calendar sync evaluates the linked conversation's open agent-created calendar tasks and cancels those Jev identifies as obsolete.Not checked
prod
When a newly synced calendar event is linked to an existing conversation, the system evaluates that conversation's open calendar tasks, while skipping the check for conversations created by the enrichment itself.Not checked
prod
A task is marked `agent_deleted` only when Jev returns a Noul score strictly greater than `0.25`; tasks at or below the threshold remain open.Not checked
prod
When a linked calendar event's start time changes, the calendar sync evaluates tasks against both the previous and new meeting times and cancels tasks made obsolete by the reschedule.Not checked
prod
Eligible tasks for one calendar event are evaluated in a single batched Jev request, with one question per task and event state including the change kind, relevant times, title, and external attendees.Not checked
prod
The calendar task gate considers only `todo` tasks on the affected conversation whose task type is `calendar`, `pre-meeting`, or `post-meeting`, or whose output kind is `calendar`.Not checked
prod

Libra found 1 production surface on prod but could not judge any of them yet. 1 surface had no requests at all. Libra checks hourly for 3 days after each deploy.

Summary

  • Adds evaluateAndCancelObsoleteTasks (apps/server/src/services/user-tasks/jev-calendar-task-gate.ts), a Jev-based gate that batches a conversation's open calendar/pre-meeting/post-meeting tasks against a just-synced calendar event (one Noul question per task, shared event state) and marks any confidently-obsolete ones agent_deleted. Same fail-open contract as the existing services/playbook/jev-action-gate.ts.
  • Wires it into three points in calendar-events.ts: event cancelled, event rescheduled (start time changed), and a new event matched onto an existing conversation (skipped for brand-new conversations, which have no pre-existing tasks to check).
  • Eligibility is deliberately narrow (task_type IN ('calendar','pre-meeting','post-meeting') or task_output.kind = 'calendar', reusing the existing isOutputKind helper) , not free-text matching, which was evaluated and rejected (see design doc for why).
  • Validated pre-implementation against 11 real (task, calendar event) pairs pulled from prod via the live Jev API , 9/11 matched expectations on the first pass, and both "misses" turned out to be correct/informative rather than model errors (see design doc's verification notes).

Design doc

docs/design/jev-calendar-task-obsolescence-gate.md , current state, proposed changes, critical files, phased plan, verification steps.

Test plan

  • jev-calendar-task-gate.test.ts (10 tests): eligibility short-circuit (zero fetch calls when no eligible tasks), batch question shape, threshold boundary, fail-open on network error/timeout/non-200/malformed response, JEV_API_KEY unset.
  • Extended calendar-events-sync.test.ts (+5 new tests, 29 total): gate fires on cancel/reschedule with correct args, does not fire without a linked conversation or without env, does not fire on a same-time update; existing "successful enrichment" test asserts the gate does not fire when matched onto a brand-new conversation.
  • pnpm --filter @zero/server run types , clean, zero errors.
  • eslint on all changed files , clean.
  • Recommend running this in shadow mode (log would_cancel, skip the write) for 1-2 weeks before trusting live writes at scale , see design doc phase 4. Not implemented in this PR; flagging as the natural next step before this reaches production traffic broadly.

šŸ¤– Generated with Claude Code

RetriggerConfidence Score: 2/5

This PR is not safe to merge until the live deletion path protects user-authored tasks and can distinguish the relevant attendee and meeting occurrence; the threshold boundary and explicit repository rule violation also require correction.

Findings

  1. P1Ā User tasks can be deleted ā–¶
  2. P1Ā Event identity context is missing ā–¶
  3. P1Ā Threshold equality deletes tasks ā–¶
  4. <img alt="P2" src="https://greptile-static-assets.s3.amazonaw
Show production surfaces and changed-file mapping

Production surfaces

SurfaceRequestsErrorsp95UsersVerdict
execute_tool list-calendar-events0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.

Changed files → surfaces

  • apps/server/src/services/crm/calendar-events.tsexecute_tool list-calendar-events
  • apps/server/src/services/crm/__tests__/calendar-events-sync.test.tsno production surface mapped
  • apps/server/src/services/user-tasks/__tests__/jev-calendar-task-gate.test.tsno production surface mapped
  • apps/server/src/services/user-tasks/jev-calendar-task-gate.tsno production surface mapped
  • docs/design/jev-calendar-task-obsolescence-gate.mdno production surface mapped