Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

fix(playbook): scope daily-agenda triage to the user's own deals

merged#2807CedarCopilot

CedarCopilot wants to merge 2 commits into staging from fix/daily-agenda-scope-to-owner

Live on prod, no production signal yetTimeline and evidence
  1. Opened
    Sep 17, 2026, 12:48 PM
  2. Sep 17, 2026, 4:03 PM
  3. Merged
    Sep 17, 2026, 5:33 PM
  4. Live on prod
    Sep 17, 2026, 5:33 PM
  5. Observed 19 hours
    Sep 17, 2026, 5:33 PM
  6. Pipelines steady after this deploy
    Sep 17, 2026, 5:33 PM
  7. Unobserved

    Live on prod, no production signal yet

    Sep 18, 2026, 1:00 PM

Behaviors Libra is checking

The daily-agenda triage sweep searches, reviews, flags, and touches only deals owned by the current user by including an `ownerId` filter with `value: 'self'` on every `find-crm-conversations` call.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 18, 2026, 1:00 PM

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

What was wrong

find-crm-conversations defaults to org-wide results when called without an ownerId filter , intentional for interactive lookups (e.g. "find my teammate's Acme deal"). The daily-agenda triage's Stage A instructions describe an open-ended catch-all query ("plus anything else your book makes worth sweeping") without ever telling the agent to scope it. When that unscoped query surfaced a teammate's conversation, the fan-out (review-conversation) dispatched a full conversation review under the wrong user , creating tasks, drafts, and Slack notifications on someone else's account, using the wrong user's own AOP/playbook against a deal they have no ownership or membership on.

Root-caused via Sherlock for , who was seeing 's Loadsmart deal in his own task list. A 90-day audit found the same pattern hit 8 users across 5 different orgs , it requires an org with 2+ active reps sharing org-visible conversations, and exposure scales inversely with how much of the org's book you personally own (Jake owned ~3% of Mastra's book; Josh, who owns ~70%, was effectively immune by volume alone).

What changed

apps/server/src/services/playbook/agent-defaults/daily-agenda.ts (the seeded default for the daily-agenda subagent's Stage A triage):

  • Added an explicit rule that every find-crm-conversations call in this stage , including the catch-all , must include {field: 'ownerId', operator: 'eq', value: 'self'}.
  • Disambiguated "query your whole book" to mean the user's own book, not the org's.

This is a config/instructions fix, deliberately not a code-enforced authorization check , the team wanted this scoping to live in the editable playbook instructions (which can vary per org) rather than hard-coded into the tool layer.

Scope of this PR: the shared default template only (affects new onboards going forward). 's already-materialized live doc was separately patched via writeDocument() (not included in this diff), and his 31 leaked tasks were cleaned up via deleteTask(). Other already-affected users/orgs found in the audit were left untouched pending a separate decision on rollout.

How to test

Not independently testable without a live daily-agenda run. To verify in practice: with two reps in the same org sharing org-visible conversations, run daily-agenda for the rep with the smaller book and confirm agent_tool_calls shows every find-crm-conversations call carrying an ownerId filter, and that no review-conversation dispatch targets a conversation owned by a different user.

🤖 Generated with Claude Code

RetriggerConfidence Score: 4/5

The ownership-scoping behavior appears sound, but the repository’s explicit formatting requirement must be satisfied before merging.

Findings

  1. P2 Instruction Lines Too Long ▶
Fix with agent prompt
### Issue 1
apps/server/src/services/playbook/agent-defaults/daily-agenda.ts:87
The expanded instructions on lines 87 and 124 are substantially longer than the repository guide’s approximately 100-character line-width requirement. Please wrap both lines before merging so this default remains readable and follows the required formatting.

Note: If this suggestion doesn't m
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/services/playbook/__tests__/seed-playbook.test.tsno production surface mapped
  • apps/server/src/services/playbook/agent-defaults/daily-agenda.tsno production surface mapped