{
  "schema": 1,
  "capturedAt": "2026-11-13T08:57:46.379Z",
  "mechanism": "Actual Bruno 4.3.0 CLI Safe Mode requests to own loopback Node API; browser replays reports only",
  "runtime": {
    "node": "v24.19.0",
    "platform": "win32",
    "bruno": "4.3.0"
  },
  "normalization": "Only local ephemeral origin, absolute suite path and JUnit hostname are normalized. Assertions, statuses, bodies and timings are actual CLI output; all credentials are public demo fixtures.",
  "runs": {
    "passed": {
      "command": "bru run scenarios --env Local --sandbox safe --reporter-json passed.json --reporter-junit passed.xml",
      "exitCode": 0,
      "summary": {
        "totalRequests": 10,
        "passedRequests": 10,
        "failedRequests": 0,
        "errorRequests": 0,
        "skippedRequests": 0,
        "skippedByBail": 0,
        "totalAssertions": 2,
        "passedAssertions": 2,
        "failedAssertions": 0,
        "totalTests": 26,
        "passedTests": 26,
        "failedTests": 0,
        "totalPreRequestTests": 0,
        "passedPreRequestTests": 0,
        "failedPreRequestTests": 0,
        "totalPostResponseTests": 0,
        "passedPostResponseTests": 0,
        "failedPostResponseTests": 0
      }
    },
    "failed": {
      "command": "bru run failure --env Local --sandbox safe --reporter-json failed.json --reporter-junit failed.xml",
      "exitCode": 1,
      "summary": {
        "totalRequests": 1,
        "passedRequests": 0,
        "failedRequests": 1,
        "errorRequests": 0,
        "skippedRequests": 0,
        "skippedByBail": 0,
        "totalAssertions": 0,
        "passedAssertions": 0,
        "failedAssertions": 0,
        "totalTests": 2,
        "passedTests": 1,
        "failedTests": 1,
        "totalPreRequestTests": 0,
        "passedPreRequestTests": 0,
        "failedPreRequestTests": 0,
        "totalPostResponseTests": 0,
        "passedPostResponseTests": 0,
        "failedPostResponseTests": 0
      }
    },
    "dataset": {
      "command": "bru run dataset --env Local --sandbox safe --reporter-json dataset.json --reporter-junit dataset.xml --json-file-path data/pagination.json",
      "exitCode": 0,
      "summary": [
        {
          "totalRequests": 1,
          "passedRequests": 1,
          "failedRequests": 0,
          "errorRequests": 0,
          "skippedRequests": 0,
          "skippedByBail": 0,
          "totalAssertions": 0,
          "passedAssertions": 0,
          "failedAssertions": 0,
          "totalTests": 2,
          "passedTests": 2,
          "failedTests": 0,
          "totalPreRequestTests": 0,
          "passedPreRequestTests": 0,
          "failedPreRequestTests": 0,
          "totalPostResponseTests": 0,
          "passedPostResponseTests": 0,
          "failedPostResponseTests": 0
        },
        {
          "totalRequests": 1,
          "passedRequests": 1,
          "failedRequests": 0,
          "errorRequests": 0,
          "skippedRequests": 0,
          "skippedByBail": 0,
          "totalAssertions": 0,
          "passedAssertions": 0,
          "failedAssertions": 0,
          "totalTests": 2,
          "passedTests": 2,
          "failedTests": 0,
          "totalPreRequestTests": 0,
          "passedPreRequestTests": 0,
          "failedPreRequestTests": 0,
          "totalPostResponseTests": 0,
          "passedPostResponseTests": 0,
          "failedPostResponseTests": 0
        },
        {
          "totalRequests": 1,
          "passedRequests": 1,
          "failedRequests": 0,
          "errorRequests": 0,
          "skippedRequests": 0,
          "skippedByBail": 0,
          "totalAssertions": 0,
          "passedAssertions": 0,
          "failedAssertions": 0,
          "totalTests": 2,
          "passedTests": 2,
          "failedTests": 0,
          "totalPreRequestTests": 0,
          "passedPreRequestTests": 0,
          "failedPreRequestTests": 0,
          "totalPostResponseTests": 0,
          "passedPostResponseTests": 0,
          "failedPostResponseTests": 0
        }
      ]
    }
  },
  "sourceHashes": {
    "package.json": "79f567f03359b0c238eef9c284000a3df95d6d5e9340ebd19a60056b8077a641",
    "package-lock.json": "42ac6f2f11dac03e58600cf8da5b86f5cf0c07234d833cc61492fb8e58519ad9",
    "src/api.mjs": "eb9d4410bf7058c272522a8499b9de24ba1fff07b1553fb2766bfaf3cdbeab05",
    "tools/capture.mjs": "4e05abb901a9bd9f541572bd77c90cf0064a56a7c411faa2e6547d082e4bb14e",
    "collection/bruno.json": "7b4569297088d12a296b2d41d14681d4ed211e1676673c10395632a5176bba17",
    "collection/data/pagination.json": "ba8081e61122b0f95ed675dbfa51252a7efdd4c5d30933c8aad7e64ced047085",
    "collection/dataset/pages.bru": "956e60553857a5028a3f38794ccac972ae5cfb72a542ba58a482fc4fbfe7e38d",
    "collection/environments/Local.bru": "a75bf7047fb2db918f29ae49a576a21fd980016038b32ffc8065499543c5d765",
    "collection/failure/08-contract-broken.bru": "23f315176a8a6dd1ed9d90b4c4c1d1b3719559b957c3020797dd6b5399689d4b",
    "collection/scenarios/01-health.bru": "0104619fa0036af8e8aa06d11caf28a9cc0d4341270d0747ff3bb2e8ffddfb7c",
    "collection/scenarios/02-pagination.bru": "cc089eba746e9347f9136300882b3e752a6e8000a40bfbb0d03bbdddd2bef23e",
    "collection/scenarios/03-create.bru": "78b3322822800deb45ee5f4482e031a74bcff4f1bd2f80196a1b87420a382d9b",
    "collection/scenarios/04-read-created.bru": "b0153d92e4375ba9f2dead413abcafeabea3bd0be2fef5338a4aea81c862cf78",
    "collection/scenarios/05-validation.bru": "4cbc633c5c6ea93195b667c0416be7545f92f9df078d64ed1200d8fdba31f43c",
    "collection/scenarios/06a-unauthorized.bru": "0233a14166ad8c13bfff2a84e7fd0940375a3c2ad759fcbc16cab4ea8f98b663",
    "collection/scenarios/06b-demo-session.bru": "883d97d8eadb9d084921ea7a6fdd004f0d9dba99a96ef603215939bc4f197fbf",
    "collection/scenarios/06c-authorized.bru": "a4c363f2d4ef92d3f27bbcb9740ef9edf0c089fca01347b723f6901e10357a14",
    "collection/scenarios/07-rate-limit.bru": "0c0a9a7d845f9dfe95bdb6bedf05d15ce330ccf81719fdbecc7418247566e61a",
    "collection/scenarios/08-contract-fixed.bru": "4d7c67764e6323cf123b10ca7f1c4d3bcf30b8a6a4e035e99c4be20f096c41b2"
  },
  "cases": [
    {
      "id": "health",
      "title": "1. Проверить готовность сервиса",
      "use": "Контроль API перед запуском интерфейса и после deploy.",
      "explain": "Сравните HTTP-статус, идентификатор сервиса и формат версии. Две декларативные проверки (assertions) дополняют JavaScript-тесты.",
      "requests": [
        {
          "test": {
            "filename": "scenarios\\01-health.bru"
          },
          "request": {
            "method": "GET",
            "url": "http://127.0.0.1:8516/health",
            "headers": {
              "Accept": "application/json, text/plain, */*",
              "User-Agent": "bruno-runtime/4.3.0",
              "Accept-Encoding": "gzip, compress, deflate, br",
              "Host": "127.0.0.1:8516",
              "Connection": "keep-alive",
              "content-type": null
            }
          },
          "response": {
            "status": 200,
            "statusText": "OK",
            "headers": {
              "content-type": "application/json; charset=utf-8",
              "cache-control": "no-store",
              "x-workshop": "Bruno",
              "date": "Fri, 13 Nov 2026 08:57:43 GMT",
              "connection": "keep-alive",
              "keep-alive": "timeout=5",
              "transfer-encoding": "chunked"
            },
            "data": {
              "status": "ok",
              "service": "bruno-demo",
              "version": 1,
              "fixture": true
            },
            "url": "http://127.0.0.1/health",
            "responseTime": 10,
            "duration": 10,
            "size": 65
          },
          "error": null,
          "status": "pass",
          "assertionResults": [
            {
              "uid": "SuKrUaT5q2A-vi8erBHFH",
              "lhsExpr": "res.status",
              "rhsExpr": "eq 200",
              "rhsOperand": "200",
              "operator": "eq",
              "status": "pass"
            },
            {
              "uid": "AaSLpiyBfyXtvklElZ5bX",
              "lhsExpr": "res.body.status",
              "rhsExpr": "eq ok",
              "rhsOperand": "ok",
              "operator": "eq",
              "status": "pass"
            }
          ],
          "testResults": [
            {
              "description": "Health returns 200",
              "status": "pass",
              "uid": "cOgDYKIZko0Ux8SbwBf6y"
            },
            {
              "description": "Service identity is stable",
              "status": "pass",
              "uid": "PyPvjVkMtD5rI968WiqoE"
            },
            {
              "description": "Version is a number",
              "status": "pass",
              "uid": "XCGGfkzPaScXv8-JaoIBI"
            }
          ],
          "preRequestTestResults": [],
          "postResponseTestResults": [],
          "shouldStopRunnerExecution": false,
          "runDuration": 0.1556717,
          "name": "01 · Health и контракт",
          "suitename": "scenarios/01-health",
          "path": "scenarios\\01-health",
          "iterationIndex": 0,
          "nativeStatus": "pass",
          "source": "scenarios/01-health.bru",
          "cliExitCode": 0
        }
      ]
    },
    {
      "id": "pagination",
      "title": "2. Параметры и пагинация",
      "use": "Таблица услуг в административной панели.",
      "explain": "Запрос второй страницы активных услуг проверяет ID 4 и 5 и общее количество. Дополнительно три строки JSON-набора проверяют первую, вторую и пустую третью страницу. Проверка 200 сама по себе не обнаружит неверную фильтрацию.",
      "requests": [
        {
          "test": {
            "filename": "scenarios\\02-pagination.bru"
          },
          "request": {
            "method": "GET",
            "url": "http://127.0.0.1:8516/services?page=2&limit=2&active=true",
            "headers": {
              "Accept": "application/json, text/plain, */*",
              "User-Agent": "bruno-runtime/4.3.0",
              "Accept-Encoding": "gzip, compress, deflate, br",
              "Host": "127.0.0.1:8516",
              "Connection": "keep-alive",
              "content-type": null
            }
          },
          "response": {
            "status": 200,
            "statusText": "OK",
            "headers": {
              "content-type": "application/json; charset=utf-8",
              "cache-control": "no-store",
              "x-workshop": "Bruno",
              "date": "Fri, 13 Nov 2026 08:57:43 GMT",
              "connection": "keep-alive",
              "keep-alive": "timeout=5",
              "transfer-encoding": "chunked"
            },
            "data": {
              "items": [
                {
                  "id": 4,
                  "title": "Проверка отчётов",
                  "active": true,
                  "price": 7000
                },
                {
                  "id": 5,
                  "title": "Импорт каталога",
                  "active": true,
                  "price": 11000
                }
              ],
              "page": 2,
              "limit": 2,
              "total": 4
            },
            "url": "http://127.0.0.1/services?page=2&limit=2&active=true",
            "responseTime": 2,
            "duration": 2,
            "size": 195
          },
          "error": null,
          "status": "pass",
          "assertionResults": [],
          "testResults": [
            {
              "description": "Pagination returns 200",
              "status": "pass",
              "uid": "8_73yRvHHtD4PpQXnxOAZ"
            },
            {
              "description": "Second active page has IDs4and5",
              "status": "pass",
              "uid": "mWe62ov5K3jZ49icgV4n_"
            },
            {
              "description": "Total is4active services",
              "status": "pass",
              "uid": "7mK_TzcjHRDXSecug0iFS"
            }
          ],
          "preRequestTestResults": [],
          "postResponseTestResults": [],
          "shouldStopRunnerExecution": false,
          "runDuration": 0.0702424,
          "name": "02 · Параметры и пагинация",
          "suitename": "scenarios/02-pagination",
          "path": "scenarios\\02-pagination",
          "iterationIndex": 0,
          "nativeStatus": "pass",
          "source": "scenarios/02-pagination.bru",
          "cliExitCode": 0
        },
        {
          "test": {
            "filename": "dataset\\pages.bru"
          },
          "request": {
            "method": "GET",
            "url": "http://127.0.0.1:8516/services?page=1&limit=2&active=true",
            "headers": {
              "Accept": "application/json, text/plain, */*",
              "User-Agent": "bruno-runtime/4.3.0",
              "Accept-Encoding": "gzip, compress, deflate, br",
              "Host": "127.0.0.1:8516",
              "Connection": "keep-alive",
              "content-type": null
            }
          },
          "response": {
            "status": 200,
            "statusText": "OK",
            "headers": {
              "content-type": "application/json; charset=utf-8",
              "cache-control": "no-store",
              "x-workshop": "Bruno",
              "date": "Fri, 13 Nov 2026 08:57:46 GMT",
              "connection": "keep-alive",
              "keep-alive": "timeout=5",
              "transfer-encoding": "chunked"
            },
            "data": {
              "items": [
                {
                  "id": 1,
                  "title": "Аудит интерфейса",
                  "active": true,
                  "price": 12000
                },
                {
                  "id": 2,
                  "title": "Настройка API",
                  "active": true,
                  "price": 18000
                }
              ],
              "page": 1,
              "limit": 2,
              "total": 4
            },
            "url": "http://127.0.0.1/services?page=1&limit=2&active=true",
            "responseTime": 6,
            "duration": 6,
            "size": 189
          },
          "error": null,
          "status": "pass",
          "assertionResults": [],
          "testResults": [
            {
              "description": "Dataset response is 200",
              "status": "pass",
              "uid": "ERJBXSdqXBVgRbgS-5v2C"
            },
            {
              "description": "IDs match this dataset row",
              "status": "pass",
              "uid": "kuKq9SmEAOqv8n7sI_Hv5"
            }
          ],
          "preRequestTestResults": [],
          "postResponseTestResults": [],
          "shouldStopRunnerExecution": false,
          "runDuration": 0.1381464,
          "name": "Пагинация из набора данных",
          "suitename": "dataset/pages",
          "path": "dataset\\pages",
          "iterationIndex": 0,
          "nativeStatus": "pass",
          "source": "dataset/pages.bru",
          "cliExitCode": 0
        },
        {
          "test": {
            "filename": "dataset\\pages.bru"
          },
          "request": {
            "method": "GET",
            "url": "http://127.0.0.1:8516/services?page=2&limit=2&active=true",
            "headers": {
              "Accept": "application/json, text/plain, */*",
              "User-Agent": "bruno-runtime/4.3.0",
              "Accept-Encoding": "gzip, compress, deflate, br",
              "Host": "127.0.0.1:8516",
              "Connection": "keep-alive",
              "content-type": null
            }
          },
          "response": {
            "status": 200,
            "statusText": "OK",
            "headers": {
              "content-type": "application/json; charset=utf-8",
              "cache-control": "no-store",
              "x-workshop": "Bruno",
              "date": "Fri, 13 Nov 2026 08:57:46 GMT",
              "connection": "keep-alive",
              "keep-alive": "timeout=5",
              "transfer-encoding": "chunked"
            },
            "data": {
              "items": [
                {
                  "id": 4,
                  "title": "Проверка отчётов",
                  "active": true,
                  "price": 7000
                },
                {
                  "id": 5,
                  "title": "Импорт каталога",
                  "active": true,
                  "price": 11000
                }
              ],
              "page": 2,
              "limit": 2,
              "total": 4
            },
            "url": "http://127.0.0.1/services?page=2&limit=2&active=true",
            "responseTime": 2,
            "duration": 2,
            "size": 195
          },
          "error": null,
          "status": "pass",
          "assertionResults": [],
          "testResults": [
            {
              "description": "Dataset response is 200",
              "status": "pass",
              "uid": "jD0B9lthqGg8M_aL3KjvZ"
            },
            {
              "description": "IDs match this dataset row",
              "status": "pass",
              "uid": "K_YBTfMqpzdjB6Koh8z-h"
            }
          ],
          "preRequestTestResults": [],
          "postResponseTestResults": [],
          "shouldStopRunnerExecution": false,
          "runDuration": 0.0600192,
          "name": "Пагинация из набора данных",
          "suitename": "dataset/pages",
          "path": "dataset\\pages",
          "iterationIndex": 1,
          "nativeStatus": "pass",
          "source": "dataset/pages.bru",
          "cliExitCode": 0
        },
        {
          "test": {
            "filename": "dataset\\pages.bru"
          },
          "request": {
            "method": "GET",
            "url": "http://127.0.0.1:8516/services?page=3&limit=2&active=true",
            "headers": {
              "Accept": "application/json, text/plain, */*",
              "User-Agent": "bruno-runtime/4.3.0",
              "Accept-Encoding": "gzip, compress, deflate, br",
              "Host": "127.0.0.1:8516",
              "Connection": "keep-alive",
              "content-type": null
            }
          },
          "response": {
            "status": 200,
            "statusText": "OK",
            "headers": {
              "content-type": "application/json; charset=utf-8",
              "cache-control": "no-store",
              "x-workshop": "Bruno",
              "date": "Fri, 13 Nov 2026 08:57:46 GMT",
              "connection": "keep-alive",
              "keep-alive": "timeout=5",
              "transfer-encoding": "chunked"
            },
            "data": {
              "items": [],
              "page": 3,
              "limit": 2,
              "total": 4
            },
            "url": "http://127.0.0.1/services?page=3&limit=2&active=true",
            "responseTime": 1,
            "duration": 1,
            "size": 41
          },
          "error": null,
          "status": "pass",
          "assertionResults": [],
          "testResults": [
            {
              "description": "Dataset response is 200",
              "status": "pass",
              "uid": "ZVBh9uSL7hbG1fK2y5AzR"
            },
            {
              "description": "IDs match this dataset row",
              "status": "pass",
              "uid": "nNEMPPK1auNMeRbopu5cV"
            }
          ],
          "preRequestTestResults": [],
          "postResponseTestResults": [],
          "shouldStopRunnerExecution": false,
          "runDuration": 0.0607459,
          "name": "Пагинация из набора данных",
          "suitename": "dataset/pages",
          "path": "dataset\\pages",
          "iterationIndex": 2,
          "nativeStatus": "pass",
          "source": "dataset/pages.bru",
          "cliExitCode": 0
        }
      ]
    },
    {
      "id": "create",
      "title": "3. Создать заявку из JSON",
      "use": "Проверить форму создания и серверный ответ.",
      "explain": "POST возвращает 201 и ID; post-response script сохраняет ID в runtime-переменную для следующего запроса.",
      "requests": [
        {
          "test": {
            "filename": "scenarios\\03-create.bru"
          },
          "request": {
            "method": "POST",
            "url": "http://127.0.0.1:8516/orders",
            "headers": {
              "Accept": "application/json, text/plain, */*",
              "User-Agent": "bruno-runtime/4.3.0",
              "Content-Length": "59",
              "Accept-Encoding": "gzip, compress, deflate, br",
              "Host": "127.0.0.1:8516",
              "Connection": "keep-alive",
              "content-type": "application/json"
            },
            "data": "{\"customer\":\"Учебная компания\",\"quantity\":3}"
          },
          "response": {
            "status": 201,
            "statusText": "Created",
            "headers": {
              "content-type": "application/json; charset=utf-8",
              "cache-control": "no-store",
              "x-workshop": "Bruno",
              "location": "/orders/100",
              "date": "Fri, 13 Nov 2026 08:57:43 GMT",
              "connection": "keep-alive",
              "keep-alive": "timeout=5",
              "transfer-encoding": "chunked"
            },
            "data": {
              "id": 100,
              "customer": "Учебная компания",
              "quantity": 3,
              "status": "draft",
              "fixture": true
            },
            "url": "http://127.0.0.1/orders",
            "responseTime": 3,
            "duration": 3,
            "size": 100
          },
          "error": null,
          "status": "pass",
          "assertionResults": [],
          "testResults": [
            {
              "description": "Create returns 201",
              "status": "pass",
              "uid": "UfrQlq37ysW_OGnHNoZGZ"
            },
            {
              "description": "ID saved for next request",
              "status": "pass",
              "uid": "CG6uP7HYygUSPBOfizSjk"
            },
            {
              "description": "Quantity is preserved",
              "status": "pass",
              "uid": "5k3f3j8D53NLPvws_tDXd"
            }
          ],
          "preRequestTestResults": [],
          "postResponseTestResults": [],
          "shouldStopRunnerExecution": false,
          "runDuration": 0.1389266,
          "name": "03 · Создать заявку из JSON",
          "suitename": "scenarios/03-create",
          "path": "scenarios\\03-create",
          "iterationIndex": 0,
          "nativeStatus": "pass",
          "source": "scenarios/03-create.bru",
          "cliExitCode": 0
        }
      ]
    },
    {
      "id": "chain",
      "title": "4. Цепочка по полученному ID",
      "use": "Сквозной сценарий создать→прочитать.",
      "explain": "Следующий запрос использует createdOrderId, а не захардкоженный номер. Проверяются тот же ID и состояние draft.",
      "requests": [
        {
          "test": {
            "filename": "scenarios\\04-read-created.bru"
          },
          "request": {
            "method": "GET",
            "url": "http://127.0.0.1:8516/orders/100",
            "headers": {
              "Accept": "application/json, text/plain, */*",
              "User-Agent": "bruno-runtime/4.3.0",
              "Accept-Encoding": "gzip, compress, deflate, br",
              "Host": "127.0.0.1:8516",
              "Connection": "keep-alive",
              "content-type": null
            }
          },
          "response": {
            "status": 200,
            "statusText": "OK",
            "headers": {
              "content-type": "application/json; charset=utf-8",
              "cache-control": "no-store",
              "x-workshop": "Bruno",
              "date": "Fri, 13 Nov 2026 08:57:43 GMT",
              "connection": "keep-alive",
              "keep-alive": "timeout=5",
              "transfer-encoding": "chunked"
            },
            "data": {
              "id": 100,
              "customer": "Учебная компания",
              "quantity": 3,
              "status": "draft",
              "fixture": true
            },
            "url": "http://127.0.0.1/orders/100",
            "responseTime": 1,
            "duration": 1,
            "size": 100
          },
          "error": null,
          "status": "pass",
          "assertionResults": [],
          "testResults": [
            {
              "description": "Created order can be read",
              "status": "pass",
              "uid": "ah-sIaCUtkMebaOPRkxOx"
            },
            {
              "description": "Read ID matches runtime variable",
              "status": "pass",
              "uid": "hvIawktscA0NNO2XgOyL1"
            },
            {
              "description": "Order remains a draft",
              "status": "pass",
              "uid": "94a7R66DULQ_1kHILiuYp"
            }
          ],
          "preRequestTestResults": [],
          "postResponseTestResults": [],
          "shouldStopRunnerExecution": false,
          "runDuration": 0.0610255,
          "name": "04 · Цепочка по ID из ответа",
          "suitename": "scenarios/04-read-created",
          "path": "scenarios\\04-read-created",
          "iterationIndex": 0,
          "nativeStatus": "pass",
          "source": "scenarios/04-read-created.bru",
          "cliExitCode": 0
        }
      ]
    },
    {
      "id": "validation",
      "title": "5. Ошибки полей 422",
      "use": "Форма должна показать понятные ошибки.",
      "explain": "Некорректный JSON-объект получает 422 с ошибками customer и quantity. Это ожидаемый ответ, поэтому тесты проходят.",
      "requests": [
        {
          "test": {
            "filename": "scenarios\\05-validation.bru"
          },
          "request": {
            "method": "POST",
            "url": "http://127.0.0.1:8516/orders",
            "headers": {
              "Accept": "application/json, text/plain, */*",
              "User-Agent": "bruno-runtime/4.3.0",
              "Content-Length": "28",
              "Accept-Encoding": "gzip, compress, deflate, br",
              "Host": "127.0.0.1:8516",
              "Connection": "keep-alive",
              "content-type": "application/json"
            },
            "data": "{\"customer\":\"\",\"quantity\":0}"
          },
          "response": {
            "status": 422,
            "statusText": "Unprocessable Entity",
            "headers": {
              "content-type": "application/json; charset=utf-8",
              "cache-control": "no-store",
              "x-workshop": "Bruno",
              "date": "Fri, 13 Nov 2026 08:57:43 GMT",
              "connection": "keep-alive",
              "keep-alive": "timeout=5",
              "transfer-encoding": "chunked"
            },
            "data": {
              "error": "validation",
              "fields": {
                "customer": "Укажите имя от 2 до 80 символов",
                "quantity": "Количество от 1 до 10"
              }
            },
            "url": "http://127.0.0.1/orders",
            "responseTime": 2,
            "duration": 2,
            "size": 149
          },
          "error": null,
          "status": "pass",
          "assertionResults": [],
          "testResults": [
            {
              "description": "Invalid input returns422",
              "status": "pass",
              "uid": "7OnnMGFGO8PYe7gqS1Vsd"
            },
            {
              "description": "Customer error is useful",
              "status": "pass",
              "uid": "gNsF_Zj9ZhLKezomTQlOI"
            },
            {
              "description": "Quantity error is present",
              "status": "pass",
              "uid": "cqI5aQX2UQ4tIZzqg6Gso"
            }
          ],
          "preRequestTestResults": [],
          "postResponseTestResults": [],
          "shouldStopRunnerExecution": false,
          "runDuration": 0.0546344,
          "name": "05 · Ошибки полей422",
          "suitename": "scenarios/05-validation",
          "path": "scenarios\\05-validation",
          "iterationIndex": 0,
          "nativeStatus": "pass",
          "source": "scenarios/05-validation.bru",
          "cliExitCode": 0
        }
      ]
    },
    {
      "id": "auth",
      "title": "6. Учебная авторизация",
      "use": "Проверить закрытый endpoint и передачу Bearer.",
      "explain": "Три запроса: без токена 401, получение учебной сессии, запрос с runtime-токеном 200. Это фиксированная фикстура, не production login.",
      "requests": [
        {
          "test": {
            "filename": "scenarios\\06a-unauthorized.bru"
          },
          "request": {
            "method": "GET",
            "url": "http://127.0.0.1:8516/private",
            "headers": {
              "Accept": "application/json, text/plain, */*",
              "User-Agent": "bruno-runtime/4.3.0",
              "Accept-Encoding": "gzip, compress, deflate, br",
              "Host": "127.0.0.1:8516",
              "Connection": "keep-alive",
              "content-type": null
            }
          },
          "response": {
            "status": 401,
            "statusText": "Unauthorized",
            "headers": {
              "content-type": "application/json; charset=utf-8",
              "cache-control": "no-store",
              "x-workshop": "Bruno",
              "www-authenticate": "********",
              "date": "Fri, 13 Nov 2026 08:57:43 GMT",
              "connection": "keep-alive",
              "keep-alive": "timeout=5",
              "transfer-encoding": "chunked"
            },
            "data": {
              "error": "unauthorized"
            },
            "url": "http://127.0.0.1/private",
            "responseTime": 1,
            "duration": 1,
            "size": 24
          },
          "error": null,
          "status": "pass",
          "assertionResults": [],
          "testResults": [
            {
              "description": "Protected endpoint refuses missing token",
              "status": "pass",
              "uid": "Xb5N9lN_N-OgEfaq0_gWD"
            },
            {
              "description": "Authentication error is explicit",
              "status": "pass",
              "uid": "7qPF9T6xPPF_hDFl0T8Fn"
            }
          ],
          "preRequestTestResults": [],
          "postResponseTestResults": [],
          "shouldStopRunnerExecution": false,
          "runDuration": 0.0685797,
          "name": "06a · Нет токена401",
          "suitename": "scenarios/06a-unauthorized",
          "path": "scenarios\\06a-unauthorized",
          "iterationIndex": 0,
          "nativeStatus": "pass",
          "source": "scenarios/06a-unauthorized.bru",
          "cliExitCode": 0
        },
        {
          "test": {
            "filename": "scenarios\\06b-demo-session.bru"
          },
          "request": {
            "method": "POST",
            "url": "http://127.0.0.1:8516/session",
            "headers": {
              "Accept": "application/json, text/plain, */*",
              "User-Agent": "bruno-runtime/4.3.0",
              "Content-Length": "46",
              "Accept-Encoding": "gzip, compress, deflate, br",
              "Host": "127.0.0.1:8516",
              "Connection": "keep-alive",
              "content-type": "application/json"
            },
            "data": "{\"username\":\"demo\",\"password\":\"workshop-only\"}"
          },
          "response": {
            "status": 200,
            "statusText": "OK",
            "headers": {
              "content-type": "application/json; charset=utf-8",
              "cache-control": "no-store",
              "x-workshop": "Bruno",
              "date": "Fri, 13 Nov 2026 08:57:43 GMT",
              "connection": "keep-alive",
              "keep-alive": "timeout=5",
              "transfer-encoding": "chunked"
            },
            "data": {
              "accessToken": "aen-demo-token-not-a-secret",
              "tokenType": "Bearer",
              "scope": "demo:read",
              "fixture": true
            },
            "url": "http://127.0.0.1/session",
            "responseTime": 1,
            "duration": 1,
            "size": 101
          },
          "error": null,
          "status": "pass",
          "assertionResults": [],
          "testResults": [
            {
              "description": "Demo session returns200",
              "status": "pass",
              "uid": "v6yklj0WxQbL_PKbxctCY"
            },
            {
              "description": "Runtime demo token exists",
              "status": "pass",
              "uid": "73v0YUwffr2VW0M2R8t2o"
            }
          ],
          "preRequestTestResults": [],
          "postResponseTestResults": [],
          "shouldStopRunnerExecution": false,
          "runDuration": 0.1095389,
          "name": "06b · Учебная сессия",
          "suitename": "scenarios/06b-demo-session",
          "path": "scenarios\\06b-demo-session",
          "iterationIndex": 0,
          "nativeStatus": "pass",
          "source": "scenarios/06b-demo-session.bru",
          "cliExitCode": 0
        },
        {
          "test": {
            "filename": "scenarios\\06c-authorized.bru"
          },
          "request": {
            "method": "GET",
            "url": "http://127.0.0.1:8516/private",
            "headers": {
              "Accept": "application/json, text/plain, */*",
              "User-Agent": "bruno-runtime/4.3.0",
              "Accept-Encoding": "gzip, compress, deflate, br",
              "Host": "127.0.0.1:8516",
              "Connection": "keep-alive",
              "Authorization": "Bearer ********",
              "content-type": null
            }
          },
          "response": {
            "status": 200,
            "statusText": "OK",
            "headers": {
              "content-type": "application/json; charset=utf-8",
              "cache-control": "no-store",
              "x-workshop": "Bruno",
              "date": "Fri, 13 Nov 2026 08:57:43 GMT",
              "connection": "keep-alive",
              "keep-alive": "timeout=5",
              "transfer-encoding": "chunked"
            },
            "data": {
              "user": "demo",
              "permissions": [
                "demo:read"
              ],
              "fixture": true
            },
            "url": "http://127.0.0.1/private",
            "responseTime": 1,
            "duration": 1,
            "size": 58
          },
          "error": null,
          "status": "pass",
          "assertionResults": [],
          "testResults": [
            {
              "description": "Demo Bearer opens endpoint",
              "status": "pass",
              "uid": "Prl1_wMWHKNkSwt_sK0sJ"
            },
            {
              "description": "Permission matches demo scope",
              "status": "pass",
              "uid": "dNkCJ1NavVupjxKj-W7ru"
            }
          ],
          "preRequestTestResults": [],
          "postResponseTestResults": [],
          "shouldStopRunnerExecution": false,
          "runDuration": 0.0621028,
          "name": "06c · Bearer из предыдущего ответа",
          "suitename": "scenarios/06c-authorized",
          "path": "scenarios\\06c-authorized",
          "iterationIndex": 0,
          "nativeStatus": "pass",
          "source": "scenarios/06c-authorized.bru",
          "cliExitCode": 0
        }
      ]
    },
    {
      "id": "limit",
      "title": "7. Ограничение 429 и Retry-After",
      "use": "Клиент узнаёт, когда повторять запрос.",
      "explain": "Endpoint намеренно всегда отдаёт 429 и Retry-After: 2. Опыт проверяет контракт ошибки; автоматический retry здесь не выполняется.",
      "requests": [
        {
          "test": {
            "filename": "scenarios\\07-rate-limit.bru"
          },
          "request": {
            "method": "GET",
            "url": "http://127.0.0.1:8516/rate-limited",
            "headers": {
              "Accept": "application/json, text/plain, */*",
              "User-Agent": "bruno-runtime/4.3.0",
              "Accept-Encoding": "gzip, compress, deflate, br",
              "Host": "127.0.0.1:8516",
              "Connection": "keep-alive",
              "content-type": null
            }
          },
          "response": {
            "status": 429,
            "statusText": "Too Many Requests",
            "headers": {
              "content-type": "application/json; charset=utf-8",
              "cache-control": "no-store",
              "x-workshop": "Bruno",
              "retry-after": "2",
              "date": "Fri, 13 Nov 2026 08:57:43 GMT",
              "connection": "keep-alive",
              "keep-alive": "timeout=5",
              "transfer-encoding": "chunked"
            },
            "data": {
              "error": "rate_limit",
              "retryAfterSeconds": 2,
              "fixture": true
            },
            "url": "http://127.0.0.1/rate-limited",
            "responseTime": 1,
            "duration": 1,
            "size": 59
          },
          "error": null,
          "status": "pass",
          "assertionResults": [],
          "testResults": [
            {
              "description": "Rate limited response is429",
              "status": "pass",
              "uid": "L5zBFGB83ohqAa28uSuBP"
            },
            {
              "description": "Retry-After is two seconds",
              "status": "pass",
              "uid": "JZaLrUAFBeNcxOmLAwW2L"
            },
            {
              "description": "Error is machine readable",
              "status": "pass",
              "uid": "BklPmteWG-ZHdJrMyFNRl"
            }
          ],
          "preRequestTestResults": [],
          "postResponseTestResults": [],
          "shouldStopRunnerExecution": false,
          "runDuration": 0.0608742,
          "name": "07 · Rate limit и Retry-After",
          "suitename": "scenarios/07-rate-limit",
          "path": "scenarios\\07-rate-limit",
          "iterationIndex": 0,
          "nativeStatus": "pass",
          "source": "scenarios/07-rate-limit.bru",
          "cliExitCode": 0
        }
      ]
    },
    {
      "id": "failure",
      "title": "8. HTTP 200 при упавшем тесте",
      "use": "Остановить CI при неверном бизнес-результате.",
      "explain": "Сервер отдаёт total 42. Намеренно неверное ожидание 99 проваливает Bruno CLI с кодом 1; исправленный тест проходит.",
      "requests": [
        {
          "test": {
            "filename": "failure\\08-contract-broken.bru"
          },
          "request": {
            "method": "GET",
            "url": "http://127.0.0.1:8516/contract",
            "headers": {
              "Accept": "application/json, text/plain, */*",
              "User-Agent": "bruno-runtime/4.3.0",
              "Accept-Encoding": "gzip, compress, deflate, br",
              "Host": "127.0.0.1:8516",
              "Connection": "keep-alive",
              "content-type": null
            }
          },
          "response": {
            "status": 200,
            "statusText": "OK",
            "headers": {
              "content-type": "application/json; charset=utf-8",
              "cache-control": "no-store",
              "x-workshop": "Bruno",
              "date": "Fri, 13 Nov 2026 08:57:44 GMT",
              "connection": "keep-alive",
              "keep-alive": "timeout=5",
              "transfer-encoding": "chunked"
            },
            "data": {
              "status": "ready",
              "total": 42,
              "fixture": true
            },
            "url": "http://127.0.0.1/contract",
            "responseTime": 6,
            "duration": 6,
            "size": 44
          },
          "error": null,
          "status": "fail",
          "assertionResults": [],
          "testResults": [
            {
              "description": "Deliberately wrong total99",
              "status": "fail",
              "error": "expected 42 to equal 99",
              "uid": "RIhnkmqBiIMemyrPAbiAb"
            },
            {
              "description": "Contract still returns200",
              "status": "pass",
              "uid": "s2uHKuYB6soGHM52yeWTS"
            }
          ],
          "preRequestTestResults": [],
          "postResponseTestResults": [],
          "shouldStopRunnerExecution": false,
          "runDuration": 0.1523744,
          "name": "08 · Намеренно неверное ожидание",
          "suitename": "failure/08-contract-broken",
          "path": "failure\\08-contract-broken",
          "iterationIndex": 0,
          "nativeStatus": "pass",
          "source": "failure/08-contract-broken.bru",
          "cliExitCode": 1
        },
        {
          "test": {
            "filename": "scenarios\\08-contract-fixed.bru"
          },
          "request": {
            "method": "GET",
            "url": "http://127.0.0.1:8516/contract",
            "headers": {
              "Accept": "application/json, text/plain, */*",
              "User-Agent": "bruno-runtime/4.3.0",
              "Accept-Encoding": "gzip, compress, deflate, br",
              "Host": "127.0.0.1:8516",
              "Connection": "keep-alive",
              "content-type": null
            }
          },
          "response": {
            "status": 200,
            "statusText": "OK",
            "headers": {
              "content-type": "application/json; charset=utf-8",
              "cache-control": "no-store",
              "x-workshop": "Bruno",
              "date": "Fri, 13 Nov 2026 08:57:43 GMT",
              "connection": "keep-alive",
              "keep-alive": "timeout=5",
              "transfer-encoding": "chunked"
            },
            "data": {
              "status": "ready",
              "total": 42,
              "fixture": true
            },
            "url": "http://127.0.0.1/contract",
            "responseTime": 1,
            "duration": 1,
            "size": 44
          },
          "error": null,
          "status": "pass",
          "assertionResults": [],
          "testResults": [
            {
              "description": "Contract returns200",
              "status": "pass",
              "uid": "Vk2pVmuiJQ1-64F0-hID_"
            },
            {
              "description": "Total matches agreed contract",
              "status": "pass",
              "uid": "4RxzFebnb-6HGIMVgQFM_"
            }
          ],
          "preRequestTestResults": [],
          "postResponseTestResults": [],
          "shouldStopRunnerExecution": false,
          "runDuration": 0.0609643,
          "name": "08 · Исправленная проверка контракта",
          "suitename": "scenarios/08-contract-fixed",
          "path": "scenarios\\08-contract-fixed",
          "iterationIndex": 0,
          "nativeStatus": "pass",
          "source": "scenarios/08-contract-fixed.bru",
          "cliExitCode": 0
        }
      ]
    }
  ]
}
