Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

feat(crm): prefix/template CRM field mappings via config-write tool

merged#2532CedarCopilot

CedarCopilot wants to merge 0 commits into staging from feat/crm-mapping-date-prefix

Live on prod, no production signal yetTimeline and evidence
  1. Opened
    Aug 20, 2026, 3:14 PM
  2. Merged
    Aug 21, 2026, 7:44 AM
  3. Live on prod
    Aug 21, 2026, 7:44 AM
  4. Observed 24 hours
    Aug 21, 2026, 7:44 AM
  5. Pipelines steady after this deploy
    Aug 21, 2026, 7:44 AM
  6. Unobserved

    Live on prod, no production signal yet

    Aug 22, 2026, 7:20 AM

Behaviors Libra is checking

CRM integration behavior from tools/applyConfigChangeTool.ts, crm/external-crm-field-mapping.ts keeps working in prod.Inconclusivelow confidence

Strict CloudWatch fallback found 84 recent prod failure log lines for [UpdateExternalCrmWorkflow] Driver update failed (Step updateOpportunityField failed: HTTP 400: [{\), but the same failure had 144 log lines in the comparable pre-deploy baseline. Libra is not blaming this PR.

prod, checked Aug 22, 2026, 7:20 AM

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

Adds complex (template) field mappings , template / prefix / transformations , to the update_crm_field_mappings config-write change, so a user can shape what Cedar pushes to their CRM through the tool (editing their own connection) instead of hand-editing connection metadata.

Motivating use case: prepend a date stamp to Salesforce next steps , e.g. 8/19: Follow up with procurement , so a manager can see next-step freshness in their forecast view. Achieved with template:"{nextSteps}", prefix:"{today}: ", transformations:{today:{type:"date",format:"M/d"}}.

Why this is small

Everything downstream already supported complex mappings , the push mapper (mapCedarFieldsToCrm) evaluates template/prefix/transformations and applies the prefix idempotently, and CrmFieldMappingSchema already validates the complex shape. The config-write path just never exposed those fields. So this is plumbing only: no runtime/mapper change, no DB migration (fieldMappings is JSONB).

Because the MCP config-write tool reuses the exact exported ConfigChange union, the schema is edited in one place and both surfaces inherit it.

Changes

  • external-crm-field-mapping.ts , export FieldTransformationSchema so the tool reuses the exact transform shape (no re-declare/drift).
  • applyConfigChangeTool.ts , add optional template / prefix / transformations to update_crm_field_mappings; thread them through; document in the change + tool description.
  • connection-config.ts (updateCrmFieldMappings):
    • require cedarFieldName XOR template (complex mappings identify their field via {placeholder} tokens, not cedarFieldName);
    • reject prefix/transformations without a template;
    • build a clean mapping and strip cross-shape keys on conversion, so a simple→complex change can't leave a stale cedarFieldName behind (and vice-versa);
    • preserve partial-update merge semantics (e.g. toggling pushEnabled keeps an existing allowedValues);
    • validate the final mapping against CrmFieldMappingSchema before persisting , the first write-time validation on this path.
  • tests , simple→complex conversion asserts the stored shape and that cedarFieldName is dropped; and that prefix without template is rejected.

Testing

  • Scoped vitest: applyConfigChangeTool.test.ts 10/10 pass (2 new).
  • Server typecheck clean.

🤖 Generated with Claude Code

Greptile Summary

This PR exposes complex CRM template mappings through the account config-write tool and adds shared-schema validation during persistence.

  • Adds template, prefix, and transformation inputs to update_crm_field_mappings.
  • Supports conversion between simple and complex mapping shapes while preserving partial-update properties.
  • Exports the shared transformation schema and adds focused tool tests.
  • Complex placeholder names still need semantic validation before mappings are saved.

Confidence Score: 4/5

The PR should not merge until complex template placeholders are validated, because a typo can be accepted and then silently prevent the intended CRM update.

The new write surface persists arbitrary template placeholders even though the downstream mapper only acts on recognized Cedar fields; the relative import is an additional non-blocking convention issue.

Files Needing Attention: apps/server/src/services/integrations/connection-config.ts; apps/server/src/mastra/skills/account-config/tools/applyConfigChangeTool.ts

Important Files Changed

FilenameOverview
apps/server/src/services/integrations/connection-config.tsAdds simple/complex conversion and final shape validation, but complex templates can persist unknown placeholders that later suppress CRM updates.
apps/server/src/mastra/skills/account-config/tools/applyConfigChangeTool.tsExposes complex mapp
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/mastra/skills/account-config/tools/__tests__/applyConfigChangeTool.test.tsno production surface mapped
  • apps/server/src/mastra/skills/account-config/tools/applyConfigChangeTool.tsno production surface mapped
  • apps/server/src/services/integrations/__tests__/connection-config.test.tsno production surface mapped
  • apps/server/src/services/integrations/connection-config.tsno production surface mapped
  • apps/server/src/services/integrations/crm/external-crm-field-mapping.tsno production surface mapped