CedarCopilot wants to merge 9 commits into staging from feat/crm-custom-object-linkage
Live on prod, 0 of 9 surfaces working, 2 days left
Libra found 9 production surfaces on prod but could not judge any of them yet. 9 surfaces had no requests at all. Libra checks hourly for 3 days after each deploy.
Generalizes Cedar's CRM integration so an AOP/playbook can be bound to any CRM object , a HubSpot Lead, an Attio Contact filtered by lead status, a Salesforce partner-directory object , not just Opportunity/Deal. Built for three real, scoped instantiations: Vooma (HubSpot Leads), Mastra (Attio people/lead_status), Warp (Salesforce Partner__c). Full design at docs/design/crm-custom-object-linkage-leads.md.
Core model: each AOP gains one new field, boundObjectApiName. A human or agent configuring anything always passes aopId, never a raw CRM object name , the system resolves objectApiName from that AOP internally. No new persisted "binding" table; it's a join between the AOP and the connection's existing field-mapping storage.
boundObjectApiName on agentOperatingProcedures/orgAops; generic recordId/recordUrl/recordName on ExternalCrmIntegrationMetadata (one pair covers every non-Deal object, since a conversation is only ever bound to one at a time); objectApiName on crm_conversation_updates (closes a real ID-collision risk between a Deal and a same-ID Lead on one connection).updateOpportunityFields/fetchOpportunityProperties take an optional objectApiName, defaulting to Opportunity , zero behavior change for every existing call site). Attio's select/status UUID-resolution gate, previously hardcoded to the literal 'stage', now works for any select field.stageRequiredFields.update_crm_field_mappings tool takes aopId; org→rep mapping propagation extended to non-Deal objects.recordId alongside dealId.deal-metrics/deal-timeline/deal-audit extended toward Lead-band (the other 3 of 6 reporting files deliberately left alone , documented why, not silently skipped).AopName.Deals comparison outside a documented allowlist.Implemented via 8 parallel subagents against a shared foundation (schema + driver interface), each required to write tests and self-run a thermo-nuclear code-quality review before reporting back. A full aggregate review across the whole branch (not just each slice) then found 4 real blocking gaps no individual slice's author could see in isolation , most importantly, the actual push-write path (update-external-crm-workflow.ts) had never been touched by any of the 8 slices, meaning nothing in the branch could yet write a field update to a non-Deal record. Two more rounds of targeted fixes closed all 4 gaps, and a final confirmation pass caught one more integration-seam bug (a field-mapping-resolution function neither fix's file list included, now called in a new non-Deal context by both). Every fix has a regression test that traces the exact bug it closes.
Verified at final HEAD: pnpm --filter @zero/server run types clean · pnpm deps:check clean (no dependency-direction violations) · 1897 tests across 175 files, all passing.
sg tool save) , external system, needs explicit review/approval. Draft IDs below.| Surface | Requests | Errors | p95 | Users | Verdict |
|---|---|---|---|---|---|
| /api/trpc/crm.searchConversationsMinimal | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| POST /api/trpc/crm.searchConversationsMinimal | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| /api/trpc/crm.getConversations | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| POST /api/trpc/crm.getConversations | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| crm.searchConversationsMinimal | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| trpc.crm.searchConversationsMinimal | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| trpc.crm.getConversations | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| /api/trpc/crm.loadCalendarConversationsBatch | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| /api/trpc/integrations.slack.syncConversationChannels | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |