{
  "id": "fix-3532",
  "title": "Remote-unbound HubSpot contact fails closed when email belongs to existing Leads",
  "kind": "hubspot_sync",
  "optional": true,
  "targetedAcceptance": {
    "schemaVersion": "hubspot-targeted-acceptance/v1",
    "reason": "Signed-webhook regression for fail-closed remote-id identity isolation with multiple same-email Leads."
  },
  "caseTimeoutMs": 300000,
  "linkedIssues": [3532, 4041],
  "provenance": {
    "businessScenario": "Supersedes the old #3532 create-a-distinct-Lead expectation after the 2026-07-17 duplicate-Lead incident. A recent_source_details contact.propertychange with a nonblank HubSpot id, no exact or merge-alias match, and existing same-email Leads must fail closed with HUBSPOT_CONTACT_IDENTITY_UNRESOLVED. It must neither create another Lead nor stamp the remote id onto either existing Lead.",
    "reportedBy": "Amber / prod duplicate Lead RCA 2026-07-17",
    "capturedAt": "2026-07-17"
  },
  "steps": [
    {
      "id": "create-dup-lead-a",
      "system": "nexuscrm",
      "authRole": "admin",
      "method": "POST",
      "path": "/services/data/v63.0/sobjects/Lead",
      "body": {
        "LastName": "Fx3532A{{__runId}}",
        "Company": "Fx3532",
        "Email": "fx3532-{{__runId}}@example.com",
        "HubSpot_Sync_Enabled__c": false
      },
      "expectStatusRange": [200, 299],
      "assertions": [
        { "path": "response.body.id", "exists": true }
      ]
    },
    {
      "id": "create-dup-lead-b",
      "system": "nexuscrm",
      "authRole": "admin",
      "method": "POST",
      "path": "/services/data/v63.0/sobjects/Lead",
      "body": {
        "LastName": "Fx3532B{{__runId}}",
        "Company": "Fx3532",
        "Email": "fx3532-{{__runId}}@example.com",
        "HubSpot_Sync_Enabled__c": false
      },
      "expectStatusRange": [200, 299],
      "assertions": [
        { "path": "response.body.id", "exists": true }
      ]
    },
    {
      "id": "create-contact",
      "system": "hubspot",
      "method": "POST",
      "path": "/crm/v3/objects/contacts",
      "body": {
        "properties": {
          "email": "fx3532-{{__runId}}@example.com",
          "firstname": "Fx3532",
          "lastname": "RemoteUnbound{{__runId}}"
        }
      },
      "expectStatusRange": [200, 299],
      "assertions": [
        { "path": "response.body.id", "exists": true }
      ]
    },
    {
      "id": "send-remote-unbound-attribution-delta",
      "system": "connector_webhook",
      "method": "POST",
      "path": "/webhooks/hubspot-crm-connector/webhook",
      "body": [
        {
          "portalId": "{{portalId || \"51280875\"}}",
          "appId": 44166359,
          "subscriptionId": 6723583,
          "eventId": "fix-3532-{{__runId}}",
          "occurredAt": "1782734624058",
          "subscriptionType": "contact.propertyChange",
          "attemptNumber": 0,
          "objectId": "{{steps.create-contact.response.body.id}}",
          "propertyName": "recent_source_details",
          "propertyValue": "LinkedIn - InMail",
          "changeSource": "AUTOMATION_PLATFORM"
        }
      ],
      "expectStatus": 202,
      "assertions": [
        { "path": "response.body", "exists": true }
      ]
    },
    {
      "id": "assert-attribution-delta-failed-closed",
      "system": "tidb",
      "method": "GET",
      "sql": "SELECT Id, Status, ProcessedAt, COALESCE(JSON_UNQUOTE(JSON_EXTRACT(Payload, '$.payload.propertyName')), JSON_UNQUOTE(JSON_EXTRACT(Payload, '$.propertyName'))) AS PropertyName, COALESCE(JSON_UNQUOTE(JSON_EXTRACT(Payload, '$.payload.propertyValue')), JSON_UNQUOTE(JSON_EXTRACT(Payload, '$.propertyValue'))) AS PropertyValue, LEFT(COALESCE(LastError, ''), 500) AS LastErrorSample FROM `_System_ConnectorEvent` WHERE Namespace = 'hubspot-crm-connector' AND EventKind = 'contact.propertychange' AND SourceObjectID = '{{steps.create-contact.response.body.id}}' AND COALESCE(JSON_UNQUOTE(JSON_EXTRACT(Payload, '$.payload.propertyName')), JSON_UNQUOTE(JSON_EXTRACT(Payload, '$.propertyName'))) = 'recent_source_details' AND COALESCE(JSON_UNQUOTE(JSON_EXTRACT(Payload, '$.payload.propertyValue')), JSON_UNQUOTE(JSON_EXTRACT(Payload, '$.propertyValue'))) = 'LinkedIn - InMail' ORDER BY CreatedDate DESC LIMIT 1",
      "expectStatus": 200,
      "poll": { "budgetMs": 180000, "intervalMs": 6000 },
      "onTimeout": "fail",
      "assertions": [
        { "path": "response.body.records", "lengthAtLeast": 1 },
        { "path": "response.body.records[0].PropertyName", "equals": "recent_source_details" },
        { "path": "response.body.records[0].PropertyValue", "equals": "LinkedIn - InMail" },
        { "path": "response.body.records[0].Status", "equals": "failed" },
        { "path": "response.body.records[0].LastErrorSample", "includes": "HUBSPOT_CONTACT_IDENTITY_UNRESOLVED" }
      ]
    },
    {
      "id": "assert-no-remote-id-lead-created",
      "system": "tidb",
      "method": "GET",
      "sql": "SELECT COUNT(*) AS RemoteIdLeadCount FROM Lead WHERE HubSpot_Id__c = '{{steps.create-contact.response.body.id}}' AND IsConverted = 0",
      "expectStatus": 200,
      "poll": { "budgetMs": 180000, "intervalMs": 6000 },
      "onTimeout": "fail",
      "assertions": [
        { "path": "response.body.records[0].RemoteIdLeadCount", "equals": 0 }
      ]
    },
    {
      "id": "assert-existing-leads-remain-unbound",
      "system": "tidb",
      "method": "GET",
      "sql": "SELECT COUNT(*) AS UnboundLeadCount FROM Lead WHERE Email = 'fx3532-{{__runId}}@example.com' AND HubSpot_Id__c IS NULL AND IsConverted = 0",
      "expectStatus": 200,
      "assertions": [
        { "path": "response.body.records[0].UnboundLeadCount", "equals": 2 }
      ]
    }
  ]
}
