{
  "id": "uwv0j8l2ATzvdHpg",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Autonomous A/B Test Orchestrator",
  "tags": [],
  "nodes": [
    {
      "id": "36414041-56c4-48bc-9a4d-de10903df58e",
      "name": "Gemini \u2014 Generate Variants1",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -432,
        3648
      ],
      "parameters": {
        "url": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=YOUR_TOKEN_HERE",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"contents\": [\n    {\n      \"parts\": [\n        {\n          \"text\": \"You are a world-class email copywriter specializing in A/B testing. Generate exactly 2 email variants for testing.\\n\\nHypothesis: {{ $json.hypothesis }}\\nMetric to optimize: {{ $json.metric }}\\nEmail Subject Base: {{ $json.emailSubject }}\\n\\nReturn ONLY valid JSON (no markdown, no explanation) in this exact format:\\n{\\n  \\\"variant_a\\\": {\\n    \\\"subject\\\": \\\"subject line for variant A\\\",\\n    \\\"preview_text\\\": \\\"preview text for variant A\\\",\\n    \\\"body_html\\\": \\\"<p>Full HTML email body for variant A.</p>\\\",\\n    \\\"rationale\\\": \\\"why this variant tests the hypothesis\\\"\\n  },\\n  \\\"variant_b\\\": {\\n    \\\"subject\\\": \\\"subject line for variant B\\\",\\n    \\\"preview_text\\\": \\\"preview text for variant B\\\",\\n    \\\"body_html\\\": \\\"<p>Full HTML email body for variant B.</p>\\\",\\n    \\\"rationale\\\": \\\"why this variant contrasts with A\\\"\\n  }\\n}\"\n        }\n      ]\n    }\n  ],\n  \"generationConfig\": {\n    \"temperature\": 0.7,\n    \"maxOutputTokens\": 3000,\n    \"thinkingConfig\": {\n      \"thinkingBudget\": 0\n    }\n  }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "content-type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "a8d3a0f5-37ee-407c-b0d2-4e7efbc3023c",
      "name": "Parse Variants from Gemini1",
      "type": "n8n-nodes-base.code",
      "position": [
        -208,
        3648
      ],
      "parameters": {
        "jsCode": "// Parse Gemini's response structure\nconst geminiResponse = $input.first().json;\nconst textContent = geminiResponse.candidates?.[0]?.content?.parts?.[0]?.text;\n\nif (!textContent) throw new Error('No response from Gemini');\n\nlet variants;\ntry {\n  variants = JSON.parse(textContent);\n} catch(e) {\n  const match = textContent.match(/\\{[\\s\\S]*\\}/);\n  if (match) {\n    variants = JSON.parse(match[0]);\n  } else {\n    throw new Error('Could not parse variants JSON from Gemini: ' + textContent);\n  }\n}\n\nconst prevData = $('Parse & Validate Form Data').first().json;\n\nreturn [{\n  json: {\n    ...prevData,\n    variant_a: variants.variant_a,\n    variant_b: variants.variant_b,\n    status: 'variants_generated'\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "074c52d5-f073-4764-a5be-44b328820de6",
      "name": "Prepare Mailjet Payloads1",
      "type": "n8n-nodes-base.code",
      "position": [
        32,
        3648
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\n\nconst cleanHtml = (html) => html\n  .replace(/[\\r\\n\\t]+/g, ' ')\n  .trim();\n\nreturn [{\n  json: {\n    ...data,\n    mailjet_payload_a: {\n      FromEmail: data.fromEmail,\n      FromName: data.fromName,\n      Subject: data.variant_a.subject,\n      \"Html-part\": cleanHtml(data.variant_a.body_html),\n      Recipients: [{ Email: data.fromEmail }],\n      Headers: {\n        \"Reply-To\": data.fromEmail\n      }\n    },\n    mailjet_payload_b: {\n      FromEmail: data.fromEmail,\n      FromName: data.fromName,\n      Subject: data.variant_b.subject,\n      \"Html-part\": cleanHtml(data.variant_b.body_html),\n      Recipients: [{ Email: data.fromEmail }],\n      Headers: {\n        \"Reply-To\": data.fromEmail\n      }\n    }\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "56344fe3-ca1f-4cd1-ae5e-70b3b30df4b4",
      "name": "Mailjet \u2014 Send Variant A1",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        272,
        3536
      ],
      "parameters": {
        "url": "https://api.mailjet.com/v3/send",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify($json.mailjet_payload_a) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "content-type",
              "value": "application/json"
            },
            {
              "name": "Authorization",
              "value": "Basic ODYyNDhiMjY4ZWE5ZWQ3YzFhYjU0Yjc2MGIxYjc5OTA6MmIxNmNhNzU2NWViYmI2ZDU4NDNhYzFhMjhmNTIyYmM="
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "82316cb0-d258-499c-9736-fca3ba3fa772",
      "name": "Mailjet \u2014 Send Variant B1",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        272,
        3776
      ],
      "parameters": {
        "url": "https://api.mailjet.com/v3/send",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify($json.mailjet_payload_b) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "content-type",
              "value": "application/json"
            },
            {
              "name": "Authorization",
              "value": "Basic ODYyNDhiMjY4ZWE5ZWQ3YzFhYjU0Yjc2MGIxYjc5OTA6MmIxNmNhNzU2NWViYmI2ZDU4NDNhYzFhMjhmNTIyYmM="
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "d11a7574-04ec-42f9-9533-80b7782d098f",
      "name": "Mailjet \u2014 Poll Results Variant A1",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -288,
        4192
      ],
      "parameters": {
        "url": "=https://api.mailjet.com/v3/REST/message?MessageUUID={{ $json.campaignIdA }}",
        "options": {},
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Basic ODYyNDhiMjY4ZWE5ZWQ3YzFhYjU0Yjc2MGIxYjc5OTA6MmIxNmNhNzU2NWViYmI2ZDU4NDNhYzFhMjhmNTIyYmM="
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "6e186f49-e14f-41b9-abe5-610c95be0c40",
      "name": "Mailjet \u2014 Poll Results Variant B1",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -288,
        4352
      ],
      "parameters": {
        "url": "=https://api.mailjet.com/v3/REST/message?MessageUUID={{ $json.campaignIdB }}",
        "options": {},
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Basic ODYyNDhiMjY4ZWE5ZWQ3YzFhYjU0Yjc2MGIxYjc5OTA6MmIxNmNhNzU2NWViYmI2ZDU4NDNhYzFhMjhmNTIyYmM="
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "235fa117-7411-41aa-bfa9-9b416e4719b7",
      "name": "Log Loser (Mailjet)1",
      "type": "n8n-nodes-base.code",
      "position": [
        1184,
        4144
      ],
      "parameters": {
        "jsCode": "// Mailjet doesn't have an archive API \u2014 log the loser UUID for reference\nconst data = $input.first().json;\nconsole.log('Loser campaign UUID:', data.loserCampaignId);\nconsole.log('Winner campaign UUID:', data.winnerCampaignId);\nreturn [{ json: { ...data, archivedAt: new Date().toISOString() } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "a43b195a-e791-41be-9df8-558b56bbe38c",
      "name": "Google Sheets Trigger",
      "type": "n8n-nodes-base.googleSheetsTrigger",
      "position": [
        -880,
        3648
      ],
      "parameters": {
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1pKhSTA4_KQfiEA69LNoY5voPvpN7vaCaYtHIVzv2EI0/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1pKhSTA4_KQfiEA69LNoY5voPvpN7vaCaYtHIVzv2EI0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1pKhSTA4_KQfiEA69LNoY5voPvpN7vaCaYtHIVzv2EI0/edit?usp=drivesdk",
          "cachedResultName": "Email responses"
        }
      },
      "credentials": {
        "googleSheetsTriggerOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "a84de7c0-16c4-4f86-800c-d9ef44f3f4f9",
      "name": "Parse & Validate Form Data",
      "type": "n8n-nodes-base.code",
      "position": [
        -656,
        3648
      ],
      "parameters": {
        "jsCode": "// Extract and validate incoming form data\nconst body = $input.first().json.body || $input.first().json;\n\nconst hypothesis = body.hypothesis || body.field_1 || '';\nconst metric = body.metric || body.field_2 || 'open_rate';\nconst emailSubject = body.email_subject || body.field_3 || 'Test Email';\nconst audienceSize = body.audience_size || 200;\nconst testDurationDays = body.test_duration_days || 7;\nconst fromEmail = body.from_email || 'user@example.com';\nconst fromName = body.from_name || 'Techdome';\nconst listId = body.list_id || 4;\n\nif (!hypothesis) throw new Error('Missing hypothesis in form data');\nif (!metric) throw new Error('Missing metric in form data');\n\nconst testId = 'ab_' + Date.now();\nconst startDate = new Date().toISOString();\nconst endDate = new Date(Date.now() + testDurationDays * 86400000).toISOString();\n\nreturn [{\n  json: {\n    testId,\n    hypothesis,\n    metric,\n    emailSubject,\n    audienceSize,\n    testDurationDays,\n    fromEmail,\n    fromName,\n    listId,\n    startDate,\n    endDate,\n    status: 'generating_variants'\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "f0fe3e6f-0b70-4dcd-8ae3-db7567ea27e0",
      "name": "Merge Campaign IDs",
      "type": "n8n-nodes-base.code",
      "position": [
        800,
        3648
      ],
      "parameters": {
        "jsCode": "// Merge MessageIDs from both Mailjet sends\nconst variantAResponse = $('Mailjet \u2014 Send Variant A1').first().json;\nconst variantBResponse = $('Mailjet \u2014 Send Variant B1').first().json;\nconst parsedData = $('Prepare Mailjet Payloads1').first().json;\n\nconst campaignIdA = variantAResponse.Sent?.[0]?.MessageUUID;\nconst campaignIdB = variantBResponse.Sent?.[0]?.MessageUUID;\nconst messageIdA = variantAResponse.Sent?.[0]?.MessageID;\nconst messageIdB = variantBResponse.Sent?.[0]?.MessageID;\n\nif (!campaignIdA || !campaignIdB) {\n  throw new Error('Failed to send Mailjet emails. Response A: ' + JSON.stringify(variantAResponse) + ', Response B: ' + JSON.stringify(variantBResponse));\n}\n\nreturn [{\n  json: {\n    ...parsedData,\n    campaignIdA,\n    campaignIdB,\n    messageIdA,\n    messageIdB,\n    status: 'campaigns_sent'\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "96b752e3-ed31-42e7-92e6-ba5e2d4a4aa8",
      "name": "Notion \u2014 Log Test Start",
      "type": "n8n-nodes-base.notion",
      "position": [
        1056,
        3648
      ],
      "parameters": {
        "title": "=A/B Test: {{ $json.testId }}",
        "options": {},
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "35ff839f-1184-804c-9b57-c474dc64d6b5",
          "cachedResultUrl": "https://www.notion.so/35ff839f1184804c9b57c474dc64d6b5",
          "cachedResultName": "Email Tracker"
        },
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Test ID|rich_text",
              "textContent": "={{ $json.testId }}"
            },
            {
              "key": "Hypothesis|rich_text",
              "textContent": "={{ $json.hypothesis }}"
            },
            {
              "key": "Metric|rich_text",
              "textContent": "={{ $json.metric }}"
            },
            {
              "key": "Status|rich_text",
              "textContent": "running"
            },
            {
              "key": "Campaign ID A|rich_text",
              "textContent": "={{ $json.campaignIdA }}"
            },
            {
              "key": "Campaign ID B|rich_text",
              "textContent": "={{ $json.campaignIdB }}"
            },
            {
              "key": "Start Date|rich_text",
              "textContent": "={{ $json.startDate }}"
            },
            {
              "key": "End Date|rich_text",
              "textContent": "={{ $json.endDate }}"
            },
            {
              "key": "Variant A Subject|rich_text",
              "textContent": "={{ $json.variant_a.subject }}"
            },
            {
              "key": "Variant A Rationale|rich_text",
              "textContent": "={{ $json.variant_a.rationale }}"
            },
            {
              "key": "Variant B Rationale|rich_text",
              "textContent": "={{ $json.variant_b.rationale }}"
            },
            {
              "key": "Variant B Subject|rich_text",
              "textContent": "={{ $json.variant_b.subject }}"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "ca2fae9a-e9a6-4235-b16e-f221e25fb85e",
      "name": "Daily Poller \u2014 Every 24hrs",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -960,
        4272
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 24
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "2b130526-7b42-4053-bc00-f70f01744f74",
      "name": "Notion \u2014 Get Active Tests",
      "type": "n8n-nodes-base.notion",
      "position": [
        -736,
        4272
      ],
      "parameters": {
        "simple": false,
        "options": {},
        "resource": "databasePage",
        "operation": "getAll",
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "35ff839f-1184-804c-9b57-c474dc64d6b5",
          "cachedResultUrl": "https://www.notion.so/35ff839f1184804c9b57c474dc64d6b5",
          "cachedResultName": "Email Tracker"
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "5d6009b9-4d15-467e-ada4-eb437e9a700b",
      "name": "Extract Active Tests",
      "type": "n8n-nodes-base.code",
      "position": [
        -512,
        4272
      ],
      "parameters": {
        "jsCode": "const pages = $input.all();\n\nif (!pages || pages.length === 0) {\n  return [];\n}\n\nconst activeTests = [];\n\nfor (const page of pages) {\n  const props = page.json.properties || {};\n  \n  const getTextProp = (key) => {\n    const prop = props[key];\n    if (!prop) return '';\n    if (prop.rich_text && prop.rich_text.length > 0) return prop.rich_text[0].plain_text;\n    if (prop.title && prop.title.length > 0) return prop.title[0].plain_text;\n    return '';\n  };\n  \n  const status = getTextProp('Status');\n  const testId = getTextProp('Test ID');\n  \n  if (status !== 'running') continue;\n  if (!testId) continue;\n  \n  activeTests.push({\n    notionPageId: page.json.id,\n    testId,\n    hypothesis: getTextProp('Hypothesis'),\n    metric: getTextProp('Metric'),\n    campaignIdA: getTextProp('Campaign ID A'),\n    campaignIdB: getTextProp('Campaign ID B'),\n    endDate: getTextProp('End Date'),\n    variantASubject: getTextProp('Variant A Subject'),\n    variantBSubject: getTextProp('Variant B Subject')\n  });\n}\n\nreturn activeTests.map(t => ({ json: t }));"
      },
      "typeVersion": 2
    },
    {
      "id": "f40bdd4f-71ff-429c-94c2-2ee50ee3a337",
      "name": "Significance Test (Chi-Squared)",
      "type": "n8n-nodes-base.code",
      "position": [
        304,
        4272
      ],
      "parameters": {
        "jsCode": "// Merge results from both variants and run statistical significance test\nconst testMeta = $('Extract Active Tests').first().json;\nconst reportA = $('Mailjet \u2014 Poll Results Variant A1').first().json;\nconst reportB = $('Mailjet \u2014 Poll Results Variant B1').first().json;\n\n// Extract stats from Mailjet message response\nconst msgA = reportA.Data?.[0] || {};\nconst msgB = reportB.Data?.[0] || {};\n\nconst sendA = 1;\nconst openA = msgA.IsOpenTracked && msgA.Status === 'opened' ? 1 : 0;\nconst clickA = msgA.IsClickTracked && msgA.Status === 'clicked' ? 1 : 0;\n\nconst sendB = 1;\nconst openB = msgB.IsOpenTracked && msgB.Status === 'opened' ? 1 : 0;\nconst clickB = msgB.IsClickTracked && msgB.Status === 'clicked' ? 1 : 0;\n\nconst metric = testMeta.metric || 'open_rate';\n\nlet successA, successB, trialsA, trialsB;\nif (metric === 'click_rate') {\n  successA = clickA; trialsA = sendA;\n  successB = clickB; trialsB = sendB;\n} else {\n  successA = openA; trialsA = sendA;\n  successB = openB; trialsB = sendB;\n}\n\nconst rateA = trialsA > 0 ? successA / trialsA : 0;\nconst rateB = trialsB > 0 ? successB / trialsB : 0;\n\nconst failA = trialsA - successA;\nconst failB = trialsB - successB;\nconst N = trialsA + trialsB;\n\nlet chiSquared = 0;\nlet isSignificant = false;\nlet winner = null;\nlet confidence = 0;\n\nif (N > 0 && trialsA > 0 && trialsB > 0) {\n  const totalSuccess = successA + successB;\n  const totalFail = failA + failB;\n  const eA_success = (trialsA * totalSuccess) / N;\n  const eA_fail = (trialsA * totalFail) / N;\n  const eB_success = (trialsB * totalSuccess) / N;\n  const eB_fail = (trialsB * totalFail) / N;\n  \n  chiSquared = 0;\n  if (eA_success > 0) chiSquared += Math.pow(successA - eA_success, 2) / eA_success;\n  if (eA_fail > 0) chiSquared += Math.pow(failA - eA_fail, 2) / eA_fail;\n  if (eB_success > 0) chiSquared += Math.pow(successB - eB_success, 2) / eB_success;\n  if (eB_fail > 0) chiSquared += Math.pow(failB - eB_fail, 2) / eB_fail;\n  \n  isSignificant = chiSquared > 3.841;\n  \n  if (chiSquared > 10.828) confidence = 99.9;\n  else if (chiSquared > 7.879) confidence = 99.5;\n  else if (chiSquared > 6.635) confidence = 99;\n  else if (chiSquared > 5.024) confidence = 97.5;\n  else if (chiSquared > 3.841) confidence = 95;\n  else if (chiSquared > 2.706) confidence = 90;\n  else confidence = Math.round(50 + chiSquared * 14.6);\n  \n  if (isSignificant) {\n    winner = rateA >= rateB ? 'A' : 'B';\n  }\n}\n\nconst endDate = new Date(testMeta.endDate);\nconst now = new Date();\nconst testExpired = now > endDate;\n\nlet decision;\nif (isSignificant) {\n  decision = 'declare_winner';\n} else if (testExpired) {\n  decision = 'no_winner_archive';\n} else {\n  decision = 'extend_test';\n}\n\nreturn [{\n  json: {\n    ...testMeta,\n    sendA, openA, clickA, rateA: Math.round(rateA * 10000) / 100,\n    sendB, openB, clickB, rateB: Math.round(rateB * 10000) / 100,\n    statusA: msgA.Status || 'unknown',\n    statusB: msgB.Status || 'unknown',\n    chiSquared: Math.round(chiSquared * 1000) / 1000,\n    isSignificant,\n    confidence,\n    winner,\n    decision,\n    testExpired,\n    analyzedAt: new Date().toISOString()\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "240e9dee-1574-4ebb-93fd-630ea8fded86",
      "name": "Route: Winner Found?",
      "type": "n8n-nodes-base.if",
      "position": [
        512,
        4272
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "winner-condition",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.decision }}",
              "rightValue": "declare_winner"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "75cdad42-c57f-4025-a880-a90a5056a2bf",
      "name": "Route: Expired or Extend?",
      "type": "n8n-nodes-base.if",
      "position": [
        736,
        4384
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "caseSensitive": true
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "no-winner-condition",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.decision }}",
              "rightValue": "no_winner_archive"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "2b7e045f-2ce0-49d7-afdc-f99ceaca0ad0",
      "name": "Notion \u2014 Log Winner",
      "type": "n8n-nodes-base.notion",
      "position": [
        736,
        4144
      ],
      "parameters": {
        "pageId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.notionPageId }}"
        },
        "options": {},
        "resource": "databasePage",
        "operation": "update",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Status|rich_text",
              "textContent": "winner_declared"
            },
            {
              "key": "Winner|rich_text",
              "textContent": "={{ \"Variant \" + $json.winner }}"
            },
            {
              "key": "Rate A|rich_text",
              "textContent": "={{ $json.rateA + \"%\" }}"
            },
            {
              "key": "Rate B|rich_text",
              "textContent": "={{ $json.rateB + \"%\" }}"
            },
            {
              "key": "Chi-Squared|rich_text",
              "textContent": "={{ $json.chiSquared }}"
            },
            {
              "key": "Confidence|rich_text",
              "textContent": "={{ $json.confidence + \"%\" }}"
            },
            {
              "key": "Decision|rich_text",
              "textContent": "={{ \"Winner declared at \" + $json.confidence + \"% confidence\" }}"
            },
            {
              "key": "Analyzed At|rich_text",
              "textContent": "={{ $json.analyzedAt }}"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "55f2d45f-b302-4759-abd5-23d5fe212306",
      "name": "Identify Loser Campaign",
      "type": "n8n-nodes-base.code",
      "position": [
        960,
        4144
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\n\nconst loserCampaignId = data.winner === 'A' ? data.campaignIdB : data.campaignIdA;\nconst winnerCampaignId = data.winner === 'A' ? data.campaignIdA : data.campaignIdB;\n\nreturn [{\n  json: {\n    ...data,\n    loserCampaignId,\n    winnerCampaignId\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "b0e4bf32-441e-4857-b1d2-d57456e3b1e7",
      "name": "Notion \u2014 Log No Winner",
      "type": "n8n-nodes-base.notion",
      "position": [
        1024,
        4400
      ],
      "parameters": {
        "pageId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.notionPageId }}"
        },
        "options": {},
        "resource": "databasePage",
        "operation": "update",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Status|rich_text",
              "textContent": "no_winner_archived"
            },
            {
              "key": "Decision|rich_text",
              "textContent": "={{ \"Test expired with no significant winner. Chi-squared: \" + $json.chiSquared + \", Confidence: \" + $json.confidence + \"%\" }}"
            },
            {
              "key": "Rate A|rich_text",
              "textContent": "={{ $json.rateA + \"%\" }}"
            },
            {
              "key": "Rate B|rich_text",
              "textContent": "={{ $json.rateB + \"%\" }}"
            },
            {
              "key": "Analyzed At|rich_text",
              "textContent": "={{ $json.analyzedAt }}"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "81b62eb1-08ba-4623-a6a6-310451456051",
      "name": "Merge1",
      "type": "n8n-nodes-base.merge",
      "position": [
        592,
        3648
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "f94a7281-c79b-49b0-b67b-a7103842e75e",
      "name": "Merge2",
      "type": "n8n-nodes-base.merge",
      "position": [
        32,
        4256
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "21e85667-f91e-406c-bd89-da99f891c1b4",
      "name": "Notion \u2014 Log Extend Test2",
      "type": "n8n-nodes-base.notion",
      "position": [
        1008,
        4608
      ],
      "parameters": {
        "pageId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.notionPageId }}"
        },
        "options": {},
        "resource": "databasePage",
        "operation": "update",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Status|rich_text",
              "textContent": "running"
            },
            {
              "key": "Decision text|rich_text",
              "textContent": "={{ \"Extending: Chi-squared \" + $json.chiSquared + \" (need >3.841). Rate A: \" + $json.rateA + \"%, Rate B: \" + $json.rateB + \"%. Checked \" + $json.analyzedAt }}"
            },
            {
              "key": "Analyzed at|rich_text",
              "textContent": "={{ $json.analyzedAt }}"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "230c50b3-d651-4d7c-88fe-0dd7953c9123",
      "name": "\ud83e\udd16 AI: Generate Email Variants (Gemini)",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -496,
        6256
      ],
      "parameters": {
        "url": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=YOUR_TOKEN_HERE",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"contents\": [\n    {\n      \"parts\": [\n        {\n          \"text\": \"You are a world-class email copywriter specializing in A/B testing. Generate exactly 2 email variants for testing.\\n\\nHypothesis: {{ $json.hypothesis }}\\nMetric to optimize: {{ $json.metric }}\\nEmail Subject Base: {{ $json.emailSubject }}\\n\\nReturn ONLY valid JSON (no markdown, no explanation) in this exact format:\\n{\\n  \\\"variant_a\\\": {\\n    \\\"subject\\\": \\\"subject line for variant A\\\",\\n    \\\"preview_text\\\": \\\"preview text for variant A\\\",\\n    \\\"body_html\\\": \\\"<p>Full HTML email body for variant A.</p>\\\",\\n    \\\"rationale\\\": \\\"why this variant tests the hypothesis\\\"\\n  },\\n  \\\"variant_b\\\": {\\n    \\\"subject\\\": \\\"subject line for variant B\\\",\\n    \\\"preview_text\\\": \\\"preview text for variant B\\\",\\n    \\\"body_html\\\": \\\"<p>Full HTML email body for variant B.</p>\\\",\\n    \\\"rationale\\\": \\\"why this variant contrasts with A\\\"\\n  }\\n}\"\n        }\n      ]\n    }\n  ],\n  \"generationConfig\": {\n    \"temperature\": 0.7,\n    \"maxOutputTokens\": 3000,\n    \"thinkingConfig\": {\n      \"thinkingBudget\": 0\n    }\n  }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "content-type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "980f05b9-c256-4042-9c14-8ff67732fd46",
      "name": "\ud83d\udcdd Parse Gemini JSON Response",
      "type": "n8n-nodes-base.code",
      "position": [
        -272,
        6256
      ],
      "parameters": {
        "jsCode": "// Parse Gemini's response structure\nconst geminiResponse = $input.first().json;\nconst textContent = geminiResponse.candidates?.[0]?.content?.parts?.[0]?.text;\n\nif (!textContent) throw new Error('No response from Gemini');\n\nlet variants;\ntry {\n  variants = JSON.parse(textContent);\n} catch(e) {\n  const match = textContent.match(/\\{[\\s\\S]*\\}/);\n  if (match) {\n    variants = JSON.parse(match[0]);\n  } else {\n    throw new Error('Could not parse variants JSON from Gemini: ' + textContent);\n  }\n}\n\nconst prevData = $('Parse & Validate Form Data').first().json;\n\nreturn [{\n  json: {\n    ...prevData,\n    variant_a: variants.variant_a,\n    variant_b: variants.variant_b,\n    status: 'variants_generated'\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "a5d73816-1bc2-4f84-bf07-b57c3a6766d4",
      "name": "\ud83d\udce6 Build Mailjet Email Payloads",
      "type": "n8n-nodes-base.code",
      "position": [
        -32,
        6256
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\n\nconst cleanHtml = (html) => html\n  .replace(/[\\r\\n\\t]+/g, ' ')\n  .trim();\n\nreturn [{\n  json: {\n    ...data,\n    mailjet_payload_a: {\n      FromEmail: data.fromEmail,\n      FromName: data.fromName,\n      Subject: data.variant_a.subject,\n      \"Html-part\": cleanHtml(data.variant_a.body_html),\n      Recipients: [{ Email: data.fromEmail }],\n      Headers: {\n        \"Reply-To\": data.fromEmail\n      }\n    },\n    mailjet_payload_b: {\n      FromEmail: data.fromEmail,\n      FromName: data.fromName,\n      Subject: data.variant_b.subject,\n      \"Html-part\": cleanHtml(data.variant_b.body_html),\n      Recipients: [{ Email: data.fromEmail }],\n      Headers: {\n        \"Reply-To\": data.fromEmail\n      }\n    }\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "25fa41e9-1858-4b54-acb2-945a63e7b1e7",
      "name": "\ud83d\udce7 Send Email \u2014 Variant A",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        208,
        6144
      ],
      "parameters": {
        "url": "https://api.mailjet.com/v3/send",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify($json.mailjet_payload_a) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "content-type",
              "value": "application/json"
            },
            {
              "name": "Authorization",
              "value": "Basic ODYyNDhiMjY4ZWE5ZWQ3YzFhYjU0Yjc2MGIxYjc5OTA6MmIxNmNhNzU2NWViYmI2ZDU4NDNhYzFhMjhmNTIyYmM="
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "d9dd578a-2dfe-4b2e-8d98-e8cf57fb9a92",
      "name": "\ud83d\udce7 Send Email \u2014 Variant B",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        208,
        6384
      ],
      "parameters": {
        "url": "https://api.mailjet.com/v3/send",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify($json.mailjet_payload_b) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "content-type",
              "value": "application/json"
            },
            {
              "name": "Authorization",
              "value": "Basic ODYyNDhiMjY4ZWE5ZWQ3YzFhYjU0Yjc2MGIxYjc5OTA6MmIxNmNhNzU2NWViYmI2ZDU4NDNhYzFhMjhmNTIyYmM="
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "f3f47e16-d084-4e85-819b-b545387c92bd",
      "name": "\ud83d\udcca Poll Mailjet \u2014 Variant A Stats",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -208,
        7200
      ],
      "parameters": {
        "url": "=https://api.mailjet.com/v3/REST/message?MessageUUID={{ $json.campaignIdA }}",
        "options": {},
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Basic ODYyNDhiMjY4ZWE5ZWQ3YzFhYjU0Yjc2MGIxYjc5OTA6MmIxNmNhNzU2NWViYmI2ZDU4NDNhYzFhMjhmNTIyYmM="
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "9b2fa353-7e2d-4e4b-a8f3-60199298f883",
      "name": "\ud83d\udcca Poll Mailjet \u2014 Variant B Stats",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -208,
        7360
      ],
      "parameters": {
        "url": "=https://api.mailjet.com/v3/REST/message?MessageUUID={{ $json.campaignIdB }}",
        "options": {},
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Basic ODYyNDhiMjY4ZWE5ZWQ3YzFhYjU0Yjc2MGIxYjc5OTA6MmIxNmNhNzU2NWViYmI2ZDU4NDNhYzFhMjhmNTIyYmM="
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "e856ede1-501c-44b9-8d8e-ca97e7e5a804",
      "name": "\ud83d\uddd1\ufe0f Log Loser Campaign UUID (Audit)",
      "type": "n8n-nodes-base.code",
      "position": [
        1264,
        7152
      ],
      "parameters": {
        "jsCode": "// Mailjet doesn't have an archive API \u2014 log the loser UUID for reference\nconst data = $input.first().json;\nconsole.log('Loser campaign UUID:', data.loserCampaignId);\nconsole.log('Winner campaign UUID:', data.winnerCampaignId);\nreturn [{ json: { ...data, archivedAt: new Date().toISOString() } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "c667abd2-7c68-478f-8312-7c07ef2048c2",
      "name": "\ud83d\udce5 Watch Form Submissions (Google Sheets)",
      "type": "n8n-nodes-base.googleSheetsTrigger",
      "position": [
        -944,
        6256
      ],
      "parameters": {
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1pKhSTA4_KQfiEA69LNoY5voPvpN7vaCaYtHIVzv2EI0/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1pKhSTA4_KQfiEA69LNoY5voPvpN7vaCaYtHIVzv2EI0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1pKhSTA4_KQfiEA69LNoY5voPvpN7vaCaYtHIVzv2EI0/edit?usp=drivesdk",
          "cachedResultName": "Email responses"
        }
      },
      "credentials": {
        "googleSheetsTriggerOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "88f50115-9d2b-402d-8041-43c894b5edcd",
      "name": "\ud83d\udd0d Parse & Validate Input Data",
      "type": "n8n-nodes-base.code",
      "position": [
        -720,
        6256
      ],
      "parameters": {
        "jsCode": "// Extract and validate incoming form data\nconst body = $input.first().json.body || $input.first().json;\n\nconst hypothesis = body.hypothesis || body.field_1 || '';\nconst metric = body.metric || body.field_2 || 'open_rate';\nconst emailSubject = body.email_subject || body.field_3 || 'Test Email';\nconst audienceSize = body.audience_size || 200;\nconst testDurationDays = body.test_duration_days || 7;\nconst fromEmail = body.from_email || 'user@example.com';\nconst fromName = body.from_name || 'Techdome';\nconst listId = body.list_id || 4;\n\nif (!hypothesis) throw new Error('Missing hypothesis in form data');\nif (!metric) throw new Error('Missing metric in form data');\n\nconst testId = 'ab_' + Date.now();\nconst startDate = new Date().toISOString();\nconst endDate = new Date(Date.now() + testDurationDays * 86400000).toISOString();\n\nreturn [{\n  json: {\n    testId,\n    hypothesis,\n    metric,\n    emailSubject,\n    audienceSize,\n    testDurationDays,\n    fromEmail,\n    fromName,\n    listId,\n    startDate,\n    endDate,\n    status: 'generating_variants'\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "bb11a65a-7ece-4246-b4c6-021ea2d4eb1e",
      "name": "\ud83d\udd17 Extract & Merge Campaign IDs",
      "type": "n8n-nodes-base.code",
      "position": [
        736,
        6256
      ],
      "parameters": {
        "jsCode": "// Merge MessageIDs from both Mailjet sends\nconst variantAResponse = $('Mailjet \u2014 Send Variant A1').first().json;\nconst variantBResponse = $('Mailjet \u2014 Send Variant B1').first().json;\nconst parsedData = $('Prepare Mailjet Payloads1').first().json;\n\nconst campaignIdA = variantAResponse.Sent?.[0]?.MessageUUID;\nconst campaignIdB = variantBResponse.Sent?.[0]?.MessageUUID;\nconst messageIdA = variantAResponse.Sent?.[0]?.MessageID;\nconst messageIdB = variantBResponse.Sent?.[0]?.MessageID;\n\nif (!campaignIdA || !campaignIdB) {\n  throw new Error('Failed to send Mailjet emails. Response A: ' + JSON.stringify(variantAResponse) + ', Response B: ' + JSON.stringify(variantBResponse));\n}\n\nreturn [{\n  json: {\n    ...parsedData,\n    campaignIdA,\n    campaignIdB,\n    messageIdA,\n    messageIdB,\n    status: 'campaigns_sent'\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "479920ae-ef42-45ef-9e8a-53dc656f75b1",
      "name": "\ud83d\udcd3 Log Test Start to Notion",
      "type": "n8n-nodes-base.notion",
      "position": [
        992,
        6256
      ],
      "parameters": {
        "title": "=A/B Test: {{ $json.testId }}",
        "options": {},
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "35ff839f-1184-804c-9b57-c474dc64d6b5",
          "cachedResultUrl": "https://www.notion.so/35ff839f1184804c9b57c474dc64d6b5",
          "cachedResultName": "Email Tracker"
        },
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Test ID|rich_text",
              "textContent": "={{ $json.testId }}"
            },
            {
              "key": "Hypothesis|rich_text",
              "textContent": "={{ $json.hypothesis }}"
            },
            {
              "key": "Metric|rich_text",
              "textContent": "={{ $json.metric }}"
            },
            {
              "key": "Status|rich_text",
              "textContent": "running"
            },
            {
              "key": "Campaign ID A|rich_text",
              "textContent": "={{ $json.campaignIdA }}"
            },
            {
              "key": "Campaign ID B|rich_text",
              "textContent": "={{ $json.campaignIdB }}"
            },
            {
              "key": "Start Date|rich_text",
              "textContent": "={{ $json.startDate }}"
            },
            {
              "key": "End Date|rich_text",
              "textContent": "={{ $json.endDate }}"
            },
            {
              "key": "Variant A Subject|rich_text",
              "textContent": "={{ $json.variant_a.subject }}"
            },
            {
              "key": "Variant A Rationale|rich_text",
              "textContent": "={{ $json.variant_a.rationale }}"
            },
            {
              "key": "Variant B Rationale|rich_text",
              "textContent": "={{ $json.variant_b.rationale }}"
            },
            {
              "key": "Variant B Subject|rich_text",
              "textContent": "={{ $json.variant_b.subject }}"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "290b8187-76fb-45e4-a65a-89e00cc6858f",
      "name": "\u23f0 Daily Poller \u2014 Runs Every 24 Hours",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -880,
        7280
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 24
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "135c478e-4864-4907-bda4-1ec6c33be44b",
      "name": "\ud83d\udccb Fetch All Running Tests from Notion",
      "type": "n8n-nodes-base.notion",
      "position": [
        -656,
        7280
      ],
      "parameters": {
        "simple": false,
        "options": {},
        "resource": "databasePage",
        "operation": "getAll",
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "35ff839f-1184-804c-9b57-c474dc64d6b5",
          "cachedResultUrl": "https://www.notion.so/35ff839f1184804c9b57c474dc64d6b5",
          "cachedResultName": "Email Tracker"
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "9b9551ef-3260-4e33-bcf4-1e0468dbf60b",
      "name": "\ud83d\uddc2\ufe0f Filter & Extract Active Test Data",
      "type": "n8n-nodes-base.code",
      "position": [
        -432,
        7280
      ],
      "parameters": {
        "jsCode": "const pages = $input.all();\n\nif (!pages || pages.length === 0) {\n  return [];\n}\n\nconst activeTests = [];\n\nfor (const page of pages) {\n  const props = page.json.properties || {};\n  \n  const getTextProp = (key) => {\n    const prop = props[key];\n    if (!prop) return '';\n    if (prop.rich_text && prop.rich_text.length > 0) return prop.rich_text[0].plain_text;\n    if (prop.title && prop.title.length > 0) return prop.title[0].plain_text;\n    return '';\n  };\n  \n  const status = getTextProp('Status');\n  const testId = getTextProp('Test ID');\n  \n  if (status !== 'running') continue;\n  if (!testId) continue;\n  \n  activeTests.push({\n    notionPageId: page.json.id,\n    testId,\n    hypothesis: getTextProp('Hypothesis'),\n    metric: getTextProp('Metric'),\n    campaignIdA: getTextProp('Campaign ID A'),\n    campaignIdB: getTextProp('Campaign ID B'),\n    endDate: getTextProp('End Date'),\n    variantASubject: getTextProp('Variant A Subject'),\n    variantBSubject: getTextProp('Variant B Subject')\n  });\n}\n\nreturn activeTests.map(t => ({ json: t }));"
      },
      "typeVersion": 2
    },
    {
      "id": "d72036e4-2bdf-4827-bdc5-99f60af6d077",
      "name": "\ud83d\udcd0 Chi-Squared Statistical Significance Test",
      "type": "n8n-nodes-base.code",
      "position": [
        384,
        7280
      ],
      "parameters": {
        "jsCode": "// Merge results from both variants and run statistical significance test\nconst testMeta = $('Extract Active Tests').first().json;\nconst reportA = $('Mailjet \u2014 Poll Results Variant A1').first().json;\nconst reportB = $('Mailjet \u2014 Poll Results Variant B1').first().json;\n\n// Extract stats from Mailjet message response\nconst msgA = reportA.Data?.[0] || {};\nconst msgB = reportB.Data?.[0] || {};\n\nconst sendA = 1;\nconst openA = msgA.IsOpenTracked && msgA.Status === 'opened' ? 1 : 0;\nconst clickA = msgA.IsClickTracked && msgA.Status === 'clicked' ? 1 : 0;\n\nconst sendB = 1;\nconst openB = msgB.IsOpenTracked && msgB.Status === 'opened' ? 1 : 0;\nconst clickB = msgB.IsClickTracked && msgB.Status === 'clicked' ? 1 : 0;\n\nconst metric = testMeta.metric || 'open_rate';\n\nlet successA, successB, trialsA, trialsB;\nif (metric === 'click_rate') {\n  successA = clickA; trialsA = sendA;\n  successB = clickB; trialsB = sendB;\n} else {\n  successA = openA; trialsA = sendA;\n  successB = openB; trialsB = sendB;\n}\n\nconst rateA = trialsA > 0 ? successA / trialsA : 0;\nconst rateB = trialsB > 0 ? successB / trialsB : 0;\n\nconst failA = trialsA - successA;\nconst failB = trialsB - successB;\nconst N = trialsA + trialsB;\n\nlet chiSquared = 0;\nlet isSignificant = false;\nlet winner = null;\nlet confidence = 0;\n\nif (N > 0 && trialsA > 0 && trialsB > 0) {\n  const totalSuccess = successA + successB;\n  const totalFail = failA + failB;\n  const eA_success = (trialsA * totalSuccess) / N;\n  const eA_fail = (trialsA * totalFail) / N;\n  const eB_success = (trialsB * totalSuccess) / N;\n  const eB_fail = (trialsB * totalFail) / N;\n  \n  chiSquared = 0;\n  if (eA_success > 0) chiSquared += Math.pow(successA - eA_success, 2) / eA_success;\n  if (eA_fail > 0) chiSquared += Math.pow(failA - eA_fail, 2) / eA_fail;\n  if (eB_success > 0) chiSquared += Math.pow(successB - eB_success, 2) / eB_success;\n  if (eB_fail > 0) chiSquared += Math.pow(failB - eB_fail, 2) / eB_fail;\n  \n  isSignificant = chiSquared > 3.841;\n  \n  if (chiSquared > 10.828) confidence = 99.9;\n  else if (chiSquared > 7.879) confidence = 99.5;\n  else if (chiSquared > 6.635) confidence = 99;\n  else if (chiSquared > 5.024) confidence = 97.5;\n  else if (chiSquared > 3.841) confidence = 95;\n  else if (chiSquared > 2.706) confidence = 90;\n  else confidence = Math.round(50 + chiSquared * 14.6);\n  \n  if (isSignificant) {\n    winner = rateA >= rateB ? 'A' : 'B';\n  }\n}\n\nconst endDate = new Date(testMeta.endDate);\nconst now = new Date();\nconst testExpired = now > endDate;\n\nlet decision;\nif (isSignificant) {\n  decision = 'declare_winner';\n} else if (testExpired) {\n  decision = 'no_winner_archive';\n} else {\n  decision = 'extend_test';\n}\n\nreturn [{\n  json: {\n    ...testMeta,\n    sendA, openA, clickA, rateA: Math.round(rateA * 10000) / 100,\n    sendB, openB, clickB, rateB: Math.round(rateB * 10000) / 100,\n    statusA: msgA.Status || 'unknown',\n    statusB: msgB.Status || 'unknown',\n    chiSquared: Math.round(chiSquared * 1000) / 1000,\n    isSignificant,\n    confidence,\n    winner,\n    decision,\n    testExpired,\n    analyzedAt: new Date().toISOString()\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "4ac85071-89ae-4633-89b0-3adb7a3c12de",
      "name": "\ud83d\udea6 Decision: Winner Found?",
      "type": "n8n-nodes-base.if",
      "position": [
        592,
        7280
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "winner-condition",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.decision }}",
              "rightValue": "declare_winner"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "3e7ffd83-db62-4570-9882-432ae234cbfc",
      "name": "\ud83d\udea6 Decision: Test Expired or Extend?",
      "type": "n8n-nodes-base.if",
      "position": [
        816,
        7392
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "caseSensitive": true
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "no-winner-condition",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.decision }}",
              "rightValue": "no_winner_archive"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "a690c742-20d7-451c-826c-9284b8400d0e",
      "name": "\ud83c\udfc6 Update Notion \u2014 Winner Declared",
      "type": "n8n-nodes-base.notion",
      "position": [
        816,
        7152
      ],
      "parameters": {
        "pageId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.notionPageId }}"
        },
        "options": {},
        "resource": "databasePage",
        "operation": "update",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Status|rich_text",
              "textContent": "winner_declared"
            },
            {
              "key": "Winner|rich_text",
              "textContent": "={{ \"Variant \" + $json.winner }}"
            },
            {
              "key": "Rate A|rich_text",
              "textContent": "={{ $json.rateA + \"%\" }}"
            },
            {
              "key": "Rate B|rich_text",
              "textContent": "={{ $json.rateB + \"%\" }}"
            },
            {
              "key": "Chi-Squared|rich_text",
              "textContent": "={{ $json.chiSquared }}"
            },
            {
              "key": "Confidence|rich_text",
              "textContent": "={{ $json.confidence + \"%\" }}"
            },
            {
              "key": "Decision|rich_text",
              "textContent": "={{ \"Winner declared at \" + $json.confidence + \"% confidence\" }}"
            },
            {
              "key": "Analyzed At|rich_text",
              "textContent": "={{ $json.analyzedAt }}"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "8cac62b2-ffe0-4348-984e-9974b244030f",
      "name": "\ud83d\udd0e Identify Losing Campaign",
      "type": "n8n-nodes-base.code",
      "position": [
        1040,
        7152
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\n\nconst loserCampaignId = data.winner === 'A' ? data.campaignIdB : data.campaignIdA;\nconst winnerCampaignId = data.winner === 'A' ? data.campaignIdA : data.campaignIdB;\n\nreturn [{\n  json: {\n    ...data,\n    loserCampaignId,\n    winnerCampaignId\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "4fc937ee-6f25-483f-b4c8-5ed9beb0089f",
      "name": "\ud83d\udced Update Notion \u2014 No Winner (Archived)",
      "type": "n8n-nodes-base.notion",
      "position": [
        1104,
        7408
      ],
      "parameters": {
        "pageId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.notionPageId }}"
        },
        "options": {},
        "resource": "databasePage",
        "operation": "update",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Status|rich_text",
              "textContent": "no_winner_archived"
            },
            {
              "key": "Decision|rich_text",
              "textContent": "={{ \"Test expired with no significant winner. Chi-squared: \" + $json.chiSquared + \", Confidence: \" + $json.confidence + \"%\" }}"
            },
            {
              "key": "Rate A|rich_text",
              "textContent": "={{ $json.rateA + \"%\" }}"
            },
            {
              "key": "Rate B|rich_text",
              "textContent": "={{ $json.rateB + \"%\" }}"
            },
            {
              "key": "Analyzed At|rich_text",
              "textContent": "={{ $json.analyzedAt }}"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "22c0637f-7441-43b4-b40c-3b78b3710109",
      "name": "\ud83d\udd00 Merge Send Confirmations",
      "type": "n8n-nodes-base.merge",
      "position": [
        528,
        6256
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "246f0850-38b7-496e-bcec-fcd582f8e53b",
      "name": "\ud83d\udd00 Merge Poll Results (A + B)",
      "type": "n8n-nodes-base.merge",
      "position": [
        112,
        7264
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "a41c0ea0-87ff-4b29-906c-af31ed1b3249",
      "name": "\ud83d\udd01 Update Notion \u2014 Test Extended",
      "type": "n8n-nodes-base.notion",
      "position": [
        1088,
        7616
      ],
      "parameters": {
        "pageId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.notionPageId }}"
        },
        "options": {},
        "resource": "databasePage",
        "operation": "update",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Status|rich_text",
              "textContent": "running"
            },
            {
              "key": "Decision text|rich_text",
              "textContent": "={{ \"Extending: Chi-squared \" + $json.chiSquared + \" (need >3.841). Rate A: \" + $json.rateA + \"%, Rate B: \" + $json.rateB + \"%. Checked \" + $json.analyzedAt }}"
            },
            {
              "key": "Analyzed at|rich_text",
              "textContent": "={{ $json.analyzedAt }}"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "52ad60e8-e26d-470b-bedb-815335c05af7",
      "name": "\ud83d\uddd2\ufe0f Workflow Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2016,
        6672
      ],
      "parameters": {
        "color": 4,
        "width": 788,
        "height": 152,
        "content": "# \ud83e\uddea Autonomous A/B Email Test Orchestrator\nThis workflow has **two independent sub-flows**: (1) **Launch Pipeline** \u2014 triggered by a Google Sheets form submission to generate & send A/B email variants via Gemini AI + Mailjet, then log to Notion. (2) **Daily Analysis Engine** \u2014 a scheduled poller that fetches running tests from Notion, polls Mailjet stats, runs a Chi-Squared significance test, and automatically declares a winner, extends, or archives the test."
      },
      "typeVersion": 1
    },
    {
      "id": "29a86b84-b1d7-41df-92c1-97f146e3699a",
      "name": "\ud83d\uddd2\ufe0f Launch Pipeline Header",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1072,
        6016
      ],
      "parameters": {
        "color": 3,
        "width": 2260,
        "content": "## \ud83d\ude80 LAUNCH PIPELINE \u2014 Triggered by Google Sheets Form Submission\nWhen a new row appears in the **Email responses** sheet, this pipeline: validates input \u2192 calls Gemini AI \u2192 generates 2 email variants \u2192 sends both via Mailjet \u2192 captures Campaign UUIDs \u2192 creates a new `running` test entry in the **Notion Email Tracker** database."
      },
      "typeVersion": 1
    },
    {
      "id": "e7a2e010-ed45-40ab-a4e3-8117f3ba8d74",
      "name": "\ud83d\uddd2\ufe0f Google Sheets Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1312,
        6256
      ],
      "parameters": {
        "color": 6,
        "width": 300,
        "height": 252,
        "content": "### \ud83d\udce5 Form Trigger\nPolls the **Email responses** Google Sheet every minute.\n\nRequired columns:\n- `hypothesis`\n- `metric` (open_rate / click_rate)\n- `email_subject`\n- `from_email`, `from_name`\n- `audience_size`, `test_duration_days`"
      },
      "typeVersion": 1
    },
    {
      "id": "ea6a7bee-e0bc-4887-bea4-2941427f7b00",
      "name": "\ud83d\uddd2\ufe0f Validate Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -832,
        6448
      ],
      "parameters": {
        "color": 6,
        "width": 280,
        "height": 216,
        "content": "### \ud83d\udd0d Input Validation\nExtracts and validates all form fields.\n\nGenerates a unique `testId` (`ab_<timestamp>`), calculates `startDate` and `endDate` based on `test_duration_days`.\n\n\u26a0\ufe0f Throws error if `hypothesis` or `metric` is missing."
      },
      "typeVersion": 1
    },
    {
      "id": "10cd6981-777d-44c6-90d3-3e64bf6ba2cb",
      "name": "\ud83d\uddd2\ufe0f Gemini Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -448,
        6432
      ],
      "parameters": {
        "color": 2,
        "width": 300,
        "height": 272,
        "content": "### \ud83e\udd16 Gemini AI \u2014 Variant Generation\nCalls **Gemini 2.5 Flash** with the hypothesis, optimisation metric, and base subject line.\n\nReturns 2 variants as JSON:\n```\n{ subject, preview_text,\n  body_html, rationale }\n```\nTemp: `0.7` \u00b7 Max tokens: `3000`\nThinking budget: `0` (fast mode)"
      },
      "typeVersion": 1
    },
    {
      "id": "ab580b3b-4562-496f-b9f0-2f26b54b845e",
      "name": "\ud83d\uddd2\ufe0f Mailjet Send Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        384,
        6448
      ],
      "parameters": {
        "color": 2,
        "width": 300,
        "height": 248,
        "content": "### \ud83d\udce7 Mailjet \u2014 Parallel Send\nBoth Variant A and Variant B are sent **simultaneously** via the Mailjet v3 `/send` API.\n\nEach response captures:\n- `MessageUUID` \u2192 used as `campaignIdA/B` for polling\n- `MessageID` \u2192 stored for reference\n\nAuth: Base64-encoded API key."
      },
      "typeVersion": 1
    },
    {
      "id": "85625247-6853-4d7c-92c9-56d4de2b22f0",
      "name": "\ud83d\uddd2\ufe0f Notion Log Start Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1168,
        6336
      ],
      "parameters": {
        "width": 300,
        "height": 262,
        "content": "### \ud83d\udcd3 Notion \u2014 Email Tracker DB\nCreates a new page in the **Email Tracker** Notion database with:\n- `Test ID`, `Hypothesis`, `Metric`\n- `Status: running`\n- `Campaign ID A & B`\n- `Variant A & B Subject + Rationale`\n- `Start Date` & `End Date`\n\nThis record is read daily by the Analysis Engine."
      },
      "typeVersion": 1
    },
    {
      "id": "85986e8c-d3a3-4a69-a365-e0d1e728ac37",
      "name": "\ud83d\uddd2\ufe0f Analysis Engine Header",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1216,
        7008
      ],
      "parameters": {
        "color": 5,
        "width": 1828,
        "content": "## \ud83d\udd2c DAILY ANALYSIS ENGINE \u2014 Runs Every 24 Hours (Scheduled)\nPolls all `running` tests from Notion, fetches per-variant open/click stats from Mailjet, runs a **Chi-Squared (\u03c7\u00b2) significance test**, then routes to one of three outcomes: **Declare Winner** (\u03c7\u00b2 > 3.841), **Archive with No Winner** (test expired, no significance), or **Extend Test** (still within window, no significance yet)."
      },
      "typeVersion": 1
    },
    {
      "id": "3f5f8d77-f48e-4a0e-bafb-e6e0f657a068",
      "name": "\ud83d\uddd2\ufe0f Schedule Trigger Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1248,
        7312
      ],
      "parameters": {
        "color": 6,
        "width": 280,
        "height": 180,
        "content": "### \u23f0 Schedule Trigger\nFires **every 24 hours** automatically.\n\nStarts the analysis cycle \u2014 fetches all tests from Notion, then checks each one against its current Mailjet stats to decide the outcome."
      },
      "typeVersion": 1
    },
    {
      "id": "9412a54e-1e1f-4756-8a51-a7a4e879c7fa",
      "name": "\ud83d\uddd2\ufe0f Extract Tests Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -912,
        7520
      ],
      "parameters": {
        "color": 6,
        "width": 280,
        "height": 232,
        "content": "### \ud83d\uddc2\ufe0f Filter Active Tests\nFilters Notion pages to only those with `Status = running` and a valid `Test ID`.\n\nOutputs one item per active test, each containing:\n`notionPageId`, `testId`, `campaignIdA/B`, `endDate`, `variantA/B Subject`"
      },
      "typeVersion": 1
    },
    {
      "id": "c218f977-190e-4f69-b354-b3ef78e29360",
      "name": "\ud83d\uddd2\ufe0f Poll Mailjet Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -528,
        7504
      ],
      "parameters": {
        "color": 2,
        "width": 300,
        "height": 316,
        "content": "### \ud83d\udcca Poll Mailjet Stats\nFetches message-level delivery data for each variant using the stored `MessageUUID`.\n\nKey fields extracted:\n- `Status` \u2192 `opened` / `clicked` / `sent`\n- `IsOpenTracked` \u2014 open tracking enabled?\n- `IsClickTracked` \u2014 click tracking enabled?\n\nBoth variants polled **in parallel**, then merged."
      },
      "typeVersion": 1
    },
    {
      "id": "52f2709b-051f-4d06-bda4-4869603cbbbb",
      "name": "\ud83d\uddd2\ufe0f Chi-Squared Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        224,
        7472
      ],
      "parameters": {
        "color": 7,
        "width": 340,
        "height": 322,
        "content": "### \ud83d\udcd0 Chi-Squared Significance Test\nCompares open or click rates between Variant A and B using **Pearson's \u03c7\u00b2 test**.\n\n**Confidence thresholds:**\n| \u03c7\u00b2 score | Confidence |\n|---|---|\n| > 3.841 | 95% \u2705 |\n| > 5.024 | 97.5% |\n| > 6.635 | 99% |\n| > 7.879 | 99.5% |\n| > 10.828 | 99.9% |\n\n**Decision output:**\n- `declare_winner` \u2192 significant result\n- `no_winner_archive` \u2192 expired, no sig\n- `extend_test` \u2192 still within window"
      },
      "typeVersion": 1
    },
    {
      "id": "dc613069-91bf-4a3b-9859-ccf7f9954a0e",
      "name": "\ud83d\uddd2\ufe0f Winner Path Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        768,
        6848
      ],
      "parameters": {
        "color": 4,
        "width": 320,
        "height": 260,
        "content": "### \ud83c\udfc6 Winner Declaration Path\nWhen `decision = declare_winner`:\n1. **Notion** is updated with: `Winner`, `Rate A/B`, `Chi-Squared`, `Confidence %`, `Status: winner_declared`\n2. The losing `campaignId` is identified (opposite of winner)\n3. **Log Loser** records the loser UUID for audit purposes\n\n\u26a0\ufe0f Mailjet has no archive API \u2014 the log is for record-keeping only."
      },
      "typeVersion": 1
    },
    {
      "id": "3dc7d0f4-9dc4-436a-8714-96d90aed4936",
      "name": "\ud83d\uddd2\ufe0f No Winner Extend Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        672,
        7600
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 292,
        "content": "### \ud83d\udced No Winner / Extend Paths\n**Expired (no significance):**\nUpdates Notion with `Status: no_winner_archived` + final rates and chi-squared score. Test lifecycle ends here.\n\n**Extend Test:**\nKeeps `Status: running` but updates the `Decision text` field with current rates and chi-squared score \u2014 test will be re-evaluated in the next 24h cycle.\n\n\ud83d\udd01 Extend loop continues until winner is found or test expires."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "428130bf-5d23-4410-9587-e06ea14707e3",
  "connections": {
    "Merge1": {
      "main": [
        [
          {
            "node": "Merge Campaign IDs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge2": {
      "main": [
        [
          {
            "node": "Significance Test (Chi-Squared)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Campaign IDs": {
      "main": [
        [
          {
            "node": "Notion \u2014 Log Test Start",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Active Tests": {
      "main": [
        [
          {
            "node": "Mailjet \u2014 Poll Results Variant A1",
            "type": "main",
            "index": 0
          },
          {
            "node": "Mailjet \u2014 Poll Results Variant B1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route: Winner Found?": {
      "main": [
        [
          {
            "node": "Notion \u2014 Log Winner",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Route: Expired or Extend?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets Trigger": {
      "main": [
        [
          {
            "node": "Parse & Validate Form Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notion \u2014 Log Winner": {
      "main": [
        [
          {
            "node": "Identify Loser Campaign",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Identify Loser Campaign": {
      "main": [
        [
          {
            "node": "Log Loser (Mailjet)1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Mailjet Payloads1": {
      "main": [
        [
          {
            "node": "Mailjet \u2014 Send Variant A1",
            "type": "main",
            "index": 0
          },
          {
            "node": "Mailjet \u2014 Send Variant B1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route: Expired or Extend?": {
      "main": [
        [
          {
            "node": "Notion \u2014 Log No Winner",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Notion \u2014 Log Extend Test2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse & Validate Form Data": {
      "main": [
        [
          {
            "node": "Gemini \u2014 Generate Variants1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mailjet \u2014 Send Variant A1": {
      "main": [
        [
          {
            "node": "Merge1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mailjet \u2014 Send Variant B1": {
      "main": [
        [
          {
            "node": "Merge1",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Notion \u2014 Get Active Tests": {
      "main": [
        [
          {
            "node": "Extract Active Tests",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Variants from Gemini1": {
      "main": [
        [
          {
            "node": "Prepare Mailjet Payloads1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily Poller \u2014 Every 24hrs": {
      "main": [
        [
          {
            "node": "Notion \u2014 Get Active Tests",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udea6 Decision: Winner Found?": {
      "main": [
        [
          {
            "node": "\ud83c\udfc6 Update Notion \u2014 Winner Declared",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "\ud83d\udea6 Decision: Test Expired or Extend?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gemini \u2014 Generate Variants1": {
      "main": [
        [
          {
            "node": "Parse Variants from Gemini1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udce7 Send Email \u2014 Variant A": {
      "main": [
        [
          {
            "node": "\ud83d\udd00 Merge Send Confirmations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udce7 Send Email \u2014 Variant B": {
      "main": [
        [
          {
            "node": "\ud83d\udd00 Merge Send Confirmations",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "\ud83d\udd00 Merge Send Confirmations": {
      "main": [
        [
          {
            "node": "\ud83d\udd17 Extract & Merge Campaign IDs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd0e Identify Losing Campaign": {
      "main": [
        [
          {
            "node": "\ud83d\uddd1\ufe0f Log Loser Campaign UUID (Audit)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Significance Test (Chi-Squared)": {
      "main": [
        [
          {
            "node": "Route: Winner Found?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udcdd Parse Gemini JSON Response": {
      "main": [
        [
          {
            "node": "\ud83d\udce6 Build Mailjet Email Payloads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd00 Merge Poll Results (A + B)": {
      "main": [
        [
          {
            "node": "\ud83d\udcd0 Chi-Squared Statistical Significance Test",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd0d Parse & Validate Input Data": {
      "main": [
        [
          {
            "node": "\ud83e\udd16 AI: Generate Email Variants (Gemini)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udce6 Build Mailjet Email Payloads": {
      "main": [
        [
          {
            "node": "\ud83d\udce7 Send Email \u2014 Variant A",
            "type": "main",
            "index": 0
          },
          {
            "node": "\ud83d\udce7 Send Email \u2014 Variant B",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd17 Extract & Merge Campaign IDs": {
      "main": [
        [
          {
            "node": "\ud83d\udcd3 Log Test Start to Notion",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mailjet \u2014 Poll Results Variant A1": {
      "main": [
        [
          {
            "node": "Merge2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mailjet \u2014 Poll Results Variant B1": {
      "main": [
        [
          {
            "node": "Merge2",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "\ud83d\udcca Poll Mailjet \u2014 Variant A Stats": {
      "main": [
        [
          {
            "node": "\ud83d\udd00 Merge Poll Results (A + B)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udcca Poll Mailjet \u2014 Variant B Stats": {
      "main": [
        [
          {
            "node": "\ud83d\udd00 Merge Poll Results (A + B)",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "\ud83c\udfc6 Update Notion \u2014 Winner Declared": {
      "main": [
        [
          {
            "node": "\ud83d\udd0e Identify Losing Campaign",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udea6 Decision: Test Expired or Extend?": {
      "main": [
        [
          {
            "node": "\ud83d\udced Update Notion \u2014 No Winner (Archived)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "\ud83d\udd01 Update Notion \u2014 Test Extended",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u23f0 Daily Poller \u2014 Runs Every 24 Hours": {
      "main": [
        [
          {
            "node": "\ud83d\udccb Fetch All Running Tests from Notion",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udccb Fetch All Running Tests from Notion": {
      "main": [
        [
          {
            "node": "\ud83d\uddc2\ufe0f Filter & Extract Active Test Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\uddc2\ufe0f Filter & Extract Active Test Data": {
      "main": [
        [
          {
            "node": "\ud83d\udcca Poll Mailjet \u2014 Variant A Stats",
            "type": "main",
            "index": 0
          },
          {
            "node": "\ud83d\udcca Poll Mailjet \u2014 Variant B Stats",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83e\udd16 AI: Generate Email Variants (Gemini)": {
      "main": [
        [
          {
            "node": "\ud83d\udcdd Parse Gemini JSON Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udce5 Watch Form Submissions (Google Sheets)": {
      "main": [
        [
          {
            "node": "\ud83d\udd0d Parse & Validate Input Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udcd0 Chi-Squared Statistical Significance Test": {
      "main": [
        [
          {
            "node": "\ud83d\udea6 Decision: Winner Found?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}