{
  "id": "candidateIntakeReliabilityHarnessV1",
  "name": "Synthetic Candidate Intake Reliability Harness",
  "nodes": [
    {
      "parameters": {},
      "id": "8e55fafe-6760-4cf2-8e58-a55290b0bb01",
      "name": "Run synthetic tests",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [260, 300]
    },
    {
      "parameters": {
        "jsCode": "const fixtures = [\n  { test: 'AT-01 first submit', submissionId: 'FORM-001', phone: '+91 98765 43210', consent: true, role: 'Cashier', location: 'Mumbai', seen: [] },\n  { test: 'AT-01 duplicate replay', submissionId: 'FORM-001', phone: '+91 98765 43210', consent: true, role: 'Cashier', location: 'Mumbai', seen: ['FORM-001'] },\n  { test: 'AT-02 resume after message timeout', submissionId: 'FORM-002', phone: '+91 91234 56789', consent: true, role: 'Delivery', location: 'Mumbai', seen: [], crmCommitted: true, messageAttempt: 2 },\n  { test: 'AT-03 missing consent', submissionId: 'FORM-003', phone: '+91 90000 00000', consent: false, role: 'Sales', location: 'Pune', seen: [] },\n  { test: 'AT-03 ambiguous phone', submissionId: 'FORM-004', phone: '555-0100', consent: true, role: 'Helper', location: 'Unknown', seen: [] },\n  { test: 'AT-04 rate limited', submissionId: 'FORM-005', phone: '+91 99887 76655', consent: true, role: 'Supervisor', location: 'Mumbai', seen: [], statusCode: 429, retryAfterSeconds: 30 }\n];\nreturn fixtures.map((json, index) => ({ json, pairedItem: { item: index } }));"
      },
      "id": "8285a59a-c0ad-498f-bd9e-29415fa6b102",
      "name": "Synthetic fixtures",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [500, 300]
    },
    {
      "parameters": {
        "jsCode": "function normalizePhone(value) {\n  const raw = String(value || '').trim();\n  if (!raw.startsWith('+')) return null;\n  const digits = raw.replace(/\\D/g, '');\n  return digits.length >= 10 && digits.length <= 15 ? '+' + digits : null;\n}\nconst results = $input.all().map((item, index) => {\n  const x = item.json;\n  const phone = normalizePhone(x.phone);\n  const errors = [];\n  if (!x.consent) errors.push('consent_required');\n  if (!phone) errors.push('unambiguous_e164_phone_required');\n  if (!x.role) errors.push('role_required');\n  if (!x.location || x.location === 'Unknown') errors.push('location_required');\n  const duplicate = Array.isArray(x.seen) && x.seen.includes(x.submissionId);\n  const retry = x.statusCode === 429 ? { action: 'bounded_backoff', delaySeconds: Math.max(1, Math.min(Number(x.retryAfterSeconds || 30), 300)) } : null;\n  const messageAction = errors.length ? 'none' : duplicate ? 'suppress_duplicate' : x.crmCommitted ? 'resume_message_only' : 'enqueue_once';\n  return { json: { test: x.test, pass: true, candidateKey: phone, idempotencyKey: phone ? 'candidate:' + phone + ':submission:' + x.submissionId : null, route: errors.length ? 'quarantine' : duplicate ? 'duplicate_event_only' : 'upsert_candidate', messageAction, retry, errors }, pairedItem: { item: index } };\n});\nconst byTest = Object.fromEntries(results.map(r => [r.json.test, r.json]));\nconst checks = [\n  byTest['AT-01 first submit'].route === 'upsert_candidate' && byTest['AT-01 first submit'].messageAction === 'enqueue_once',\n  byTest['AT-01 duplicate replay'].route === 'duplicate_event_only' && byTest['AT-01 duplicate replay'].messageAction === 'suppress_duplicate',\n  byTest['AT-02 resume after message timeout'].messageAction === 'resume_message_only',\n  byTest['AT-03 missing consent'].route === 'quarantine' && byTest['AT-03 missing consent'].errors.includes('consent_required'),\n  byTest['AT-03 ambiguous phone'].route === 'quarantine' && byTest['AT-03 ambiguous phone'].candidateKey === null,\n  byTest['AT-04 rate limited'].retry.action === 'bounded_backoff' && byTest['AT-04 rate limited'].retry.delaySeconds === 30\n];\nif (checks.some(v => !v)) throw new Error('Reliability harness failed: ' + JSON.stringify(checks));\nreturn [{ json: { synthetic: true, productionReady: false, passed: checks.length, failed: 0, results: results.map(r => r.json), nextStep: 'Map these contracts to your own credentialed Airtable and WhatsApp nodes only after review.' } }];"
      },
      "id": "f7dc9e52-0f4b-431b-8b77-40add651cd03",
      "name": "Normalize and assert contracts",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [760, 300]
    }
  ],
  "connections": {
    "Run synthetic tests": { "main": [[{ "node": "Synthetic fixtures", "type": "main", "index": 0 }]] },
    "Synthetic fixtures": { "main": [[{ "node": "Normalize and assert contracts", "type": "main", "index": 0 }]] }
  },
  "pinData": {},
  "settings": { "executionOrder": "v1" },
  "active": false,
  "versionId": "fda53531-a6f0-45c7-b72a-cf6d0ccbff88",
  "meta": { "templateCredsSetupCompleted": true },
  "tags": []
}
