{
  "name": "Lead Grading Engine",
  "nodes": [
    {
      "id": "f1b8dabd-8b92-42ac-abbf-17e058bf6ab3",
      "name": "Weekday Grading Run",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        200
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "45 7 * * 1-5"
            }
          ]
        }
      }
    },
    {
      "id": "3c187250-f444-48b7-8c2a-6d75a755511b",
      "name": "Get HubSpot Contacts",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        220,
        200
      ],
      "parameters": {
        "method": "GET",
        "url": "https://api.hubapi.com/crm/v3/objects/contacts?limit=100&associations=companies&properties=email,firstname,lastname,company,jobtitle,lifecyclestage,hs_email_open,hs_email_click,hs_analytics_num_page_views,num_conversion_events",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "hubspotAppToken",
        "options": {}
      },
      "credentials": {
        "hubspotAppToken": {
          "id": "ynUSCUtMOnX1f4Jl",
          "name": "HubSpot Service Key account"
        }
      }
    },
    {
      "id": "4d131ea1-7218-46df-952c-ae566aa67d52",
      "name": "Get HubSpot Companies",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        440,
        200
      ],
      "parameters": {
        "method": "GET",
        "url": "https://api.hubapi.com/crm/v3/objects/companies?limit=100&properties=name,domain,industry,numberofemployees",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "hubspotAppToken",
        "options": {}
      },
      "credentials": {
        "hubspotAppToken": {
          "id": "ynUSCUtMOnX1f4Jl",
          "name": "HubSpot Service Key account"
        }
      },
      "executeOnce": true
    },
    {
      "id": "ba31b890-cd32-481d-8769-9c647828d527",
      "name": "Get Salesforce Accounts",
      "type": "n8n-nodes-base.salesforce",
      "typeVersion": 1.1,
      "position": [
        660,
        200
      ],
      "parameters": {
        "resource": "search",
        "operation": "query",
        "query": "SELECT Id, Name, Industry FROM Account WHERE Industry != null"
      },
      "credentials": {
        "salesforceOAuth2Api": {
          "id": "553Tae1kPe5Wpthq",
          "name": "Salesforce account"
        }
      },
      "executeOnce": true
    },
    {
      "id": "003fbfcf-cbd9-4f30-8165-1723ab64f8af",
      "name": "Get Clay Enrichment",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        880,
        200
      ],
      "parameters": {
        "resource": "row",
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "Uih8u82Pk1H2idvy",
          "cachedResultName": "Clay Firmographic Enrichment"
        },
        "returnAll": true
      },
      "executeOnce": true
    },
    {
      "id": "21656742-f739-4ebe-a71a-6220ad9aaf85",
      "name": "Get ICP Definitions",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1100,
        200
      ],
      "parameters": {
        "resource": "row",
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "niD4hm70QGLUzTO1",
          "cachedResultName": "ICP Definitions"
        },
        "returnAll": true
      },
      "executeOnce": true
    },
    {
      "id": "e8df45d4-723b-47c7-9ebb-21ccdb21c448",
      "name": "Get Previous Grades",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1320,
        200
      ],
      "parameters": {
        "resource": "row",
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "ZPfeY9UgTf7WUkJW",
          "cachedResultName": "Lead Grade Log"
        },
        "returnAll": true
      },
      "executeOnce": true,
      "alwaysOutputData": true
    },
    {
      "id": "69a17e9f-b8de-4431-94f1-a5991a8fac85",
      "name": "Build Lead List",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1540,
        200
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// One item per open (non-customer) HubSpot lead, with fit resolved deterministically.\nconst contacts = ($('Get HubSpot Contacts').first().json.results || []);\nconst companies = ($('Get HubSpot Companies').first().json.results || []);\nconst sfAccounts = $('Get Salesforce Accounts').all().map(i => i.json);\nconst clayRows = $('Get Clay Enrichment').all().map(i => i.json);\nconst icpRows = $('Get ICP Definitions').all().map(i => i.json).filter(r => r.runId);\nconst prevRows = $('Get Previous Grades').all().map(i => i.json).filter(r => r.contactId);\n\n// Latest ICP run only (the ICP engine logs one row per criterion per run)\nconst latestRun = icpRows.sort((a, b) => String(b.loggedAt).localeCompare(String(a.loggedAt)))[0];\nconst icp = latestRun ? icpRows.filter(r => r.runId === latestRun.runId) : [];\n\nconst GENERIC = new Set(['inc','corp','corporation','co','company','llc','llp','ltd','limited','private','group','the','of','and','partners','systems','technologies','holdings','plc']);\nfunction toks(s) { return new Set((s || '').toLowerCase().replace(/[^a-z0-9 ]/g, ' ').split(/\\s+/).filter(t => t && !GENERIC.has(t))); }\nfunction jaccard(a, b) { const A = toks(a), B = toks(b); if (!A.size || !B.size) return 0; let i = 0; for (const t of A) if (B.has(t)) i++; return i / (A.size + B.size - i); }\nfunction pretty(ind) { return (ind || '').toLowerCase().replace(/_/g, ' ').replace(/\\b\\w/g, c => c.toUpperCase()); }\n\nconst companyById = {}; for (const c of companies) companyById[c.id] = c.properties || {};\nconst sfByName = {}; for (const a of sfAccounts) if (a.Name) sfByName[a.Name.toLowerCase()] = a;\nconst clayByName = {}; for (const r of clayRows) clayByName[(r.accountName || '').toLowerCase()] = r;\nconst prevByContact = {};\nfor (const r of prevRows.sort((a, b) => String(a.loggedAt).localeCompare(String(b.loggedAt)))) prevByContact[r.contactId] = r.grade;\n\n// Fit from the evidence-based ICP (Day 16): include 90, known-but-neutral 60, unknown 35, exclude 15.\nfunction fitFor(industry) {\n  if (!industry) return { fitScore: 35, fitTier: 'unknown', fitReason: 'No industry on record in HubSpot, Salesforce, or Clay, so fit cannot be judged' };\n  const NON_DISTINCT = new Set(['services','industry','management','development','solutions','products']);\n  const words = [...toks(industry)].filter(w => w.length >= 4 && !NON_DISTINCT.has(w));\n  const hit = icp.find(c => words.some(w => (c.criterion || '').toLowerCase().includes(w)));\n  if (!icp.length) return { fitScore: 60, fitTier: 'baseline', fitReason: industry + ' (no ICP Definitions logged yet; baseline fit for a known industry)' };\n  if (hit && hit.criterionType === 'include') return { fitScore: 90, fitTier: 'icp-include', fitReason: industry + ' matches ICP include: \"' + hit.criterion + '\" (' + hit.segmentWinRate + '% win rate vs ' + hit.baselineWinRate + '% baseline, z=' + hit.zScore + ')' };\n  if (hit && hit.criterionType === 'exclude') return { fitScore: 15, fitTier: 'icp-exclude', fitReason: industry + ' matches ICP exclusion: \"' + hit.criterion + '\" (' + hit.segmentWinRate + '% win rate vs ' + hit.baselineWinRate + '% baseline, z=' + hit.zScore + ')' };\n  return { fitScore: 60, fitTier: 'neutral', fitReason: industry + ' is known and not excluded by the ICP (no significant win-rate signal either way)' };\n}\n\nconst out = [];\nfor (const c of contacts) {\n  const p = c.properties || {};\n  if ((p.lifecyclestage || '').toLowerCase() === 'customer') continue;\n  const compIds = (((c.associations || {}).companies || {}).results || []).map(r => r.id);\n  const comp = compIds.length ? (companyById[compIds[0]] || {}) : {};\n  const companyName = comp.name || p.company || '';\n  let industry = '', industrySource = 'none';\n  if (comp.industry) { industry = pretty(comp.industry); industrySource = 'HubSpot'; }\n  else if (sfByName[companyName.toLowerCase()] && sfByName[companyName.toLowerCase()].Industry) { industry = sfByName[companyName.toLowerCase()].Industry; industrySource = 'Salesforce'; }\n  else {\n    const cl = clayByName[companyName.toLowerCase()];\n    if (cl && cl.clayResult === 'matched' && jaccard(companyName, cl.clayMatchedName) >= 0.5 && cl.clayIndustry) { industry = cl.clayIndustry; industrySource = 'Clay'; }\n  }\n  const cl = clayByName[companyName.toLowerCase()];\n  const clayNote = !cl ? 'not sent to Clay' : cl.clayResult === 'matched' ? ('Clay: ' + cl.clayMatchedName + ', ' + (cl.clayEmployees || '?') + ' employees, ' + (cl.clayIndustry || '?')) : ('Clay: ' + cl.clayResult.replace('_', ' '));\n  out.push({ json: Object.assign({\n    contactId: c.id, contactName: ((p.firstname || '') + ' ' + (p.lastname || '')).trim(), email: p.email, jobTitle: p.jobtitle || '',\n    company: companyName, lifecycleStage: p.lifecyclestage || '', industry, industrySource, clayNote,\n    formFills: Number(p.num_conversion_events || 0), emailOpens: Number(p.hs_email_open || 0), emailClicks: Number(p.hs_email_click || 0), pageViews: Number(p.hs_analytics_num_page_views || 0),\n    previousGrade: prevByContact[c.id] || '', icpRunId: latestRun ? latestRun.runId : 'none'\n  }, fitFor(industry)) });\n}\nreturn out;\n"
      },
      "executeOnce": true
    },
    {
      "id": "fb9915e8-b1de-443f-ac3f-dcd2390357d2",
      "name": "Get Lead Engagements",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1760,
        200
      ],
      "parameters": {
        "method": "GET",
        "url": "=https://api.hubapi.com/engagements/v1/engagements/associated/CONTACT/{{ $json.contactId }}/paged?limit=100",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "hubspotAppToken",
        "options": {}
      },
      "credentials": {
        "hubspotAppToken": {
          "id": "ynUSCUtMOnX1f4Jl",
          "name": "HubSpot Service Key account"
        }
      }
    },
    {
      "id": "c4c8dd19-2624-453a-a91e-33aaf0c3e379",
      "name": "Score & Grade",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1980,
        200
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// Deterministic engagement score + 2x2 grade. Only prospect-side activity counts; outbound touches are shown but never scored.\nconst leads = $('Build Lead List').all().map(i => i.json);\nconst engs = $input.all().map(i => i.json);\nconst now = Date.now(), DAY = 86400000;\nconst WEIGHTS = { INCOMING_EMAIL: 25, MEETING: 35, CALL: 20 };\nconst FIT_HIGH = 60, ENG_HIGH = 40;\nreturn leads.map((lead, idx) => {\n  const results = (engs[idx] && engs[idx].results) || [];\n  let score = 0; const parts = []; let outbound = 0;\n  for (const r of results) {\n    const e = r.engagement || {}; const age = Math.floor((now - e.timestamp) / DAY);\n    if (WEIGHTS[e.type] === undefined) { if (e.type === 'EMAIL') outbound++; continue; }\n    const mult = age <= 30 ? 1 : age <= 90 ? 0.5 : 0;\n    if (!mult) continue;\n    score += WEIGHTS[e.type] * mult;\n    parts.push(e.type.toLowerCase().replace('_', ' ') + ' ' + age + 'd ago' + (mult < 1 ? ' (half weight)' : ''));\n  }\n  score += lead.formFills * 20 + lead.emailClicks * 8 + lead.emailOpens * 3 + lead.pageViews * 2;\n  if (lead.formFills) parts.push(lead.formFills + ' form fill(s)');\n  if (lead.emailOpens || lead.emailClicks) parts.push(lead.emailOpens + ' opens / ' + lead.emailClicks + ' clicks');\n  if (lead.pageViews) parts.push(lead.pageViews + ' page views');\n  const engagementScore = Math.min(100, Math.round(score));\n  const fitHigh = lead.fitScore >= FIT_HIGH, engHigh = engagementScore >= ENG_HIGH;\n  const grade = fitHigh && engHigh ? 'A' : fitHigh ? 'B' : engHigh ? 'C' : 'D';\n  const lever = { A: 'Work now: right account and actively engaging', B: 'Right account, not engaged yet: pull the outreach lever', C: 'Engaged but fit is weak or unverified: qualify fit before investing', D: 'Low fit and no engagement: park it' }[grade];\n  return { json: Object.assign({}, lead, {\n    engagementScore, engagementDetail: parts.length ? parts.join(', ') : 'no prospect-side activity',\n    outboundTouches: outbound, grade, lever, gradeChanged: lead.previousGrade !== grade\n  }) };\n});\n"
      }
    },
    {
      "id": "1074bbc4-164f-43c3-a3a3-d5a28e31afc2",
      "name": "Grade Rationale Writer",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        2200,
        200
      ],
      "parameters": {
        "promptType": "define",
        "text": "=Graded leads (grades are final; write the rationale only):\n{{ JSON.stringify($('Score & Grade').all().map(i => ({ contactId: i.json.contactId, name: i.json.contactName, title: i.json.jobTitle, company: i.json.company, grade: i.json.grade, lever: i.json.lever, fit: i.json.fitScore + '/100 - ' + i.json.fitReason, engagement: i.json.engagementScore + '/100 - ' + i.json.engagementDetail + (i.json.outboundTouches ? ' (plus ' + i.json.outboundTouches + ' outbound emails we sent, not scored)' : ''), enrichment: i.json.clayNote })), null, 1) }}",
        "hasOutputParser": true,
        "options": {
          "systemMessage": "You write lead-grade rationales for Fortavault, Inc. (a fictional data protection and security platform) so a rep can scan their queue in half a second. The grade for every lead has ALREADY been decided by a deterministic fit x engagement rule; you never change it.\n\nFor each lead, write ONE sentence under 170 characters that states: the grade letter, the single most important fit fact, the single most important engagement fact, and the lever to pull (taken from the lead's \"lever\" field). A = work now. B = right account but not engaged: outreach is the lever. C = engaged but fit is weak or unverified: qualify fit before investing time. D = park.\n\nDescribe fit exactly as strong as the evidence: an ICP include is strong fit; a fit of 60 marked 'known and not excluded' is NEUTRAL fit (no win-rate signal either way) and must be called neutral, never 'solid', 'good' or 'strong'; an ICP exclusion is poor fit; no industry on record means fit is unknown.\n\nUse only the facts provided. Never invent job titles, activities, dates or numbers, and don't editorialize beyond them. Return every contactId you were given, exactly as given."
        }
      },
      "executeOnce": true
    },
    {
      "id": "b9dca3ee-849f-4ba5-aaa2-712e28b3e57b",
      "name": "Claude Sonnet",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "typeVersion": 1.3,
      "position": [
        2200,
        420
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "claude-sonnet-4-6",
          "cachedResultName": "Claude Sonnet 4.6"
        },
        "options": {
          "temperature": 0.4
        }
      },
      "credentials": {
        "anthropicApi": {
          "id": "3d3ZiTi7BwnkFwqU",
          "name": "Anthropic account"
        }
      }
    },
    {
      "id": "88e1849f-378a-482d-ad30-3cc63288af1d",
      "name": "Rationale Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "typeVersion": 1.3,
      "position": [
        2340,
        420
      ],
      "parameters": {
        "schemaType": "fromJson",
        "jsonSchemaExample": "{ \"leads\": [ { \"contactId\": \"246640450092\", \"rationale\": \"A: Insurance is the ICP's one include, and she booked a CISO-attended walkthrough yesterday. Work it now.\" } ] }"
      }
    },
    {
      "id": "38bba427-6a40-4736-a803-c5820fd2bcdc",
      "name": "Attach Rationales",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2500,
        200
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const graded = $('Score & Grade').all().map(i => i.json);\nconst out = $('Grade Rationale Writer').first().json.output;\nconst byId = {}; for (const r of (out.leads || [])) byId[String(r.contactId)] = r.rationale;\nconst runId = 'grade-' + $now.toFormat('yyyyLLdd-HHmm');\nreturn graded.map(g => ({ json: Object.assign({}, g, {\n  runId, rationale: (byId[g.contactId] || (g.grade + ': ' + g.lever)).replace(/\\s+/g, ' ').trim(), loggedAt: $now.toISO()\n}) }));\n"
      }
    },
    {
      "id": "4408b50b-8479-4439-b5cb-69a340042ea8",
      "name": "Write Grade to HubSpot",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2720,
        100
      ],
      "parameters": {
        "method": "PATCH",
        "url": "=https://api.hubapi.com/crm/v3/objects/contacts/{{ $json.contactId }}",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "hubspotAppToken",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ properties: { fortavault_lead_grade: $json.grade, fortavault_grade_rationale: $json.rationale } }) }}",
        "options": {}
      },
      "credentials": {
        "hubspotAppToken": {
          "id": "ynUSCUtMOnX1f4Jl",
          "name": "HubSpot Service Key account"
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "id": "211f0853-39b4-4256-adbe-5f6001eb7948",
      "name": "Build Log Rows",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2940,
        100
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const src = $('Attach Rationales').all().map(i => i.json);\nreturn $input.all().map((it, i) => {\n  const r = src[i] || {};\n  const err = it.json && it.json.error;\n  return { json: {\n    runId: r.runId, contactId: r.contactId, contactName: r.contactName, company: r.company, industry: r.industry || 'unknown', industrySource: r.industrySource,\n    fitScore: r.fitScore, fitTier: r.fitTier, fitReason: r.fitReason, engagementScore: r.engagementScore, engagementDetail: r.engagementDetail,\n    grade: r.grade, previousGrade: r.previousGrade || '', gradeChanged: !!r.gradeChanged, rationale: r.rationale, icpRunId: r.icpRunId,\n    hubspotWrite: err ? ('failed: ' + (err.description || err.message || 'unknown error')).slice(0, 300) : 'written', loggedAt: r.loggedAt\n  } };\n});\n"
      }
    },
    {
      "id": "19897875-518a-42c9-98dd-a75337d435d1",
      "name": "Log Grade History",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        3160,
        100
      ],
      "parameters": {
        "resource": "row",
        "operation": "insert",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "ZPfeY9UgTf7WUkJW",
          "cachedResultName": "Lead Grade Log"
        },
        "columns": {
          "mappingMode": "autoMapInputData",
          "value": {}
        }
      }
    },
    {
      "id": "5bf15b60-9d0f-4b46-888d-3d3f85b7880c",
      "name": "Build A/B Digest",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2720,
        320
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const rows = $('Attach Rationales').all().map(i => i.json);\nconst counts = { A: 0, B: 0, C: 0, D: 0 }; rows.forEach(r => counts[r.grade]++);\nconst hot = rows.filter(r => (r.grade === 'A' || r.grade === 'B') && r.gradeChanged).sort((a, b) => a.grade.localeCompare(b.grade) || b.engagementScore - a.engagementScore);\nconst icon = { A: ':large_green_circle:', B: ':large_yellow_circle:' };\nconst lines = hot.map(r => icon[r.grade] + ' *' + r.grade + '* — *' + r.contactName + '*, ' + (r.jobTitle ? r.jobTitle + ', ' : '') + r.company + ' (fit ' + r.fitScore + ' / engagement ' + r.engagementScore + ')\\n      _' + r.rationale + '_');\nconst text = ':mortar_board: *Daily Lead Grades — Fortavault*\\n' +\n  rows.length + ' open HubSpot leads graded: *' + counts.A + ' A · ' + counts.B + ' B · ' + counts.C + ' C · ' + counts.D + ' D*. Fit is checked against the latest ICP Definitions run; engagement counts only prospect-side activity.\\n\\n' +\n  (hot.length ? '*Newly graded or changed A/B leads:*\\n' + lines.join('\\n') : '_No new or changed A/B leads today._') +\n  '\\n\\nGrades + rationales are written to each HubSpot contact (Fortavault Lead Grade) and logged to the Lead Grade Log for history.';\nreturn [{ json: { slackText: text.slice(0, 2900) } }];\n"
      }
    },
    {
      "id": "510f84ab-557b-4331-8c13-8a34719c7893",
      "name": "Post Digest to Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.7,
      "position": [
        2940,
        320
      ],
      "parameters": {
        "resource": "message",
        "operation": "post",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "C0BQ3G96HL6",
          "cachedResultName": "general"
        },
        "text": "={{ $json.slackText }}",
        "otherOptions": {
          "includeLinkToWorkflow": false
        }
      },
      "credentials": {
        "slackApi": {
          "id": "mv7TIi8kucFPqPg6",
          "name": "Slack account"
        }
      }
    }
  ],
  "connections": {
    "Weekday Grading Run": {
      "main": [
        [
          {
            "node": "Get HubSpot Contacts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get HubSpot Contacts": {
      "main": [
        [
          {
            "node": "Get HubSpot Companies",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get HubSpot Companies": {
      "main": [
        [
          {
            "node": "Get Salesforce Accounts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Salesforce Accounts": {
      "main": [
        [
          {
            "node": "Get Clay Enrichment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Clay Enrichment": {
      "main": [
        [
          {
            "node": "Get ICP Definitions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get ICP Definitions": {
      "main": [
        [
          {
            "node": "Get Previous Grades",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Previous Grades": {
      "main": [
        [
          {
            "node": "Build Lead List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Lead List": {
      "main": [
        [
          {
            "node": "Get Lead Engagements",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Lead Engagements": {
      "main": [
        [
          {
            "node": "Score & Grade",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Score & Grade": {
      "main": [
        [
          {
            "node": "Grade Rationale Writer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Grade Rationale Writer": {
      "main": [
        [
          {
            "node": "Attach Rationales",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Attach Rationales": {
      "main": [
        [
          {
            "node": "Write Grade to HubSpot",
            "type": "main",
            "index": 0
          },
          {
            "node": "Build A/B Digest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Write Grade to HubSpot": {
      "main": [
        [
          {
            "node": "Build Log Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Log Rows": {
      "main": [
        [
          {
            "node": "Log Grade History",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build A/B Digest": {
      "main": [
        [
          {
            "node": "Post Digest to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude Sonnet": {
      "ai_languageModel": [
        [
          {
            "node": "Grade Rationale Writer",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Rationale Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Grade Rationale Writer",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "instanceId": "hainehainehaine"
  }
}