CedarCopilot wants to merge 2 commits into staging from worktree-send-it-sf-multipicklist-fix
Live on prod, 0 of 1 surfaces working, 2 days left
internal_only
internal_only
internal_only
internal_only
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.
list-type custom fields (e.g. won_reason, pain_points_list, competitors_mentioned) are comma-joined internally, but Salesforce multipicklist fields require one semicolon-delimited string on the wire. getLabelFromAopEnumOptions() only ever recognized an already-semicolon-joined value, so a genuine Cedar multi-select value never converted correctly and failed Salesforce's own picklist validation , with the whole-string-match-before-split guard added so a compound option label (one that legitimately contains a comma) is never corrupted, even when its own comma-fragments happen to also be separately-defined option values.updateOpportunityFields() validated every field in a push up front and aborted the whole batch on the first invalid field, one bad multi-select field silently killed unrelated, valid fields in the same push , including closed_won_reason_details/closed_lost_reason_details, the customer-visible symptom this was root-caused from (a Warp rep's deal close-detail fields populating "sometimes" and not others). Per-field validation failures are now isolated: a bad field is dropped and logged, valid fields still reach Salesforce, and the result carries an optional failedFields array , plumbed through driver.ts, the sync workflow, and both tRPC mutations that push CRM field batches (upsertWorkingMemory, updateConversation) so a partial drop is surfaced to the caller instead of silently reporting bare success.pnpm --filter @zero/server run types , clean.pnpm --filter @zero/server exec vitest run on all 7 touched/new test files , 69/69 passing:
salesforce-multipicklist.test.ts , comma→semicolon conversion, compound-label-not-corrupted, ;-input regression, isMultiPicklist:false no-op.salesforce-partial-field-validation.test.ts (new) , mixed valid/invalid batch still writes the valid fields; all-invalid batch makes no Salesforce call; dropped fields logged and returned in failedFields.update-external-crm-workflow.test.ts (extended) , updatedFields excludes a driver-dropped field instead of reporting the full attempted set.crm-upsert-working-memory-partial-failure.test.ts / crm-update-conversation-partial-failure.test.ts (new) , both tRPC mutations throw naming the dropped field(s) on a partial CRM-sync failure, via a shared throwIfPartialCrmFailure() helper.salesforce-object-binding.test.ts / salesforce-reference-resolution.test.ts , re-run for regression coverage on the shared updateOpportunityFields/validateAllowedValue path./thermo-review (each a context-free subagent, not the implementer) , 0 blocking issues survived to the final round. Fixed along the way: the failedFields plumbing gap on updateConversation, the compound-option-label corruption edge case, three line-width nits, and a stale doc comment.pnpm deps:check , 0 violations across 2011 modules.autofix:local was run once; its only failure (apps/mail/tests/modules/chat-store/chatHistoryList.test.ts) is a pre-existing, unrelated real-clock "Today"/"Yesterday" bucketing flake , confirmed via git diff --stat origin/staging -- apps/mail/ showing zero mail-app changes in this branch.cedar-prod , a comma-joined multi-select value that fails the "every token is a known option" check:
['cedar-prod'] | where _time > ago(1h) and message contains "Comma-joined multipicklist value did not split into known options"
| project _time, fieldName, value, parts
cedar-prod , a field dropped from a Salesforce push by local validation:
['cedar-prod'] | where _time > ago(1h) and message == "[updateOpportunityFields] Dropped field , failed local validation"
| project _time, user_id, opportunity_id, field, value, allowed_values
cedar-prod , the workflow-level view of the sam| Surface | Requests | Errors | p95 | Users | Verdict |
|---|---|---|---|---|---|
| salesforce.updateOpportunityFields | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| salesforce.updateOpportunityFields | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |