{
  "nodes": [
    {
      "parameters": {
        "jsCode": "const data = $input.first().json;\n\nconst systemPrompt = `\u0422\u044b QA-\u0438\u043d\u0436\u0435\u043d\u0435\u0440 \u043a\u043e\u043c\u0430\u043d\u0434\u044b your-company.example.com \u2014 \u043c\u0430\u0440\u043a\u0435\u0442\u043f\u043b\u0435\u0439\u0441 \u0431\u0430\u043d\u043a\u043e\u0432\u0441\u043a\u0438\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432.\n\n\u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0439 \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u044b \u0441\u0442\u0440\u043e\u0433\u043e \u043f\u043e \u041d\u0410\u0428\u0418\u041c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0430\u043c (\u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0438\u0437 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u0422\u041a).\n\n---\n\n## \u0421\u0422\u0410\u041d\u0414\u0410\u0420\u0422 \u041d\u0410\u0417\u0412\u0410\u041d\u0418\u042f\n\n### \u0424\u043e\u0440\u043c\u0430\u0442 \u0434\u043b\u044f API:\n\\`/endpoint - [\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f]\\`\n\n### \u041f\u0440\u0438\u043c\u0435\u0440\u044b \u0438\u0437 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0430:\n\u2705 \"/applicationProcessDeposit - \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0437\u0430\u0432\u0438\u0441\u0448\u0438\u0445 \u0437\u0430\u044f\u0432\u043e\u043a \u043d\u0430 \u0434\u0435\u043f\u043e\u0437\u0438\u0442\"\n\u2705 \"/confirmCourierMeeting - \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u0441\u0442\u0440\u0435\u0447\u0438 \u043f\u0440\u0438 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c userId\"\n\u2705 \"/earlyTermination - \u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0432 \u0442\u0435\u043b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\"\n\u2705 \"/getDeliverySlots - \u0417\u0430\u043f\u0440\u043e\u0441 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0441\u043b\u043e\u0442\u0430\u043c \u043f\u0440\u0438 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c leadId\"\n\u2705 \"/depositAccount - \u0417\u0430\u043f\u0440\u043e\u0441 \u0440\u0435\u043a\u0432\u0438\u0437\u0438\u0442\u043e\u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043f\u043e leadId \u0441 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u043e\u043c\"\n\n### \u0424\u043e\u0440\u043c\u0430\u0442 \u0434\u043b\u044f \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432/Consumer:\n\\`[\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442/\u041f\u0440\u043e\u0446\u0435\u0441\u0441] - [\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0439]\\`\n\n\u2705 \"CONSUMER bankApiGate/application/process/deposit - \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0437\u0430\u0432\u0438\u0441\u0448\u0438\u0445 \u0437\u0430\u044f\u0432\u043e\u043a\"\n\u2705 \"EOD-\u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u0430 - \u0423\u0441\u043f\u0435\u0448\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0441\u0447\u0451\u0442 \u043e\u0441\u0442\u0430\u0442\u043a\u043e\u0432 \u0437\u0430 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u0434\u0435\u043d\u044c\"\n\n### \u0414\u043b\u044f \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0445:\n\\`/endpoint - [\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435] \u043f\u0440\u0438 [\u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u0435]\\`\n\n\u2705 \"/confirmCourierMeeting - \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u0441\u0442\u0440\u0435\u0447\u0438 \u043f\u0440\u0438 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c userId\"\n\u2705 \"/getClientIdByAuthProvider - \u041f\u043e\u0438\u0441\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u043e userId \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u0434\u043b\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439\"\n\n---\n\n## \u0421\u0422\u0410\u041d\u0414\u0410\u0420\u0422 \u041e\u041f\u0418\u0421\u0410\u041d\u0418\u042f\n\n### \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430:\n1. \u041e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u0435 \u0447\u0442\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f (1-2 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f)\n2. \u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e Confluence (\u041e\u0411\u042f\u0417\u0410\u0422\u0415\u041b\u042c\u041d\u041e \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c)\n\n### \u041f\u0440\u0438\u043c\u0435\u0440\u044b \u0438\u0437 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0430:\n\u2705 \"\u0422\u0435\u0441\u0442-\u043a\u0435\u0439\u0441 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043b\u043e\u0433\u043e\u0442\u0438\u043f\u0430 \u0411\u0430\u043d\u043a\u0430 \u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f \u0434\u0435\u043d\u0435\u0436\u043d\u044b\u0445 \u0441\u0440\u0435\u0434\u0441\u0442\u0432.\"\n\n\u2705 \"\u0422\u0435\u0441\u0442-\u043a\u0435\u0439\u0441 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0439 userId \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u0442\u0435\u043b\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.\n\n[\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f /confirmCourierMeeting](https://your-confluence.example.com/pages/viewpage.action?pageId=18944396)\"\n\n\u2705 \"\u0422\u0435\u0441\u0442-\u043a\u0435\u0439\u0441 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0432\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u043f\u0440\u0435\u0434\u043c\u0435\u0442 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432: userId, leadId, bik.\n\n[\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f /earlyTermination](https://your-confluence.example.com/pages/viewpage.action?pageId=18943904)\"\n\n### \u0428\u0430\u0431\u043b\u043e\u043d:\n\"\u0422\u0435\u0441\u0442-\u043a\u0435\u0439\u0441 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c [\u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f].\n\n[\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f [\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435]](CONFLUENCE_URL)\"\n\n---\n\n## \u0421\u0422\u0410\u041d\u0414\u0410\u0420\u0422 \u041f\u0420\u0415\u0414\u0423\u0421\u041b\u041e\u0412\u0418\u042f\n\n### \u0427\u0442\u043e \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c:\n1. \u0421\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0435 \u043a\u0435\u0439\u0441\u044b \u2014 \"[\u0442\u0435\u043a\u0441\u0442](https://your-services.example.comst-cases/XXXXX)\"\n2. \u0414\u0430\u043d\u043d\u044b\u0435 \u0432 \u0411\u0414 \u2014 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u043f\u043e\u043b\u044f, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\n3. \u0421\u0442\u0430\u0442\u0443\u0441\u044b \u2014 \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u0437\u0430\u044f\u0432\u043a\u0438, \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0430\n4. \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u2014 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0435 \u0442\u043e\u0433\u043b\u044b, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\n5. \u041d\u0443\u043c\u0435\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u2014 \u043a\u0430\u0436\u0434\u043e\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u0441 \u0446\u0438\u0444\u0440\u043e\u0439\n\n### \u041f\u0440\u0438\u043c\u0435\u0440\u044b \u0438\u0437 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0430:\n\n\u2705 \"1. \u0412\u043a\u043b\u044e\u0447\u0435\u043d \u0442\u043e\u0433\u0433\u043b [IDENTITY_PARTNER_CODE_ALWAYS_FD_ENABLED](https://your-services.example.comsole/index);\n2. \u0421\u043e\u0437\u0434\u0430\u043d\u0430 \u0434\u0435\u043f\u043e\u0437\u0438\u0442\u043d\u0430\u044f \u0437\u0430\u044f\u0432\u043a\u0430 \u0432 \u043b\u044e\u0431\u043e\u0439 \u0431\u0430\u043d\u043a;\n3. \u0414\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 midb.core_client_data \u0437\u0430\u0434\u0430\u0442\u044c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043f\u043e\u043b\u044f user_id.\"\n\n\u2705 \"1. \u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d \u043a\u0435\u0439\u0441 \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0438 \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0430, \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0437\u0430\u044f\u0432\u043a\u0430 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441\u0435 OFFER_SELECTED.\n2. \u0417\u0430\u044f\u0432\u043a\u0430 \u043d\u0435 \u0441\u0442\u0430\u0440\u0448\u0435 45 \u0434\u043d\u0435\u0439 \u0438 \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u044f\u0432\u043a\u043e\u0439 \u043d\u0430 \u043f\u0440\u043e\u043b\u043e\u043d\u0433\u0430\u0446\u0438\u044e.\n3. \u041a\u043b\u0438\u0435\u043d\u0442 \u0438\u043c\u0435\u0435\u0442 \u0441\u0442\u0430\u0442\u0443\u0441: recordStatus=ACTIVE, identificationsStatus=FULL_IDENT.\"\n\n\u2705 \u0414\u043b\u044f \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0445: null \u2014 \u0435\u0441\u043b\u0438 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438.\n\n---\n\n## \u0421\u0422\u0410\u041d\u0414\u0410\u0420\u0422 \u0428\u0410\u0413\u041e\u0412\n\n### \u0424\u043e\u0440\u043c\u0430\u0442 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0448\u0430\u0433\u0430:\n\"[\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435] \u2192 [\u041e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442]\"\n\n### \u041f\u0440\u0438\u043c\u0435\u0440\u044b:\n\"\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c POST /depositAccount \u0441 leadId \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0430 \u2192 \u041a\u043e\u0434 \u043e\u0442\u0432\u0435\u0442\u0430 200, \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u0440\u0435\u043a\u0432\u0438\u0437\u0438\u0442\u044b\"\n\"\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c POST /confirmCourierMeeting \u0441 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c userId \u2192 \u041a\u043e\u0434 \u043e\u0448\u0438\u0431\u043a\u0438 400, \u0442\u0435\u043a\u0441\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 USER_NOT_FOUND\"\n\"\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 portfolio_fee_EOD \u0434\u043b\u044f \u0414\u043e\u0433\u043e\u0432\u043e\u0440\u0430 \u0410 \u2192 \u0417\u0430\u043f\u0438\u0441\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0430, balance=800\"\n\n---\n\n## \u041f\u0420\u0410\u0412\u0418\u041b\u0410 \u0413\u0415\u041d\u0415\u0420\u0410\u0426\u0418\u0418\n\n### \u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e: 8-12 \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432\n\n### \u0422\u0438\u043f\u044b (\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e):\n1. **Happy path** (2-3 \u043a\u0435\u0439\u0441\u0430) \u2014 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438\n2. **Negative** (3-4 \u043a\u0435\u0439\u0441\u0430) \u2014 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 ID, \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u044b, \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432\n3. **Validation** (2-3 \u043a\u0435\u0439\u0441\u0430) \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439, \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432, \u0433\u0440\u0430\u043d\u0438\u0447\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439\n4. **Edge cases** (1-2 \u043a\u0435\u0439\u0441\u0430) \u2014 \u0433\u0440\u0430\u043d\u0438\u0447\u043d\u044b\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f, \u0434\u0443\u0431\u043b\u0438, \u0433\u043e\u043d\u043a\u0438\n\n### \u0412\u0441\u0435\u0433\u0434\u0430:\n- \u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 Confluence \u0432 description \u041a\u0410\u0416\u0414\u041e\u0413\u041e \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u0430 (\u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f)\n- \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 (\u043d\u0435 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0435)\n- \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0438\u043c\u0435\u043d\u0430 \u0442\u0430\u0431\u043b\u0438\u0446 \u0411\u0414, \u0441\u0442\u0430\u0442\u0443\u0441\u044b, \u043a\u043e\u0434\u044b \u043e\u0448\u0438\u0431\u043e\u043a \u0438\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438\n- Steps: \u043c\u0438\u043d\u0438\u043c\u0443\u043c 3, \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e 5-7, \u0447\u0435\u0440\u0435\u0437 \"\u2192\"\n\n---\n\n## PRODUCTION \u041f\u0420\u0418\u041c\u0415\u0420\u042b\n\n### \u041f\u0440\u0438\u043c\u0435\u0440 1: API Happy Path\n{\n  \"name\": \"/depositAccount - \u0417\u0430\u043f\u0440\u043e\u0441 \u0440\u0435\u043a\u0432\u0438\u0437\u0438\u0442\u043e\u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043f\u043e leadId \u0441 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u043e\u043c\",\n  \"description\": \"\u0422\u0435\u0441\u0442-\u043a\u0435\u0439\u0441 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u043c\u0435\u0442\u043e\u0434\u0430 \u043f\u0440\u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0440\u0435\u043a\u0432\u0438\u0437\u0438\u0442\u043e\u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0430.\\n\\n[\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f /depositAccount](https://your-confluence.example.com/pages/viewpage.action?pageId=18944483)\",\n  \"preconditions\": \"\u0421\u043e\u0437\u0434\u0430\u043d\u0430 \u0434\u0435\u043f\u043e\u0437\u0438\u0442\u043d\u0430\u044f \u0437\u0430\u044f\u0432\u043a\u0430 \u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d \u0434\u043e\u0433\u043e\u0432\u043e\u0440, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043b\u044f \u0431\u0430\u043d\u043a\u0430 \u0421\u0438\u043d\u0430\u0440\u0430.\",\n  \"steps\": [\n    \"\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c POST /depositAccount \u0441 leadId \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0430 \u2192 \u041a\u043e\u0434 \u043e\u0442\u0432\u0435\u0442\u0430 200\",\n    \"\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043f\u043e\u043b\u0435\u0439 accountNumber, bik, bankName \u0432 \u0442\u0435\u043b\u0435 \u043e\u0442\u0432\u0435\u0442\u0430 \u2192 \u0412\u0441\u0435 \u043f\u043e\u043b\u044f \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u0438 \u043d\u0435 \u043f\u0443\u0441\u0442\u044b\u0435\",\n    \"\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 midb.deposit_account \u2192 \u0417\u0430\u043f\u0438\u0441\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043e\u0442\u0432\u0435\u0442\u0443 API\"\n  ],\n  \"expectedResult\": \"\u041c\u0435\u0442\u043e\u0434 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u0440\u0435\u043a\u0432\u0438\u0437\u0438\u0442\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c 200\"\n}\n\n### \u041f\u0440\u0438\u043c\u0435\u0440 2: Negative\n{\n  \"name\": \"/confirmCourierMeeting - \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u0441\u0442\u0440\u0435\u0447\u0438 \u043f\u0440\u0438 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c userId\",\n  \"description\": \"\u0422\u0435\u0441\u0442-\u043a\u0435\u0439\u0441 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0439 userId \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.\\n\\n[\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f /confirmCourierMeeting](https://your-confluence.example.com/pages/viewpage.action?pageId=18944396)\",\n  \"preconditions\": null,\n  \"steps\": [\n    \"\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c POST /confirmCourierMeeting \u0441 userId=999999999 (\u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439) \u2192 \u041a\u043e\u0434 \u043e\u0442\u0432\u0435\u0442\u0430 400 \u0438\u043b\u0438 404\",\n    \"\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u2192 \u0421\u043e\u0434\u0435\u0440\u0436\u0438\u0442 errorCode=USER_NOT_FOUND \u0438\u043b\u0438 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438\",\n    \"\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0447\u0442\u043e \u0437\u0430\u043f\u0438\u0441\u044c \u043e \u0432\u0441\u0442\u0440\u0435\u0447\u0435 \u041d\u0415 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 midb.courier_meeting \u2192 \u0417\u0430\u043f\u0438\u0441\u0438 \u043d\u0435\u0442\"\n  ],\n  \"expectedResult\": \"\u041c\u0435\u0442\u043e\u0434 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443 \u0441 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c, \u0432\u0441\u0442\u0440\u0435\u0447\u0430 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f\"\n}\n\n### \u041f\u0440\u0438\u043c\u0435\u0440 3: Validation\n{\n  \"name\": \"/earlyTermination - \u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0432 \u0442\u0435\u043b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\",\n  \"description\": \"\u0422\u0435\u0441\u0442-\u043a\u0435\u0439\u0441 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0432\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430: \u043f\u043e\u043b\u044f userId, leadId, bik \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b.\\n\\n[\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f /earlyTermination](https://your-confluence.example.com/pages/viewpage.action?pageId=18943904)\",\n  \"preconditions\": null,\n  \"steps\": [\n    \"\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c POST /earlyTermination \u0431\u0435\u0437 \u043f\u043e\u043b\u044f userId \u2192 \u041a\u043e\u0434 \u043e\u0442\u0432\u0435\u0442\u0430 400, \u043e\u0448\u0438\u0431\u043a\u0430 VALIDATION_ERROR\",\n    \"\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c POST /earlyTermination \u0431\u0435\u0437 \u043f\u043e\u043b\u044f leadId \u2192 \u041a\u043e\u0434 \u043e\u0442\u0432\u0435\u0442\u0430 400, \u043e\u0448\u0438\u0431\u043a\u0430 VALIDATION_ERROR\",\n    \"\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c POST /earlyTermination \u0431\u0435\u0437 bik \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 accountNumber \u2192 \u041a\u043e\u0434 \u043e\u0442\u0432\u0435\u0442\u0430 400\",\n    \"\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c POST /earlyTermination \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438 \u2192 \u041a\u043e\u0434 \u043e\u0442\u0432\u0435\u0442\u0430 200\"\n  ],\n  \"expectedResult\": \"\u041f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043c\u0435\u0442\u043e\u0434 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 400. \u041f\u0440\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u2014 200\"\n}\n\n---\n\n\u0412\u042b\u0425\u041e\u0414\u041d\u041e\u0419 \u0424\u041e\u0420\u041c\u0410\u0422 \u2014 \u0422\u041e\u041b\u042c\u041a\u041e \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 JSON \u0431\u0435\u0437 markdown:\n{\n  \"testCases\": [\n    {\n      \"name\": \"...\",\n      \"description\": \"...\",\n      \"preconditions\": \"...\" | null,\n      \"steps\": [\"action \u2192 expected\", \"...\"],\n      \"expectedResult\": \"...\"\n    }\n  ]\n}\n\n\u0412\u0410\u0416\u041d\u041e:\n- \u0420\u041e\u0412\u041d\u041e \u044d\u0442\u043e\u0442 \u0444\u043e\u0440\u043c\u0430\u0442, \u0431\u0435\u0437 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439\n- description \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \\\\n \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u043e\u0432 \u0441\u0442\u0440\u043e\u043a\n- preconditions \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c null\n- steps \u2014 \u043c\u0430\u0441\u0441\u0438\u0432 \u0441\u0442\u0440\u043e\u043a, \u043a\u0430\u0436\u0434\u044b\u0439 \u0448\u0430\u0433 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \"\u2192\" \u0434\u043b\u044f \u043e\u0442\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e\u0433\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\n- \u041d\u0415 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0439 markdown-\u043e\u0431\u0451\u0440\u0442\u043a\u0438 \\`\\`\\`json\n- \u0412\u0421\u0415\u0413\u0414\u0410 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0439 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 Confluence \u0432 description \u0435\u0441\u043b\u0438 \u043e\u043d\u0430 \u0435\u0441\u0442\u044c \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435`;\n\nconst userPrompt = `\u0420\u041e\u0414\u0418\u0422\u0415\u041b\u042c\u0421\u041a\u0410\u042f \u0417\u0410\u0414\u0410\u0427\u0410: ${data.parentKey} - ${data.parentSummary}\n\n\u041e\u041f\u0418\u0421\u0410\u041d\u0418\u0415 \u0417\u0410\u0414\u0410\u0427\u0418:\n${data.parentDescription || '(\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442)'}\n\n${data.confluenceUrl ? `\u0414\u041e\u041a\u0423\u041c\u0415\u041d\u0422\u0410\u0426\u0418\u042f (Confluence):\n${data.allConfluenceUrls || data.confluenceUrl}\n` : ''}${data.confluenceContent ? `\\n\ud83d\udcc4 \u0421\u041e\u0414\u0415\u0420\u0416\u0418\u041c\u041e\u0415 \u0414\u041e\u041a\u0423\u041c\u0415\u041d\u0422\u0410\u0426\u0418\u0418:\\n${data.confluenceContent}\\n\\n---\\n\\n\u26a0\ufe0f \u041e\u0411\u042f\u0417\u0410\u0422\u0415\u041b\u042c\u041d\u041e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439 \u044d\u0442\u0443 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e! \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0439 \u0441\u0441\u044b\u043b\u043a\u0443 ${data.confluenceUrl} \u0432 description \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0422\u041a.\\n\u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0439 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 endpoints, \u043a\u043e\u0434\u044b \u043e\u0448\u0438\u0431\u043e\u043a, \u0441\u0442\u0430\u0442\u0443\u0441\u044b, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u0435\u0439 \u0438\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0432\u044b\u0448\u0435.\\n` : `\\n\u26a0\ufe0f \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f Confluence \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430 \u2014 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0439 \u0422\u041a \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438.\\n`}\n\u041f\u041e\u0414\u0417\u0410\u0414\u0410\u0427\u0410 QA: ${data.subtaskKey} - ${data.subtaskSummary}\n\n\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0439 8-12 \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432:\n- 2-3 happy path\n- 3-4 negative (\u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 ID, \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432, \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u044b)\n- 2-3 validation (\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u0435\u0439, \u0444\u043e\u0440\u043c\u0430\u0442\u044b, \u0433\u0440\u0430\u043d\u0438\u0446\u044b)\n- 1-2 edge cases\n\n\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439 \u041d\u0410\u0428\u0418 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u044b \u0438\u0437 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u0432\u044b\u0448\u0435!`;\n\nconst claudeBody = JSON.stringify({\n  model: \"anthropic/claude-sonnet-4-6\",\n  max_tokens: 16000,\n  messages: [\n    { role: \"system\", content: systemPrompt },\n    { role: \"user\", content: userPrompt }\n  ]\n});\n\nreturn [{\n  json: {\n    ...data,\n    systemPrompt,\n    userPrompt,\n    claudeBody,\n  }\n}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "id": "78e61c7a-a791-4319-87fd-3f87452491c1",
      "name": "Build Prompt V2",
      "position": [
        -6672,
        640
      ]
    },
    {
      "parameters": {
        "jsCode": "const input = $input.first().json;\nconst loopData = $('Build Prompt V2').first().json;\n\ntry {\n  let responseText = '';\n  if (input.content?.[0]?.text) {\n    responseText = input.content[0].text;\n  } else if (input.choices?.[0]?.message?.content) {\n    responseText = input.choices[0].message.content;\n  } else {\n    throw new Error('Unknown Claude response format: ' + JSON.stringify(Object.keys(input)));\n  }\n\n  if (input.stop_reason === 'max_tokens') {\n    throw new Error(\n      `Claude hit max_tokens (${input.usage?.output_tokens} tokens). ` +\n      `Response truncated. Increase max_tokens in \"Build Prompt V2\".`\n    );\n  }\n\n  responseText = responseText\n    .replace(/^```(?:json)?\\s*/i, '')\n    .replace(/```\\s*$/i, '')\n    .trim();\n\n  const jsonMatch = responseText.match(/\\{[\\s\\S]*\\}/);\n  if (!jsonMatch) {\n    throw new Error('No JSON object found in response. Preview: ' + responseText.substring(0, 200));\n  }\n\n  const parsed = JSON.parse(jsonMatch[0]);\n\n  if (!Array.isArray(parsed.testCases)) {\n    throw new Error('Invalid structure: \"testCases\" must be an array');\n  }\n\n  if (parsed.testCases.length === 0) {\n    throw new Error('Claude returned empty testCases array');\n  }\n\n  return [{\n    json: {\n      testCases: parsed.testCases,\n      metadata: parsed.metadata || {\n        parentKey: loopData.parentKey,\n        subtaskKey: loopData.subtaskKey\n      },\n      parentKey: loopData.parentKey,\n      subtaskKey: loopData.subtaskKey,\n      existingLabels: loopData.existingLabels,\n      confluenceUrl: loopData.confluenceUrl || '',\n      parseSuccess: true\n    }\n  }];\n\n} catch (error) {\n  const errorMsg = error instanceof Error ? error.message : String(error);\n  console.log(`ERR Parse error for ${loopData.subtaskKey}: ${errorMsg}`);\n  return [{\n    json: {\n      parseSuccess: false,\n      error: errorMsg,\n      subtaskKey: loopData.subtaskKey,\n      existingLabels: loopData.existingLabels,\n      confluenceUrl: loopData.confluenceUrl || ''\n    }\n  }];\n}"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "id": "4ca50440-962c-4923-8231-da1111a3be23",
      "name": "Parse Test Cases V3",
      "position": [
        -6352,
        640
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 1
          },
          "conditions": [
            {
              "id": "parse-success",
              "leftValue": "={{ $json.parseSuccess }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "cb18cbed-bfec-4545-b8e6-84dd01919adf",
      "name": "Parse OK?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        -6192,
        640
      ]
    },
    {
      "parameters": {
        "operation": "toText",
        "sourceProperty": "csv",
        "options": {
          "fileName": "={{ $json.subtaskKey }}_testcases.csv"
        }
      },
      "type": "n8n-nodes-base.convertToFile",
      "typeVersion": 1.1,
      "id": "2d7d0e02-7487-45b7-9959-c44b50fdc370",
      "name": "Convert CSV to File",
      "position": [
        -5728,
        1232
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://your-allure.example.com/api/importrequest?projectId=61&type=test_case_csv",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Api-Token YOUR_ALLURE_API_TOKEN"
            }
          ]
        },
        "sendBody": true,
        "contentType": "multipart-form-data",
        "bodyParameters": {
          "parameters": [
            {
              "parameterType": "formBinaryData",
              "name": "file",
              "inputDataFieldName": "data"
            }
          ]
        },
        "options": {}
      },
      "id": "ce46c7c5-30e0-4325-bf8d-efdf8488a9d5",
      "name": "Upload CSV to Allure",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -5552,
        1232
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000,
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://your-allure.example.com/api/testcase/import/csv/{{ $json.importId }}/submit",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Api-Token YOUR_ALLURE_API_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "={{ $json.submitBody }}",
        "options": {}
      },
      "id": "17dccd14-b1ea-40db-b996-1fd60d8e5684",
      "name": "Submit CSV Import",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -5008,
        1232
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000,
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "jsCode": "return [{\n  json: {\n    status: 'no_tasks',\n    message: '\u041d\u0435\u0442 QA-\u043f\u043e\u0434\u0437\u0430\u0434\u0430\u0447 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441\u0435 In Progress \u0431\u0435\u0437 \u043c\u0435\u0442\u043a\u0438 tc-generated',\n    timestamp: new Date().toISOString()\n  }\n}];"
      },
      "id": "ff3241f9-b749-453a-b18a-6afdcd466c49",
      "name": "No Tasks Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -8832,
        1712
      ]
    },
    {
      "parameters": {
        "url": "=https://your-confluence.example.com/rest/api/content/{{ $json.confluenceLinks[0].pageId }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "expand",
              "value": "body.storage"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -8784,
        928
      ],
      "id": "62e588f9-9ea1-44d8-a967-8e1620f1df32",
      "name": "Get Confluence Content",
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const loopItem = $('Loop Issues1').item.json;\nconst extractData = $('Extract Confluence Links1').first().json;\n\nlet confluenceContent = '';\n\ntry {\n  const directInput = $input.first().json;\n  if (directInput?.content?.[0]?.text) {\n    confluenceContent = directInput.content[0].text;\n    console.log('Using direct input (Mock or Call Claude Summary)');\n  }\n} catch (e) {}\n\nif (!confluenceContent) {\n  try {\n    const summaryResp = $('Call Claude Summary')?.first()?.json;\n    if (summaryResp?.content?.[0]?.text) {\n      confluenceContent = summaryResp.content[0].text;\n      console.log('Using Call Claude Summary');\n    }\n  } catch (e) {}\n}\n\nif (!confluenceContent) {\n  try {\n    const processed = $('Summarize Confluence (Code)')?.first()?.json;\n    if (processed?.cleanText) {\n      confluenceContent = processed.cleanText.substring(0, 10000);\n      if (processed.sectionHints) {\n        confluenceContent += '\\n\\n--- \u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b ---\\n' + processed.sectionHints;\n      }\n      if (processed.otherPagesNote) {\n        confluenceContent += processed.otherPagesNote;\n      }\n      console.log('Using cleanText from Summarize Confluence');\n    } else if (processed?.prioritySections) {\n      confluenceContent = processed.prioritySections;\n      console.log('Using prioritySections fallback');\n    }\n  } catch (e) {}\n}\n\nif (!confluenceContent) {\n  try {\n    const confData = $('Get Confluence Content')?.first()?.json;\n    if (confData?.body?.storage?.value) {\n      confluenceContent = confData.body.storage.value\n        .replace(/<[^>]+>/g, ' ')\n        .replace(/\\s+/g, ' ')\n        .trim()\n        .substring(0, 8000);\n      console.log('Using raw content (fallback)');\n    }\n  } catch (e) {}\n}\n\nconst confluenceLinks = extractData.confluenceLinks || [];\nconst confluenceUrl = confluenceLinks.length > 0 && confluenceLinks[0].pageId\n  ? `https://your-confluence.example.com/pages/viewpage.action?pageId=${confluenceLinks[0].pageId}`\n  : '';\nconst allConfluenceUrls = extractData.allConfluenceUrls || confluenceUrl;\n\nreturn [{\n  json: {\n    subtaskKey: loopItem.subtaskKey,\n    subtaskSummary: loopItem.subtaskSummary,\n    parentKey: loopItem.parentKey,\n    parentSummary: extractData.fields?.summary || '',\n    parentDescription: extractData.fields?.description || '\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442',\n    confluenceContent: confluenceContent,\n    confluenceUrl: confluenceUrl,\n    allConfluenceUrls: allConfluenceUrls,\n    existingLabels: loopItem.existingLabels\n  }\n}];"
      },
      "id": "9df1cad4-cb0f-49c1-b6ce-13e8d43434dd",
      "name": "Prepare Context",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -7568,
        832
      ]
    },
    {
      "parameters": {
        "jsCode": "const confData = $input.first().json;\nconst extractData = $('Extract Confluence Links1').first().json;\nconst rawHtml = confData?.body?.storage?.value || '';\n\nconst text = rawHtml\n  .replace(/<(script|style)[^>]*>[\\s\\S]*?<\\/\\1>/gi, '')\n  .replace(/<[^>]+>/g, ' ')\n  .replace(/&nbsp;/g, ' ')\n  .replace(/&amp;/g, '&')\n  .replace(/&lt;/g, '<')\n  .replace(/&gt;/g, '>')\n  .replace(/&quot;/g, '\"')\n  .replace(/&#\\d+;/g, '')\n  .replace(/\\s+/g, ' ')\n  .trim();\n\nconst SECTIONS = [\n  { name: 'API', regex: /(?:POST|GET|PUT|DELETE|PATCH)\\s+\\/[^\\s]+/gi, limit: 20 },\n  { name: '\u041e\u0448\u0438\u0431\u043a\u0438', regex: /(?:\u043e\u0448\u0438\u0431\u043a|error|ERR\\.\\d+)[^.]*\\./gi, limit: 15 },\n  { name: '\u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438', regex: /(?:\u0432\u0430\u043b\u0438\u0434\u0430\u0446|\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d|\u043c\u0438\u043d\u0438\u043c\u0430\u043b|\u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b|\u0444\u043e\u0440\u043c\u0430\u0442)[^.]*\\./gi, limit: 10 },\n  { name: '\u041f\u0440\u0430\u0432\u0438\u043b\u0430', regex: /(?:\u0435\u0441\u043b\u0438|\u043a\u043e\u0433\u0434\u0430|\u043f\u0440\u0438 \u0443\u0441\u043b\u043e\u0432\u0438\u0438|\u0434\u043e\u043b\u0436\u0435\u043d|\u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d)[^.]*\\./gi, limit: 15 }\n];\n\nconst sectionHints = SECTIONS\n  .map(({ name, regex, limit }) => {\n    const matches = [...text.matchAll(regex)].slice(0, limit);\n    return matches.length > 0 ? `${name}: ${matches.map(m => m[0]).join(' | ')}` : '';\n  })\n  .filter(Boolean)\n  .join('\\n\\n');\n\nconst allLinks = extractData.confluenceLinks || [];\nconst allConfluenceUrls = extractData.allConfluenceUrls || '';\nconst otherPagesNote = allLinks.length > 1\n  ? `\\n\\n\u26a0\ufe0f \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 (\u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u043d\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439 URL \u0432 description):\\n${allLinks.slice(1).map(l => '- ' + l.url).join('\\n')}`\n  : '';\n\nconst needsSummary = text.length > 12000 ? 'true' : 'false';\n\nconsole.log(`Doc: ${text.length} chars, pages: ${allLinks.length}, needsSummary: ${needsSummary}`);\n\nreturn [{\n  json: {\n    ...confData,\n    cleanText: text,\n    sectionHints,\n    prioritySections: sectionHints,\n    needsSummary,\n    textLength: text.length,\n    allConfluenceUrls,\n    otherPagesNote,\n    confluenceCount: allLinks.length,\n    hasApiEndpoints: (text.match(/(?:POST|GET|PUT|DELETE|PATCH)\\s+\\//gi) || []).length\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -8608,
        928
      ],
      "id": "c5dc6682-1488-4558-83cb-fc9f70929817",
      "name": "Summarize Confluence (Code)"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 3
          },
          "conditions": [
            {
              "id": "ddec0c57-9d51-4040-ab3a-da8e0b18308f",
              "leftValue": "={{ $json.needsSummary }}",
              "rightValue": "true",
              "operator": {
                "type": "string",
                "operation": "equals",
                "name": "filter.operator.equals"
              }
            }
          ],
          "combinator": "and"
        },
        "looseTypeValidation": true,
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -8432,
        928
      ],
      "id": "bea35b9c-75d5-488b-bb62-2b111988da34",
      "name": "If Need Summary?"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://your-litellm.example.com/v1/chat/completions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_LITELLM_API_KEY"
            }
          ]
        },
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "={{ $json.claudeBody }}",
        "options": {
          "timeout": 60000
        }
      },
      "id": "b0e39327-6d75-4857-892b-80700555b937",
      "name": "Call Claude Summary",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -7792,
        976
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconst text = data.cleanText || '';\nconst hints = data.sectionHints || data.prioritySections || '';\nconst otherPagesNote = data.otherPagesNote || '';\n\nif (!text) {\n  console.log('No cleanText \u2014 skipping summary');\n  return [{ json: { skipSummary: true, directContent: '' } }];\n}\n\nif (text.length <= 12000) {\n  console.log(`Text ${text.length} chars \u2014 passing full text directly`);\n  const directContent = text + (hints ? `\\n\\n---\\n\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b:\\n${hints}` : '') + otherPagesNote;\n  return [{ json: { skipSummary: true, directContent } }];\n}\n\nconsole.log(`Text ${text.length} chars \u2014 compressing via Claude`);\n\nconst summaryPrompt = `\u0422\u044b Senior QA Engineer. \u0421\u043e\u0436\u043c\u0438 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432.\n\n\u0414\u041e\u041a\u0423\u041c\u0415\u041d\u0422 (${text.length} \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432):\n${text.substring(0, 50000)}\n\n${hints ? `\u0423\u0416\u0415 \u0412\u042b\u0414\u0415\u041b\u0415\u041d\u041d\u042b\u0415 \u041a\u041b\u042e\u0427\u0415\u0412\u042b\u0415 \u041c\u041e\u041c\u0415\u041d\u0422\u042b:\\n${hints}\\n\\n` : ''}\n\u0421\u041e\u0425\u0420\u0410\u041d\u0418 \u041e\u0411\u042f\u0417\u0410\u0422\u0415\u041b\u042c\u041d\u041e:\n1. \u0412\u0441\u0435 API endpoints (\u043c\u0435\u0442\u043e\u0434, URL, \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0444\u043e\u0440\u043c\u0430\u0442\u044b \u043e\u0442\u0432\u0435\u0442\u043e\u0432)\n2. \u0412\u0441\u0435 \u043a\u043e\u0434\u044b \u043e\u0448\u0438\u0431\u043e\u043a \u0441 \u0442\u0435\u043a\u0441\u0442\u0430\u043c\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 (ERR.XXXX, BUSINESS_ERROR \u0438 \u0442.\u0434.)\n3. \u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u0435\u0439: \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u0444\u043e\u0440\u043c\u0430\u0442\u044b (YYYY-MM-DD etc), \u043c\u0438\u043d/\u043c\u0430\u043a\u0441 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\n4. \u0411\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0430\u0432\u0438\u043b\u0430: \u0441\u0442\u0430\u0442\u0443\u0441\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b, \u0443\u0441\u043b\u043e\u0432\u0438\u044f, \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b\n5. Retry-\u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0438 \u0438 \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u044b\n6. \u041c\u0430\u043f\u043f\u0438\u043d\u0433\u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432 \u0438 \u043f\u043e\u043b\u0435\u0439\n7. \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446 \u0411\u0414 \u0438 \u043f\u043e\u043b\u0435\u0439\n8. \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u0435\u0439 \u0438 \u0442\u043e\u043f\u0438\u043a\u043e\u0432\n\n\u0423\u0411\u0415\u0420\u0418: \u0432\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f, \u0438\u0441\u0442\u043e\u0440\u0438\u044e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439, \u043e\u0440\u0433\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u043f\u043e\u0432\u0442\u043e\u0440\u0435\u043d\u0438\u044f.\n\n\u0412\u0435\u0440\u043d\u0438 \u0422\u041e\u041b\u042c\u041a\u041e \u0441\u0436\u0430\u0442\u0443\u044e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u043c \u0432\u0438\u0434\u0435 (\u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c 6000 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432).${otherPagesNote}`;\n\nreturn [{\n  json: {\n    skipSummary: false,\n    claudeBody: JSON.stringify({\n      model: \"anthropic/claude-sonnet-4-6\",\n      max_tokens: 5000,\n      messages: [{ role: \"user\", content: summaryPrompt }]\n    }),\n    originalData: data\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -8208,
        720
      ],
      "id": "bfb917a0-2680-4dd6-aea8-d91e17db5212",
      "name": "Build Summary Prompt"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 8
            }
          ]
        }
      },
      "id": "78e5574a-ae07-49d2-8907-c1e635e6e10c",
      "name": "Schedule Trigger1",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        -9520,
        1344
      ]
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\n\nif (items.length === 0) {\n  return [{ json: { status: 'no_tasks' } }];\n}\n\nreturn items.map(({ json: issue }) => ({\n  json: {\n    subtaskKey: issue.key,\n    subtaskSummary: issue.fields?.summary || '',\n    parentKey: issue.fields?.parent?.key || '',\n    existingLabels: issue.fields?.labels || []\n  }\n}));"
      },
      "id": "586ec41c-9522-4097-9ab3-f24970a5c568",
      "name": "Split Issues1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -9184,
        1344
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 1
          },
          "conditions": [
            {
              "id": "check-no-tasks",
              "leftValue": "={{ $json.status }}",
              "rightValue": "no_tasks",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "fc86d203-e664-4c77-8dcd-ed7f75337225",
      "name": "Has Tasks?1",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        -9024,
        1344
      ]
    },
    {
      "parameters": {
        "jiraVersion": "serverPat",
        "operation": "get",
        "issueKey": "={{ $('Loop Issues1').item.json.parentKey }}",
        "additionalFields": {}
      },
      "id": "f050e89c-b369-46bd-8646-30c4bc942c69",
      "name": "Get Parent Issue2",
      "type": "n8n-nodes-base.jira",
      "typeVersion": 1,
      "position": [
        -9440,
        1072
      ],
      "retryOnFail": true,
      "maxTries": 2,
      "waitBetweenTries": 3000,
      "credentials": {
        "jiraSoftwareServerPatApi": {
          "name": "<your credential>"
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "const parent = $input.first().json;\nconst description = parent.fields?.description || '';\n\nconst pageIdRegex = /your-confluence\\.example\\.com\\/(?:.*?pageId=(\\d+)|.*?\\/(?:pages|content)\\/(\\d+))/gi;\nconst links = [];\nconst seenIds = new Set();\n\nlet match;\nwhile ((match = pageIdRegex.exec(description)) !== null) {\n  const pageId = match[1] || match[2];\n  if (pageId && !seenIds.has(pageId)) {\n    seenIds.add(pageId);\n    links.push({\n      pageId,\n      url: `https://your-confluence.example.com/pages/viewpage.action?pageId=${pageId}`\n    });\n  }\n}\n\nconst displayLinks = [];\nconst displayRe = /https?:\\/\\/your-confluence\\.example\\.com\\/display\\/[^\\s\\|\\]\\[\\\"\\']+/gi;\nlet dm;\nwhile ((dm = displayRe.exec(description)) !== null) {\n  const url = dm[0].replace(/[.,;:!?)]+$/, '');\n  displayLinks.push(url);\n}\n\nconst allConfluenceUrls = [\n  ...links.map(l => l.url),\n  ...displayLinks\n].join('\\n');\n\nreturn [{\n  json: {\n    ...parent,\n    confluenceLinks: links,\n    confluenceDisplayLinks: displayLinks,\n    allConfluenceUrls,\n    hasConfluence: links.length > 0,\n    confluenceCount: links.length\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -9280,
        1072
      ],
      "id": "da676097-504a-423a-950c-b4ac0c52a414",
      "name": "Extract Confluence Links1"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "has-confluence",
              "leftValue": "={{ $json.hasConfluence }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -9120,
        1072
      ],
      "id": "f1ed2f57-c74c-43df-9d27-3a099f90a331",
      "name": "Has Confluence?1"
    },
    {
      "parameters": {
        "jsCode": "const ctx = $input.first().json;\n\nconst labels = Array.isArray(ctx.existingLabels)\n\t? ctx.existingLabels.filter(Boolean)\n\t: [];\n\nif (!ctx || (!ctx.subtaskKey && !ctx.parentKey)) {\n\treturn [{ json: { ...ctx, action: 'skip', reason: 'no_context' } }];\n}\n\nconst tasks = [];\n\nconst needTC = labels.includes('need-tc');\nconst hasTCGenerated = labels.includes('tc-generated');\n\nif (needTC && !hasTCGenerated) {\n\ttasks.push({ ...ctx, action: 'tc' });\n}\n\nconst needChecklist = labels.includes('need-checklist');\nconst hasChecklistGenerated = labels.includes('checklist-generated');\n\nif (needChecklist && !hasChecklistGenerated) {\n\ttasks.push({ ...ctx, action: 'checklist' });\n}\n\nif (tasks.length === 0) {\n\treturn [{ json: { ...ctx, action: 'skip' } }];\n}\n\nreturn tasks.map(t => ({ json: t }));"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -7056,
        720
      ],
      "id": "f04ea5e6-2854-422b-8127-b80faf29863b",
      "name": "Check What To Generate"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "tc",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "id": "7d872622-6a54-49fd-9453-0fd6a98f61c5"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "TC"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "15fbec28-5b66-4e65-8d03-7ef90b301883",
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "checklist",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Checklist"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "21ec4b7f-56f9-45b0-8a30-fa53b79d2eb7",
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "skip",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Skip"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        -6912,
        704
      ],
      "id": "8f18e954-b281-45e5-a824-a7af318d6761",
      "name": "Route by Action"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://your-litellm.example.com/v1/chat/completions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_LITELLM_API_KEY"
            }
          ]
        },
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "={{ $json.claudeBody }}",
        "options": {
          "timeout": 120000
        }
      },
      "id": "dbc68078-52ad-440d-a0b4-dbdf73b5f437",
      "name": "Call Claude1",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -6512,
        640
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "const ctx = $input.first().json;\n\nconst systemPrompt = `\u0422\u044b \u043e\u043f\u044b\u0442\u043d\u044b\u0439 QA-\u0438\u043d\u0436\u0435\u043d\u0435\u0440 \u0434\u043b\u044f \u0444\u0438\u043d\u0442\u0435\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430 \u2014 \u043c\u0430\u0440\u043a\u0435\u0442\u043f\u043b\u0435\u0439\u0441 \u0431\u0430\u043d\u043a\u043e\u0432\u0441\u043a\u0438\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432 (\u043a\u0440\u0435\u0434\u0438\u0442\u044b, \u0434\u0435\u043f\u043e\u0437\u0438\u0442\u044b, \u0438\u043f\u043e\u0442\u0435\u043a\u0430, \u0441\u0442\u0440\u0430\u0445\u043e\u0432\u0430\u043d\u0438\u0435).\n\n\u0421\u043e\u0441\u0442\u0430\u0432\u044c \u041a\u041e\u041d\u041a\u0420\u0415\u0422\u041d\u042b\u0419 QA-\u0447\u0435\u043a\u043b\u0438\u0441\u0442 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 \u0418 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438.\n\n## \u0418\u0421\u0422\u041e\u0427\u041d\u0418\u041a\u0418 \u0418\u041d\u0424\u041e\u0420\u041c\u0410\u0426\u0418\u0418:\n1. **\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438** \u2014 \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c\n2. **\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0438\u0437 Confluence** \u2014 \u0434\u0435\u0442\u0430\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, API \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u044b, \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0430\u0432\u0438\u043b\u0430\n\n## \u041f\u0420\u0410\u0412\u0418\u041b\u0410 \u0421\u041e\u0421\u0422\u0410\u0412\u041b\u0415\u041d\u0418\u042f:\n\n### \u041a\u0430\u0436\u0434\u044b\u0439 \u043f\u0443\u043d\u043a\u0442 \u0447\u0435\u043a\u043b\u0438\u0441\u0442\u0430 \u0414\u041e\u041b\u0416\u0415\u041d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c:\n- \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0438\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443\n- \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043f\u043e\u043b\u044f, \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0438\u0437 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f/\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438\n- \u041e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\n\n### \u041f\u041b\u041e\u0425\u041e (\u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e):\n* \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432\n* \u042d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0439 \u043e\u0442\u0432\u0435\u0442\n\n### \u0425\u041e\u0420\u041e\u0428\u041e (\u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e):\n* POST /api/v1/deposits \u0441 amount=0 \u2192 \u043e\u0448\u0438\u0431\u043a\u0430 400 \"\u0421\u0443\u043c\u043c\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 0\"\n* \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0434\u0435\u043f\u043e\u0437\u0438\u0442 \u0441 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0443\u043c\u043c\u043e\u0439 10000\u20bd \u2192 \u0434\u0435\u043f\u043e\u0437\u0438\u0442 \u0441\u043e\u0437\u0434\u0430\u043d, \u0441\u0442\u0430\u0442\u0443\u0441 ACTIVE\n\n### \u0427\u0422\u041e \u0418\u0421\u041a\u0410\u0422\u042c \u0412 \u0414\u041e\u041a\u0423\u041c\u0415\u041d\u0422\u0410\u0426\u0418\u0418:\n- API endpoints (method, URL, \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u043e\u0442\u0432\u0435\u0442\u044b)\n- \u0411\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f\n- \u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u0435\u0439 (\u043c\u0438\u043d/\u043c\u0430\u043a\u0441 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u0444\u043e\u0440\u043c\u0430\u0442\u044b)\n- \u041a\u043e\u0434\u044b \u043e\u0448\u0438\u0431\u043e\u043a \u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\n- \u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438\n- \u041f\u0440\u0438\u043c\u0435\u0440\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432/\u043e\u0442\u0432\u0435\u0442\u043e\u0432\n\n### \u0424\u041e\u0420\u041c\u0410\u0422 \u041e\u0422\u0412\u0415\u0422\u0410 (Jira wiki markup):\n\nh2. \ud83e\uddea QA \u0427\u0435\u043a\u043b\u0438\u0441\u0442: [\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 \u0438\u0437 \u0437\u0430\u0434\u0430\u0447\u0438]\n\nh3. \u2705 \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 (Happy Path)\n* [\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438] \u2192 [\u041e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442]\n\nh3. \u274c \u041d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438\n* [\u041d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435] \u2192 [\u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u0438\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438]\n\nh3. \ud83d\udd22 \u0413\u0440\u0430\u043d\u0438\u0447\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\n* [\u041f\u043e\u043b\u0435] = [\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438] \u2192 [\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442]\n\nh3. \ud83d\udd0c API \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438\n* [METHOD] [endpoint \u0438\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438] \u0441 [\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b] \u2192 [\u0441\u0442\u0430\u0442\u0443\u0441], [\u043e\u0442\u0432\u0435\u0442]\n\nh3. \ud83d\udd10 \u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c/\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f (\u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c)\n* [\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0440\u0430\u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430]\n\nh3. \ud83d\udd04 \u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 (\u0435\u0441\u043b\u0438 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044b)\n* [\u0421\u0435\u0440\u0432\u0438\u0441] \u2014 [\u0447\u0442\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c]\n\n### \u041f\u0420\u0410\u0412\u0418\u041b\u0410:\n- \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0439 \u0412\u0421\u0415 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438\n- \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u044b API \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0435 endpoints\n- \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u044c \u043a\u0430\u0436\u0434\u043e\u0435\n- 10-25 \u043f\u0443\u043d\u043a\u0442\u043e\u0432\n- \u0413\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u0439 \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438`;\n\nlet userMessage = `# \u0417\u0410\u0414\u0410\u0427\u0410\n${ctx.parentKey} - ${ctx.parentSummary}\n\n## \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435:\n${ctx.parentDescription}`;\n\nif (ctx.confluenceContent && ctx.confluenceContent.trim()) {\n  userMessage += `\\n\\n---\\n# \ud83d\udcc4 \u0414\u041e\u041a\u0423\u041c\u0415\u041d\u0422\u0410\u0426\u0418\u042f \u0418\u0417 CONFLUENCE:\\n\\n${ctx.confluenceContent}\\n\\n---`;\n} else {\n  userMessage += `\\n\\n(\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0438\u0437 Confluence \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430 \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438)`;\n}\n\nuserMessage += `\\n\\n# \u041f\u041e\u0414\u0417\u0410\u0414\u0410\u0427\u0410\\n${ctx.subtaskKey} - ${ctx.subtaskSummary}\\n\\n\u0421\u043e\u0441\u0442\u0430\u0432\u044c \u041a\u041e\u041d\u041a\u0420\u0415\u0422\u041d\u042b\u0419 QA-\u0447\u0435\u043a\u043b\u0438\u0441\u0442. \u0418\u0437\u0432\u043b\u0435\u043a\u0438 \u0432\u0441\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, endpoints, \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0438\u0437 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0438 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438.`;\n\nconst claudeBody = JSON.stringify({\n  model: \"anthropic/claude-sonnet-4-6\",\n  max_tokens: 4000,\n  messages: [\n    { role: \"system\", content: systemPrompt },\n    { role: \"user\", content: userMessage }\n  ]\n});\n\nreturn [{ json: { claudeBody, ...ctx } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -6800,
        2368
      ],
      "id": "5080cfed-6e1e-4e23-adf2-22d63dc08e59",
      "name": "Build Checklist Prompt"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://your-litellm.example.com/v1/chat/completions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_LITELLM_API_KEY"
            }
          ]
        },
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "={{ $json.claudeBody }}",
        "options": {
          "timeout": 120000
        }
      },
      "id": "5126c539-b8dc-48b2-8593-fc8060b94df5",
      "name": "Call Claude Checklist",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -6624,
        2368
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jiraVersion": "serverPat",
        "resource": "issueComment",
        "issueKey": "={{ $('Build Checklist Prompt').item.json.subtaskKey }}",
        "comment": "={{ $json.choices?.[0]?.message?.content ?? $json.content?.[0]?.text ?? '\u26a0\ufe0f \u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0442 Claude. \u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u0437\u0430\u0434\u0430\u0447\u0443.' }}",
        "options": {}
      },
      "id": "cebd5614-9ecd-496f-ab61-6eb1471b5b24",
      "name": "Add Jira Comment",
      "type": "n8n-nodes-base.jira",
      "typeVersion": 1,
      "position": [
        -6448,
        2368
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000,
      "credentials": {
        "jiraSoftwareServerPatApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "return [{ json: { done: true } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -5744,
        2368
      ],
      "id": "6bda7252-8418-49e3-9733-9a0526aa9791",
      "name": "Ignore Response"
    },
    {
      "parameters": {
        "jsCode": "const commentResp = $input.first().json;\nconst loopData = $('Loop Issues1').item.json;\n\nconst subtaskKey = String(loopData.subtaskKey || '');\nconst existingLabels = Array.isArray(loopData.existingLabels)\n  ? loopData.existingLabels.map(l => String(l))\n  : [];\n\nif (!subtaskKey) {\n  throw new Error('Missing subtaskKey from Loop Issues');\n}\n\nif (!commentResp?.id) {\n  throw new Error(`Jira comment not created for ${subtaskKey}. Response: ${JSON.stringify(commentResp).substring(0, 200)}`);\n}\n\nreturn [{\n  json: {\n    subtaskKey,\n    existingLabels,\n    checklistAdded: true\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -6272,
        2368
      ],
      "id": "6c2ab056-86ac-405c-b8c0-61b3a001a6b0",
      "name": "Clean Checklist Response"
    },
    {
      "parameters": {
        "jsCode": "const cleanData = $input.first().json;\n\nconst subtaskKey = String(cleanData.subtaskKey || '');\nconst existingLabels = Array.isArray(cleanData.existingLabels)\n  ? cleanData.existingLabels.map(l => String(l))\n  : [];\n\nconst labelsBody = JSON.stringify({\n  update: {\n    labels: [\n      { remove: \"need-checklist\" },\n      { add: \"checklist-generated\" }\n    ]\n  }\n});\n\nconsole.log(`Preparing label update for ${subtaskKey}: remove \"need-checklist\", add \"checklist-generated\"`);\n\nreturn [{\n  json: {\n    subtaskKey: subtaskKey,\n    labelsBody: labelsBody,\n    existingLabels: existingLabels\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -6096,
        2368
      ],
      "id": "8d83a758-1421-4def-9322-5502f9f8ea40",
      "name": "Prepare Label Update1"
    },
    {
      "parameters": {
        "jsCode": "return [{\n  json: {\n    success: false,\n    stage: 'upload_csv',\n    error: $json.error || $json.message || 'No importRequest id returned from Allure',\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -5056,
        2608
      ],
      "id": "96eb13d0-982f-4dde-9e82-7ddbd0062cca",
      "name": "ImportRequest"
    },
    {
      "parameters": {
        "jsCode": "const response = $input.first().json;\nconst ctx = $('Transform to CSV').first().json;\n\nconst errorDetails = {\n  error: response.error,\n  message: response.message,\n  status: response.status,\n  statusText: response.statusText,\n  validationErrors: response.validationErrors,\n  hint: response.hint\n};\n\nlet errorMsg = 'Submit import failed';\nif (response.message) {\n  errorMsg = response.message;\n} else if (response.error) {\n  errorMsg = response.error;\n}\n\nif (response.validationErrors && Array.isArray(response.validationErrors)) {\n  errorMsg += '\\n\\nValidation errors:\\n' +\n    response.validationErrors.map((e, i) => `${i+1}. ${e}`).join('\\n');\n}\n\nconsole.log(`Submit failed for ${ctx.subtaskKey}:`, errorMsg);\n\nreturn [{\n  json: {\n    success: false,\n    stage: 'submit_import',\n    subtaskKey: ctx.subtaskKey,\n    error: errorMsg,\n    errorDetails,\n    csvPreview: ctx.csv.substring(0, 500)\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -4512,
        1360
      ],
      "id": "3fd1894b-8899-49b5-8d90-d0f5b0aaa442",
      "name": "Fail: Submit CSV"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "submit-ok",
              "leftValue": "={{ !$json.error }}",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -4768,
        1232
      ],
      "id": "51700dd8-1f75-467c-8845-f3799d6782b8",
      "name": "Submit OK?1"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "has-import-id",
              "leftValue": "={{ !!$json.id }}",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -5376,
        1232
      ],
      "id": "022bb2dc-fe26-4d47-8e87-39d1b773b02f",
      "name": "Has ImportRequest ID?1"
    },
    {
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconst subtaskKey = data.subtaskKey || 'UNKNOWN';\nconst error = data.error || 'JSON parsing failed';\n\nconst labelsBody = JSON.stringify({\n  update: {\n    labels: [\n      { remove: \"need-tc\" },\n      { add: \"tc-error\" }\n    ]\n  }\n});\n\nreturn [{\n  json: {\n    subtaskKey,\n    existingLabels: data.existingLabels || [],\n    labelsBody,\n    updatedLabels: (data.existingLabels || [])\n      .filter(l => l !== 'need-tc')\n      .concat(['tc-error'])\n      .filter((v, i, a) => a.indexOf(v) === i),\n    parseError: error,\n    comment: `ERR \u041e\u0448\u0438\u0431\u043a\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432 \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u0447\u0438 *${subtaskKey}*.\\n\\n\u041f\u0440\u0438\u0447\u0438\u043d\u0430: ${error}\\n\\n\u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u0437\u0430\u0434\u0430\u0447\u0443 \u0438\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u044b \u0432\u0440\u0443\u0447\u043d\u0443\u044e.`\n  }\n}];"
      },
      "id": "e77fee74-3df4-450f-b5d5-8133945b4eec",
      "name": "Handle Parse Error",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -5952,
        1024
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "skip-summary-check",
              "leftValue": "={{ $json.skipSummary }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "6f922f05-b6d1-42f8-bb92-8386f8313d78",
      "name": "Skip Summary?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -8016,
        720
      ]
    },
    {
      "parameters": {
        "jsCode": "const data = $input.first().json;\n\nreturn [{\n  json: {\n    content: [{ type: 'text', text: data.directContent || '' }],\n    _mocked: true\n  }\n}];"
      },
      "id": "7c7d4076-6470-4594-ad3e-6d2a105f8e09",
      "name": "Mock Claude Summary",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -7792,
        736
      ]
    },
    {
      "parameters": {
        "jiraVersion": "serverPat",
        "operation": "getAll",
        "options": {
          "fields": "summary,parent,issuetype,labels",
          "jql": "project in (MARKET, MINT)  AND issuetype = \"\u041f\u043e\u0434\u0437\u0430\u0434\u0430\u0447\u0430\"  AND status in (\"\u0412 \u0440\u0430\u0431\u043e\u0442\u0435\", \"In Progress\")  AND (  (labels = \"need-tc\" AND labels not in (\"tc-generated\", \"tc-error\"))  OR  (labels = \"need-checklist\" AND labels not in (\"checklist-generated\")) )"
        }
      },
      "id": "5a01af41-7bd7-437f-ac2e-26e15985a778",
      "name": "Search Jira1",
      "type": "n8n-nodes-base.jira",
      "typeVersion": 1,
      "position": [
        -9344,
        1344
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000,
      "credentials": {
        "jiraSoftwareServerPatApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const importId = $input.first().json.id;\n\nreturn [{\n  json: {\n    importId: importId,\n    submitBody: JSON.stringify({\n      withHeaders: true,\n      columnSeparator: \";\",\n      mapping: [\n        { field: \"skip\" },\n        { field: \"name\" },\n        { field: \"full_name\" },\n        { field: \"skip\" },\n        { field: \"description\" },\n        { field: \"precondition\" },\n        { field: \"expected_result\" },\n        { field: \"skip\" },\n        { field: \"scenario\" },\n        { field: \"tag\" },\n        { field: \"link\" },\n        { field: \"skip\" },\n        { field: \"parameter\" },\n        { field: \"skip\" },\n        { field: \"skip\" },\n        { field: \"skip\" },\n        { field: \"skip\" },\n        { field: \"skip\" },\n        { field: \"skip\" },\n        { field: \"skip\" },\n        { field: \"skip\" },\n        { field: \"skip\" },\n        { field: \"skip\" },\n        { field: \"skip\" },\n        { field: \"skip\" },\n        { field: \"skip\" },\n        { field: \"skip\" },\n        { field: \"skip\" },\n        { field: \"skip\" }\n      ]\n    })\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -5184,
        1232
      ],
      "id": "016a00c0-5aff-4966-84e9-e3f5bc4fd826",
      "name": "Prepare Submit Body"
    },
    {
      "parameters": {
        "options": {
          "reset": false
        }
      },
      "id": "2aa61f6b-affd-40d7-b610-28a88bf1f815",
      "name": "Loop Issues1",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        -8848,
        1344
      ]
    },
    {
      "parameters": {
        "jiraVersion": "serverPat",
        "resource": "issueComment",
        "issueKey": "={{ $json.subtaskKey }}",
        "comment": "={{ $json.comment }}",
        "options": {}
      },
      "id": "9e03d64c-84bd-4d1a-b9f1-5636de733e9e",
      "name": "Add Comment to Subtask (HTTP)",
      "type": "n8n-nodes-base.jira",
      "typeVersion": 1,
      "position": [
        -3440,
        656
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 3000,
      "credentials": {
        "jiraSoftwareServerPatApi": {
          "name": "<your credential>"
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "amount": 10
      },
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        -4800,
        800
      ],
      "id": "7d1ce315-6899-46fa-b2b3-b87bd24895c4",
      "name": "Wait"
    },
    {
      "parameters": {
        "jsCode": "const prev = $input.first().json;\n\nreturn [{\n  json: {\n    ...prev,\n    attempt: (prev.attempt ?? 1) + 1,\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "id": "ca6c9ba7-20b2-4776-8bc5-e6ee5c989b4d",
      "name": "Inc Attempt",
      "position": [
        -4672,
        800
      ]
    },
    {
      "parameters": {
        "jsCode": "const st = $input.first().json;\n\nreturn [{\n  json: {\n    success: false,\n    stage: 'poll_search',\n    subtaskKey: st.subtaskKey,\n    parentKey: st.parentKey,\n    existingLabels: st.existingLabels || [],\n    attempts: st.attempt,\n    error: `No test cases found in Allure by tag ${st.runTag} after ${st.attempt} attempts`,\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -4368,
        800
      ],
      "id": "2b0e1a80-a3a5-4979-8c61-f50b825a019b",
      "name": "Poll Fail"
    },
    {
      "parameters": {
        "jsCode": "const allureResp = $input.first().json;\nconst st = $('Init Poll1').first().json;\n\nreturn [{\n  json: {\n    success: true,\n    subtaskKey: st.subtaskKey,\n    parentKey: st.parentKey,\n    existingLabels: st.existingLabels || [],\n    attempts: st.attempt,\n    response: allureResp,\n    importedCount: Array.isArray(allureResp.content) ? allureResp.content.length : 0,\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "id": "6953a188-d2d7-42bb-879e-310c58a90f78",
      "name": "Wrap Found",
      "position": [
        -4816,
        496
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://your-jira.example.com/rest/api/2/issue/{{ $('Prepare Label Update').first().json.subtaskKey }}/comment",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_JIRA_PAT_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "={{ JSON.stringify({ body: $('Prepare Label Update').first().json.comment || '' }) }}",
        "options": {}
      },
      "id": "aaa375cf-15ce-44ac-9198-9d2da5ac58f5",
      "name": "Add Comment After Label Update",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -3104,
        1008
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 3000,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "const fail = $input.first().json;\n\nreturn [{\n  json: {\n    subtaskKey: fail.subtaskKey,\n    parentKey: fail.parentKey,\n    existingLabels: fail.existingLabels || [],\n    comment:\n      `\u26a0\ufe0f \u0418\u043c\u043f\u043e\u0440\u0442 \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432 \u0437\u0430\u043f\u0443\u0449\u0435\u043d, \u043d\u043e \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u044b \u043d\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u0438\u0441\u044c \u0432 Allure \u043f\u043e \u0442\u0435\u0433\u0443 *${fail.subtaskKey}*.\\n` +\n      `\u041f\u043e\u043f\u044b\u0442\u043e\u043a: ${fail.attempts}.\\n\\n` +\n      `\u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0432\u0440\u0443\u0447\u043d\u0443\u044e: https://your-allure.example.com/project/61/test-cases`,\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -3824,
        816
      ],
      "id": "be9cb037-0945-4281-a5a1-283ad2ebda62",
      "name": "Build Comment No TCs"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "found-tcs",
              "leftValue": "={{ Array.isArray($json.content) && $json.content.length > 0 }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -5056,
        448
      ],
      "id": "59d0449f-9f57-4868-b79f-20d6adae5373",
      "name": "Found TCs?1"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "attempts-left",
              "leftValue": "={{ ($json.attempt ?? 1) <= ($json.maxAttempts ?? 6) }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -4528,
        800
      ],
      "id": "4b496ae4-5214-4d4d-ab84-8b4fd8e74194",
      "name": "Attempts Left?2"
    },
    {
      "parameters": {
        "jsCode": "const pollData = $input.first().json;\n\nconst tcs = Array.isArray(pollData.response?.content)\n  ? pollData.response.content\n  : [];\n\nif (!pollData.parentKey) throw new Error('parentKey missing in pollData');\n\nif (tcs.length === 0) {\n  return [{\n    json: {\n      mode: 'no_tcs',\n      subtaskKey: pollData.subtaskKey,\n      parentKey: pollData.parentKey,\n      existingLabels: pollData.existingLabels || [],\n      comment: `\u26a0\ufe0f \u0422\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u044b \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b, \u043d\u043e \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b \u043f\u043e \u0442\u0435\u0433\u0443 *${pollData.subtaskKey}*.\\n\\n\u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435: https://your-allure.example.com/project/61/test-cases`\n    }\n  }];\n}\n\nreturn tcs.map(tc => ({\n  json: {\n    mode: 'tc',\n    subtaskKey: pollData.subtaskKey,\n    parentKey: pollData.parentKey,\n    existingLabels: pollData.existingLabels || [],\n    tcId: tc.id,\n    tcName: tc.name || `TC ${tc.id}`,\n    tcUrl: `https://your-allure.example.com/project/61/test-cases/${tc.id}`\n  }\n}));"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -4672,
        496
      ],
      "id": "3d0a1280-f6fd-450c-a637-faeba5928843",
      "name": "Explode TCs1"
    },
    {
      "parameters": {
        "jsCode": "let ctx = null;\n\ntry {\n  const bsc = $('Build Success Comment').first().json;\n  if (bsc?.subtaskKey) {\n    ctx = bsc;\n    console.log('Context from Build Success Comment:', bsc.subtaskKey);\n  }\n} catch (e) {}\n\nif (!ctx) {\n  try {\n    const bcn = $('Build Comment No TCs').first().json;\n    if (bcn?.subtaskKey) {\n      ctx = bcn;\n      console.log('Context from Build Comment No TCs:', bcn.subtaskKey);\n    }\n  } catch (e) {}\n}\n\nif (!ctx || !ctx.subtaskKey) {\n  throw new Error('Prepare Label Update: subtaskKey not found in any source node');\n}\n\nconst labelsBody = JSON.stringify({\n  update: {\n    labels: [\n      { remove: 'need-tc' },\n      { add: 'tc-generated' }\n    ]\n  }\n});\n\nconsole.log('Prepare delta label update for', ctx.subtaskKey, ': remove need-tc, add tc-generated');\n\nreturn [{\n  json: {\n    subtaskKey: ctx.subtaskKey,\n    existingLabels: ctx.existingLabels || [],\n    labelsBody,\n    comment: ctx.comment || ''\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -3104,
        464
      ],
      "id": "0f443ff1-c0ff-44ed-9ad6-6a372cb0873d",
      "name": "Prepare Label Update"
    },
    {
      "parameters": {
        "jsCode": "const jiraResp = $input.first().json;\nconst ctx = $('Prepare Context').first().json;\n\nconst freshLabels = jiraResp.fields?.labels || ctx.existingLabels || [];\n\nreturn [{\n  json: {\n    ...ctx,\n    existingLabels: freshLabels,\n    labelsRefreshed: true\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -7200,
        720
      ],
      "id": "d0212f7f-ff54-4ff7-b6ca-5249e299f086",
      "name": "Apply Refreshed Labels"
    },
    {
      "parameters": {
        "method": "PUT",
        "url": "=https://your-jira.example.com/rest/api/2/issue/{{ $json.subtaskKey }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_JIRA_PAT_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "={{ $json.labelsBody }}",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -5936,
        2368
      ],
      "id": "a791b40a-e97b-410d-970c-6e8338df4c5d",
      "name": "Update Checklist Labels1",
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 3000,
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "url": "=https://your-jira.example.com/rest/api/2/issue/{{ $json.subtaskKey }}?fields=labels",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_JIRA_PAT_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -7408,
        832
      ],
      "id": "272e59a0-7c46-476d-808d-90fc8213e8fc",
      "name": "Refresh Labels from Jira",
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "method": "PUT",
        "url": "=https://your-jira.example.com/rest/api/2/issue/{{ $json.subtaskKey }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_JIRA_PAT_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "={{ $json.labelsBody }}",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -3104,
        736
      ],
      "id": "ade402ee-0cee-4cac-8c6c-b49a9e1d0f7f",
      "name": "Jira Update Labels (HTTP)1",
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 3000,
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "jsCode": "const data = $input.first().json;\n\nfunction escapeCsv(val) {\n  if (val === undefined || val === null) return '';\n  val = val.toString();\n  if (val.includes(';') || val.includes('\\n') || val.includes('\"')) {\n    val = '\"' + val.replace(/\"/g, '\"\"') + '\"';\n  }\n  return val;\n}\n\nconst runTag = `${data.subtaskKey}__${Date.now()}`;\n\nconst headers = [\n  'allure_id', 'name', 'full_name', 'automated', 'description', 'precondition',\n  'expected_result', 'status', 'scenario', 'tag', 'links', 'Issue', 'parameter',\n  'Issue tracker', 'Lead', 'Owner', 'Suite', 'Component', 'Story', 'Feature',\n  'Epic', 'Issues links', 'Feature2', 'Feature3', 'Product', 'Side', 'Layer', 'Team', 'SortKey'\n];\n\nconst lines = [headers.join(';')];\n\nfor (const tc of data.testCases) {\n  const scenario = (tc.steps || []).map((s, i) => {\n    let action = '', expected = '';\n    if (typeof s === 'string') {\n      const arrowIdx = s.indexOf('\u2192');\n      if (arrowIdx !== -1) {\n        action   = s.substring(0, arrowIdx).trim();\n        expected = s.substring(arrowIdx + 1).trim();\n      } else {\n        action = s.trim();\n      }\n    } else if (s && typeof s === 'object') {\n      action   = s.action   || s.step   || '';\n      expected = s.expected || s.result || '';\n    }\n    const expLine = expected ? `\\n\u041e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442: ${expected}` : '';\n    return `[step ${i+1}] ${action}${expLine}`;\n  }).join('\\n\\n');\n\n  const row = [\n    '',\n    tc.name || '',\n    '',\n    'false',\n    tc.description || '',\n    tc.preconditions || '',\n    tc.expectedResult || '',\n    'Draft',\n    scenario,\n    runTag,\n    data.confluenceUrl || '',\n    '',\n    '',\n    'https://your-jira.example.com',\n    '',\n    'claude-bot',\n    '', '', '', '', '', '', '', '', '', '', '', '', ''\n  ].map(escapeCsv);\n\n  lines.push(row.join(';'));\n}\n\nconst csv = lines.join('\\n');\n\nreturn [{\n  json: {\n    csv,\n    runTag,\n    parentKey: data.parentKey,\n    subtaskKey: data.subtaskKey,\n    existingLabels: data.existingLabels,\n    confluenceUrl: data.confluenceUrl || '',\n    testCasesCount: data.testCases.length,\n    importStartTime: Date.now()\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "id": "01987dec-0fd6-42a5-81e9-c2f3562b6c15",
      "name": "Transform to CSV",
      "position": [
        -5904,
        1232
      ]
    },
    {
      "parameters": {
        "jsCode": "const ctx = $('Transform to CSV').first().json;\n\nconst runTag = ctx.runTag;\n\nconst aql = `tag = \"${runTag}\"`;\nconst searchUrl = `https://your-allure.example.com/api/testcase/__search`\n  + `?projectId=61`\n  + `&rql=${encodeURIComponent(aql)}`\n  + `&size=50`;\n\nconsole.log('Poll init. runTag:', runTag);\nconsole.log('Search URL:', searchUrl);\n\nreturn [{\n  json: {\n    attempt: 1,\n    maxAttempts: 6,\n    waitSeconds: 10,\n    subtaskKey: ctx.subtaskKey,\n    parentKey: ctx.parentKey,\n    runTag: runTag,\n    searchUrl: searchUrl,\n    existingLabels: ctx.existingLabels || [],\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "id": "891e22fc-7a50-4a51-9ad6-c427a6e67914",
      "name": "Init Poll1",
      "position": [
        -5504,
        448
      ]
    },
    {
      "parameters": {
        "url": "={{ $json.searchUrl }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Api-Token YOUR_ALLURE_API_TOKEN"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "id": "9d1610ab-dc44-49e6-a0ca-4ebf64e7cde1",
      "name": "Search Allure TCs1",
      "position": [
        -5360,
        448
      ]
    },
    {
      "parameters": {
        "jsCode": "const pollData = $('Wrap Found').first().json;\nconst tcs = pollData.response?.content || [];\n\nif (!Array.isArray(tcs)) {\n  throw new Error(`Invalid response.content - expected array, got ${typeof tcs}`);\n}\n\nconst tcIds = tcs\n  .map((tc, idx) => {\n    if (!tc || typeof tc !== 'object') {\n      console.log(`TC[${idx}] invalid object:`, tc);\n      return null;\n    }\n    if (!tc.id || typeof tc.id !== 'number') {\n      console.log(`TC[${idx}] missing valid id:`, JSON.stringify(tc).substring(0, 100));\n      return null;\n    }\n    return tc.id;\n  })\n  .filter(Boolean);\n\nconst uniqueIds = [...new Set(tcIds)];\n\nif (uniqueIds.length === 0) {\n  throw new Error('No valid TC IDs found to link');\n}\n\nif (uniqueIds.length < tcIds.length) {\n  console.log(`Removed ${tcIds.length - uniqueIds.length} duplicate TC IDs`);\n}\n\nconsole.log(`Collected ${uniqueIds.length} unique TC IDs for bulk linking to ${pollData.parentKey}`);\n\nreturn [{\n  json: {\n    tcIds: uniqueIds,\n    parentKey: pollData.parentKey,\n    subtaskKey: pollData.subtaskKey,\n    existingLabels: pollData.existingLabels || [],\n    tcCount: uniqueIds.length\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "id": "ffa7df32-1015-4bfe-b74b-02a0000df2bf",
      "name": "Collect TC IDs",
      "position": [
        -4528,
        496
      ]
    },
    {
      "parameters": {
        "jsCode": "// Read from Pass Through Tag to bypass HTTP response data loss\nconst data = $('Pass Through Tag').first().json;\n\nconst JIRA_INTEGRATION_ID = 5;\n\nconst bulkPayload = {\n  issues: [{\n    integrationId: JIRA_INTEGRATION_ID,\n    name: data.parentKey,\n    url: `https://your-jira.example.com/browse/${data.parentKey}`\n  }],\n  selection: {\n    projectId: 61,\n    leafsInclude: data.tcIds\n  }\n};\n\nconsole.log('Bulk link payload:', JSON.stringify(bulkPayload));\n\nreturn [{\n  json: {\n    ...data,\n    bulkBody: JSON.stringify(bulkPayload)\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "id": "553148fb-75a4-4819-a1f0-358c61903691",
      "name": "Prepare Bulk Body",
      "position": [
        -3984,
        496
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://your-allure.example.com/api/testcase/bulk/issue/add",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Api-Token YOUR_ALLURE_API_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "={{ $json.bulkBody }}",
        "options": {
          "timeout": 30000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "id": "5c54d50a-f34b-46da-a7af-c8a440cf8f1f",
      "name": "Bulk Link TCs to Parent",
      "position": [
        -3824,
        496
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000,
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "jsCode": "const linkResp = $input.first().json;\nconst ctx = $('Collect TC IDs').first().json;\n\nconst statusCode = linkResp.statusCode || linkResp.status || 200;\nconst success = !linkResp.error && statusCode >= 200 && statusCode < 300;\n\nconst tcLinks = (ctx.tcIds || []).map((id, i) =>\n  `- [TC #${id}|https://your-allure.example.com/project/61/test-cases/${id}]`\n).join('\\n');\n\nlet comment;\nif (success) {\n  comment = `*\u0422\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u044b \u0441\u043e\u0437\u0434\u0430\u043d\u044b \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u044b \u043a* [${ctx.parentKey}|https://your-jira.example.com/browse/${ctx.parentKey}]\\n\\n`\n    + `*\u0421\u043e\u0437\u0434\u0430\u043d\u043e \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432:* ${ctx.tcCount}\\n\\n`\n    + `*\u0421\u043f\u0438\u0441\u043e\u043a \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432:*\\n${tcLinks}\\n\\n`\n    + `[\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u0432\u0441\u0435 \u0432 Allure|https://your-allure.example.com/project/61/test-cases?tags=${encodeURIComponent(ctx.subtaskKey)}]`;\n} else {\n  const errorMsg = linkResp.error?.message || linkResp.message || 'Unknown error';\n  comment = `*\u0422\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u044b \u0441\u043e\u0437\u0434\u0430\u043d\u044b, \u043d\u043e \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u043a* [${ctx.parentKey}|https://your-jira.example.com/browse/${ctx.parentKey}] *\u043d\u0435 \u0443\u0434\u0430\u043b\u0430\u0441\u044c.*\\n\\n`\n    + `*\u0421\u043e\u0437\u0434\u0430\u043d\u043e \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432:* ${ctx.tcCount}\\n\\n`\n    + `*\u0421\u043f\u0438\u0441\u043e\u043a \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432:*\\n${tcLinks}\\n\\n`\n    + `\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438: ${errorMsg}\\n`\n    + `[\u041f\u0440\u0438\u0432\u044f\u0437\u0430\u0442\u044c \u0432\u0440\u0443\u0447\u043d\u0443\u044e|https://your-allure.example.com/project/61/test-cases?tags=${encodeURIComponent(ctx.subtaskKey)}]`;\n}\n\nreturn [{\n  json: {\n    comment,\n    subtaskKey: ctx.subtaskKey,\n    parentKey: ctx.parentKey,\n    existingLabels: ctx.existingLabels,\n    linked: success,\n    tcCount: ctx.tcCount,\n    tcIds: ctx.tcIds,\n    linkStatus: success ? 'success' : 'failed'\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "id": "dc920ca2-e9c5-44ab-a682-792ea2a2daca",
      "name": "Build Success Comment",
      "position": [
        -3632,
        496
      ]
    },
    {
      "parameters": {
        "jsCode": "const allureResp = $input.first().json;\nconst pollState = $('Init Poll1').first().json;\nconst expectedTag = pollState.runTag;\n\nconst rawContent = allureResp.content;\n\nif (!rawContent || !Array.isArray(rawContent)) {\n  console.log('No content in __search response');\n  return [{\n    json: {\n      attempt: pollState.attempt,\n      maxAttempts: pollState.maxAttempts,\n      waitSeconds: pollState.waitSeconds,\n      subtaskKey: pollState.subtaskKey,\n      parentKey: pollState.parentKey,\n      runTag: pollState.runTag,\n      searchUrl: pollState.searchUrl,\n      existingLabels: pollState.existingLabels || [],\n      content: [],\n      totalFound: 0,\n      exactMatches: 0,\n      filtered: 0,\n      filterApplied: true,\n      expectedTag\n    }\n  }];\n}\n\nconst totalFound = rawContent.length;\n\nconst exactMatches = rawContent.filter(tc => {\n  if (!tc.tags || !Array.isArray(tc.tags)) return false;\n  return tc.tags.some(tag => {\n    const tagName = typeof tag === 'string' ? tag : (tag.name || tag.value || '');\n    return tagName === expectedTag;\n  });\n});\n\nconst filtered = totalFound - exactMatches.length;\nconsole.log(`AQL found ${totalFound}, exact match: ${exactMatches.length}, tag: ${expectedTag}`);\n\nreturn [{\n  json: {\n    attempt: pollState.attempt,\n    maxAttempts: pollState.maxAttempts,\n    waitSeconds: pollState.waitSeconds,\n    subtaskKey: pollState.subtaskKey,\n    parentKey: pollState.parentKey,\n    runTag: pollState.runTag,\n    searchUrl: pollState.searchUrl,\n    existingLabels: pollState.existingLabels || [],\n    content: exactMatches,\n    totalFound,\n    exactMatches: exactMatches.length,\n    filtered,\n    filterApplied: true,\n    expectedTag\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "id": "3fa42f76-4445-4e8c-ab2c-f0278107bee9",
      "name": "Filter Exact Tag Match",
      "position": [
        -5216,
        448
      ]
    },
    {
      "parameters": {
        "jsCode": "const data = $input.first().json;\n\nif (!data.tcIds || data.tcIds.length === 0) {\n  throw new Error('No tcIds available to tag');\n}\n\nconst tagBody = {\n  selection: {\n    projectId: 61,\n    testCasesInclude: data.tcIds\n  },\n  tags: [{ name: 'generated' }]\n};\n\nconsole.log(`Tagging ${data.tcIds.length} TCs with 'generated' tag`);\n\nreturn [{\n  json: {\n    ...data,\n    tagBody: JSON.stringify(tagBody)\n  }\n}];"
      },
      "id": "124d9827-be3a-49a3-91fd-84563bde66e4",
      "name": "Prepare Tag Body",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -4384,
        496
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://your-allure.example.com/api/v2/test-case/bulk/tag/add",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Authorization",
              "value": "Api-Token YOUR_ALLURE_API_TOKEN"
            }
          ]
        },
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "={{ $json.tagBody }}",
        "options": {}
      },
      "id": "4d7b848d-4d6e-4942-a504-40ff9fc282f0",
      "name": "Add Generated Tag",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -4240,
        496
      ]
    },
    {
      "parameters": {
        "jsCode": "const collectData = $('Collect TC IDs').first().json;\n\nconsole.log(`Tag 'generated' added to ${collectData.tcIds.length} TCs`);\n\nreturn [{\n  json: {\n    tcIds: collectData.tcIds,\n    parentKey: collectData.parentKey,\n    subtaskKey: collectData.subtaskKey,\n    existingLabels: collectData.existingLabels || [],\n    tcCount: collectData.tcCount\n  }\n}];"
      },
      "id": "1b962f23-1257-45e8-a8cf-93b44eaf8282",
      "name": "Pass Through Tag",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -4096,
        496
      ]
    },
    {
      "id": "3eb372b6-c5aa-4801-bbcd-05c0994b1e5c",
      "name": "Prepare Move Body",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -3872,
        496
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const data = $input.first().json;\n\n// Add 'AI-Generated' folder via CFV (custom field value) bulk add\nconst cfvPayload = {\n  cfv: [{\n    id: 8622,\n    name: 'AI-Generated',\n    customField: { id: -2, name: 'Feature' }\n  }],\n  selection: {\n    projectId: 61,\n    testCasesInclude: data.tcIds\n  }\n};\n\nconst statusPayload = {\n  selection: {\n    projectId: 61,\n    testCasesInclude: data.tcIds,\n    treeId: 120\n  },\n  statusId: 6,\n  workflowId: 1\n};\n\nconsole.log('CFV add payload:', JSON.stringify(cfvPayload));\nconsole.log('Status payload:', JSON.stringify(statusPayload));\n\nreturn [{\n  json: {\n    ...data,\n    moveBody: JSON.stringify(cfvPayload),\n    statusBody: JSON.stringify(statusPayload)\n  }\n}];"
      }
    },
    {
      "id": "028e2fef-34f6-4a4e-9f5d-b8efa0de093f",
      "name": "Move TCs to AI-Generated",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        -3744,
        496
      ],
      "parameters": {
        "method": "POST",
        "url": "https://your-allure.example.com/api/v2/test-case/bulk/cfv/add",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Api-Token YOUR_ALLURE_API_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "={{ $json.moveBody }}",
        "options": {
          "timeout": 30000
        }
      }
    },
    {
      "id": "86d89b9a-b2c8-4c27-b4cd-78bc2fb60052",
      "name": "Prepare Status Body",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -3616,
        496
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// Bypass HTTP response - get original data from Prepare Move Body\nconst data = $('Prepare Move Body').first().json;\nconst statusBody = JSON.stringify({\n  selection: {\n    projectId: 61,\n    testCasesInclude: data.tcIds,\n    treeId: 120\n  },\n  statusId: 6,\n  workflowId: 1\n});\nconsole.log('Preparing bulk status update for', data.tcIds.length, 'TCs');\nreturn [{ json: { ...data, statusBody } }];"
      }
    },
    {
      "id": "3991abee-2c6f-456c-b94b-c4e6d5ec682b",
      "name": "Set TC Status Bulk",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        -3488,
        496
      ],
      "parameters": {
        "method": "POST",
        "url": "https://your-allure.example.com/api/v2/test-case/bulk/status/set",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Api-Token YOUR_ALLURE_API_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "={{ $json.statusBody }}",
        "options": {
          "timeout": 30000
        }
      }
    }
  ],
  "connections": {
    "Build Prompt V2": {
      "main": [
        [
          {
            "node": "Call Claude1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Test Cases V3": {
      "main": [
        [
          {
            "node": "Parse OK?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse OK?": {
      "main": [
        [
          {
            "node": "Transform to CSV",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle Parse Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert CSV to File": {
      "main": [
        [
          {
            "node": "Upload CSV to Allure",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload CSV to Allure": {
      "main": [
        [
          {
            "node": "Has ImportRequest ID?1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "ImportRequest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Submit CSV Import": {
      "main": [
        [
          {
            "node": "Submit OK?1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Confluence Content": {
      "main": [
        [
          {
            "node": "Summarize Confluence (Code)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Context": {
      "main": [
        [
          {
            "node": "Refresh Labels from Jira",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Summarize Confluence (Code)": {
      "main": [
        [
          {
            "node": "If Need Summary?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Need Summary?": {
      "main": [
        [
          {
            "node": "Build Summary Prompt",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Prepare Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call Claude Summary": {
      "main": [
        [
          {
            "node": "Prepare Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Summary Prompt": {
      "main": [
        [
          {
            "node": "Skip Summary?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger1": {
      "main": [
        [
          {
            "node": "Search Jira1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Issues1": {
      "main": [
        [
          {
            "node": "Has Tasks?1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Tasks?1": {
      "main": [
        [
          {
            "node": "Loop Issues1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Tasks Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Parent Issue2": {
      "main": [
        [
          {
            "node": "Extract Confluence Links1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Confluence Links1": {
      "main": [
        [
          {
            "node": "Has Confluence?1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Confluence?1": {
      "main": [
        [
          {
            "node": "Get Confluence Content",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Prepare Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check What To Generate": {
      "main": [
        [
          {
            "node": "Route by Action",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Action": {
      "main": [
        [
          {
            "node": "Build Prompt V2",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Checklist Prompt",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Ignore Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call Claude1": {
      "main": [
        [
          {
            "node": "Parse Test Cases V3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Checklist Prompt": {
      "main": [
        [
          {
            "node": "Call Claude Checklist",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call Claude Checklist": {
      "main": [
        [
          {
            "node": "Add Jira Comment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Jira Comment": {
      "main": [
        [
          {
            "node": "Clean Checklist Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ignore Response": {
      "main": [
        [
          {
            "node": "Loop Issues1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clean Checklist Response": {
      "main": [
        [
          {
            "node": "Prepare Label Update1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Label Update1": {
      "main": [
        [
          {
            "node": "Update Checklist Labels1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ImportRequest": {
      "main": [
        [
          {
            "node": "Loop Issues1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fail: Submit CSV": {
      "main": [
        [
          {
            "node": "Loop Issues1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Submit OK?1": {
      "main": [
        [
          {
            "node": "Init Poll1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Fail: Submit CSV",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has ImportRequest ID?1": {
      "main": [
        [
          {
            "node": "Prepare Submit Body",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "ImportRequest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Handle Parse Error": {
      "main": [
        [
          {
            "node": "Jira Update Labels (HTTP)1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Skip Summary?": {
      "main": [
        [
          {
            "node": "Mock Claude Summary",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Call Claude Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mock Claude Summary": {
      "main": [
        [
          {
            "node": "Prepare Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Jira1": {
      "main": [
        [
          {
            "node": "Split Issues1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Submit Body": {
      "main": [
        [
          {
            "node": "Submit CSV Import",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Issues1": {
      "main": [
        [],
        [
          {
            "node": "Get Parent Issue2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Comment to Subtask (HTTP)": {
      "main": [
        [
          {
            "node": "Prepare Label Update",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait": {
      "main": [
        [
          {
            "node": "Inc Attempt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Inc Attempt": {
      "main": [
        [
          {
            "node": "Attempts Left?2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Poll Fail": {
      "main": [
        [
          {
            "node": "Build Comment No TCs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wrap Found": {
      "main": [
        [
          {
            "node": "Explode TCs1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Comment After Label Update": {
      "main": [
        [
          {
            "node": "Loop Issues1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Comment No TCs": {
      "main": [
        [
          {
            "node": "Add Comment to Subtask (HTTP)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Found TCs?1": {
      "main": [
        [
          {
            "node": "Wrap Found",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Attempts Left?2": {
      "main": [
        [
          {
            "node": "Search Allure TCs1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Poll Fail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Explode TCs1": {
      "main": [
        [
          {
            "node": "Collect TC IDs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Label Update": {
      "main": [
        [
          {
            "node": "Jira Update Labels (HTTP)1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Apply Refreshed Labels": {
      "main": [
        [
          {
            "node": "Check What To Generate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Checklist Labels1": {
      "main": [
        [
          {
            "node": "Ignore Response",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Ignore Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Refresh Labels from Jira": {
      "main": [
        [
          {
            "node": "Apply Refreshed Labels",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Jira Update Labels (HTTP)1": {
      "main": [
        [
          {
            "node": "Add Comment After Label Update",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop Issues1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Transform to CSV": {
      "main": [
        [
          {
            "node": "Convert CSV to File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Init Poll1": {
      "main": [
        [
          {
            "node": "Search Allure TCs1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Allure TCs1": {
      "main": [
        [
          {
            "node": "Filter Exact Tag Match",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Collect TC IDs": {
      "main": [
        [
          {
            "node": "Prepare Tag Body",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Bulk Body": {
      "main": [
        [
          {
            "node": "Bulk Link TCs to Parent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Bulk Link TCs to Parent": {
      "main": [
        [
          {
            "node": "Build Success Comment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Success Comment": {
      "main": [
        [
          {
            "node": "Add Comment to Subtask (HTTP)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Exact Tag Match": {
      "main": [
        [
          {
            "node": "Found TCs?1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Tag Body": {
      "main": [
        [
          {
            "node": "Add Generated Tag",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Generated Tag": {
      "main": [
        [
          {
            "node": "Pass Through Tag",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pass Through Tag": {
      "main": [
        [
          {
            "node": "Prepare Move Body",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Move Body": {
      "main": [
        [
          {
            "node": "Move TCs to AI-Generated",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Move TCs to AI-Generated": {
      "main": [
        [
          {
            "node": "Prepare Status Body",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Status Body": {
      "main": [
        [
          {
            "node": "Set TC Status Bulk",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set TC Status Bulk": {
      "main": [
        [
          {
            "node": "Prepare Bulk Body",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "_note": "Sanitized version for public sharing. Replace all YOUR_* placeholders with your actual values before use."
}