{
  "id": "k-camp-05",
  "title": "Set Campaign bulk enrollment integrity (self-contained; replays the real Set Campaign action)",
  "kind": "hubspot_sync",
  "caseTimeoutMs": 480000,
  "linkedIssues": [
    2862,
    2863,
    4273
  ],
  "provenance": {
    "businessScenario": "K-CAMP-05 (P-BULK + Campaign) — batch-enroll N unique Contacts into one Campaign via the real 'Set NexusCRM Campaign' workflow Action; assert Lead count=N, CampaignMember count=N, every CampaignMember carries the requested Status ('Sent'), every Lead has First_Campaign__c and Last_Campaign__c set to that Campaign, lost=0, duplicate Lead=0, duplicate CampaignMember=0. REAL SCALES & GATES (QA to run): N<=50 -> P95<=30s, max<=60s; N=500 -> total<=10min, throughput>=50/min.",
    "selfContained": "This case creates its own fresh Campaign per run (staging restarts wipe data) and drives the actual Set Campaign action over a `connector_action` step: one HMAC-signed POST per contact to /webhooks/hubspot-crm-connector/workflow-action, exactly as the HubSpot workflow Action does. No pre-seeded campaignId, no HubSpot list/workflow dependency, no crm.lists scope. A fresh Campaign auto-provisions the default CampaignMemberStatus 'Sent'/'Responded', so status=Sent is always valid.",
    "scaling": "N is set by `generate.count` on s1-batch-create and the four numericEquals on s2/s3/s4/s5. Committed N=8 is a CI-reliable representative. To scale: raise count (HubSpot batch-create caps at 100/call; for 500 QA runs the same case in <=100 chunks) and the matching numericEquals. The signed action fan-out and the campaign-scoped count assertions already scale to any N. s5 re-reads Status from the persisted CampaignMember rows: paired with s4 (total=N) it proves every member landed with the Status the action asked for, closing the gap where a dropped or rewritten status still passed the case.",
    "reportedBy": "HubSpot sync spec K-CAMP-05 (hubspot-nexuscrm-sync-CASE-EXEC-SELFCONTAINED)",
    "capturedAt": "2026-06-29",
    "calibrated": "[calibrated] optional removed — self-contained via connector_action signed Set Campaign action (validated on staging: 202 + CampaignMember on a fresh campaign)"
  },
  "steps": [
    {
      "id": "s0-create-campaign",
      "system": "nexuscrm",
      "authRole": "admin",
      "method": "POST",
      "path": "/services/data/v63.0/sobjects/Campaign",
      "body": {
        "Name": "IT K-CAMP-05 {{__runId}}",
        "IsActive": true
      },
      "expectStatusRange": [
        200,
        299
      ],
      "assertions": [
        {
          "path": "response.body.id",
          "exists": true
        }
      ]
    },
    {
      "id": "s1-batch-create",
      "system": "hubspot",
      "method": "POST",
      "path": "/crm/v3/objects/contacts/batch/create",
      "generate": {
        "count": 8,
        "into": "inputs",
        "itemTemplate": {
          "properties": {
            "email": "kcamp05-{{__runId}}-{{i}}@example.com",
            "firstname": "KCamp05",
            "lastname": "Member-{{i}}",
            "company": "IT BulkCo {{i}}",
            "country_picklist__sfdc_": "Japan",
            "lifecyclestage": "lead"
          }
        }
      },
      "expectStatusRange": [
        200,
        299
      ],
      "assertions": [
        {
          "path": "response.body.results",
          "lengthAtLeast": 8
        }
      ]
    },
    {
      "id": "s2-set-campaign",
      "system": "connector_action",
      "path": "/webhooks/hubspot-crm-connector/workflow-action",
      "forEach": "steps.s1-batch-create.response.body.results",
      "contactIdField": "id",
      "emailField": "properties.email",
      "campaignId": "{{steps.s0-create-campaign.response.body.id}}",
      "status": "Sent",
      "concurrency": 4,
      "assertions": [
        {
          "path": "response.body.failedCount",
          "numericEquals": 0
        },
        {
          "path": "response.body.acceptedCount",
          "numericEquals": 8
        }
      ]
    },
    {
      "id": "s3-lead-attribution-count",
      "system": "nexuscrm",
      "authRole": "admin",
      "method": "GET",
      "path": "/services/data/v63.0/query?q=SELECT COUNT() FROM Lead WHERE Id IN (SELECT LeadId FROM CampaignMember WHERE CampaignId='{{steps.s0-create-campaign.response.body.id}}') AND First_Campaign__c='{{steps.s0-create-campaign.response.body.id}}' AND Last_Campaign__c='{{steps.s0-create-campaign.response.body.id}}'",
      "expectStatus": 200,
      "poll": {
        "budgetMs": 240000,
        "intervalMs": 10000
      },
      "onTimeout": "fail",
      "assertions": [
        {
          "path": "response.body.totalSize",
          "numericEquals": 8
        }
      ]
    },
    {
      "id": "s4-campaignmember-count",
      "system": "nexuscrm",
      "authRole": "admin",
      "method": "GET",
      "path": "/services/data/v63.0/query?q=SELECT COUNT() FROM CampaignMember WHERE CampaignId='{{steps.s0-create-campaign.response.body.id}}'",
      "expectStatus": 200,
      "poll": {
        "budgetMs": 120000,
        "intervalMs": 10000
      },
      "onTimeout": "fail",
      "assertions": [
        {
          "path": "response.body.totalSize",
          "numericEquals": 8
        }
      ]
    },
    {
      "id": "s5-campaignmember-status-count",
      "system": "nexuscrm",
      "authRole": "admin",
      "method": "GET",
      "path": "/services/data/v63.0/query?q=SELECT COUNT() FROM CampaignMember WHERE CampaignId='{{steps.s0-create-campaign.response.body.id}}' AND Status='Sent'",
      "expectStatus": 200,
      "poll": {
        "budgetMs": 60000,
        "intervalMs": 10000
      },
      "onTimeout": "fail",
      "assertions": [
        {
          "path": "response.body.totalSize",
          "numericEquals": 8
        }
      ]
    }
  ]
}
