CedarCopilot wants to merge 3 commits into staging from fix/hubspot-leads-scope-and-reconnect-safety
Live on prod, 0 of 2 surfaces working, 2 days left
Libra found 2 production surfaces on prod but could not judge any of them yet. 2 surfaces had no requests at all. Libra checks hourly for 3 days after each deploy.
leads-read (confirmed live via a 403 without it) and leads-write (inferred) to HUBSPOT_OAUTH_SCOPES, needed for the CRM custom-object-linkage work (PR #2833) to read/write HubSpot Leads.applyOrgCrmDefaults so it only fills genuinely-unset fields (fieldMappings, dealSyncFilter, stageRequiredFields, customObjectConfig, settings) instead of unconditionally overwriting them , a rep who customized their integration and then reconnects (e.g. to pick up the new Leads scope) was having those customizations silently wiped back to org defaults.trpc/routes/integrations.ts (OAuth path, api_key path) now fetch the existing connection row first and pass its metadata through so the fix actually takes effect.Adding leads-read/leads-write means every existing HubSpot-connected rep must hit "Reconnect" to re-authorize. Before this fix, that reconnect would have reset their fieldMappings/dealSyncFilter/etc. back to org defaults , this PR ships the scope addition and the reconnect-safety fix together so the scope change can't cause that regression.
provider-config.applyOrgCrmDefaults.test.ts (new, 7 tests) covering fill-only-if-unset behavior for each fieldš¤ Generated with Claude Code
The PR should not merge until reconnect settings are protected from stale-snapshot overwrites and the explicit no-cast repository requirement is satisfied.
### Issue 1
apps/server/src/services/integrations/provider-config.ts:247-259
During reconnect, this code rebuilds the complete `settings` object from an earlier database read. The later shallow JSONB upsert replaces the stored `settings` object, so if another settings update lands between the read and the upsert, reconnect writes the stale snapshot over it and silently loses the newer user configuration. Preserve or backfill nested settings atomically, or otherwise protect this read-modify-write sequence.
### Issue 2
apps/server/src/services/integrations/crm/hubspot.ts:769
`leads-write` is now requested during every HubSpot authorization even though the comment says it was inferred, has not been validated with a write, and supports only an eventual write path. If the production HubSpot app cannot grant this scope, all HubSpot connects and reconnects can fail even when Cedar only needs Lead reads. Verify the scope against the live app before requesting it
| Surface | Requests | Errors | p95 | Users | Verdict |
|---|---|---|---|---|---|
| /api/trpc/integrations.slack.syncConversationChannels | 0 ā 0 | 0 ā 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| POST /api/trpc/integrations.slack.syncConversationChannels | 0 ā 0 | 0 ā 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |