{
  "id": "out-owner",
  "title": "NX owner with binding outbounds shadow value to HubSpot hubspot_owner_id",
  "kind": "hubspot_sync",
  "caseTimeoutMs": 660000,
  "linkedIssues": [2591],
  "provenance": {
    "businessScenario": "OUT-OWNER — a native NexusCRM record owned by a User with a bound HubSpotOwnerBinding__c outbounds so the HubSpot contact's hubspot_owner_id is stamped with the binding shadow value.",
    "reportedBy": "HubSpot sync spec OUT-OWNER (hubspot-nexuscrm-sync-CASE-EXEC-SELFCONTAINED)",
    "capturedAt": "2026-06-18",
    "note": "[recalibrated 2026-08-26] The bound-owner half discovers its environment-local CRM principal and proves the positive provider value. The second half moves the same Lead to an active User with no bound HubSpotOwnerBinding, requires the before-save flow to clear HubSpot_Owner_Id__c, and proves a simultaneous business-field PATCH lands while the prior provider owner is retained rather than leaking an unauthorized owner value (#2591)."
  },
  "steps": [
    {
      "id": "binding",
      "system": "nexuscrm",
      "authRole": "admin",
      "method": "GET",
      "path": "/services/data/v63.0/query?q=SELECT HubSpotOwnerId__c,CRMPrincipalId__c FROM HubSpotOwnerBinding__c WHERE BindingStatus__c='bound' AND HubSpotOwnerId__c='45282439' LIMIT 1",
      "expectStatus": 200,
      "poll": { "budgetMs": 30000, "intervalMs": 6000 },
      "onTimeout": "blocked",
      "assertions": [
        { "path": "response.body.records", "lengthAtLeast": 1 },
        { "path": "response.body.records[0].HubSpotOwnerId__c", "equals": "45282439" },
        { "path": "response.body.records[0].CRMPrincipalId__c", "exists": true }
      ]
    },
    {
      "id": "lead",
      "system": "nexuscrm",
      "authRole": "admin",
      "method": "POST",
      "path": "/services/data/v63.0/sobjects/Lead",
      "body": {
        "LastName": "OutOwner{{__runId}}",
        "Company": "OOCo{{__runId}}",
        "Email": "outowner-{{__runId}}@example.com",
        "OwnerId": "{{steps.binding.response.body.records[0].CRMPrincipalId__c}}"
      },
      "expectStatusRange": [200, 299],
      "assertions": [
        { "path": "response.body.id", "exists": true }
      ]
    },
    {
      "id": "idQ",
      "system": "nexuscrm",
      "authRole": "admin",
      "method": "GET",
      "path": "/services/data/v63.0/query?q=SELECT HubSpot_Id__c FROM Lead WHERE Id = '{{steps.lead.response.body.id}}'",
      "expectStatus": 200,
      "poll": { "budgetMs": 90000, "intervalMs": 3000 },
      "onTimeout": "fail",
      "assertions": [
        { "path": "response.body.records[0].HubSpot_Id__c", "exists": true }
      ]
    },
    {
      "id": "hsGet",
      "system": "hubspot",
      "method": "GET",
      "path": "/crm/v3/objects/contacts/{{steps.idQ.response.body.records[0].HubSpot_Id__c}}?properties=hubspot_owner_id",
      "expectStatusRange": [200, 299],
      "poll": { "budgetMs": 90000, "intervalMs": 3000 },
      "onTimeout": "fail",
      "assertions": [
        { "path": "response.body.properties.hubspot_owner_id", "equals": "{{steps.binding.response.body.records[0].HubSpotOwnerId__c}}" }
      ]
    },
    {
      "id": "find-unbound-owner",
      "system": "tidb",
      "method": "GET",
      "sql": "SELECT U.Id FROM `User` U WHERE U.IsActive = 1 AND U.Id <> '{{steps.binding.response.body.records[0].CRMPrincipalId__c}}' AND NOT EXISTS (SELECT 1 FROM `HubSpotOwnerBinding__c` B WHERE B.CRMPrincipalType__c = 'User' AND B.CRMPrincipalId__c = U.Id AND B.BindingStatus__c = 'bound') ORDER BY U.Id LIMIT 1",
      "expectStatus": 200,
      "poll": { "budgetMs": 30000, "intervalMs": 3000 },
      "onTimeout": "blocked",
      "assertions": [{ "path": "response.body.records[0].Id", "exists": true }]
    },
    {
      "id": "move-lead-to-unbound-owner",
      "system": "nexuscrm",
      "authRole": "admin",
      "method": "PATCH",
      "path": "/services/data/v63.0/sobjects/Lead/{{steps.lead.response.body.id}}",
      "body": {
        "OwnerId": "{{steps.find-unbound-owner.response.body.records[0].Id}}",
        "Title": "UnboundOwner{{__runId}}",
        "HubSpot_Sync_Enabled__c": true
      },
      "expectStatus": 204
    },
    {
      "id": "assert-unbound-owner-shadow-cleared",
      "system": "nexuscrm",
      "authRole": "admin",
      "method": "GET",
      "path": "/services/data/v63.0/query?q=SELECT OwnerId,HubSpot_Owner_Id__c,Title FROM Lead WHERE Id='{{steps.lead.response.body.id}}' LIMIT 1",
      "expectStatus": 200,
      "poll": { "budgetMs": 120000, "intervalMs": 6000 },
      "onTimeout": "fail",
      "assertions": [
        { "path": "response.body.records[0].OwnerId", "equals": "{{steps.find-unbound-owner.response.body.records[0].Id}}" },
        { "path": "response.body.records[0].HubSpot_Owner_Id__c", "exists": false },
        { "path": "response.body.records[0].Title", "equals": "UnboundOwner{{__runId}}" }
      ]
    },
    {
      "id": "assert-unbound-owner-not-pushed",
      "system": "hubspot",
      "method": "GET",
      "path": "/crm/v3/objects/contacts/{{steps.idQ.response.body.records[0].HubSpot_Id__c}}?properties=hubspot_owner_id,jobtitle",
      "expectStatus": 200,
      "poll": { "budgetMs": 180000, "intervalMs": 6000 },
      "onTimeout": "fail",
      "assertions": [
        { "path": "response.body.properties.hubspot_owner_id", "equals": "{{steps.binding.response.body.records[0].HubSpotOwnerId__c}}" },
        { "path": "response.body.properties.jobtitle", "equals": "UnboundOwner{{__runId}}" }
      ]
    }
  ]
}
