Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

feat(fields): unify CRM mapping writer + add multi-rep rollup read to list-fields

merged#2722CedarCopilot

CedarCopilot wants to merge 4 commits into staging from feat/field-propagation-primitive

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

    Live on prod, no production signal yet

    Sep 10, 2026, 5:31 PM

Behaviors Libra is checking

`config-propagate` is exposed as a separate mutating MCP family requiring playbook-write scope and org-admin authorization, and is hidden from viewer-readable actions.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 10, 2026, 2:47 PM
Org admins can propagate an org AOP field definition to explicit reps, all reps, or only uniform-and-missing reps, immediately patching uniform and missing targets while refusing divergent targets with their diffs unless force is requested.Inconclusivemedium confidence

Since the deploy, there are 0 production OTEL spans matching config-propagate/propagate-field and 0 CloudWatch log lines matching config-propagate, propagate-field, or propagation result identifiers. Therefore no successful executions, failures, latency, volume, or.

prod, checked Sep 10, 2026, 3:28 PM
Field propagation reports differences in immutable or unsupported properties such as type, owner agent, and background but never force-writes those properties through the single-field update primitive.Inconclusivelow confidence

Verification reached its budget before a verdict.

prod, checked Sep 10, 2026, 3:29 PM
A force-enabled write against an allowed divergent target is applied immediately only on autonomous surfaces, while interactive surfaces create an individual approval card and do not write until approval.Inconclusivelow confidence

Unable to complete the telemetry verification within the available tool loop.

prod, checked Sep 10, 2026, 4:28 PM
A force request containing more than one divergent target is rejected atomically before any uniform, missing, or divergent target is written.Inconclusivehigh confidence

Since deployment at 2026-09-08T00:34:33Z, OTEL returned 0 matching config-propagate/propagate-field/propagate-mapping spans, so volume, success/error rate, latency, and distinct users are unavailable. CloudWatch showed config-propagate only in MCP tool-discovery listings.

prod, checked Sep 10, 2026, 4:30 PM
Org admins can propagate a CRM mapping to explicit reps or all reps using the source mapping payload while classifying uniform, missing, and divergent mappings consistently with field propagation.Inconclusivelow confidence

Verification reached its budget before a verdict.

prod, checked Sep 10, 2026, 5:29 PM

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

Summary

A field-propagation primitive: lets an admin see, across every rep linked to an org AOP, which fields/mappings match the org default vs. have drifted vs. are missing entirely, and push updates to many reps at once without a blind overwrite. Design doc: apps/server/docs/design/field-propagation-primitive.md.

1. Unify the CRM-mapping write path (closes a pre-existing bug). Two paths wrote connection.metadata.fieldMappings and diverged: config-write's link-mapping action ran live CRM introspection + option reconciliation for select/list fields, but connection-write's update_crm_field_mappings never did , a simple mapping onto a select/list field written through connection-write silently skipped reconciliation. writeCrmFieldMapping() (services/integrations/crm/field-mapping-writer.ts) is now the one function both paths call; linkMapping() is a thin wrapper over it with its external contract and existing tests unchanged. Mapping validation now runs before option reconciliation commits, so a failed mapping write (e.g. op:'add' on an existing mapping) can never leave a field's options mutated.

2. Rollup read mode on list-fields. listFields() gains targetUserIds/rollup params for viewing many reps' field configs at once instead of one call per rep, via two new pure comparison functions (field-diff.ts's diffFieldAgainstOrgDefault/rollupFieldsAcrossUsers, field-mapping-diff.ts's diffMappingAgainstReference). Wired through config-read-tool.ts's list-fields action with an authorize() gate for cross-user targeting.

3. config-propagate , new MCP tool, propagate-field/propagate-mapping. Admin-only, service-layer functions kept free of any Mastra dependency (services/aop/propagate-field.ts, services/aop/propagate-mapping.ts) so a future UI can call them directly. Uniform/missing targets apply immediately; a target that genuinely diverges from the source is refused with the diff attached unless force: true, which routes it through the same runMutation/proposed-card mechanism every other config-write action already uses , an explicit per-target Slack Accept, never a blanket approval across reps.

Two real security/correctness issues found across two review passes, both fixed on this branch (not left as follow-ups):

  • Cross-tenant aopId gap (self-review): an org-scope authorize() verdict alone only proves the caller administers some organization , it never sees the client-supplied aopId. Added a callerOrgId row-binding check in list-fields.ts's loadOrgContext that refuses when the AOP's actual owning org doesn't match the verdict's org.
  • Cross-tenant data leak via explicit targetUserIds (caught by Greptile, verified independently before fixing): the AOP-definitions query was correctly org-scoped, but the connection and user-name queries inside loadPerUserFields were not , an admin naming a foreign-tenant userId in an explicit array got that user's real display name and a real slice of their CRM connection's mapping metadata back, via field-key overlap on shared built-in keys like status/dealValue. Fixed: every target is now validated against the caller's own orgOwnerId before any connection/name query runs; an invalid target is dropped entirely and reported via a separate invalidTargetUserIds, never blended into a "missing" rep.

Test plan

  • pnpm exec tsc -p tsconfig.json --noEmit , clean
  • pnpm deps:check , no dependency violations
  • pnpm exec eslint on all touched source + test files , clean
  • Scoped vitest across all touched/new test files , 593 passing, including:
    • field-diff.test.ts, field-mapping-diff.test.ts, field-mapping-writer.test.ts (new) , diff/rollup bucketing, reconciliation triggering rules, mapping-validation-before-reconciliation ordering
    • list-fields.test.ts , byte-for-byte single-user regression, rollup fixture, cross-tenant row-binding refusal, and the new
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/.claude/skills/cedar-configuration/fields-and-values.mdno production surface mapped
  • apps/server/docs/design/field-propagation-primitive.mdno production surface mapped
  • apps/server/src/mastra/mcp/external/__tests__/mutating-actions-are-administrable.test.tsno production surface mapped
  • apps/server/src/mastra/mcp/external/scope-map.tsno production surface mapped
  • apps/server/src/mastra/mcp/external/server.tsno production surface mapped
  • apps/server/src/mastra/skills/account-config/tools/__tests__/applyConfigChangeTool.reconciliation.test.tsno production surface mapped
  • apps/server/src/mastra/skills/account-config/tools/applyConfigChangeTool.tsno production surface mapped
  • apps/server/src/mastra/tools/config/__tests__/config-propagate-tool.test.tsno production surface mapped
  • apps/server/src/mastra/tools/config/__tests__/configTool.test.tsno production surface mapped
  • apps/server/src/mastra/tools/config/config-propagate-tool.tsno production surface mapped
  • apps/server/src/mastra/tools/config/config-read-tool.tsno production surface mapped
  • apps/server/src/mastra/tools/config/config-tool-shared.tsno production surface mapped
  • apps/server/src/mastra/tools/config/connection-write-tool.tsno production surface mapped
  • apps/server/src/mastra/utils/approval-policy.tsno production surface mapped
  • apps/server/src/services/aop/__tests__/field-diff.test.tsno production surface mapped
  • apps/server/src/services/aop/__tests__/link-mapping.test.tsno production surface mapped
  • apps/server/src/services/aop/__tests__/list-fields.test.tsno production surface mapped
  • apps/server/src/services/aop/__tests__/propagate-field.test.tsno production surface mapped
  • apps/server/src/services/aop/__tests__/propagate-mapping.test.tsno production surface mapped
  • apps/server/src/services/aop/field-diff.tsno production surface mapped
  • apps/server/src/services/aop/link-mapping.tsno production surface mapped
  • apps/server/src/services/aop/list-fields.tsno production surface mapped
  • apps/server/src/services/aop/propagate-field.tsno production surface mapped
  • apps/server/src/services/aop/propagate-mapping.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/__tests__/field-mapping-diff.test.tsno production surface mapped
  • apps/server/src/services/integrations/crm/__tests__/field-mapping-writer.test.tsno production surface mapped
  • apps/server/src/services/integrations/crm/external-crm-field-mapping.tsno production surface mapped
  • apps/server/src/services/integrations/crm/field-mapping-diff.tsno production surface mapped
  • apps/server/src/services/integrations/crm/field-mapping-writer.tsno production surface mapped
  • apps/server/src/services/shared/config-change.tsno production surface mapped