{
  "name": "Bank Payments to Invoice Reconciliation",
  "activeVersionId": null,
  "settings": {
    "executionOrder": "v1",
    "availableInMCP": false
  },
  "connections": {
    "Import Webhook": {
      "main": [
        [
          {
            "node": "Validate Import Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Runtime Simulator Sweep": {
      "main": [
        [
          {
            "node": "Build Runtime Bank Fixture",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Import Token": {
      "main": [
        [
          {
            "node": "Import Authorized?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Import Authorized?": {
      "main": [
        [
          {
            "node": "Build Webhook Statement Contract",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Unauthorized Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Unauthorized Response": {
      "main": [
        [
          {
            "node": "Respond Unauthorized",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run Webhook Reconciliation Engine": {
      "main": [
        [
          {
            "node": "Emit Webhook Transaction Rows",
            "type": "main",
            "index": 0
          },
          {
            "node": "Emit Webhook Invoice Rows",
            "type": "main",
            "index": 0
          },
          {
            "node": "Emit Webhook Allocation Rows",
            "type": "main",
            "index": 0
          },
          {
            "node": "Emit Webhook Review Rows",
            "type": "main",
            "index": 0
          },
          {
            "node": "Emit Webhook Signal Rows",
            "type": "main",
            "index": 0
          },
          {
            "node": "Emit Webhook Summary Row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run Runtime Reconciliation Engine": {
      "main": [
        [
          {
            "node": "Emit Runtime Transaction Rows",
            "type": "main",
            "index": 0
          },
          {
            "node": "Emit Runtime Invoice Rows",
            "type": "main",
            "index": 0
          },
          {
            "node": "Emit Runtime Allocation Rows",
            "type": "main",
            "index": 0
          },
          {
            "node": "Emit Runtime Review Rows",
            "type": "main",
            "index": 0
          },
          {
            "node": "Emit Runtime Signal Rows",
            "type": "main",
            "index": 0
          },
          {
            "node": "Emit Runtime Summary Row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Emit Webhook Transaction Rows": {
      "main": [
        [
          {
            "node": "Insert Webhook Transaction Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Emit Webhook Invoice Rows": {
      "main": [
        [
          {
            "node": "Insert Webhook Invoice Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Emit Webhook Allocation Rows": {
      "main": [
        [
          {
            "node": "Insert Webhook Allocation Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Emit Webhook Review Rows": {
      "main": [
        [
          {
            "node": "Insert Webhook Review Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Emit Webhook Signal Rows": {
      "main": [
        [
          {
            "node": "Insert Webhook Paid Signal Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Emit Webhook Summary Row": {
      "main": [
        [
          {
            "node": "Insert Webhook Summary Row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Emit Runtime Transaction Rows": {
      "main": [
        [
          {
            "node": "Insert Runtime Transaction Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Emit Runtime Invoice Rows": {
      "main": [
        [
          {
            "node": "Insert Runtime Invoice Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Emit Runtime Allocation Rows": {
      "main": [
        [
          {
            "node": "Insert Runtime Allocation Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Emit Runtime Review Rows": {
      "main": [
        [
          {
            "node": "Insert Runtime Review Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Emit Runtime Signal Rows": {
      "main": [
        [
          {
            "node": "Insert Runtime Paid Signal Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Emit Runtime Summary Row": {
      "main": [
        [
          {
            "node": "Insert Runtime Summary Row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Insert Webhook Summary Row": {
      "main": [
        [
          {
            "node": "Send Controlled Webhook Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Insert Runtime Summary Row": {
      "main": [
        [
          {
            "node": "Send Controlled Runtime Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Controlled Webhook Summary": {
      "main": [
        [
          {
            "node": "Build Webhook Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Webhook Response": {
      "main": [
        [
          {
            "node": "Respond Import Complete",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Webhook Statement Contract": {
      "main": [
        [
          {
            "node": "Get Webhook Existing Transactions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Webhook Existing Transactions": {
      "main": [
        [
          {
            "node": "Merge Webhook Existing Transactions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Webhook Existing Transactions": {
      "main": [
        [
          {
            "node": "Get Webhook Existing Reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Webhook Existing Reviews": {
      "main": [
        [
          {
            "node": "Merge Webhook Existing Reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Webhook Existing Reviews": {
      "main": [
        [
          {
            "node": "Run Webhook Reconciliation Engine",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Runtime Bank Fixture": {
      "main": [
        [
          {
            "node": "Get Runtime Existing Transactions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Runtime Existing Transactions": {
      "main": [
        [
          {
            "node": "Merge Runtime Existing Transactions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Runtime Existing Transactions": {
      "main": [
        [
          {
            "node": "Get Runtime Existing Reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Runtime Existing Reviews": {
      "main": [
        [
          {
            "node": "Merge Runtime Existing Reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Runtime Existing Reviews": {
      "main": [
        [
          {
            "node": "Run Runtime Reconciliation Engine",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "nodes": [
    {
      "id": "15272723-1fad-443b-94a0-c42a203c1cd9",
      "name": "Import Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -260,
        -20
      ],
      "parameters": {
        "httpMethod": "POST",
        "path": "bank-reconciliation-import",
        "responseMode": "responseNode"
      }
    },
    {
      "id": "1ea17a86-9b5d-4fe5-bd62-d1c968d61383",
      "name": "Runtime Simulator Sweep",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        -260,
        520
      ],
      "parameters": {}
    },
    {
      "id": "3cd8f352-55a6-49cb-8b0a-132806ef4ebf",
      "name": "Validate Import Token",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -20,
        -20
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const root = $input.item.json || {};\nconst headers = root.headers || {};\nconst pick = (name) => headers[name] || headers[name.toLowerCase()] || headers[name.toUpperCase()] || '';\nconst auth = String(pick('authorization') || '');\nconst bearer = auth.toLowerCase().startsWith('bearer ') ? auth.slice(7).trim() : '';\nconst provided = String(pick('x-bank-import-token') || bearer || '').trim();\nconst expected = String($vars.BANK_IMPORT_TOKEN || '').trim();\nreturn { json: {\n  ...root,\n  auth_ok: Boolean(expected && provided && provided === expected),\n  auth_reason: !expected ? 'missing_server_token_var' : !provided ? 'missing_token_header' : provided === expected ? '' : 'bad_token',\n  checked_at_utc: new Date().toISOString(),\n} };"
      }
    },
    {
      "id": "7743dabf-815e-423d-82f3-729dc9a0136a",
      "name": "Import Authorized?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        220,
        -20
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "leftValue": "={{ $json.auth_ok }}",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "rightValue": true
            }
          ],
          "combinator": "and"
        }
      }
    },
    {
      "id": "ae034797-427b-444a-8fbd-c677e4b9bbe8",
      "name": "Build Unauthorized Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        500,
        160
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const item = $input.item.json || {};\nreturn { json: { ok: false, status: 'unauthorized', reason: item.auth_reason || 'unauthorized' } };"
      }
    },
    {
      "id": "da0fef25-0073-4eb1-88ce-b1cc191ce4f5",
      "name": "Respond Unauthorized",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        760,
        160
      ],
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $json }}",
        "options": {
          "responseCode": 401
        }
      }
    },
    {
      "id": "6bb2848b-d29c-4a59-aa88-f8af616ca9eb",
      "name": "Build Webhook Statement Contract",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        500,
        -120
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const root = $input.item.json || {};\nconst body = root.body && typeof root.body === 'object' ? root.body : {};\nreturn { json: {\n  batch_source: 'webhook-simulated-statement-contract',\n  import_run_key: String(body.import_run_key || ('recon-webhook-' + $execution.id)),\n  smoke_tag: String(body.smoke_tag || ''),\n  bank_rows: Array.isArray(body.bank_rows) ? body.bank_rows : [],\n  open_invoices: Array.isArray(body.open_invoices) ? body.open_invoices : [],\n  payer_aliases: Array.isArray(body.payer_aliases) ? body.payer_aliases : [],\n  existing_transactions: Array.isArray(body.existing_transactions) ? body.existing_transactions : [],\n  existing_review_rows: Array.isArray(body.existing_review_rows) ? body.existing_review_rows : [],\n  ledger_complete: body.ledger_complete !== false,\n  amount_tolerance_grosz: Number.isFinite(Number(body.amount_tolerance_grosz)) ? Number(body.amount_tolerance_grosz) : 0,\n  simulated_write_failures: body.simulated_write_failures && typeof body.simulated_write_failures === 'object' ? body.simulated_write_failures : {},\n  now_utc: String(body.now_utc || ''),\n} };"
      }
    },
    {
      "id": "ce411d12-42fc-4494-9a09-8f4125344a12",
      "name": "Build Runtime Bank Fixture",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        0,
        520
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "return { json: {\n  \"batch_source\": \"runtime-simulator-mbank-pko-contract\",\n  \"import_run_key\": \"recon-runtime-fixture-v2-identity-hardening\",\n  \"smoke_tag\": \"RECON-RUNTIME-SMOKE\",\n  \"now_utc\": \"2026-07-05T12:00:00.000Z\",\n  \"ledger_complete\": true,\n  \"amount_tolerance_grosz\": 0,\n  \"existing_transactions\": [\n    {\n      \"transaction_key\": \"0811fc2c5cfe5108077f7658bf55eaa6fcec153dd64d344d8e6d33d3c00fcb1b\",\n      \"seed_reason\": \"R2 no-bank-id durable preseed repro\"\n    }\n  ],\n  \"existing_review_rows\": [\n    {\n      \"review_key\": \"seed-old-review\",\n      \"queue_reason\": \"seeded_old_unresolved_review\",\n      \"created_at_utc\": \"2026-07-01T12:00:00.000Z\",\n      \"resolved_at_utc\": \"\"\n    }\n  ],\n  \"payer_aliases\": [\n    {\n      \"payer_name\": \"ACME SP ZOO\",\n      \"client_key\": \"acme\"\n    },\n    {\n      \"payer_name\": \"GAMMA SP ZOO\",\n      \"client_key\": \"gamma\"\n    },\n    {\n      \"payer_name\": \"DELTA SP ZOO\",\n      \"client_key\": \"delta\"\n    },\n    {\n      \"payer_name\": \"EPSILON SP ZOO\",\n      \"client_key\": \"epsilon\"\n    },\n    {\n      \"payer_name\": \"BETA DENTAL\",\n      \"client_key\": \"beta\"\n    },\n    {\n      \"payer_name\": \"OMEGA HOLDING\",\n      \"client_key\": \"omega\"\n    },\n    {\n      \"payer_name\": \"OMEGA HOLDING\",\n      \"client_key\": \"omega-alt\"\n    },\n    {\n      \"payer_name\": \"\",\n      \"client_key\": \"\"\n    },\n    {\n      \"payer_name\": \"AC\",\n      \"client_key\": \"ac\"\n    },\n    {\n      \"payer_name\": \"ZETA SP ZOO\",\n      \"client_key\": \"zeta\"\n    },\n    {\n      \"payer_name\": \"TOKEN TEST SP ZOO\",\n      \"client_key\": \"token\"\n    },\n    {\n      \"payer_name\": \"PAIDONLY SP ZOO\",\n      \"client_key\": \"paidonly\"\n    },\n    {\n      \"payer_name\": \"THETA SP ZOO\",\n      \"client_key\": \"theta\"\n    },\n    {\n      \"payer_name\": \"UNMAPPED SP ZOO\",\n      \"client_key\": \"unmapped\"\n    }\n  ],\n  \"open_invoices\": [\n    {\n      \"invoice_key\": \"INV-ACME-001\",\n      \"job_id\": \"recon-job-acme-001\",\n      \"client_key\": \"acme\",\n      \"client_name\": \"ACME Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-001\",\n      \"gross_amount\": 1200,\n      \"open_amount\": 1200,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-10\"\n    },\n    {\n      \"invoice_key\": \"INV-BETA-101\",\n      \"job_id\": \"recon-job-beta-101\",\n      \"client_key\": \"beta\",\n      \"client_name\": \"Beta Dental\",\n      \"invoice_number\": \"FV-2026-101\",\n      \"gross_amount\": 800,\n      \"open_amount\": 800,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-11\"\n    },\n    {\n      \"invoice_key\": \"INV-BETA-102\",\n      \"job_id\": \"recon-job-beta-102\",\n      \"client_key\": \"beta\",\n      \"client_name\": \"Beta Dental\",\n      \"invoice_number\": \"FV-2026-102\",\n      \"gross_amount\": 800,\n      \"open_amount\": 800,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-12\"\n    },\n    {\n      \"invoice_key\": \"INV-GAMMA-003\",\n      \"job_id\": \"recon-job-gamma-003\",\n      \"client_key\": \"gamma\",\n      \"client_name\": \"Gamma Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-003\",\n      \"gross_amount\": 300,\n      \"open_amount\": 300,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-12\"\n    },\n    {\n      \"invoice_key\": \"INV-GAMMA-004\",\n      \"job_id\": \"recon-job-gamma-004\",\n      \"client_key\": \"gamma\",\n      \"client_name\": \"Gamma Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-004\",\n      \"gross_amount\": 250,\n      \"open_amount\": 250,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-13\"\n    },\n    {\n      \"invoice_key\": \"INV-GAMMA-005\",\n      \"job_id\": \"recon-job-gamma-005\",\n      \"client_key\": \"gamma\",\n      \"client_name\": \"Gamma Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-005\",\n      \"gross_amount\": 350,\n      \"open_amount\": 350,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-14\"\n    },\n    {\n      \"invoice_key\": \"INV-DELTA-006\",\n      \"job_id\": \"recon-job-delta-006\",\n      \"client_key\": \"delta\",\n      \"client_name\": \"Delta Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-006\",\n      \"gross_amount\": 1000,\n      \"open_amount\": 1000,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-15\"\n    },\n    {\n      \"invoice_key\": \"INV-EPSILON-007\",\n      \"job_id\": \"recon-job-epsilon-007\",\n      \"client_key\": \"epsilon\",\n      \"client_name\": \"Epsilon Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-007\",\n      \"gross_amount\": 1400,\n      \"open_amount\": 1400,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-16\"\n    },\n    {\n      \"invoice_key\": \"INV-ACME-012A\",\n      \"job_id\": \"recon-job-acme-012a\",\n      \"client_key\": \"acme\",\n      \"client_name\": \"ACME Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-012A\",\n      \"gross_amount\": 111,\n      \"open_amount\": 111,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-17\"\n    },\n    {\n      \"invoice_key\": \"INV-ACME-012B\",\n      \"job_id\": \"recon-job-acme-012b\",\n      \"client_key\": \"acme\",\n      \"client_name\": \"ACME Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-012B\",\n      \"gross_amount\": 111,\n      \"open_amount\": 111,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-18\"\n    },\n    {\n      \"invoice_key\": \"INV-OMEGA-201\",\n      \"job_id\": \"recon-job-omega-201\",\n      \"client_key\": \"omega\",\n      \"client_name\": \"Omega Holding\",\n      \"invoice_number\": \"FV-2026-201\",\n      \"gross_amount\": 222,\n      \"open_amount\": 222,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-19\"\n    },\n    {\n      \"invoice_key\": \"INV-OMEGAALT-201\",\n      \"job_id\": \"recon-job-omegaalt-201\",\n      \"client_key\": \"omega-alt\",\n      \"client_name\": \"Omega Alternate\",\n      \"invoice_number\": \"FV-2026-202\",\n      \"gross_amount\": 222,\n      \"open_amount\": 222,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-19\"\n    },\n    {\n      \"invoice_key\": \"INV-BLANK-001\",\n      \"job_id\": \"recon-job-blank-001\",\n      \"client_key\": \"\",\n      \"client_name\": \"Blank Client Key\",\n      \"invoice_number\": \"FV-2026-BLANK\",\n      \"gross_amount\": 333,\n      \"open_amount\": 333,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-20\"\n    },\n    {\n      \"invoice_key\": \"INV-ZETA-100\",\n      \"job_id\": \"recon-job-zeta-100\",\n      \"client_key\": \"zeta\",\n      \"client_name\": \"Zeta Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-Z100\",\n      \"gross_amount\": 100,\n      \"open_amount\": 100,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-21\"\n    },\n    {\n      \"invoice_key\": \"INV-ZETA-060\",\n      \"job_id\": \"recon-job-zeta-060\",\n      \"client_key\": \"zeta\",\n      \"client_name\": \"Zeta Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-Z060\",\n      \"gross_amount\": 60,\n      \"open_amount\": 60,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-22\"\n    },\n    {\n      \"invoice_key\": \"INV-ZETA-040\",\n      \"job_id\": \"recon-job-zeta-040\",\n      \"client_key\": \"zeta\",\n      \"client_name\": \"Zeta Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-Z040\",\n      \"gross_amount\": 40,\n      \"open_amount\": 40,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-23\"\n    },\n    {\n      \"invoice_key\": \"INV-TOKEN-003\",\n      \"job_id\": \"recon-job-token-003\",\n      \"client_key\": \"token\",\n      \"client_name\": \"Token Test Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-3\",\n      \"gross_amount\": 300,\n      \"open_amount\": 300,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-24\"\n    },\n    {\n      \"invoice_key\": \"INV-TOKEN-030\",\n      \"job_id\": \"recon-job-token-030\",\n      \"client_key\": \"token\",\n      \"client_name\": \"Token Test Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-30\",\n      \"gross_amount\": 3000,\n      \"open_amount\": 3000,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-25\"\n    },\n    {\n      \"invoice_key\": \"INV-PAID-017\",\n      \"job_id\": \"recon-job-paid-017\",\n      \"client_key\": \"paidonly\",\n      \"client_name\": \"Paidonly Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-017\",\n      \"gross_amount\": 170,\n      \"open_amount\": 0,\n      \"currency\": \"PLN\",\n      \"status\": \"Paid\",\n      \"due_date\": \"2026-07-26\"\n    },\n    {\n      \"invoice_key\": \"INV-THETA-018\",\n      \"job_id\": \"recon-job-theta-018\",\n      \"client_key\": \"theta\",\n      \"client_name\": \"Theta Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-018\",\n      \"gross_amount\": 1000,\n      \"open_amount\": 1000,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-27\"\n    },\n    {\n      \"invoice_key\": \"INV-ACME-019\",\n      \"job_id\": \"recon-job-acme-019\",\n      \"client_key\": \"acme\",\n      \"client_name\": \"ACME Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-019\",\n      \"gross_amount\": 1210,\n      \"open_amount\": 1210,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-28\"\n    },\n    {\n      \"invoice_key\": \"INV-UNMAPPED-020\",\n      \"job_id\": \"\",\n      \"client_key\": \"unmapped\",\n      \"client_name\": \"Unmapped Sp. z o.o.\",\n      \"invoice_number\": \"FV-2026-020\",\n      \"gross_amount\": 420,\n      \"open_amount\": 420,\n      \"currency\": \"PLN\",\n      \"status\": \"Open\",\n      \"due_date\": \"2026-07-28\"\n    }\n  ],\n  \"bank_rows\": [\n    {\n      \"scenario_id\": \"S01-happy-exact-invoice\",\n      \"source_bank\": \"mBank\",\n      \"source_account_ref\": \"MBANK-PLN-1\",\n      \"source_file_id\": \"mbank-2026-07-a.csv\",\n      \"source_row_number\": 1,\n      \"bank_txn_id\": \"MBK-001\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 1200,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"ACME SP ZOO\",\n      \"payer_iban\": \"PL00111111111111111111111111\",\n      \"title\": \"Zap\u0142ata za FV-2026-001\"\n    },\n    {\n      \"scenario_id\": \"S02-duplicate-statement-import\",\n      \"source_bank\": \"mBank\",\n      \"source_account_ref\": \"MBANK-PLN-1\",\n      \"source_file_id\": \"mbank-2026-07-a-copy.csv\",\n      \"source_row_number\": 1,\n      \"bank_txn_id\": \"MBK-001\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 1200,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"ACME SP ZOO\",\n      \"payer_iban\": \"PL00111111111111111111111111\",\n      \"title\": \"Zap\u0142ata za FV-2026-001\"\n    },\n    {\n      \"scenario_id\": \"S03-same-amount-two-open-invoices\",\n      \"source_bank\": \"PKO\",\n      \"source_account_ref\": \"PKO-PLN-1\",\n      \"source_file_id\": \"pko-2026-07-a.csv\",\n      \"source_row_number\": 2,\n      \"bank_txn_id\": \"PKO-002\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 800,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"Beta Dental\",\n      \"payer_iban\": \"PL00222222222222222222222222\",\n      \"title\": \"przelew za fakture\"\n    },\n    {\n      \"scenario_id\": \"S04-one-transfer-three-invoices\",\n      \"source_bank\": \"PKO\",\n      \"source_account_ref\": \"PKO-PLN-1\",\n      \"source_file_id\": \"pko-2026-07-a.csv\",\n      \"source_row_number\": 3,\n      \"bank_txn_id\": \"PKO-003\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 900,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"GAMMA SP ZOO\",\n      \"payer_iban\": \"PL00333333333333333333333333\",\n      \"title\": \"FV-2026-003 FV-2026-004 FV-2026-005\"\n    },\n    {\n      \"scenario_id\": \"S05-partial-payment\",\n      \"source_bank\": \"mBank\",\n      \"source_account_ref\": \"MBANK-PLN-1\",\n      \"source_file_id\": \"mbank-2026-07-b.csv\",\n      \"source_row_number\": 4,\n      \"bank_txn_id\": \"MBK-004\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 500,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"DELTA SP ZOO\",\n      \"payer_iban\": \"PL00444444444444444444444444\",\n      \"title\": \"cz\u0119\u015bciowo FV-2026-006\"\n    },\n    {\n      \"scenario_id\": \"S06-over-payment\",\n      \"source_bank\": \"mBank\",\n      \"source_account_ref\": \"MBANK-PLN-1\",\n      \"source_file_id\": \"mbank-2026-07-b.csv\",\n      \"source_row_number\": 5,\n      \"bank_txn_id\": \"MBK-005\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 1500,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"EPSILON SP ZOO\",\n      \"payer_iban\": \"PL00555555555555555555555555\",\n      \"title\": \"FV-2026-007 plus nadplata\"\n    },\n    {\n      \"scenario_id\": \"S07-unknown-payer\",\n      \"source_bank\": \"PKO\",\n      \"source_account_ref\": \"PKO-PLN-1\",\n      \"source_file_id\": \"pko-2026-07-b.csv\",\n      \"source_row_number\": 6,\n      \"bank_txn_id\": \"PKO-006\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 700,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"Unknown Consulting\",\n      \"payer_iban\": \"PL00666666666666666666666666\",\n      \"title\": \"oplata\"\n    },\n    {\n      \"scenario_id\": \"S08-malformed-csv-row\",\n      \"source_bank\": \"mBank\",\n      \"source_account_ref\": \"MBANK-PLN-1\",\n      \"source_file_id\": \"mbank-bad.csv\",\n      \"source_row_number\": 7,\n      \"bank_txn_id\": \"MBK-007\",\n      \"booking_date\": \"\",\n      \"amount\": \"\",\n      \"currency\": \"PLN\",\n      \"payer_name\": \"Broken Row\",\n      \"payer_iban\": \"\",\n      \"title\": \"malformed;missing;amount\"\n    },\n    {\n      \"scenario_id\": \"S09-encoding-garbage\",\n      \"source_bank\": \"PKO\",\n      \"source_account_ref\": \"PKO-PLN-1\",\n      \"source_file_id\": \"pko-win1250.csv\",\n      \"source_row_number\": 8,\n      \"bank_txn_id\": \"PKO-008\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 650,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"Za\u00c5\u00bc\u00c3\u00b3\u00c5\u201a\u00c4\u2021 Ltd\",\n      \"payer_iban\": \"PL00888888888888888888888888\",\n      \"title\": \"p\u00c5\u201aatno\u00c5\u203a\u00c4\u2021 za faktur\u00c4\u2122\"\n    },\n    {\n      \"scenario_id\": \"S10-overlapping-bank-export-title-jitter\",\n      \"source_bank\": \"PKO\",\n      \"source_account_ref\": \"PKO-PLN-2\",\n      \"source_file_id\": \"pko-overlap.csv\",\n      \"source_row_number\": 9,\n      \"bank_txn_id\": \"\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 1200,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"ACME SP ZOO\",\n      \"payer_iban\": \"PL00111111111111111111111111\",\n      \"title\": \"Zaplata FV/2026/001\"\n    },\n    {\n      \"scenario_id\": \"S11-alias-payer-without-invoice-number\",\n      \"source_bank\": \"mBank\",\n      \"source_account_ref\": \"MBANK-PLN-1\",\n      \"source_file_id\": \"mbank-alias.csv\",\n      \"source_row_number\": 10,\n      \"bank_txn_id\": \"MBK-010\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 800,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"BETA DENTAL JAN KOWALSKI\",\n      \"payer_iban\": \"PL00222222222222222222222222\",\n      \"title\": \"zap\u0142ata\"\n    },\n    {\n      \"scenario_id\": \"S12a-distinct-bank-id-same-natural-a\",\n      \"source_bank\": \"mBank\",\n      \"source_account_ref\": \"MBANK-PLN-1\",\n      \"source_file_id\": \"mbank-distinct-a.csv\",\n      \"source_row_number\": 11,\n      \"bank_txn_id\": \"MBK-012A\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 111,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"ACME SP ZOO\",\n      \"payer_iban\": \"PL00111111111111111111111111\",\n      \"title\": \"FV-2026-012A\"\n    },\n    {\n      \"scenario_id\": \"S12b-distinct-bank-id-same-natural-b\",\n      \"source_bank\": \"PKO\",\n      \"source_account_ref\": \"PKO-PLN-2\",\n      \"source_file_id\": \"pko-distinct-b.csv\",\n      \"source_row_number\": 12,\n      \"bank_txn_id\": \"PKO-012B\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 111,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"ACME SP ZOO\",\n      \"payer_iban\": \"PL00111111111111111111111111\",\n      \"title\": \"FV-2026-012B\"\n    },\n    {\n      \"scenario_id\": \"S13-ambiguous-alias-payer\",\n      \"source_bank\": \"mBank\",\n      \"source_account_ref\": \"MBANK-PLN-1\",\n      \"source_file_id\": \"mbank-ambiguous-alias.csv\",\n      \"source_row_number\": 13,\n      \"bank_txn_id\": \"MBK-013\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 222,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"OMEGA HOLDING\",\n      \"payer_iban\": \"PL00999999999999999999999999\",\n      \"title\": \"zap\u0142ata\"\n    },\n    {\n      \"scenario_id\": \"S14-empty-client-key-rejected\",\n      \"source_bank\": \"PKO\",\n      \"source_account_ref\": \"PKO-PLN-1\",\n      \"source_file_id\": \"pko-empty-key.csv\",\n      \"source_row_number\": 14,\n      \"bank_txn_id\": \"PKO-014\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 333,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"Blank Client Key\",\n      \"payer_iban\": \"PL00141414141414141414141414\",\n      \"title\": \"zap\u0142ata\"\n    },\n    {\n      \"scenario_id\": \"S15-ambiguous-subset-sum\",\n      \"source_bank\": \"mBank\",\n      \"source_account_ref\": \"MBANK-PLN-1\",\n      \"source_file_id\": \"mbank-subset.csv\",\n      \"source_row_number\": 15,\n      \"bank_txn_id\": \"MBK-015\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 100,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"ZETA SP ZOO\",\n      \"payer_iban\": \"PL00151515151515151515151515\",\n      \"title\": \"zap\u0142ata\"\n    },\n    {\n      \"scenario_id\": \"S16-invoice-token-boundary\",\n      \"source_bank\": \"PKO\",\n      \"source_account_ref\": \"PKO-PLN-1\",\n      \"source_file_id\": \"pko-token.csv\",\n      \"source_row_number\": 16,\n      \"bank_txn_id\": \"PKO-016\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 300,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"TOKEN TEST SP ZOO\",\n      \"payer_iban\": \"PL00161616161616161616161616\",\n      \"title\": \"FV-2026-3\"\n    },\n    {\n      \"scenario_id\": \"S17-paid-invoice-number-title\",\n      \"source_bank\": \"mBank\",\n      \"source_account_ref\": \"MBANK-PLN-1\",\n      \"source_file_id\": \"mbank-paid-title.csv\",\n      \"source_row_number\": 17,\n      \"bank_txn_id\": \"MBK-017\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 170,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"PAIDONLY SP ZOO\",\n      \"payer_iban\": \"PL00171717171717171717171717\",\n      \"title\": \"FV-2026-017\"\n    },\n    {\n      \"scenario_id\": \"S18a-intrabatch-partial-first\",\n      \"source_bank\": \"PKO\",\n      \"source_account_ref\": \"PKO-PLN-1\",\n      \"source_file_id\": \"pko-partials.csv\",\n      \"source_row_number\": 18,\n      \"bank_txn_id\": \"PKO-018A\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 400,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"THETA SP ZOO\",\n      \"payer_iban\": \"PL00181818181818181818181818\",\n      \"title\": \"FV-2026-018 pierwsza cz\u0119\u015b\u0107\"\n    },\n    {\n      \"scenario_id\": \"S18b-intrabatch-partial-second\",\n      \"source_bank\": \"PKO\",\n      \"source_account_ref\": \"PKO-PLN-1\",\n      \"source_file_id\": \"pko-partials.csv\",\n      \"source_row_number\": 19,\n      \"bank_txn_id\": \"PKO-018B\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 600,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"THETA SP ZOO\",\n      \"payer_iban\": \"PL00181818181818181818181818\",\n      \"title\": \"FV-2026-018 druga cz\u0119\u015b\u0107\"\n    },\n    {\n      \"scenario_id\": \"S19-no-bank-id-durable-preseed\",\n      \"source_bank\": \"mBank\",\n      \"source_account_ref\": \"MBANK-PLN-1\",\n      \"source_file_id\": \"mbank-no-bank-id-preseed.csv\",\n      \"source_row_number\": 20,\n      \"bank_txn_id\": \"\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 1210,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"ACME SP ZOO\",\n      \"payer_iban\": \"PL00111111111111111111111111\",\n      \"title\": \"FV-2026-019\"\n    },\n    {\n      \"scenario_id\": \"S20-unmapped-invoice-job-id\",\n      \"source_bank\": \"PKO\",\n      \"source_account_ref\": \"PKO-PLN-1\",\n      \"source_file_id\": \"pko-unmapped-job-id.csv\",\n      \"source_row_number\": 21,\n      \"bank_txn_id\": \"PKO-020\",\n      \"booking_date\": \"2026-07-05\",\n      \"amount\": 420,\n      \"currency\": \"PLN\",\n      \"payer_name\": \"UNMAPPED SP ZOO\",\n      \"payer_iban\": \"PL00202020202020202020202020\",\n      \"title\": \"FV-2026-020\"\n    }\n  ]\n} };"
      }
    },
    {
      "id": "39c30833-4ba7-467c-8d5f-ec1ef2737f90",
      "name": "Run Webhook Reconciliation Engine",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1700,
        -120
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const pruneStore = (obj, max = 5000) => {\n  const keys = Object.keys(obj);\n  for (let i = 0; i < keys.length - max; i++) delete obj[keys[i]];\n};\nconst crypto = require('crypto');\nconst root = $input.item.json || {};\nconst now = root.now_utc || new Date().toISOString();\nconst collapse = (value) => String(value ?? '').replace(/\\s+/g, ' ').trim();\nconst esc = (value) => collapse(value).replace(/[&<>\"']/g, (ch) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[ch]));\nconst hash = (value) => crypto.createHash('sha256').update(String(value)).digest('hex');\nconst money = (value) => Math.round(Number(value) * 100) / 100;\nconst norm = (value) => collapse(value).toLowerCase().normalize('NFD').replace(/[\\u0300-\\u036f]/g, '');\nconst normText = (value) => norm(value).replace(/[^a-z0-9]+/g, ' ').trim();\nconst tokens = (value) => normText(value).split(/\\s+/).filter(Boolean);\nconst tokenKey = (value) => tokens(value).join('|');\nconst hasTokenSubsequence = (haystackValue, needleValue) => {\n  const hay = tokens(haystackValue);\n  const needle = tokens(needleValue);\n  if (!needle.length || hay.length < needle.length) return false;\n  for (let i = 0; i <= hay.length - needle.length; i++) {\n    let ok = true;\n    for (let j = 0; j < needle.length; j++) if (hay[i + j] !== needle[j]) ok = false;\n    if (ok) return true;\n  }\n  return false;\n};\nconst tokenSetContains = (haystackValue, needleValue) => {\n  const hay = new Set(tokens(haystackValue));\n  const needle = tokens(needleValue);\n  return needle.length > 0 && needle.every((t) => hay.has(t));\n};\nconst invoiceKey = (jobId) => jobId ? hash('invoice.v1\\n' + collapse(jobId)) : 'unmapped';\nconst hasMojibake = (value) => /(?:\u00c3|\u00c5|\u00c4|\u00c2)/.test(String(value || ''));\nconst evidence = (obj) => JSON.stringify(obj).slice(0, 4500);\nconst staticData = $getWorkflowStaticData ? $getWorkflowStaticData('global') : {};\nstaticData.recon_seen_transactions = staticData.recon_seen_transactions || {};\npruneStore(staticData.recon_seen_transactions);\nstaticData.recon_seen_natural = staticData.recon_seen_natural || {};\npruneStore(staticData.recon_seen_natural);\nstaticData.recon_seen_signals = staticData.recon_seen_signals || {};\npruneStore(staticData.recon_seen_signals);\nconst amountTolerance = Number.isFinite(Number(root.amount_tolerance_grosz)) ? Math.max(0, Number(root.amount_tolerance_grosz)) / 100 : 0;\nconst amountsEqual = (a, b) => Math.abs(money(a) - money(b)) <= amountTolerance;\nconst seenExactInBatch = new Set();\nconst seenNaturalInBatch = new Map();\nconst existingTransactionKeys = new Set((Array.isArray(root.existing_transactions) ? root.existing_transactions : []).map((row) => collapse(row.transaction_key || row.exact_transaction_key || '')).filter(Boolean));\nconst transactions = [];\nconst invoiceRows = [];\nconst allocations = [];\nconst reviews = [];\nconst signals = [];\nconst configWarnings = [];\nconst invoices = (Array.isArray(root.open_invoices) ? root.open_invoices : []).map((inv) => {\n  const rawClientKey = norm(inv.client_key || '');\n  const validClientKey = rawClientKey.length >= 3 ? rawClientKey : '';\n  if (!validClientKey) configWarnings.push({ type: 'invalid_client_key', invoice_number: collapse(inv.invoice_number || ''), client_name: collapse(inv.client_name || '') });\n  const explicitInvoice = collapse(inv.invoice_key || '');\n  const jobId = collapse(inv.job_id || '');\n  const mappingStatus = explicitInvoice || jobId ? 'mapped' : 'unmapped';\n  const row = {\n    invoice_key: explicitInvoice || (jobId ? invoiceKey(jobId) : hash('recon:invoice:' + rawClientKey + ':' + inv.invoice_number)),\n    job_id: jobId,\n    client_key: validClientKey,\n    client_name: collapse(inv.client_name || inv.client_key || ''),\n    invoice_number: collapse(inv.invoice_number || ''),\n    gross_amount: money(inv.gross_amount || inv.open_amount || 0),\n    open_amount: money(inv.open_amount || inv.gross_amount || 0),\n    currency: collapse(inv.currency || 'PLN').toUpperCase(),\n    status: collapse(inv.status || 'Open'),\n    due_date: collapse(inv.due_date || ''),\n    paid_signal_status: mappingStatus === 'mapped' ? 'not_signalled' : 'unmapped_invoice_key',\n    smoke_tag: collapse(root.smoke_tag || ''),\n    created_at_utc: now,\n    last_execution_id: $execution.id,\n  };\n  invoiceRows.push(row);\n  return row;\n});\nconst clientKeys = new Set(invoices.map((inv) => inv.client_key).filter(Boolean));\nconst aliasRows = [];\nfor (const a of Array.isArray(root.payer_aliases) ? root.payer_aliases : []) {\n  const aliasName = collapse(a.payer_name || a.alias || '');\n  const aliasNorm = normText(aliasName);\n  const clientKey = norm(a.client_key || '');\n  if (!aliasNorm || aliasNorm.length < 3 || !clientKey || clientKey.length < 3 || !clientKeys.has(clientKey)) {\n    configWarnings.push({ type: 'invalid_payer_alias', alias: aliasName, client_key: clientKey });\n    continue;\n  }\n  aliasRows.push({ alias_name: aliasName, alias_norm: aliasNorm, client_key: clientKey });\n}\nconst remainingOpen = new Map(invoices.map((inv) => [inv.invoice_key, inv.open_amount]));\nconst partialTouched = new Set();\nconst isOpenInvoice = (inv) => inv && inv.client_key && remainingOpen.get(inv.invoice_key) > 0 && !/^paid$/i.test(inv.status);\nconst openForClient = (clientKey) => invoices.filter((inv) => inv.client_key === clientKey && isOpenInvoice(inv));\nconst collectClientCandidates = (row) => {\n  const payer = collapse(row.payer_name || '');\n  const matches = new Map();\n  for (const alias of aliasRows) {\n    if (normText(payer) === alias.alias_norm || tokenSetContains(payer, alias.alias_name)) matches.set(alias.client_key, { source: 'explicit_alias', alias: alias.alias_name });\n  }\n  for (const inv of invoices) {\n    if (!inv.client_key) continue;\n    if (tokenSetContains(payer, inv.client_key) || (inv.client_name && tokenSetContains(payer, inv.client_name))) matches.set(inv.client_key, { source: 'client_catalog', client_name: inv.client_name });\n  }\n  return Array.from(matches.entries()).map(([client_key, meta]) => ({ client_key, ...meta }));\n};\nconst exactFingerprint = (row) => collapse(row.bank_txn_id) ? hash('recon:bank-txn-id:' + norm(row.source_bank) + ':' + norm(row.source_account_ref) + ':' + collapse(row.bank_txn_id)) : '';\nconst naturalFingerprint = (row) => hash('recon:bank-natural:' + [row.booking_date, money(row.amount || 0), row.currency, norm(row.payer_iban || '') || norm(row.payer_name)].join('|'));\nconst candidateDetails = (candidates) => (candidates || []).map((c) => ({ invoice_key: c.invoice_key, invoice_number: c.invoice_number, open_amount: remainingOpen.get(c.invoice_key) ?? c.open_amount, due_date: c.due_date, client_key: c.client_key }));\nconst addReview = (tx, reason, summary, candidates, facts) => {\n  const details = candidateDetails(candidates);\n  reviews.push({\n    review_key: hash('recon:review:' + tx.transaction_key + ':' + reason),\n    transaction_key: tx.transaction_key,\n    queue_reason: reason,\n    human_summary: summary,\n    candidate_invoice_keys: details.map((c) => c.invoice_key).join(','),\n    candidate_invoice_numbers: details.map((c) => c.invoice_number).join(','),\n    candidate_invoice_amounts: details.map((c) => c.open_amount).join(','),\n    candidate_invoice_due_dates: details.map((c) => c.due_date).join(','),\n    candidate_invoice_details_json: evidence(details),\n    evidence_json: evidence({ ...facts, candidates: details }),\n    smoke_tag: tx.smoke_tag,\n    created_at_utc: now,\n    last_execution_id: $execution.id,\n  });\n};\nconst allocate = (tx, inv, amount, status, confidence, facts) => {\n  const allocAmount = money(amount);\n  const allocationKey = hash('recon:allocation:' + tx.transaction_key + ':' + inv.invoice_key + ':' + allocAmount);\n  allocations.push({\n    allocation_key: allocationKey,\n    transaction_key: tx.transaction_key,\n    invoice_key: inv.invoice_key,\n    invoice_key: inv.invoice_key,\n    allocated_amount: allocAmount,\n    allocation_status: status,\n    confidence_label: confidence,\n    evidence_json: evidence(facts),\n    smoke_tag: tx.smoke_tag,\n    created_at_utc: now,\n    last_execution_id: $execution.id,\n  });\n  remainingOpen.set(inv.invoice_key, money((remainingOpen.get(inv.invoice_key) || 0) - allocAmount));\n  if (status === 'matched_partial_no_paid_signal') partialTouched.add(inv.invoice_key);\n  if (status === 'matched_full' && inv.invoice_key !== 'unmapped') {\n    const eventId = 'recon-' + allocationKey.slice(0, 24);\n    const signalKey = hash('recon:paid-signal:' + inv.invoice_key + ':' + eventId);\n    if (!staticData.recon_seen_signals[signalKey]) {\n      staticData.recon_seen_signals[signalKey] = now;\n      signals.push({\n        signal_key: signalKey,\n        invoice_key: inv.invoice_key,\n        invoice_payment_event_id: eventId,\n        transaction_key: tx.transaction_key,\n        invoice_key: inv.invoice_key,\n        event_type: 'invoice.paid',\n        paid_at: tx.booking_date || now,\n        payload_json: evidence({ event_type: 'invoice.paid', invoice_key: inv.invoice_key, source_invoice_key: inv.invoice_key, job_id: inv.job_id, invoice_payment_event_id: eventId, payment_event_id: eventId, paid_at: tx.booking_date || now, mapping_status: 'mapped', source: 'Recon_Paid_Signals' }),\n        signal_status: 'pending_invoice_delivery',\n        smoke_tag: tx.smoke_tag,\n        created_at_utc: now,\n        last_execution_id: $execution.id,\n      });\n    }\n  }\n};\nconst mentionedOpenInvoices = (title, currency) => invoices.filter((inv) => isOpenInvoice(inv) && inv.invoice_number && (!currency || collapse(inv.currency || 'PLN') === currency) && hasTokenSubsequence(title, inv.invoice_number));\nconst mentionedClosedInvoices = (title) => invoices.filter((inv) => inv.invoice_number && !isOpenInvoice(inv) && hasTokenSubsequence(title, inv.invoice_number));\nconst subsetSums = (arr, target, maxSize = 3) => {\n  const out = [];\n  const walk = (start, chosen, sum) => {\n    if (chosen.length > 0 && amountsEqual(sum, target)) out.push([...chosen]);\n    if (chosen.length >= maxSize || sum >= target + amountTolerance) return;\n    for (let i = start; i < arr.length; i++) walk(i + 1, [...chosen, arr[i]], money(sum + (remainingOpen.get(arr[i].invoice_key) || 0)));\n  };\n  walk(0, [], 0);\n  return out;\n};\nfor (const raw of Array.isArray(root.bank_rows) ? root.bank_rows : []) {\n  const amount = Number(raw.amount);\n  const currency = collapse(raw.currency || 'PLN').toUpperCase();\n  const rawHash = hash('recon:raw-row:' + JSON.stringify(raw));\n  const exactKey = exactFingerprint(raw);\n  const naturalKey = naturalFingerprint({ ...raw, amount, currency });\n  const txKey = exactKey || naturalKey;\n  const tx = {\n    transaction_key: txKey,\n    import_run_key: collapse(root.import_run_key || ('recon-' + $execution.id)),\n    source_bank: collapse(raw.source_bank || ''),\n    source_account_ref: collapse(raw.source_account_ref || ''),\n    source_file_id: collapse(raw.source_file_id || ''),\n    source_row_number: Number(raw.source_row_number || 0),\n    booking_date: collapse(raw.booking_date || ''),\n    amount: Number.isFinite(amount) ? money(amount) : 0,\n    currency,\n    payer_name: collapse(raw.payer_name || ''),\n    payer_iban_hash: raw.payer_iban ? hash('iban:' + collapse(raw.payer_iban)) : '',\n    title: collapse(raw.title || ''),\n    raw_row_hash: rawHash,\n    match_status: 'held_for_review',\n    held_reason: '',\n    evidence_json: '',\n    smoke_tag: collapse(root.smoke_tag || ''),\n    created_at_utc: now,\n    last_execution_id: $execution.id,\n  };\n  const facts = { scenario_id: raw.scenario_id || '', source_file_id: tx.source_file_id, source_row_number: tx.source_row_number, amount: tx.amount, currency, title: tx.title, payer_name: tx.payer_name, exact_transaction_key: exactKey, natural_fingerprint: naturalKey };\n  if (!tx.booking_date || !Number.isFinite(amount) || amount <= 0 || !currency) {\n    tx.match_status = 'malformed_held';\n    tx.held_reason = 'malformed_csv_row';\n    tx.evidence_json = evidence({ ...facts, failure: 'required bank row fields missing or invalid' });\n    transactions.push(tx);\n    addReview(tx, tx.held_reason, 'Malformed bank CSV row held before matching.', [], facts);\n    continue;\n  }\n  const duplicateKey = txKey;\n  const durableDuplicate = existingTransactionKeys.has(duplicateKey);\n  const staticDuplicate = Boolean(staticData.recon_seen_transactions[duplicateKey]);\n  const batchExactDuplicate = Boolean(exactKey && seenExactInBatch.has(exactKey));\n  if (durableDuplicate || staticDuplicate || batchExactDuplicate) {\n    tx.match_status = 'duplicate_suppressed';\n    tx.held_reason = 'duplicate_statement_import';\n    tx.evidence_json = evidence({ ...facts, duplicate_key: duplicateKey, duplicate_layer: durableDuplicate ? 'durable_existing_transactions' : 'static_or_batch', duplicate_identity: exactKey ? 'exact_bank_transaction_id' : 'natural_transaction_key' });\n    transactions.push(tx);\n    continue;\n  }\n  const naturalCollision = Boolean(!exactKey && (seenNaturalInBatch.has(naturalKey) || staticData.recon_seen_natural[naturalKey]));\n  if (naturalCollision) {\n    const previous = seenNaturalInBatch.get(naturalKey) || { source: 'existing_or_static' };\n    tx.match_status = 'held_for_review';\n    tx.held_reason = 'possible_cross_bank_duplicate';\n    tx.evidence_json = evidence({ ...facts, previous, identity_rule: 'booking_date_amount_currency_counterparty_without_title' });\n    transactions.push(tx);\n    addReview(tx, tx.held_reason, 'Possible cross-bank duplicate held; title is evidence only and no invoice is marked paid.', [], { ...facts, previous });\n    staticData.recon_seen_transactions[tx.transaction_key] = now;\n    continue;\n  }\n  if (exactKey) seenExactInBatch.add(exactKey);\n  seenNaturalInBatch.set(naturalKey, { scenario_id: raw.scenario_id || '', source_bank: tx.source_bank, source_file_id: tx.source_file_id, source_row_number: tx.source_row_number, exact_transaction_key: exactKey || '' });\n  staticData.recon_seen_transactions[tx.transaction_key] = now;\n  staticData.recon_seen_natural[naturalKey] = now;\n  if (hasMojibake(raw.payer_name) || hasMojibake(raw.title)) {\n    tx.match_status = 'held_for_review';\n    tx.held_reason = 'encoding_garbage_bank_export';\n    tx.evidence_json = evidence({ ...facts, encoding: 'mojibake markers present' });\n    transactions.push(tx);\n    addReview(tx, tx.held_reason, 'Bank export encoding is damaged; hold for human decoding.', [], facts);\n    continue;\n  }\n  const clientCandidates = collectClientCandidates(raw);\n  if (clientCandidates.length > 1) {\n    tx.match_status = 'held_for_review';\n    tx.held_reason = 'ambiguous_payer_multiple_clients';\n    tx.evidence_json = evidence({ ...facts, client_candidates: clientCandidates });\n    transactions.push(tx);\n    addReview(tx, tx.held_reason, 'Payer identity matches more than one client; no invoice is marked paid.', clientCandidates.flatMap((c) => openForClient(c.client_key)), { ...facts, client_candidates: clientCandidates });\n    continue;\n  }\n  const clientKey = clientCandidates[0]?.client_key || '';\n  const clientInvoices = clientKey ? openForClient(clientKey) : [];\n  const mentioned = mentionedOpenInvoices(raw.title || '', collapse(raw.currency || 'PLN'));\n  const mentionedClosed = mentionedClosedInvoices(raw.title || '');\n  if (!mentioned.length && mentionedClosed.length) {\n    tx.match_status = 'held_for_review';\n    tx.held_reason = 'invoice_number_not_open';\n    tx.evidence_json = evidence({ ...facts, closed_invoice_numbers: mentionedClosed.map((i) => i.invoice_number) });\n    transactions.push(tx);\n    addReview(tx, tx.held_reason, 'Invoice number appears in title but it is not open; no dunning stop signal emitted.', mentionedClosed, facts);\n    continue;\n  }\n  if (!clientKey && mentioned.length === 0) {\n    tx.match_status = 'held_for_review';\n    tx.held_reason = 'unknown_or_invalid_payer_no_invoice_number';\n    tx.evidence_json = evidence({ ...facts, config_warning_count: configWarnings.length });\n    transactions.push(tx);\n    addReview(tx, tx.held_reason, 'Unknown or invalid payer and no usable open invoice number; no dunning stop signal emitted.', [], facts);\n    continue;\n  }\n  if (mentioned.length) {\n    const totalOpen = money(mentioned.reduce((sum, inv) => sum + (remainingOpen.get(inv.invoice_key) || 0), 0));\n    if (tx.amount > totalOpen && !amountsEqual(tx.amount, totalOpen)) {\n      tx.match_status = 'held_for_review';\n      tx.held_reason = 'overpayment_requires_policy';\n      tx.evidence_json = evidence({ ...facts, total_open: totalOpen, mentioned_invoice_numbers: mentioned.map((i) => i.invoice_number) });\n      transactions.push(tx);\n      addReview(tx, tx.held_reason, 'Payment exceeds mentioned open invoice total; hold until overpayment policy is known.', mentioned, facts);\n      continue;\n    }\n    if (tx.amount < totalOpen && !amountsEqual(tx.amount, totalOpen)) {\n      tx.match_status = 'partial_matched_no_paid_signal';\n      tx.held_reason = 'partial_payment_no_paid_signal';\n      tx.evidence_json = evidence({ ...facts, mentioned_invoice_numbers: mentioned.map((i) => i.invoice_number), total_open: totalOpen });\n      transactions.push(tx);\n      if (mentioned.length === 1) allocate(tx, mentioned[0], tx.amount, 'matched_partial_no_paid_signal', 'deterministic_invoice_number_partial', facts);\n      addReview(tx, tx.held_reason, 'Partial payment recorded as evidence but invoice is not marked paid.', mentioned, facts);\n      continue;\n    }\n    if (mentioned.some((inv) => partialTouched.has(inv.invoice_key))) {\n      tx.match_status = 'partial_matched_no_paid_signal';\n      tx.held_reason = 'partial_payment_sequence_no_paid_signal';\n      tx.evidence_json = evidence({ ...facts, mentioned_invoice_numbers: mentioned.map((i) => i.invoice_number), total_open: totalOpen });\n      transactions.push(tx);\n      if (mentioned.length === 1) allocate(tx, mentioned[0], tx.amount, 'matched_partial_no_paid_signal', 'intrabatch_partial_sequence', facts);\n      addReview(tx, tx.held_reason, 'Second same-batch partial would close the invoice only cumulatively; held for human confirmation and no paid signal emitted.', mentioned, facts);\n      continue;\n    }\n    tx.match_status = mentioned.length > 1 ? 'matched_full_multi_invoice' : 'matched_full_single_invoice';\n    tx.held_reason = '';\n    tx.evidence_json = evidence({ ...facts, matched_invoice_numbers: mentioned.map((i) => i.invoice_number), total_open: totalOpen });\n    transactions.push(tx);\n    for (const inv of mentioned) allocate(tx, inv, remainingOpen.get(inv.invoice_key) || inv.open_amount, 'matched_full', mentioned.length > 1 ? 'deterministic_invoice_numbers_total_exact' : 'deterministic_invoice_number_amount_exact', facts);\n    continue;\n  }\n  const sameAmountCandidates = clientInvoices.filter((inv) => inv.currency === currency && amountsEqual(remainingOpen.get(inv.invoice_key) || 0, tx.amount));\n  if (sameAmountCandidates.length > 1) {\n    tx.match_status = 'held_for_review';\n    tx.held_reason = 'ambiguous_same_amount_open_invoices';\n    tx.evidence_json = evidence({ ...facts, candidate_invoice_numbers: sameAmountCandidates.map((c) => c.invoice_number) });\n    transactions.push(tx);\n    addReview(tx, tx.held_reason, 'Same amount fits more than one open invoice; false match risk is higher than no match.', sameAmountCandidates, facts);\n    continue;\n  }\n  if (sameAmountCandidates.length === 1) {\n    const alternatives = subsetSums(clientInvoices.filter((inv) => inv.invoice_key !== sameAmountCandidates[0].invoice_key), tx.amount, 3).filter((set) => set.length >= 2);\n    if (alternatives.length > 0) {\n      tx.match_status = 'held_for_review';\n      tx.held_reason = 'ambiguous_subset_sum';\n      tx.evidence_json = evidence({ ...facts, exact_invoice: sameAmountCandidates[0].invoice_number, alternative_subsets: alternatives.map((set) => set.map((i) => i.invoice_number)) });\n      transactions.push(tx);\n      addReview(tx, tx.held_reason, 'Amount fits one invoice and also another invoice subset; held instead of pick-first.', [sameAmountCandidates[0]].concat(alternatives.flat()), facts);\n      continue;\n    }\n    tx.match_status = 'matched_full_single_invoice';\n    tx.held_reason = '';\n    tx.evidence_json = evidence({ ...facts, matched_invoice_number: sameAmountCandidates[0].invoice_number });\n    transactions.push(tx);\n    allocate(tx, sameAmountCandidates[0], tx.amount, 'matched_full', 'deterministic_alias_amount_unique', facts);\n    continue;\n  }\n  tx.match_status = 'held_for_review';\n  tx.held_reason = 'below_threshold_no_safe_match';\n  tx.evidence_json = evidence(facts);\n  transactions.push(tx);\n  addReview(tx, tx.held_reason, 'Below matching threshold: do nothing irreversible and give evidence to a human.', mentioned.concat(clientInvoices), facts);\n}\nconst needsReview = transactions.filter((t) => t.match_status.includes('held') || t.match_status === 'malformed_held' || t.match_status === 'partial_matched_no_paid_signal');\nconst existingOpenReviews = (Array.isArray(root.existing_review_rows) ? root.existing_review_rows : []).filter((row) => !row.resolved_at_utc);\nconst ageDays = (created) => {\n  const ms = Date.parse(now) - Date.parse(created || now);\n  return Number.isFinite(ms) && ms > 0 ? Math.floor(ms / 86400000) : 0;\n};\nconst oldestAge = Math.max(0, ...reviews.map((r) => ageDays(r.created_at_utc)), ...existingOpenReviews.map((r) => ageDays(r.created_at_utc)));\nconst simulatedWriteFailures = root.simulated_write_failures && typeof root.simulated_write_failures === 'object' ? root.simulated_write_failures : {};\nconst writeFailureCount = Object.values(simulatedWriteFailures).reduce((sum, value) => sum + (Number(value) || 0), 0);\nconst counts = {\n  total_rows: transactions.length,\n  auto_matched_count: transactions.filter((t) => /^matched_full/.test(t.match_status)).length,\n  held_count: needsReview.length,\n  duplicate_count: transactions.filter((t) => t.match_status === 'duplicate_suppressed').length,\n  malformed_count: transactions.filter((t) => t.match_status === 'malformed_held').length,\n  partial_count: transactions.filter((t) => t.match_status === 'partial_matched_no_paid_signal').length,\n  paid_signal_count: signals.length,\n  needs_review_count: needsReview.length,\n  review_queue_size: reviews.length + existingOpenReviews.length,\n  oldest_unresolved_review_age_days: oldestAge,\n  incomplete_ledger_flag: root.ledger_complete === false ? 'true' : 'false',\n  write_failure_count: writeFailureCount,\n  config_warning_count: configWarnings.length,\n};\nconst summaryKey = hash('recon:summary:' + (root.import_run_key || $execution.id) + ':' + $execution.id);\nconst rowsHtml = transactions.map((t) => '<li><strong>' + esc(t.match_status) + '</strong> ' + esc(t.source_bank) + ' row ' + esc(t.source_row_number) + ' amount ' + esc(t.amount) + ' title \"' + esc(t.title) + '\"' + (t.held_reason ? ' reason ' + esc(t.held_reason) : '') + '</li>').join('');\nconst operatorSubject = '[TEST] Bank reconciliation: ' + counts.auto_matched_count + ' matched, ' + counts.needs_review_count + ' need review';\nconst operatorBody = '<p>Draft-only reconciliation summary for the reconciliation operator.</p><p>False match policy: below threshold does nothing irreversible and creates review evidence.</p><p>Review queue size: ' + esc(counts.review_queue_size) + '; oldest unresolved age days: ' + esc(counts.oldest_unresolved_review_age_days) + '; incomplete ledger: ' + esc(counts.incomplete_ledger_flag) + '; write failures: ' + esc(counts.write_failure_count) + '; config warnings: ' + esc(counts.config_warning_count) + '.</p><ul>' + rowsHtml + '</ul>';\nreturn { json: {\n  transaction_rows_json: JSON.stringify(transactions),\n  invoice_rows_json: JSON.stringify(invoiceRows),\n  allocation_rows_json: JSON.stringify(allocations),\n  review_rows_json: JSON.stringify(reviews),\n  paid_signal_rows_json: JSON.stringify(signals),\n  summary_row_json: JSON.stringify({\n    summary_key: summaryKey,\n    import_run_key: collapse(root.import_run_key || ('recon-' + $execution.id)),\n    batch_source: collapse(root.batch_source || ''),\n    ...counts,\n    operator_subject: operatorSubject,\n    operator_body_html: operatorBody,\n    smoke_tag: collapse(root.smoke_tag || ''),\n    created_at_utc: now,\n    last_execution_id: $execution.id,\n  }),\n  response_status: 'reconciled_draft_only',\n  quoted_field_values: 'payer_name=\"' + (transactions[0]?.payer_name || '') + '\" title=\"' + (transactions[0]?.title || '') + '\" matched_invoice_key=\"' + (allocations[0]?.invoice_key || '') + '\" held_reason=\"' + (transactions.find((t) => t.held_reason)?.held_reason || '') + '\"',\n} };"
      }
    },
    {
      "id": "bf89f2bb-5d3f-465d-8446-69f2dfe53437",
      "name": "Run Runtime Reconciliation Engine",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1200,
        520
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const pruneStore = (obj, max = 5000) => {\n  const keys = Object.keys(obj);\n  for (let i = 0; i < keys.length - max; i++) delete obj[keys[i]];\n};\nconst crypto = require('crypto');\nconst root = $input.item.json || {};\nconst now = root.now_utc || new Date().toISOString();\nconst collapse = (value) => String(value ?? '').replace(/\\s+/g, ' ').trim();\nconst esc = (value) => collapse(value).replace(/[&<>\"']/g, (ch) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[ch]));\nconst hash = (value) => crypto.createHash('sha256').update(String(value)).digest('hex');\nconst money = (value) => Math.round(Number(value) * 100) / 100;\nconst norm = (value) => collapse(value).toLowerCase().normalize('NFD').replace(/[\\u0300-\\u036f]/g, '');\nconst normText = (value) => norm(value).replace(/[^a-z0-9]+/g, ' ').trim();\nconst tokens = (value) => normText(value).split(/\\s+/).filter(Boolean);\nconst tokenKey = (value) => tokens(value).join('|');\nconst hasTokenSubsequence = (haystackValue, needleValue) => {\n  const hay = tokens(haystackValue);\n  const needle = tokens(needleValue);\n  if (!needle.length || hay.length < needle.length) return false;\n  for (let i = 0; i <= hay.length - needle.length; i++) {\n    let ok = true;\n    for (let j = 0; j < needle.length; j++) if (hay[i + j] !== needle[j]) ok = false;\n    if (ok) return true;\n  }\n  return false;\n};\nconst tokenSetContains = (haystackValue, needleValue) => {\n  const hay = new Set(tokens(haystackValue));\n  const needle = tokens(needleValue);\n  return needle.length > 0 && needle.every((t) => hay.has(t));\n};\nconst invoiceKey = (jobId) => jobId ? hash('invoice.v1\\n' + collapse(jobId)) : 'unmapped';\nconst hasMojibake = (value) => /(?:\u00c3|\u00c5|\u00c4|\u00c2)/.test(String(value || ''));\nconst evidence = (obj) => JSON.stringify(obj).slice(0, 4500);\nconst staticData = $getWorkflowStaticData ? $getWorkflowStaticData('global') : {};\nstaticData.recon_seen_transactions = staticData.recon_seen_transactions || {};\npruneStore(staticData.recon_seen_transactions);\nstaticData.recon_seen_natural = staticData.recon_seen_natural || {};\npruneStore(staticData.recon_seen_natural);\nstaticData.recon_seen_signals = staticData.recon_seen_signals || {};\npruneStore(staticData.recon_seen_signals);\nconst amountTolerance = Number.isFinite(Number(root.amount_tolerance_grosz)) ? Math.max(0, Number(root.amount_tolerance_grosz)) / 100 : 0;\nconst amountsEqual = (a, b) => Math.abs(money(a) - money(b)) <= amountTolerance;\nconst seenExactInBatch = new Set();\nconst seenNaturalInBatch = new Map();\nconst existingTransactionKeys = new Set((Array.isArray(root.existing_transactions) ? root.existing_transactions : []).map((row) => collapse(row.transaction_key || row.exact_transaction_key || '')).filter(Boolean));\nconst transactions = [];\nconst invoiceRows = [];\nconst allocations = [];\nconst reviews = [];\nconst signals = [];\nconst configWarnings = [];\nconst invoices = (Array.isArray(root.open_invoices) ? root.open_invoices : []).map((inv) => {\n  const rawClientKey = norm(inv.client_key || '');\n  const validClientKey = rawClientKey.length >= 3 ? rawClientKey : '';\n  if (!validClientKey) configWarnings.push({ type: 'invalid_client_key', invoice_number: collapse(inv.invoice_number || ''), client_name: collapse(inv.client_name || '') });\n  const explicitInvoice = collapse(inv.invoice_key || '');\n  const jobId = collapse(inv.job_id || '');\n  const mappingStatus = explicitInvoice || jobId ? 'mapped' : 'unmapped';\n  const row = {\n    invoice_key: explicitInvoice || (jobId ? invoiceKey(jobId) : hash('recon:invoice:' + rawClientKey + ':' + inv.invoice_number)),\n    job_id: jobId,\n    client_key: validClientKey,\n    client_name: collapse(inv.client_name || inv.client_key || ''),\n    invoice_number: collapse(inv.invoice_number || ''),\n    gross_amount: money(inv.gross_amount || inv.open_amount || 0),\n    open_amount: money(inv.open_amount || inv.gross_amount || 0),\n    currency: collapse(inv.currency || 'PLN').toUpperCase(),\n    status: collapse(inv.status || 'Open'),\n    due_date: collapse(inv.due_date || ''),\n    paid_signal_status: mappingStatus === 'mapped' ? 'not_signalled' : 'unmapped_invoice_key',\n    smoke_tag: collapse(root.smoke_tag || ''),\n    created_at_utc: now,\n    last_execution_id: $execution.id,\n  };\n  invoiceRows.push(row);\n  return row;\n});\nconst clientKeys = new Set(invoices.map((inv) => inv.client_key).filter(Boolean));\nconst aliasRows = [];\nfor (const a of Array.isArray(root.payer_aliases) ? root.payer_aliases : []) {\n  const aliasName = collapse(a.payer_name || a.alias || '');\n  const aliasNorm = normText(aliasName);\n  const clientKey = norm(a.client_key || '');\n  if (!aliasNorm || aliasNorm.length < 3 || !clientKey || clientKey.length < 3 || !clientKeys.has(clientKey)) {\n    configWarnings.push({ type: 'invalid_payer_alias', alias: aliasName, client_key: clientKey });\n    continue;\n  }\n  aliasRows.push({ alias_name: aliasName, alias_norm: aliasNorm, client_key: clientKey });\n}\nconst remainingOpen = new Map(invoices.map((inv) => [inv.invoice_key, inv.open_amount]));\nconst partialTouched = new Set();\nconst isOpenInvoice = (inv) => inv && inv.client_key && remainingOpen.get(inv.invoice_key) > 0 && !/^paid$/i.test(inv.status);\nconst openForClient = (clientKey) => invoices.filter((inv) => inv.client_key === clientKey && isOpenInvoice(inv));\nconst collectClientCandidates = (row) => {\n  const payer = collapse(row.payer_name || '');\n  const matches = new Map();\n  for (const alias of aliasRows) {\n    if (normText(payer) === alias.alias_norm || tokenSetContains(payer, alias.alias_name)) matches.set(alias.client_key, { source: 'explicit_alias', alias: alias.alias_name });\n  }\n  for (const inv of invoices) {\n    if (!inv.client_key) continue;\n    if (tokenSetContains(payer, inv.client_key) || (inv.client_name && tokenSetContains(payer, inv.client_name))) matches.set(inv.client_key, { source: 'client_catalog', client_name: inv.client_name });\n  }\n  return Array.from(matches.entries()).map(([client_key, meta]) => ({ client_key, ...meta }));\n};\nconst exactFingerprint = (row) => collapse(row.bank_txn_id) ? hash('recon:bank-txn-id:' + norm(row.source_bank) + ':' + norm(row.source_account_ref) + ':' + collapse(row.bank_txn_id)) : '';\nconst naturalFingerprint = (row) => hash('recon:bank-natural:' + [row.booking_date, money(row.amount || 0), row.currency, norm(row.payer_iban || '') || norm(row.payer_name)].join('|'));\nconst candidateDetails = (candidates) => (candidates || []).map((c) => ({ invoice_key: c.invoice_key, invoice_number: c.invoice_number, open_amount: remainingOpen.get(c.invoice_key) ?? c.open_amount, due_date: c.due_date, client_key: c.client_key }));\nconst addReview = (tx, reason, summary, candidates, facts) => {\n  const details = candidateDetails(candidates);\n  reviews.push({\n    review_key: hash('recon:review:' + tx.transaction_key + ':' + reason),\n    transaction_key: tx.transaction_key,\n    queue_reason: reason,\n    human_summary: summary,\n    candidate_invoice_keys: details.map((c) => c.invoice_key).join(','),\n    candidate_invoice_numbers: details.map((c) => c.invoice_number).join(','),\n    candidate_invoice_amounts: details.map((c) => c.open_amount).join(','),\n    candidate_invoice_due_dates: details.map((c) => c.due_date).join(','),\n    candidate_invoice_details_json: evidence(details),\n    evidence_json: evidence({ ...facts, candidates: details }),\n    smoke_tag: tx.smoke_tag,\n    created_at_utc: now,\n    last_execution_id: $execution.id,\n  });\n};\nconst allocate = (tx, inv, amount, status, confidence, facts) => {\n  const allocAmount = money(amount);\n  const allocationKey = hash('recon:allocation:' + tx.transaction_key + ':' + inv.invoice_key + ':' + allocAmount);\n  allocations.push({\n    allocation_key: allocationKey,\n    transaction_key: tx.transaction_key,\n    invoice_key: inv.invoice_key,\n    invoice_key: inv.invoice_key,\n    allocated_amount: allocAmount,\n    allocation_status: status,\n    confidence_label: confidence,\n    evidence_json: evidence(facts),\n    smoke_tag: tx.smoke_tag,\n    created_at_utc: now,\n    last_execution_id: $execution.id,\n  });\n  remainingOpen.set(inv.invoice_key, money((remainingOpen.get(inv.invoice_key) || 0) - allocAmount));\n  if (status === 'matched_partial_no_paid_signal') partialTouched.add(inv.invoice_key);\n  if (status === 'matched_full' && inv.invoice_key !== 'unmapped') {\n    const eventId = 'recon-' + allocationKey.slice(0, 24);\n    const signalKey = hash('recon:paid-signal:' + inv.invoice_key + ':' + eventId);\n    if (!staticData.recon_seen_signals[signalKey]) {\n      staticData.recon_seen_signals[signalKey] = now;\n      signals.push({\n        signal_key: signalKey,\n        invoice_key: inv.invoice_key,\n        invoice_payment_event_id: eventId,\n        transaction_key: tx.transaction_key,\n        invoice_key: inv.invoice_key,\n        event_type: 'invoice.paid',\n        paid_at: tx.booking_date || now,\n        payload_json: evidence({ event_type: 'invoice.paid', invoice_key: inv.invoice_key, source_invoice_key: inv.invoice_key, job_id: inv.job_id, invoice_payment_event_id: eventId, payment_event_id: eventId, paid_at: tx.booking_date || now, mapping_status: 'mapped', source: 'Recon_Paid_Signals' }),\n        signal_status: 'pending_invoice_delivery',\n        smoke_tag: tx.smoke_tag,\n        created_at_utc: now,\n        last_execution_id: $execution.id,\n      });\n    }\n  }\n};\nconst mentionedOpenInvoices = (title, currency) => invoices.filter((inv) => isOpenInvoice(inv) && inv.invoice_number && (!currency || collapse(inv.currency || 'PLN') === currency) && hasTokenSubsequence(title, inv.invoice_number));\nconst mentionedClosedInvoices = (title) => invoices.filter((inv) => inv.invoice_number && !isOpenInvoice(inv) && hasTokenSubsequence(title, inv.invoice_number));\nconst subsetSums = (arr, target, maxSize = 3) => {\n  const out = [];\n  const walk = (start, chosen, sum) => {\n    if (chosen.length > 0 && amountsEqual(sum, target)) out.push([...chosen]);\n    if (chosen.length >= maxSize || sum >= target + amountTolerance) return;\n    for (let i = start; i < arr.length; i++) walk(i + 1, [...chosen, arr[i]], money(sum + (remainingOpen.get(arr[i].invoice_key) || 0)));\n  };\n  walk(0, [], 0);\n  return out;\n};\nfor (const raw of Array.isArray(root.bank_rows) ? root.bank_rows : []) {\n  const amount = Number(raw.amount);\n  const currency = collapse(raw.currency || 'PLN').toUpperCase();\n  const rawHash = hash('recon:raw-row:' + JSON.stringify(raw));\n  const exactKey = exactFingerprint(raw);\n  const naturalKey = naturalFingerprint({ ...raw, amount, currency });\n  const txKey = exactKey || naturalKey;\n  const tx = {\n    transaction_key: txKey,\n    import_run_key: collapse(root.import_run_key || ('recon-' + $execution.id)),\n    source_bank: collapse(raw.source_bank || ''),\n    source_account_ref: collapse(raw.source_account_ref || ''),\n    source_file_id: collapse(raw.source_file_id || ''),\n    source_row_number: Number(raw.source_row_number || 0),\n    booking_date: collapse(raw.booking_date || ''),\n    amount: Number.isFinite(amount) ? money(amount) : 0,\n    currency,\n    payer_name: collapse(raw.payer_name || ''),\n    payer_iban_hash: raw.payer_iban ? hash('iban:' + collapse(raw.payer_iban)) : '',\n    title: collapse(raw.title || ''),\n    raw_row_hash: rawHash,\n    match_status: 'held_for_review',\n    held_reason: '',\n    evidence_json: '',\n    smoke_tag: collapse(root.smoke_tag || ''),\n    created_at_utc: now,\n    last_execution_id: $execution.id,\n  };\n  const facts = { scenario_id: raw.scenario_id || '', source_file_id: tx.source_file_id, source_row_number: tx.source_row_number, amount: tx.amount, currency, title: tx.title, payer_name: tx.payer_name, exact_transaction_key: exactKey, natural_fingerprint: naturalKey };\n  if (!tx.booking_date || !Number.isFinite(amount) || amount <= 0 || !currency) {\n    tx.match_status = 'malformed_held';\n    tx.held_reason = 'malformed_csv_row';\n    tx.evidence_json = evidence({ ...facts, failure: 'required bank row fields missing or invalid' });\n    transactions.push(tx);\n    addReview(tx, tx.held_reason, 'Malformed bank CSV row held before matching.', [], facts);\n    continue;\n  }\n  const duplicateKey = txKey;\n  const durableDuplicate = existingTransactionKeys.has(duplicateKey);\n  const staticDuplicate = Boolean(staticData.recon_seen_transactions[duplicateKey]);\n  const batchExactDuplicate = Boolean(exactKey && seenExactInBatch.has(exactKey));\n  if (durableDuplicate || staticDuplicate || batchExactDuplicate) {\n    tx.match_status = 'duplicate_suppressed';\n    tx.held_reason = 'duplicate_statement_import';\n    tx.evidence_json = evidence({ ...facts, duplicate_key: duplicateKey, duplicate_layer: durableDuplicate ? 'durable_existing_transactions' : 'static_or_batch', duplicate_identity: exactKey ? 'exact_bank_transaction_id' : 'natural_transaction_key' });\n    transactions.push(tx);\n    continue;\n  }\n  const naturalCollision = Boolean(!exactKey && (seenNaturalInBatch.has(naturalKey) || staticData.recon_seen_natural[naturalKey]));\n  if (naturalCollision) {\n    const previous = seenNaturalInBatch.get(naturalKey) || { source: 'existing_or_static' };\n    tx.match_status = 'held_for_review';\n    tx.held_reason = 'possible_cross_bank_duplicate';\n    tx.evidence_json = evidence({ ...facts, previous, identity_rule: 'booking_date_amount_currency_counterparty_without_title' });\n    transactions.push(tx);\n    addReview(tx, tx.held_reason, 'Possible cross-bank duplicate held; title is evidence only and no invoice is marked paid.', [], { ...facts, previous });\n    staticData.recon_seen_transactions[tx.transaction_key] = now;\n    continue;\n  }\n  if (exactKey) seenExactInBatch.add(exactKey);\n  seenNaturalInBatch.set(naturalKey, { scenario_id: raw.scenario_id || '', source_bank: tx.source_bank, source_file_id: tx.source_file_id, source_row_number: tx.source_row_number, exact_transaction_key: exactKey || '' });\n  staticData.recon_seen_transactions[tx.transaction_key] = now;\n  staticData.recon_seen_natural[naturalKey] = now;\n  if (hasMojibake(raw.payer_name) || hasMojibake(raw.title)) {\n    tx.match_status = 'held_for_review';\n    tx.held_reason = 'encoding_garbage_bank_export';\n    tx.evidence_json = evidence({ ...facts, encoding: 'mojibake markers present' });\n    transactions.push(tx);\n    addReview(tx, tx.held_reason, 'Bank export encoding is damaged; hold for human decoding.', [], facts);\n    continue;\n  }\n  const clientCandidates = collectClientCandidates(raw);\n  if (clientCandidates.length > 1) {\n    tx.match_status = 'held_for_review';\n    tx.held_reason = 'ambiguous_payer_multiple_clients';\n    tx.evidence_json = evidence({ ...facts, client_candidates: clientCandidates });\n    transactions.push(tx);\n    addReview(tx, tx.held_reason, 'Payer identity matches more than one client; no invoice is marked paid.', clientCandidates.flatMap((c) => openForClient(c.client_key)), { ...facts, client_candidates: clientCandidates });\n    continue;\n  }\n  const clientKey = clientCandidates[0]?.client_key || '';\n  const clientInvoices = clientKey ? openForClient(clientKey) : [];\n  const mentioned = mentionedOpenInvoices(raw.title || '', collapse(raw.currency || 'PLN'));\n  const mentionedClosed = mentionedClosedInvoices(raw.title || '');\n  if (!mentioned.length && mentionedClosed.length) {\n    tx.match_status = 'held_for_review';\n    tx.held_reason = 'invoice_number_not_open';\n    tx.evidence_json = evidence({ ...facts, closed_invoice_numbers: mentionedClosed.map((i) => i.invoice_number) });\n    transactions.push(tx);\n    addReview(tx, tx.held_reason, 'Invoice number appears in title but it is not open; no dunning stop signal emitted.', mentionedClosed, facts);\n    continue;\n  }\n  if (!clientKey && mentioned.length === 0) {\n    tx.match_status = 'held_for_review';\n    tx.held_reason = 'unknown_or_invalid_payer_no_invoice_number';\n    tx.evidence_json = evidence({ ...facts, config_warning_count: configWarnings.length });\n    transactions.push(tx);\n    addReview(tx, tx.held_reason, 'Unknown or invalid payer and no usable open invoice number; no dunning stop signal emitted.', [], facts);\n    continue;\n  }\n  if (mentioned.length) {\n    const totalOpen = money(mentioned.reduce((sum, inv) => sum + (remainingOpen.get(inv.invoice_key) || 0), 0));\n    if (tx.amount > totalOpen && !amountsEqual(tx.amount, totalOpen)) {\n      tx.match_status = 'held_for_review';\n      tx.held_reason = 'overpayment_requires_policy';\n      tx.evidence_json = evidence({ ...facts, total_open: totalOpen, mentioned_invoice_numbers: mentioned.map((i) => i.invoice_number) });\n      transactions.push(tx);\n      addReview(tx, tx.held_reason, 'Payment exceeds mentioned open invoice total; hold until overpayment policy is known.', mentioned, facts);\n      continue;\n    }\n    if (tx.amount < totalOpen && !amountsEqual(tx.amount, totalOpen)) {\n      tx.match_status = 'partial_matched_no_paid_signal';\n      tx.held_reason = 'partial_payment_no_paid_signal';\n      tx.evidence_json = evidence({ ...facts, mentioned_invoice_numbers: mentioned.map((i) => i.invoice_number), total_open: totalOpen });\n      transactions.push(tx);\n      if (mentioned.length === 1) allocate(tx, mentioned[0], tx.amount, 'matched_partial_no_paid_signal', 'deterministic_invoice_number_partial', facts);\n      addReview(tx, tx.held_reason, 'Partial payment recorded as evidence but invoice is not marked paid.', mentioned, facts);\n      continue;\n    }\n    if (mentioned.some((inv) => partialTouched.has(inv.invoice_key))) {\n      tx.match_status = 'partial_matched_no_paid_signal';\n      tx.held_reason = 'partial_payment_sequence_no_paid_signal';\n      tx.evidence_json = evidence({ ...facts, mentioned_invoice_numbers: mentioned.map((i) => i.invoice_number), total_open: totalOpen });\n      transactions.push(tx);\n      if (mentioned.length === 1) allocate(tx, mentioned[0], tx.amount, 'matched_partial_no_paid_signal', 'intrabatch_partial_sequence', facts);\n      addReview(tx, tx.held_reason, 'Second same-batch partial would close the invoice only cumulatively; held for human confirmation and no paid signal emitted.', mentioned, facts);\n      continue;\n    }\n    tx.match_status = mentioned.length > 1 ? 'matched_full_multi_invoice' : 'matched_full_single_invoice';\n    tx.held_reason = '';\n    tx.evidence_json = evidence({ ...facts, matched_invoice_numbers: mentioned.map((i) => i.invoice_number), total_open: totalOpen });\n    transactions.push(tx);\n    for (const inv of mentioned) allocate(tx, inv, remainingOpen.get(inv.invoice_key) || inv.open_amount, 'matched_full', mentioned.length > 1 ? 'deterministic_invoice_numbers_total_exact' : 'deterministic_invoice_number_amount_exact', facts);\n    continue;\n  }\n  const sameAmountCandidates = clientInvoices.filter((inv) => inv.currency === currency && amountsEqual(remainingOpen.get(inv.invoice_key) || 0, tx.amount));\n  if (sameAmountCandidates.length > 1) {\n    tx.match_status = 'held_for_review';\n    tx.held_reason = 'ambiguous_same_amount_open_invoices';\n    tx.evidence_json = evidence({ ...facts, candidate_invoice_numbers: sameAmountCandidates.map((c) => c.invoice_number) });\n    transactions.push(tx);\n    addReview(tx, tx.held_reason, 'Same amount fits more than one open invoice; false match risk is higher than no match.', sameAmountCandidates, facts);\n    continue;\n  }\n  if (sameAmountCandidates.length === 1) {\n    const alternatives = subsetSums(clientInvoices.filter((inv) => inv.invoice_key !== sameAmountCandidates[0].invoice_key), tx.amount, 3).filter((set) => set.length >= 2);\n    if (alternatives.length > 0) {\n      tx.match_status = 'held_for_review';\n      tx.held_reason = 'ambiguous_subset_sum';\n      tx.evidence_json = evidence({ ...facts, exact_invoice: sameAmountCandidates[0].invoice_number, alternative_subsets: alternatives.map((set) => set.map((i) => i.invoice_number)) });\n      transactions.push(tx);\n      addReview(tx, tx.held_reason, 'Amount fits one invoice and also another invoice subset; held instead of pick-first.', [sameAmountCandidates[0]].concat(alternatives.flat()), facts);\n      continue;\n    }\n    tx.match_status = 'matched_full_single_invoice';\n    tx.held_reason = '';\n    tx.evidence_json = evidence({ ...facts, matched_invoice_number: sameAmountCandidates[0].invoice_number });\n    transactions.push(tx);\n    allocate(tx, sameAmountCandidates[0], tx.amount, 'matched_full', 'deterministic_alias_amount_unique', facts);\n    continue;\n  }\n  tx.match_status = 'held_for_review';\n  tx.held_reason = 'below_threshold_no_safe_match';\n  tx.evidence_json = evidence(facts);\n  transactions.push(tx);\n  addReview(tx, tx.held_reason, 'Below matching threshold: do nothing irreversible and give evidence to a human.', mentioned.concat(clientInvoices), facts);\n}\nconst needsReview = transactions.filter((t) => t.match_status.includes('held') || t.match_status === 'malformed_held' || t.match_status === 'partial_matched_no_paid_signal');\nconst existingOpenReviews = (Array.isArray(root.existing_review_rows) ? root.existing_review_rows : []).filter((row) => !row.resolved_at_utc);\nconst ageDays = (created) => {\n  const ms = Date.parse(now) - Date.parse(created || now);\n  return Number.isFinite(ms) && ms > 0 ? Math.floor(ms / 86400000) : 0;\n};\nconst oldestAge = Math.max(0, ...reviews.map((r) => ageDays(r.created_at_utc)), ...existingOpenReviews.map((r) => ageDays(r.created_at_utc)));\nconst simulatedWriteFailures = root.simulated_write_failures && typeof root.simulated_write_failures === 'object' ? root.simulated_write_failures : {};\nconst writeFailureCount = Object.values(simulatedWriteFailures).reduce((sum, value) => sum + (Number(value) || 0), 0);\nconst counts = {\n  total_rows: transactions.length,\n  auto_matched_count: transactions.filter((t) => /^matched_full/.test(t.match_status)).length,\n  held_count: needsReview.length,\n  duplicate_count: transactions.filter((t) => t.match_status === 'duplicate_suppressed').length,\n  malformed_count: transactions.filter((t) => t.match_status === 'malformed_held').length,\n  partial_count: transactions.filter((t) => t.match_status === 'partial_matched_no_paid_signal').length,\n  paid_signal_count: signals.length,\n  needs_review_count: needsReview.length,\n  review_queue_size: reviews.length + existingOpenReviews.length,\n  oldest_unresolved_review_age_days: oldestAge,\n  incomplete_ledger_flag: root.ledger_complete === false ? 'true' : 'false',\n  write_failure_count: writeFailureCount,\n  config_warning_count: configWarnings.length,\n};\nconst summaryKey = hash('recon:summary:' + (root.import_run_key || $execution.id) + ':' + $execution.id);\nconst rowsHtml = transactions.map((t) => '<li><strong>' + esc(t.match_status) + '</strong> ' + esc(t.source_bank) + ' row ' + esc(t.source_row_number) + ' amount ' + esc(t.amount) + ' title \"' + esc(t.title) + '\"' + (t.held_reason ? ' reason ' + esc(t.held_reason) : '') + '</li>').join('');\nconst operatorSubject = '[TEST] Bank reconciliation: ' + counts.auto_matched_count + ' matched, ' + counts.needs_review_count + ' need review';\nconst operatorBody = '<p>Draft-only reconciliation summary for the reconciliation operator.</p><p>False match policy: below threshold does nothing irreversible and creates review evidence.</p><p>Review queue size: ' + esc(counts.review_queue_size) + '; oldest unresolved age days: ' + esc(counts.oldest_unresolved_review_age_days) + '; incomplete ledger: ' + esc(counts.incomplete_ledger_flag) + '; write failures: ' + esc(counts.write_failure_count) + '; config warnings: ' + esc(counts.config_warning_count) + '.</p><ul>' + rowsHtml + '</ul>';\nreturn { json: {\n  transaction_rows_json: JSON.stringify(transactions),\n  invoice_rows_json: JSON.stringify(invoiceRows),\n  allocation_rows_json: JSON.stringify(allocations),\n  review_rows_json: JSON.stringify(reviews),\n  paid_signal_rows_json: JSON.stringify(signals),\n  summary_row_json: JSON.stringify({\n    summary_key: summaryKey,\n    import_run_key: collapse(root.import_run_key || ('recon-' + $execution.id)),\n    batch_source: collapse(root.batch_source || ''),\n    ...counts,\n    operator_subject: operatorSubject,\n    operator_body_html: operatorBody,\n    smoke_tag: collapse(root.smoke_tag || ''),\n    created_at_utc: now,\n    last_execution_id: $execution.id,\n  }),\n  response_status: 'reconciled_draft_only',\n  quoted_field_values: 'payer_name=\"' + (transactions[0]?.payer_name || '') + '\" title=\"' + (transactions[0]?.title || '') + '\" matched_invoice_key=\"' + (allocations[0]?.invoice_key || '') + '\" held_reason=\"' + (transactions.find((t) => t.held_reason)?.held_reason || '') + '\"',\n} };"
      }
    },
    {
      "id": "8044e26e-d4bc-41e5-b4f1-74ba07801772",
      "name": "Emit Webhook Transaction Rows",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1220,
        -260
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const payload = $input.all()[0]?.json?.transaction_rows_json || '[]';\nconst rows = JSON.parse(payload);\nreturn rows.map((row) => ({ json: row }));"
      }
    },
    {
      "id": "746df442-6c26-4653-bd48-549316936333",
      "name": "Emit Webhook Invoice Rows",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1220,
        -140
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const payload = $input.all()[0]?.json?.invoice_rows_json || '[]';\nconst rows = JSON.parse(payload);\nreturn rows.map((row) => ({ json: row }));"
      }
    },
    {
      "id": "0acd5307-8610-4893-a16a-1c8de6e273ab",
      "name": "Emit Webhook Allocation Rows",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1220,
        -20
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const payload = $input.all()[0]?.json?.allocation_rows_json || '[]';\nconst rows = JSON.parse(payload);\nreturn rows.map((row) => ({ json: row }));"
      }
    },
    {
      "id": "3ac54070-f688-44c1-ac4c-2439e9dbdc14",
      "name": "Emit Webhook Review Rows",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1220,
        100
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const payload = $input.all()[0]?.json?.review_rows_json || '[]';\nconst rows = JSON.parse(payload);\nreturn rows.map((row) => ({ json: row }));"
      }
    },
    {
      "id": "cae426ed-c860-4a44-9b08-995235b0caa3",
      "name": "Emit Webhook Signal Rows",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1220,
        220
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const payload = $input.all()[0]?.json?.paid_signal_rows_json || '[]';\nconst rows = JSON.parse(payload);\nreturn rows.map((row) => ({ json: row }));"
      }
    },
    {
      "id": "dcb501fa-b785-45ab-86ec-ab1a4f0dcdf6",
      "name": "Emit Webhook Summary Row",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1220,
        340
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const payload = $input.item.json.summary_row_json || '{}';\nreturn { json: JSON.parse(payload) };"
      }
    },
    {
      "id": "89a7a6f3-964e-4d86-a99c-cf05ebea7b6c",
      "name": "Emit Runtime Transaction Rows",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        760,
        260
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const payload = $input.all()[0]?.json?.transaction_rows_json || '[]';\nconst rows = JSON.parse(payload);\nreturn rows.map((row) => ({ json: row }));"
      }
    },
    {
      "id": "db08fee8-3f51-4c6f-86fb-3c9735d01820",
      "name": "Emit Runtime Invoice Rows",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        760,
        380
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const payload = $input.all()[0]?.json?.invoice_rows_json || '[]';\nconst rows = JSON.parse(payload);\nreturn rows.map((row) => ({ json: row }));"
      }
    },
    {
      "id": "fd89ea6f-1d81-4791-aec6-ba43b08171b8",
      "name": "Emit Runtime Allocation Rows",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        760,
        500
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const payload = $input.all()[0]?.json?.allocation_rows_json || '[]';\nconst rows = JSON.parse(payload);\nreturn rows.map((row) => ({ json: row }));"
      }
    },
    {
      "id": "e801f846-2b7b-45f8-abcc-fcbaf8355fc3",
      "name": "Emit Runtime Review Rows",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        760,
        620
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const payload = $input.all()[0]?.json?.review_rows_json || '[]';\nconst rows = JSON.parse(payload);\nreturn rows.map((row) => ({ json: row }));"
      }
    },
    {
      "id": "e1e0748a-be14-4d12-a2e0-9335b6a7b192",
      "name": "Emit Runtime Signal Rows",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        760,
        740
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const payload = $input.all()[0]?.json?.paid_signal_rows_json || '[]';\nconst rows = JSON.parse(payload);\nreturn rows.map((row) => ({ json: row }));"
      }
    },
    {
      "id": "a483341b-e8d5-4c38-9096-402fce4ed50d",
      "name": "Emit Runtime Summary Row",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        760,
        860
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const payload = $input.item.json.summary_row_json || '{}';\nreturn { json: JSON.parse(payload) };"
      }
    },
    {
      "id": "5406c8e0-b6c0-4012-b57e-004808c81d91",
      "name": "Insert Webhook Transaction Rows",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1500,
        -260
      ],
      "parameters": {
        "resource": "row",
        "operation": "insert",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Bank_Transactions"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "transaction_key": "={{ $json.transaction_key }}",
            "import_run_key": "={{ $json.import_run_key }}",
            "source_bank": "={{ $json.source_bank }}",
            "source_account_ref": "={{ $json.source_account_ref }}",
            "source_file_id": "={{ $json.source_file_id }}",
            "source_row_number": "={{ $json.source_row_number }}",
            "booking_date": "={{ $json.booking_date }}",
            "amount": "={{ $json.amount }}",
            "currency": "={{ $json.currency }}",
            "payer_name": "={{ $json.payer_name }}",
            "payer_iban_hash": "={{ $json.payer_iban_hash }}",
            "title": "={{ $json.title }}",
            "raw_row_hash": "={{ $json.raw_row_hash }}",
            "match_status": "={{ $json.match_status }}",
            "held_reason": "={{ $json.held_reason }}",
            "evidence_json": "={{ $json.evidence_json }}",
            "smoke_tag": "={{ $json.smoke_tag }}",
            "created_at_utc": "={{ $json.created_at_utc }}",
            "last_execution_id": "={{ $json.last_execution_id }}"
          },
          "schema": [
            {
              "id": "transaction_key",
              "displayName": "transaction_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "import_run_key",
              "displayName": "import_run_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "source_bank",
              "displayName": "source_bank",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "source_account_ref",
              "displayName": "source_account_ref",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "source_file_id",
              "displayName": "source_file_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "source_row_number",
              "displayName": "source_row_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "booking_date",
              "displayName": "booking_date",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "amount",
              "displayName": "amount",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "currency",
              "displayName": "currency",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "payer_name",
              "displayName": "payer_name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "payer_iban_hash",
              "displayName": "payer_iban_hash",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "title",
              "displayName": "title",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "raw_row_hash",
              "displayName": "raw_row_hash",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "match_status",
              "displayName": "match_status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "held_reason",
              "displayName": "held_reason",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "evidence_json",
              "displayName": "evidence_json",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "smoke_tag",
              "displayName": "smoke_tag",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "created_at_utc",
              "displayName": "created_at_utc",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "last_execution_id",
              "displayName": "last_execution_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            }
          ]
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "id": "1b4141c2-99a8-4d8b-9fb0-9fa958f4798d",
      "name": "Insert Webhook Invoice Rows",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1500,
        -140
      ],
      "parameters": {
        "resource": "row",
        "operation": "insert",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Invoices"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "invoice_key": "={{ $json.invoice_key }}",
            "job_id": "={{ $json.job_id }}",
            "client_key": "={{ $json.client_key }}",
            "client_name": "={{ $json.client_name }}",
            "invoice_number": "={{ $json.invoice_number }}",
            "gross_amount": "={{ $json.gross_amount }}",
            "open_amount": "={{ $json.open_amount }}",
            "currency": "={{ $json.currency }}",
            "status": "={{ $json.status }}",
            "due_date": "={{ $json.due_date }}",
            "paid_signal_status": "={{ $json.paid_signal_status }}",
            "smoke_tag": "={{ $json.smoke_tag }}",
            "created_at_utc": "={{ $json.created_at_utc }}",
            "last_execution_id": "={{ $json.last_execution_id }}"
          },
          "schema": [
            {
              "id": "invoice_key",
              "displayName": "invoice_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "invoice_key",
              "displayName": "invoice_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "job_id",
              "displayName": "job_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "client_key",
              "displayName": "client_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "client_name",
              "displayName": "client_name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "invoice_number",
              "displayName": "invoice_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "gross_amount",
              "displayName": "gross_amount",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "open_amount",
              "displayName": "open_amount",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "currency",
              "displayName": "currency",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "status",
              "displayName": "status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "due_date",
              "displayName": "due_date",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "paid_signal_status",
              "displayName": "paid_signal_status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "smoke_tag",
              "displayName": "smoke_tag",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "created_at_utc",
              "displayName": "created_at_utc",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "last_execution_id",
              "displayName": "last_execution_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            }
          ]
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "id": "665b67e8-c438-4af4-9601-4348b3e9d020",
      "name": "Insert Webhook Allocation Rows",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1500,
        -20
      ],
      "parameters": {
        "resource": "row",
        "operation": "insert",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Allocations"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "allocation_key": "={{ $json.allocation_key }}",
            "transaction_key": "={{ $json.transaction_key }}",
            "invoice_key": "={{ $json.invoice_key }}",
            "allocated_amount": "={{ $json.allocated_amount }}",
            "allocation_status": "={{ $json.allocation_status }}",
            "confidence_label": "={{ $json.confidence_label }}",
            "evidence_json": "={{ $json.evidence_json }}",
            "smoke_tag": "={{ $json.smoke_tag }}",
            "created_at_utc": "={{ $json.created_at_utc }}",
            "last_execution_id": "={{ $json.last_execution_id }}"
          },
          "schema": [
            {
              "id": "allocation_key",
              "displayName": "allocation_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "transaction_key",
              "displayName": "transaction_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "invoice_key",
              "displayName": "invoice_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "invoice_key",
              "displayName": "invoice_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "allocated_amount",
              "displayName": "allocated_amount",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "allocation_status",
              "displayName": "allocation_status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "confidence_label",
              "displayName": "confidence_label",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "evidence_json",
              "displayName": "evidence_json",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "smoke_tag",
              "displayName": "smoke_tag",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "created_at_utc",
              "displayName": "created_at_utc",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "last_execution_id",
              "displayName": "last_execution_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            }
          ]
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "id": "d22da317-4e93-41e5-9aec-5eb5bde7573e",
      "name": "Insert Webhook Review Rows",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1500,
        100
      ],
      "parameters": {
        "resource": "row",
        "operation": "insert",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Review_Queue"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "review_key": "={{ $json.review_key }}",
            "transaction_key": "={{ $json.transaction_key }}",
            "queue_reason": "={{ $json.queue_reason }}",
            "human_summary": "={{ $json.human_summary }}",
            "candidate_invoice_keys": "={{ $json.candidate_invoice_keys }}",
            "candidate_invoice_numbers": "={{ $json.candidate_invoice_numbers }}",
            "candidate_invoice_amounts": "={{ $json.candidate_invoice_amounts }}",
            "candidate_invoice_due_dates": "={{ $json.candidate_invoice_due_dates }}",
            "candidate_invoice_details_json": "={{ $json.candidate_invoice_details_json }}",
            "evidence_json": "={{ $json.evidence_json }}",
            "smoke_tag": "={{ $json.smoke_tag }}",
            "created_at_utc": "={{ $json.created_at_utc }}",
            "last_execution_id": "={{ $json.last_execution_id }}"
          },
          "schema": [
            {
              "id": "review_key",
              "displayName": "review_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "transaction_key",
              "displayName": "transaction_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "queue_reason",
              "displayName": "queue_reason",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "human_summary",
              "displayName": "human_summary",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "candidate_invoice_keys",
              "displayName": "candidate_invoice_keys",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "candidate_invoice_numbers",
              "displayName": "candidate_invoice_numbers",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "candidate_invoice_amounts",
              "displayName": "candidate_invoice_amounts",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "candidate_invoice_due_dates",
              "displayName": "candidate_invoice_due_dates",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "candidate_invoice_details_json",
              "displayName": "candidate_invoice_details_json",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "evidence_json",
              "displayName": "evidence_json",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "smoke_tag",
              "displayName": "smoke_tag",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "created_at_utc",
              "displayName": "created_at_utc",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "last_execution_id",
              "displayName": "last_execution_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            }
          ]
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "id": "8f6ab4db-c4a3-4cb0-bc73-9f3912bbcdcd",
      "name": "Insert Webhook Paid Signal Rows",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1500,
        220
      ],
      "parameters": {
        "resource": "row",
        "operation": "insert",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Paid_Signals"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "signal_key": "={{ $json.signal_key }}",
            "invoice_key": "={{ $json.invoice_key }}",
            "invoice_payment_event_id": "={{ $json.invoice_payment_event_id }}",
            "transaction_key": "={{ $json.transaction_key }}",
            "event_type": "={{ $json.event_type }}",
            "paid_at": "={{ $json.paid_at }}",
            "payload_json": "={{ $json.payload_json }}",
            "signal_status": "={{ $json.signal_status }}",
            "smoke_tag": "={{ $json.smoke_tag }}",
            "created_at_utc": "={{ $json.created_at_utc }}",
            "last_execution_id": "={{ $json.last_execution_id }}"
          },
          "schema": [
            {
              "id": "signal_key",
              "displayName": "signal_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "invoice_key",
              "displayName": "invoice_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "invoice_payment_event_id",
              "displayName": "invoice_payment_event_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "transaction_key",
              "displayName": "transaction_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "invoice_key",
              "displayName": "invoice_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "event_type",
              "displayName": "event_type",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "paid_at",
              "displayName": "paid_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "payload_json",
              "displayName": "payload_json",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "signal_status",
              "displayName": "signal_status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "smoke_tag",
              "displayName": "smoke_tag",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "created_at_utc",
              "displayName": "created_at_utc",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "last_execution_id",
              "displayName": "last_execution_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            }
          ]
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "id": "a6096816-6fc3-4fc9-ab7a-3d9baf6d4a49",
      "name": "Insert Webhook Summary Row",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1500,
        340
      ],
      "parameters": {
        "resource": "row",
        "operation": "insert",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Run_Summaries"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "summary_key": "={{ $json.summary_key }}",
            "import_run_key": "={{ $json.import_run_key }}",
            "batch_source": "={{ $json.batch_source }}",
            "total_rows": "={{ $json.total_rows }}",
            "auto_matched_count": "={{ $json.auto_matched_count }}",
            "held_count": "={{ $json.held_count }}",
            "duplicate_count": "={{ $json.duplicate_count }}",
            "malformed_count": "={{ $json.malformed_count }}",
            "partial_count": "={{ $json.partial_count }}",
            "paid_signal_count": "={{ $json.paid_signal_count }}",
            "needs_review_count": "={{ $json.needs_review_count }}",
            "review_queue_size": "={{ $json.review_queue_size }}",
            "oldest_unresolved_review_age_days": "={{ $json.oldest_unresolved_review_age_days }}",
            "incomplete_ledger_flag": "={{ $json.incomplete_ledger_flag }}",
            "write_failure_count": "={{ $json.write_failure_count }}",
            "config_warning_count": "={{ $json.config_warning_count }}",
            "operator_subject": "={{ $json.operator_subject }}",
            "operator_body_html": "={{ $json.operator_body_html }}",
            "smoke_tag": "={{ $json.smoke_tag }}",
            "created_at_utc": "={{ $json.created_at_utc }}",
            "last_execution_id": "={{ $json.last_execution_id }}"
          },
          "schema": [
            {
              "id": "summary_key",
              "displayName": "summary_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "import_run_key",
              "displayName": "import_run_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "batch_source",
              "displayName": "batch_source",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "total_rows",
              "displayName": "total_rows",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "auto_matched_count",
              "displayName": "auto_matched_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "held_count",
              "displayName": "held_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "duplicate_count",
              "displayName": "duplicate_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "malformed_count",
              "displayName": "malformed_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "partial_count",
              "displayName": "partial_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "paid_signal_count",
              "displayName": "paid_signal_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "needs_review_count",
              "displayName": "needs_review_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "review_queue_size",
              "displayName": "review_queue_size",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "oldest_unresolved_review_age_days",
              "displayName": "oldest_unresolved_review_age_days",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "incomplete_ledger_flag",
              "displayName": "incomplete_ledger_flag",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "write_failure_count",
              "displayName": "write_failure_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "config_warning_count",
              "displayName": "config_warning_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "operator_subject",
              "displayName": "operator_subject",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "operator_body_html",
              "displayName": "operator_body_html",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "smoke_tag",
              "displayName": "smoke_tag",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "created_at_utc",
              "displayName": "created_at_utc",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "last_execution_id",
              "displayName": "last_execution_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            }
          ]
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "id": "97c9a265-9056-4230-bda6-1ab932e727ca",
      "name": "Insert Runtime Transaction Rows",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1040,
        260
      ],
      "parameters": {
        "resource": "row",
        "operation": "insert",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Bank_Transactions"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "transaction_key": "={{ $json.transaction_key }}",
            "import_run_key": "={{ $json.import_run_key }}",
            "source_bank": "={{ $json.source_bank }}",
            "source_account_ref": "={{ $json.source_account_ref }}",
            "source_file_id": "={{ $json.source_file_id }}",
            "source_row_number": "={{ $json.source_row_number }}",
            "booking_date": "={{ $json.booking_date }}",
            "amount": "={{ $json.amount }}",
            "currency": "={{ $json.currency }}",
            "payer_name": "={{ $json.payer_name }}",
            "payer_iban_hash": "={{ $json.payer_iban_hash }}",
            "title": "={{ $json.title }}",
            "raw_row_hash": "={{ $json.raw_row_hash }}",
            "match_status": "={{ $json.match_status }}",
            "held_reason": "={{ $json.held_reason }}",
            "evidence_json": "={{ $json.evidence_json }}",
            "smoke_tag": "={{ $json.smoke_tag }}",
            "created_at_utc": "={{ $json.created_at_utc }}",
            "last_execution_id": "={{ $json.last_execution_id }}"
          },
          "schema": [
            {
              "id": "transaction_key",
              "displayName": "transaction_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "import_run_key",
              "displayName": "import_run_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "source_bank",
              "displayName": "source_bank",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "source_account_ref",
              "displayName": "source_account_ref",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "source_file_id",
              "displayName": "source_file_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "source_row_number",
              "displayName": "source_row_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "booking_date",
              "displayName": "booking_date",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "amount",
              "displayName": "amount",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "currency",
              "displayName": "currency",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "payer_name",
              "displayName": "payer_name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "payer_iban_hash",
              "displayName": "payer_iban_hash",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "title",
              "displayName": "title",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "raw_row_hash",
              "displayName": "raw_row_hash",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "match_status",
              "displayName": "match_status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "held_reason",
              "displayName": "held_reason",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "evidence_json",
              "displayName": "evidence_json",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "smoke_tag",
              "displayName": "smoke_tag",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "created_at_utc",
              "displayName": "created_at_utc",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "last_execution_id",
              "displayName": "last_execution_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            }
          ]
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "id": "fb572acf-d20b-4cf1-b521-49fff7d7e1ec",
      "name": "Insert Runtime Invoice Rows",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1040,
        380
      ],
      "parameters": {
        "resource": "row",
        "operation": "insert",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Invoices"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "invoice_key": "={{ $json.invoice_key }}",
            "job_id": "={{ $json.job_id }}",
            "client_key": "={{ $json.client_key }}",
            "client_name": "={{ $json.client_name }}",
            "invoice_number": "={{ $json.invoice_number }}",
            "gross_amount": "={{ $json.gross_amount }}",
            "open_amount": "={{ $json.open_amount }}",
            "currency": "={{ $json.currency }}",
            "status": "={{ $json.status }}",
            "due_date": "={{ $json.due_date }}",
            "paid_signal_status": "={{ $json.paid_signal_status }}",
            "smoke_tag": "={{ $json.smoke_tag }}",
            "created_at_utc": "={{ $json.created_at_utc }}",
            "last_execution_id": "={{ $json.last_execution_id }}"
          },
          "schema": [
            {
              "id": "invoice_key",
              "displayName": "invoice_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "invoice_key",
              "displayName": "invoice_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "job_id",
              "displayName": "job_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "client_key",
              "displayName": "client_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "client_name",
              "displayName": "client_name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "invoice_number",
              "displayName": "invoice_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "gross_amount",
              "displayName": "gross_amount",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "open_amount",
              "displayName": "open_amount",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "currency",
              "displayName": "currency",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "status",
              "displayName": "status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "due_date",
              "displayName": "due_date",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "paid_signal_status",
              "displayName": "paid_signal_status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "smoke_tag",
              "displayName": "smoke_tag",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "created_at_utc",
              "displayName": "created_at_utc",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "last_execution_id",
              "displayName": "last_execution_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            }
          ]
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "id": "c3108e33-d8b0-477d-aa61-b113ed8589e8",
      "name": "Insert Runtime Allocation Rows",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1040,
        500
      ],
      "parameters": {
        "resource": "row",
        "operation": "insert",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Allocations"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "allocation_key": "={{ $json.allocation_key }}",
            "transaction_key": "={{ $json.transaction_key }}",
            "invoice_key": "={{ $json.invoice_key }}",
            "allocated_amount": "={{ $json.allocated_amount }}",
            "allocation_status": "={{ $json.allocation_status }}",
            "confidence_label": "={{ $json.confidence_label }}",
            "evidence_json": "={{ $json.evidence_json }}",
            "smoke_tag": "={{ $json.smoke_tag }}",
            "created_at_utc": "={{ $json.created_at_utc }}",
            "last_execution_id": "={{ $json.last_execution_id }}"
          },
          "schema": [
            {
              "id": "allocation_key",
              "displayName": "allocation_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "transaction_key",
              "displayName": "transaction_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "invoice_key",
              "displayName": "invoice_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "invoice_key",
              "displayName": "invoice_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "allocated_amount",
              "displayName": "allocated_amount",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "allocation_status",
              "displayName": "allocation_status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "confidence_label",
              "displayName": "confidence_label",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "evidence_json",
              "displayName": "evidence_json",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "smoke_tag",
              "displayName": "smoke_tag",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "created_at_utc",
              "displayName": "created_at_utc",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "last_execution_id",
              "displayName": "last_execution_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            }
          ]
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "id": "f12bf0c9-a764-459e-965a-8dd20a6d3f07",
      "name": "Insert Runtime Review Rows",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1040,
        620
      ],
      "parameters": {
        "resource": "row",
        "operation": "insert",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Review_Queue"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "review_key": "={{ $json.review_key }}",
            "transaction_key": "={{ $json.transaction_key }}",
            "queue_reason": "={{ $json.queue_reason }}",
            "human_summary": "={{ $json.human_summary }}",
            "candidate_invoice_keys": "={{ $json.candidate_invoice_keys }}",
            "candidate_invoice_numbers": "={{ $json.candidate_invoice_numbers }}",
            "candidate_invoice_amounts": "={{ $json.candidate_invoice_amounts }}",
            "candidate_invoice_due_dates": "={{ $json.candidate_invoice_due_dates }}",
            "candidate_invoice_details_json": "={{ $json.candidate_invoice_details_json }}",
            "evidence_json": "={{ $json.evidence_json }}",
            "smoke_tag": "={{ $json.smoke_tag }}",
            "created_at_utc": "={{ $json.created_at_utc }}",
            "last_execution_id": "={{ $json.last_execution_id }}"
          },
          "schema": [
            {
              "id": "review_key",
              "displayName": "review_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "transaction_key",
              "displayName": "transaction_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "queue_reason",
              "displayName": "queue_reason",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "human_summary",
              "displayName": "human_summary",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "candidate_invoice_keys",
              "displayName": "candidate_invoice_keys",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "candidate_invoice_numbers",
              "displayName": "candidate_invoice_numbers",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "candidate_invoice_amounts",
              "displayName": "candidate_invoice_amounts",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "candidate_invoice_due_dates",
              "displayName": "candidate_invoice_due_dates",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "candidate_invoice_details_json",
              "displayName": "candidate_invoice_details_json",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "evidence_json",
              "displayName": "evidence_json",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "smoke_tag",
              "displayName": "smoke_tag",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "created_at_utc",
              "displayName": "created_at_utc",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "last_execution_id",
              "displayName": "last_execution_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            }
          ]
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "id": "1165ef8e-f9d1-4ef9-afdc-52e53e07beae",
      "name": "Insert Runtime Paid Signal Rows",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1040,
        740
      ],
      "parameters": {
        "resource": "row",
        "operation": "insert",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Paid_Signals"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "signal_key": "={{ $json.signal_key }}",
            "invoice_key": "={{ $json.invoice_key }}",
            "invoice_payment_event_id": "={{ $json.invoice_payment_event_id }}",
            "transaction_key": "={{ $json.transaction_key }}",
            "event_type": "={{ $json.event_type }}",
            "paid_at": "={{ $json.paid_at }}",
            "payload_json": "={{ $json.payload_json }}",
            "signal_status": "={{ $json.signal_status }}",
            "smoke_tag": "={{ $json.smoke_tag }}",
            "created_at_utc": "={{ $json.created_at_utc }}",
            "last_execution_id": "={{ $json.last_execution_id }}"
          },
          "schema": [
            {
              "id": "signal_key",
              "displayName": "signal_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "invoice_key",
              "displayName": "invoice_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "invoice_payment_event_id",
              "displayName": "invoice_payment_event_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "transaction_key",
              "displayName": "transaction_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "invoice_key",
              "displayName": "invoice_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "event_type",
              "displayName": "event_type",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "paid_at",
              "displayName": "paid_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "payload_json",
              "displayName": "payload_json",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "signal_status",
              "displayName": "signal_status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "smoke_tag",
              "displayName": "smoke_tag",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "created_at_utc",
              "displayName": "created_at_utc",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "last_execution_id",
              "displayName": "last_execution_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            }
          ]
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "id": "2ae5fae7-28d6-4c37-82bd-7ae88489cce8",
      "name": "Insert Runtime Summary Row",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1040,
        860
      ],
      "parameters": {
        "resource": "row",
        "operation": "insert",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Run_Summaries"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "summary_key": "={{ $json.summary_key }}",
            "import_run_key": "={{ $json.import_run_key }}",
            "batch_source": "={{ $json.batch_source }}",
            "total_rows": "={{ $json.total_rows }}",
            "auto_matched_count": "={{ $json.auto_matched_count }}",
            "held_count": "={{ $json.held_count }}",
            "duplicate_count": "={{ $json.duplicate_count }}",
            "malformed_count": "={{ $json.malformed_count }}",
            "partial_count": "={{ $json.partial_count }}",
            "paid_signal_count": "={{ $json.paid_signal_count }}",
            "needs_review_count": "={{ $json.needs_review_count }}",
            "review_queue_size": "={{ $json.review_queue_size }}",
            "oldest_unresolved_review_age_days": "={{ $json.oldest_unresolved_review_age_days }}",
            "incomplete_ledger_flag": "={{ $json.incomplete_ledger_flag }}",
            "write_failure_count": "={{ $json.write_failure_count }}",
            "config_warning_count": "={{ $json.config_warning_count }}",
            "operator_subject": "={{ $json.operator_subject }}",
            "operator_body_html": "={{ $json.operator_body_html }}",
            "smoke_tag": "={{ $json.smoke_tag }}",
            "created_at_utc": "={{ $json.created_at_utc }}",
            "last_execution_id": "={{ $json.last_execution_id }}"
          },
          "schema": [
            {
              "id": "summary_key",
              "displayName": "summary_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "import_run_key",
              "displayName": "import_run_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "batch_source",
              "displayName": "batch_source",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "total_rows",
              "displayName": "total_rows",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "auto_matched_count",
              "displayName": "auto_matched_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "held_count",
              "displayName": "held_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "duplicate_count",
              "displayName": "duplicate_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "malformed_count",
              "displayName": "malformed_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "partial_count",
              "displayName": "partial_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "paid_signal_count",
              "displayName": "paid_signal_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "needs_review_count",
              "displayName": "needs_review_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "review_queue_size",
              "displayName": "review_queue_size",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "oldest_unresolved_review_age_days",
              "displayName": "oldest_unresolved_review_age_days",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "incomplete_ledger_flag",
              "displayName": "incomplete_ledger_flag",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "write_failure_count",
              "displayName": "write_failure_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "config_warning_count",
              "displayName": "config_warning_count",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": false
            },
            {
              "id": "operator_subject",
              "displayName": "operator_subject",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "operator_body_html",
              "displayName": "operator_body_html",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "smoke_tag",
              "displayName": "smoke_tag",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "created_at_utc",
              "displayName": "created_at_utc",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            },
            {
              "id": "last_execution_id",
              "displayName": "last_execution_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": false
            }
          ]
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "id": "e98fa4fb-e9de-4a3b-b418-428579dbdf76",
      "name": "Send Controlled Webhook Summary",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        1760,
        340
      ],
      "parameters": {
        "resource": "message",
        "operation": "send",
        "sendTo": "ops@example.com",
        "subject": "={{ $('Emit Webhook Summary Row').item.json.operator_subject }}",
        "emailType": "html",
        "message": "={{ $('Emit Webhook Summary Row').item.json.operator_body_html }}",
        "options": {
          "senderName": "Ops Notifications"
        }
      },
      "retryOnFail": true,
      "maxTries": 2,
      "waitBetweenTries": 1000,
      "onError": "continueRegularOutput"
    },
    {
      "id": "9dc009ac-fad5-44a2-ad22-236690d18c47",
      "name": "Build Webhook Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2020,
        340
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const engine = $('Run Webhook Reconciliation Engine').item.json || {};\nlet summary = {};\ntry { summary = JSON.parse(engine.summary_row_json || '{}'); } catch (err) { summary = {}; }\nreturn { json: {\n  ok: true,\n  status: engine.response_status || 'reconciled_draft_only',\n  import_run_key: summary.import_run_key || '',\n  auto_matched_count: summary.auto_matched_count || 0,\n  held_count: summary.held_count || 0,\n  paid_signal_count: summary.paid_signal_count || 0,\n} };"
      }
    },
    {
      "id": "c2104673-742d-4a1b-90b8-628fe325e866",
      "name": "Respond Import Complete",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        2260,
        340
      ],
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $json }}",
        "options": {
          "responseCode": 202
        }
      }
    },
    {
      "id": "ae5845f3-ab99-4444-a456-1ca8a10f0bdc",
      "name": "Send Controlled Runtime Summary",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        1300,
        860
      ],
      "parameters": {
        "resource": "message",
        "operation": "send",
        "sendTo": "ops@example.com",
        "subject": "={{ $('Emit Runtime Summary Row').item.json.operator_subject }}",
        "emailType": "html",
        "message": "={{ $('Emit Runtime Summary Row').item.json.operator_body_html }}",
        "options": {
          "senderName": "Ops Notifications"
        }
      },
      "retryOnFail": true,
      "maxTries": 2,
      "waitBetweenTries": 1000,
      "onError": "continueRegularOutput"
    },
    {
      "id": "2ee98f4b-e9dd-451b-98e4-c8977243feb7",
      "name": "Get Webhook Existing Transactions",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        740,
        -260
      ],
      "parameters": {
        "resource": "row",
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Bank_Transactions"
        },
        "returnAll": true
      },
      "onError": "continueRegularOutput",
      "alwaysOutputData": true,
      "executeOnce": true
    },
    {
      "id": "ae323ff3-0767-4037-894a-aacb0c8eb4a0",
      "name": "Merge Webhook Existing Transactions",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        980,
        -260
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const base = $('Build Webhook Statement Contract').item.json || {};\nconst bodyRows = Array.isArray(base.existing_transactions) ? base.existing_transactions : [];\nconst tableRows = $input.all().map((item) => item.json || {}).filter((row) => row.transaction_key);\nreturn { json: { ...base, existing_transactions: bodyRows.concat(tableRows) } };"
      }
    },
    {
      "id": "5b8a5d5f-86d6-4331-9f74-6f2b85325b20",
      "name": "Get Webhook Existing Reviews",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1220,
        -260
      ],
      "parameters": {
        "resource": "row",
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Review_Queue"
        },
        "returnAll": true
      },
      "onError": "continueRegularOutput",
      "alwaysOutputData": true,
      "executeOnce": true
    },
    {
      "id": "8be23b48-db07-4b9b-9ae5-741a9e31187a",
      "name": "Merge Webhook Existing Reviews",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1460,
        -260
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const base = $('Merge Webhook Existing Transactions').item.json || {};\nconst bodyRows = Array.isArray(base.existing_review_rows) ? base.existing_review_rows : [];\nconst tableRows = $input.all().map((item) => item.json || {}).filter((row) => row.review_key);\nreturn { json: { ...base, existing_review_rows: bodyRows.concat(tableRows) } };"
      }
    },
    {
      "id": "83eb39cb-ea2e-47c5-a75c-f3bad811d3c2",
      "name": "Get Runtime Existing Transactions",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        240,
        300
      ],
      "parameters": {
        "resource": "row",
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Bank_Transactions"
        },
        "returnAll": true
      },
      "onError": "continueRegularOutput",
      "alwaysOutputData": true,
      "executeOnce": true
    },
    {
      "id": "5b5ad29e-a09f-4124-a9a1-a38985512767",
      "name": "Merge Runtime Existing Transactions",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        480,
        300
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const base = $('Build Runtime Bank Fixture').item.json || {};\nconst bodyRows = Array.isArray(base.existing_transactions) ? base.existing_transactions : [];\nconst allTableRows = $input.all().map((item) => item.json || {}).filter((row) => row.transaction_key);\nconst tableRows = String(base.smoke_tag || '') === 'RECON-RUNTIME-SMOKE' ? allTableRows.filter((row) => row.smoke_tag !== 'RECON-RUNTIME-SMOKE') : allTableRows;\nreturn { json: { ...base, existing_transactions: bodyRows.concat(tableRows) } };"
      }
    },
    {
      "id": "6012430c-edd2-44c1-9b21-dc0b77c01723",
      "name": "Get Runtime Existing Reviews",
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        720,
        300
      ],
      "parameters": {
        "resource": "row",
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_TABLE_ID",
          "cachedResultName": "Recon_Review_Queue"
        },
        "returnAll": true
      },
      "onError": "continueRegularOutput",
      "alwaysOutputData": true,
      "executeOnce": true
    },
    {
      "id": "a032b3d0-c33c-4dd4-a1f7-b8e82c9f168d",
      "name": "Merge Runtime Existing Reviews",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        960,
        300
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const base = $('Merge Runtime Existing Transactions').item.json || {};\nconst bodyRows = Array.isArray(base.existing_review_rows) ? base.existing_review_rows : [];\nconst allTableRows = $input.all().map((item) => item.json || {}).filter((row) => row.review_key);\nconst tableRows = String(base.smoke_tag || '') === 'RECON-RUNTIME-SMOKE' ? allTableRows.filter((row) => row.smoke_tag !== 'RECON-RUNTIME-SMOKE') : allTableRows;\nreturn { json: { ...base, existing_review_rows: bodyRows.concat(tableRows) } };"
      }
    }
  ],
  "nodeGroups": [],
  "activeVersion": null,
  "parentFolderId": null,
  "scopes": [
    "execution:reveal",
    "workflow:create",
    "workflow:delete",
    "workflow:disableRedaction",
    "workflow:enableRedaction",
    "workflow:execute",
    "workflow:execute-chat",
    "workflow:export",
    "workflow:import",
    "workflow:list",
    "workflow:move",
    "workflow:publish",
    "workflow:read",
    "workflow:share",
    "workflow:unpublish",
    "workflow:unshare",
    "workflow:update"
  ],
  "canExecute": true
}