dd-trace 6.15.0 → 6.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (378) hide show
  1. package/README.md +15 -0
  2. package/ci/diagnose.js +0 -23
  3. package/ci/test-optimization-validation/approval-artifacts.js +0 -3
  4. package/ci/test-optimization-validation/approval.js +0 -6
  5. package/ci/test-optimization-validation/artifact-id.js +0 -1
  6. package/ci/test-optimization-validation/bounded-json.js +0 -1
  7. package/ci/test-optimization-validation/cli.js +0 -12
  8. package/ci/test-optimization-validation/command-output-policy.js +0 -1
  9. package/ci/test-optimization-validation/command-runner.js +0 -3
  10. package/ci/test-optimization-validation/environment.js +0 -4
  11. package/ci/test-optimization-validation/executable-approval.js +0 -1
  12. package/ci/test-optimization-validation/executable.js +0 -5
  13. package/ci/test-optimization-validation/framework-adapters/cucumber.js +4 -8
  14. package/ci/test-optimization-validation/framework-adapters/cypress.js +0 -3
  15. package/ci/test-optimization-validation/framework-adapters/playwright.js +0 -6
  16. package/ci/test-optimization-validation/framework-adapters/vitest.js +0 -4
  17. package/ci/test-optimization-validation/generated-test-contract.js +0 -5
  18. package/ci/test-optimization-validation/generated-verifier.js +0 -1
  19. package/ci/test-optimization-validation/literal-environment.js +0 -1
  20. package/ci/test-optimization-validation/manifest-scaffold.js +0 -17
  21. package/ci/test-optimization-validation/manifest-schema.js +0 -21
  22. package/ci/test-optimization-validation/offline-fixtures.js +0 -4
  23. package/ci/test-optimization-validation/package-check.js +4 -1
  24. package/ci/test-optimization-validation/plan-writer.js +0 -11
  25. package/ci/test-optimization-validation/preflight-runner.js +0 -1
  26. package/ci/test-optimization-validation/redaction.js +0 -4
  27. package/ci/test-optimization-validation/report-writer.js +0 -16
  28. package/ci/test-optimization-validation/runner-command.js +0 -3
  29. package/ci/test-optimization-validation/runner-contract.js +0 -4
  30. package/ci/test-optimization-validation/safe-files.js +0 -1
  31. package/ci/test-optimization-validation/scenarios/basic-reporting.js +0 -1
  32. package/ci/test-optimization-validation/scenarios/ci-wiring.js +1 -2
  33. package/ci/test-optimization-validation/source-text.js +0 -3
  34. package/ci/vitest-no-worker-init-setup.mjs +41 -16
  35. package/index.d.ts +169 -0
  36. package/next.d.ts +27 -0
  37. package/next.js +3 -0
  38. package/package.json +28 -23
  39. package/packages/datadog-esbuild/index.js +14 -1
  40. package/packages/datadog-esbuild/src/resolver.js +284 -0
  41. package/packages/datadog-esbuild/src/utils.js +162 -120
  42. package/packages/datadog-instrumentations/src/aerospike.js +28 -6
  43. package/packages/datadog-instrumentations/src/ai.js +39 -97
  44. package/packages/datadog-instrumentations/src/anthropic.js +76 -134
  45. package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +1 -3
  46. package/packages/datadog-instrumentations/src/aws-sdk.js +0 -2
  47. package/packages/datadog-instrumentations/src/azure-cosmos.js +1 -1
  48. package/packages/datadog-instrumentations/src/azure-durable-functions.js +23 -9
  49. package/packages/datadog-instrumentations/src/azure-functions.js +48 -0
  50. package/packages/datadog-instrumentations/src/bullmq.js +1 -1
  51. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +1 -3
  52. package/packages/datadog-instrumentations/src/console.js +97 -0
  53. package/packages/datadog-instrumentations/src/cucumber.js +72 -12
  54. package/packages/datadog-instrumentations/src/cypress-config.js +0 -23
  55. package/packages/datadog-instrumentations/src/dd-trace-api.js +2 -2
  56. package/packages/datadog-instrumentations/src/graphql.js +1 -1
  57. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +39 -14
  58. package/packages/datadog-instrumentations/src/helpers/channel.js +0 -2
  59. package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +0 -5
  60. package/packages/datadog-instrumentations/src/helpers/hooks.js +8 -0
  61. package/packages/datadog-instrumentations/src/helpers/instrument.js +25 -8
  62. package/packages/datadog-instrumentations/src/helpers/instrumentation-utils.js +69 -0
  63. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +0 -6
  64. package/packages/datadog-instrumentations/src/helpers/register.js +13 -64
  65. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +109 -29
  66. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +39 -0
  67. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-durable-functions.js +17 -0
  68. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +3 -16
  69. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +12 -0
  70. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/postgres.js +36 -0
  71. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/supabase.js +128 -0
  72. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +6 -7
  73. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +17 -0
  74. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms/postgres.js +388 -0
  75. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +99 -75
  76. package/packages/datadog-instrumentations/src/helpers/router-helper.js +0 -1
  77. package/packages/datadog-instrumentations/src/jest.js +141 -51
  78. package/packages/datadog-instrumentations/src/knex.js +0 -1
  79. package/packages/datadog-instrumentations/src/langchain.js +1 -1
  80. package/packages/datadog-instrumentations/src/langgraph.js +1 -1
  81. package/packages/datadog-instrumentations/src/mariadb-bundle.js +0 -24
  82. package/packages/datadog-instrumentations/src/mariadb.js +0 -2
  83. package/packages/datadog-instrumentations/src/mercurius.js +1 -1
  84. package/packages/datadog-instrumentations/src/mocha/common.js +0 -1
  85. package/packages/datadog-instrumentations/src/mocha/main.js +22 -25
  86. package/packages/datadog-instrumentations/src/mocha/utils.js +119 -49
  87. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +0 -6
  88. package/packages/datadog-instrumentations/src/mocha/worker.js +14 -17
  89. package/packages/datadog-instrumentations/src/modelcontextprotocol-sdk.js +1 -1
  90. package/packages/datadog-instrumentations/src/mysql2.js +0 -2
  91. package/packages/datadog-instrumentations/src/openai-agents.js +1 -1
  92. package/packages/datadog-instrumentations/src/openai-realtime/audio-accumulator.js +241 -0
  93. package/packages/datadog-instrumentations/src/openai-realtime/events.js +76 -0
  94. package/packages/datadog-instrumentations/src/openai-realtime/index.js +301 -0
  95. package/packages/datadog-instrumentations/src/openai-realtime/session.js +998 -0
  96. package/packages/datadog-instrumentations/src/openai-realtime/turns.js +211 -0
  97. package/packages/datadog-instrumentations/src/openai.js +97 -80
  98. package/packages/datadog-instrumentations/src/oracledb.js +9 -3
  99. package/packages/datadog-instrumentations/src/playwright-reporter.js +3 -16
  100. package/packages/datadog-instrumentations/src/playwright.js +238 -55
  101. package/packages/datadog-instrumentations/src/postgres.js +7 -0
  102. package/packages/datadog-instrumentations/src/router.js +0 -2
  103. package/packages/datadog-instrumentations/src/rum-browser-scripts.js +0 -2
  104. package/packages/datadog-instrumentations/src/sequelize.js +0 -1
  105. package/packages/datadog-instrumentations/src/supabase.js +15 -0
  106. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +18 -18
  107. package/packages/datadog-instrumentations/src/vitest-main.js +37 -17
  108. package/packages/datadog-instrumentations/src/vitest-util.js +7 -1
  109. package/packages/datadog-instrumentations/src/vitest-worker.js +56 -23
  110. package/packages/datadog-instrumentations/src/webdriverio.js +23 -42
  111. package/packages/datadog-instrumentations/src/ws.js +0 -1
  112. package/packages/datadog-plugin-ai/src/utils.js +0 -2
  113. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +0 -1
  114. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +0 -2
  115. package/packages/datadog-plugin-aws-sdk/src/base.js +0 -1
  116. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +7 -2
  117. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +0 -1
  118. package/packages/datadog-plugin-aws-sdk/src/util.js +0 -1
  119. package/packages/datadog-plugin-azure-cosmos/src/index.js +1 -1
  120. package/packages/datadog-plugin-azure-durable-functions/src/index.js +95 -1
  121. package/packages/datadog-plugin-cucumber/src/index.js +10 -0
  122. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +171 -75
  123. package/packages/datadog-plugin-cypress/src/finalization.js +0 -3
  124. package/packages/datadog-plugin-cypress/src/source-map-utils.js +0 -4
  125. package/packages/datadog-plugin-cypress/src/support.js +52 -7
  126. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -24
  127. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +2 -36
  128. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-request-context.js +31 -0
  129. package/packages/datadog-plugin-graphql/src/resolve-error.js +32 -11
  130. package/packages/datadog-plugin-graphql/src/utils.js +0 -5
  131. package/packages/datadog-plugin-jest/src/index.js +13 -0
  132. package/packages/datadog-plugin-kafkajs/src/producer.js +0 -1
  133. package/packages/datadog-plugin-mocha/src/index.js +39 -11
  134. package/packages/datadog-plugin-mongodb-core/src/query.js +0 -1
  135. package/packages/datadog-plugin-openai/src/index.js +16 -1
  136. package/packages/datadog-plugin-openai/src/realtime.js +144 -0
  137. package/packages/datadog-plugin-openai-agents/src/integration.js +0 -4
  138. package/packages/datadog-plugin-openai-agents/src/util.js +0 -1
  139. package/packages/datadog-plugin-playwright/src/index.js +76 -9
  140. package/packages/datadog-plugin-postgres/src/index.js +167 -0
  141. package/packages/datadog-plugin-prisma/src/datadog-tracing-helper.js +0 -1
  142. package/packages/datadog-plugin-redis/src/index.js +15 -1
  143. package/packages/datadog-plugin-supabase/src/error.js +18 -0
  144. package/packages/datadog-plugin-supabase/src/index.js +21 -0
  145. package/packages/datadog-plugin-supabase/src/supabase-auth-js-gotrueclient-getuser.js +69 -0
  146. package/packages/datadog-plugin-supabase/src/supabase-functions-js-functionsclient-invoke.js +70 -0
  147. package/packages/datadog-plugin-supabase/src/supabase-postgrest-js-postgrestbuilder-then.js +122 -0
  148. package/packages/datadog-plugin-supabase/src/supabase-realtime-js-realtimechannel-send.js +66 -0
  149. package/packages/datadog-plugin-supabase/src/supabase-storage-js-handle-request.js +93 -0
  150. package/packages/datadog-plugin-supabase/src/url.js +17 -0
  151. package/packages/datadog-plugin-vitest/src/index.js +10 -0
  152. package/packages/datadog-plugin-ws/src/util.js +0 -4
  153. package/packages/datadog-turbopack/index.js +206 -0
  154. package/packages/datadog-turbopack/src/constants.js +5 -0
  155. package/packages/datadog-turbopack/src/loader.js +484 -0
  156. package/packages/datadog-webpack/src/loader.js +0 -1
  157. package/packages/dd-trace/src/aiguard/client.js +2 -3
  158. package/packages/dd-trace/src/aiguard/evaluation.js +6 -12
  159. package/packages/dd-trace/src/aiguard/index.js +3 -2
  160. package/packages/dd-trace/src/aiguard/integrations/anthropic.js +53 -25
  161. package/packages/dd-trace/src/aiguard/integrations/evaluate.js +49 -25
  162. package/packages/dd-trace/src/aiguard/integrations/index.js +4 -3
  163. package/packages/dd-trace/src/aiguard/integrations/openai.js +132 -29
  164. package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +116 -42
  165. package/packages/dd-trace/src/aiguard/messages/anthropic.js +0 -2
  166. package/packages/dd-trace/src/aiguard/messages/openai.js +64 -1
  167. package/packages/dd-trace/src/aiguard/messages/utils.js +29 -2
  168. package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +25 -0
  169. package/packages/dd-trace/src/aiguard/redaction.js +0 -1
  170. package/packages/dd-trace/src/aiguard/sdk.js +1 -1
  171. package/packages/dd-trace/src/appsec/activation.js +1 -1
  172. package/packages/dd-trace/src/appsec/api_security/normalized-route.js +0 -5
  173. package/packages/dd-trace/src/appsec/api_security/sampler.js +0 -4
  174. package/packages/dd-trace/src/appsec/blocking/index.js +3 -3
  175. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -4
  176. package/packages/dd-trace/src/appsec/iast/index.js +1 -1
  177. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +5 -5
  178. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +1 -1
  179. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
  180. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +3 -3
  181. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +8 -10
  182. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +2 -2
  183. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -2
  184. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +4 -1
  185. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +7 -7
  186. package/packages/dd-trace/src/appsec/index.js +2 -2
  187. package/packages/dd-trace/src/appsec/lambda.js +71 -2
  188. package/packages/dd-trace/src/appsec/rasp/utils.js +5 -1
  189. package/packages/dd-trace/src/appsec/remote_config.js +8 -6
  190. package/packages/dd-trace/src/appsec/reporter.js +10 -6
  191. package/packages/dd-trace/src/appsec/rule_manager.js +3 -3
  192. package/packages/dd-trace/src/appsec/sdk/track_event.js +0 -2
  193. package/packages/dd-trace/src/appsec/telemetry/api_security.js +1 -3
  194. package/packages/dd-trace/src/appsec/telemetry/common.js +4 -0
  195. package/packages/dd-trace/src/appsec/telemetry/index.js +23 -5
  196. package/packages/dd-trace/src/appsec/telemetry/rasp.js +1 -20
  197. package/packages/dd-trace/src/appsec/telemetry/user.js +1 -3
  198. package/packages/dd-trace/src/appsec/telemetry/waf.js +1 -20
  199. package/packages/dd-trace/src/appsec/waf/index.js +2 -2
  200. package/packages/dd-trace/src/appsec/waf/waf_manager.js +8 -5
  201. package/packages/dd-trace/src/carrier.js +0 -5
  202. package/packages/dd-trace/src/ci-visibility/dynamic-atr-retries.js +104 -0
  203. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +0 -2
  204. package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +34 -3
  205. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +0 -1
  206. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +0 -1
  207. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +0 -1
  208. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +0 -4
  209. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +0 -1
  210. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +0 -2
  211. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +37 -15
  212. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +0 -3
  213. package/packages/dd-trace/src/ci-visibility/exporters/request.js +0 -11
  214. package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +0 -1
  215. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +0 -1
  216. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +0 -6
  217. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +2 -2
  218. package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +0 -1
  219. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +0 -5
  220. package/packages/dd-trace/src/ci-visibility/requests/video-request.js +0 -1
  221. package/packages/dd-trace/src/ci-visibility/telemetry.js +13 -0
  222. package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +0 -1
  223. package/packages/dd-trace/src/ci-visibility/test-screenshot.js +0 -2
  224. package/packages/dd-trace/src/ci-visibility/test-video.js +0 -1
  225. package/packages/dd-trace/src/config/defaults.js +3 -2
  226. package/packages/dd-trace/src/config/generated-config-types.d.ts +74 -66
  227. package/packages/dd-trace/src/config/helper.js +9 -2
  228. package/packages/dd-trace/src/config/index.js +44 -29
  229. package/packages/dd-trace/src/config/parsers.js +34 -6
  230. package/packages/dd-trace/src/config/remote_config.js +25 -109
  231. package/packages/dd-trace/src/config/supported-configurations.json +146 -9
  232. package/packages/dd-trace/src/datastreams/encoding.js +0 -1
  233. package/packages/dd-trace/src/datastreams/pathway.js +0 -1
  234. package/packages/dd-trace/src/debugger/constants.js +10 -0
  235. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +76 -17
  236. package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -0
  237. package/packages/dd-trace/src/debugger/devtools_client/guardrail-metrics.js +15 -0
  238. package/packages/dd-trace/src/debugger/devtools_client/index.js +103 -27
  239. package/packages/dd-trace/src/debugger/devtools_client/json-buffer.js +50 -7
  240. package/packages/dd-trace/src/debugger/devtools_client/log.js +3 -1
  241. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +34 -8
  242. package/packages/dd-trace/src/debugger/devtools_client/send.js +40 -14
  243. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +53 -13
  244. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +118 -71
  245. package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +0 -3
  246. package/packages/dd-trace/src/debugger/devtools_client/status.js +20 -6
  247. package/packages/dd-trace/src/debugger/guardrail-metrics.js +167 -0
  248. package/packages/dd-trace/src/debugger/index.js +50 -2
  249. package/packages/dd-trace/src/debugger/inspect-segment.js +0 -3
  250. package/packages/dd-trace/src/debugger/probe_sampler.js +133 -9
  251. package/packages/dd-trace/src/debugger/probe_sampler_constants.js +31 -1
  252. package/packages/dd-trace/src/dogstatsd.js +0 -23
  253. package/packages/dd-trace/src/encode/0.4-cross-payload.js +0 -3
  254. package/packages/dd-trace/src/encode/0.4.js +0 -7
  255. package/packages/dd-trace/src/encode/0.5.js +0 -2
  256. package/packages/dd-trace/src/encode/tags-processors.js +0 -1
  257. package/packages/dd-trace/src/evp_proxy/discovery.js +3 -5
  258. package/packages/dd-trace/src/evp_proxy/path.js +11 -4
  259. package/packages/dd-trace/src/exporters/agent/writer.js +0 -1
  260. package/packages/dd-trace/src/exporters/agentless/index.js +0 -1
  261. package/packages/dd-trace/src/exporters/agentless/intake.js +0 -1
  262. package/packages/dd-trace/src/exporters/agentless/writer.js +0 -3
  263. package/packages/dd-trace/src/exporters/common/docker.js +4 -1
  264. package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +0 -6
  265. package/packages/dd-trace/src/exporters/common/proxy.js +3 -0
  266. package/packages/dd-trace/src/exporters/common/request.js +1 -0
  267. package/packages/dd-trace/src/exporters/common/url.js +0 -2
  268. package/packages/dd-trace/src/exporters/common/writer.js +0 -2
  269. package/packages/dd-trace/src/id.js +0 -11
  270. package/packages/dd-trace/src/llmobs/audio-codec.js +192 -0
  271. package/packages/dd-trace/src/llmobs/audio-utils.js +121 -0
  272. package/packages/dd-trace/src/llmobs/constants/audio.js +35 -0
  273. package/packages/dd-trace/src/llmobs/constants/prompts.js +14 -0
  274. package/packages/dd-trace/src/llmobs/constants/tags.js +17 -0
  275. package/packages/dd-trace/src/llmobs/eval-metric.js +0 -6
  276. package/packages/dd-trace/src/llmobs/experiments/dataset.js +0 -4
  277. package/packages/dd-trace/src/llmobs/experiments/experiment.js +0 -3
  278. package/packages/dd-trace/src/llmobs/experiments/index.js +7 -6
  279. package/packages/dd-trace/src/llmobs/experiments/util.js +1 -11
  280. package/packages/dd-trace/src/llmobs/index.js +1 -3
  281. package/packages/dd-trace/src/llmobs/noop.js +10 -0
  282. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +0 -4
  283. package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +0 -1
  284. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +0 -4
  285. package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/utils.js +0 -2
  286. package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +0 -2
  287. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +4 -6
  288. package/packages/dd-trace/src/llmobs/plugins/openai/realtime.js +285 -0
  289. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +16 -3
  290. package/packages/dd-trace/src/llmobs/prompts/cache.js +272 -0
  291. package/packages/dd-trace/src/llmobs/prompts/manager.js +639 -0
  292. package/packages/dd-trace/src/llmobs/prompts/noop.js +29 -0
  293. package/packages/dd-trace/src/llmobs/prompts/prompt.js +92 -0
  294. package/packages/dd-trace/src/llmobs/sdk.js +21 -6
  295. package/packages/dd-trace/src/llmobs/span_processor.js +81 -2
  296. package/packages/dd-trace/src/llmobs/tagger.js +30 -7
  297. package/packages/dd-trace/src/llmobs/telemetry.js +36 -4
  298. package/packages/dd-trace/src/llmobs/util.js +0 -34
  299. package/packages/dd-trace/src/llmobs/writers/base.js +0 -1
  300. package/packages/dd-trace/src/llmobs/writers/util.js +1 -2
  301. package/packages/dd-trace/src/log/channels.js +3 -0
  302. package/packages/dd-trace/src/log/index.js +23 -5
  303. package/packages/dd-trace/src/log-submission/log-submission-plugin.js +74 -6
  304. package/packages/dd-trace/src/msgpack/chunk.js +0 -1
  305. package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +0 -12
  306. package/packages/dd-trace/src/openfeature/encoding.js +0 -2
  307. package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +0 -1
  308. package/packages/dd-trace/src/openfeature/index.js +0 -4
  309. package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +0 -1
  310. package/packages/dd-trace/src/openfeature/span-enrichment.js +0 -4
  311. package/packages/dd-trace/src/openfeature/writers/base.js +0 -6
  312. package/packages/dd-trace/src/openfeature/writers/exposures.js +0 -5
  313. package/packages/dd-trace/src/openfeature/writers/util.js +0 -4
  314. package/packages/dd-trace/src/opentelemetry/logs/logger.js +0 -1
  315. package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +0 -1
  316. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +0 -1
  317. package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +0 -2
  318. package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
  319. package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +4 -4
  320. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +0 -1
  321. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +0 -1
  322. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +103 -35
  323. package/packages/dd-trace/src/opentelemetry/metrics/time.js +0 -1
  324. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +36 -13
  325. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +0 -1
  326. package/packages/dd-trace/src/opentelemetry/span-helpers.js +0 -1
  327. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +0 -1
  328. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +0 -3
  329. package/packages/dd-trace/src/opentracing/propagation/text_map.js +0 -6
  330. package/packages/dd-trace/src/opentracing/span_context.js +0 -1
  331. package/packages/dd-trace/src/otel-thread-ctx.js +38 -11
  332. package/packages/dd-trace/src/payload-tagging/tagging.js +15 -3
  333. package/packages/dd-trace/src/plugin_manager.js +9 -3
  334. package/packages/dd-trace/src/plugins/ci_plugin.js +0 -1
  335. package/packages/dd-trace/src/plugins/database.js +2 -6
  336. package/packages/dd-trace/src/plugins/index.js +8 -0
  337. package/packages/dd-trace/src/plugins/plugin.js +0 -4
  338. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  339. package/packages/dd-trace/src/plugins/util/git.js +1 -3
  340. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +0 -1
  341. package/packages/dd-trace/src/plugins/util/llm.js +0 -2
  342. package/packages/dd-trace/src/plugins/util/status-validator.js +0 -1
  343. package/packages/dd-trace/src/plugins/util/test.js +25 -21
  344. package/packages/dd-trace/src/plugins/util/url.js +0 -5
  345. package/packages/dd-trace/src/priority_sampler.js +0 -6
  346. package/packages/dd-trace/src/process-tags/index.js +0 -1
  347. package/packages/dd-trace/src/profiler.js +132 -35
  348. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +0 -1
  349. package/packages/dd-trace/src/profiling/profiler.js +101 -41
  350. package/packages/dd-trace/src/profiling/ssi-heuristics.js +29 -15
  351. package/packages/dd-trace/src/propagation-hash/index.js +0 -1
  352. package/packages/dd-trace/src/proxy.js +21 -45
  353. package/packages/dd-trace/src/random_sampler.js +0 -4
  354. package/packages/dd-trace/src/rate_limiter.js +0 -4
  355. package/packages/dd-trace/src/remote_config/capabilities.js +1 -9
  356. package/packages/dd-trace/src/remote_config/index.js +0 -1
  357. package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +0 -3
  358. package/packages/dd-trace/src/sampler.js +0 -4
  359. package/packages/dd-trace/src/sampling_rule.js +0 -7
  360. package/packages/dd-trace/src/serverless/vercel.js +0 -1
  361. package/packages/dd-trace/src/serverless.js +0 -1
  362. package/packages/dd-trace/src/service-naming/index.js +0 -1
  363. package/packages/dd-trace/src/service-naming/schemas/util.js +0 -1
  364. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +7 -0
  365. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +5 -0
  366. package/packages/dd-trace/src/span_processor.js +2 -2
  367. package/packages/dd-trace/src/span_sampler.js +0 -1
  368. package/packages/dd-trace/src/standalone/product.js +2 -2
  369. package/packages/dd-trace/src/standalone/tracesource.js +0 -1
  370. package/packages/dd-trace/src/startup-log.js +1 -1
  371. package/packages/dd-trace/src/telemetry/endpoints.js +0 -8
  372. package/packages/dd-trace/src/telemetry/logs/index.js +16 -5
  373. package/packages/dd-trace/src/telemetry/logs/log-collector.js +16 -6
  374. package/packages/dd-trace/src/telemetry/metrics.js +0 -2
  375. package/packages/dd-trace/src/telemetry/telemetry.js +4 -1
  376. package/packages/dd-trace/src/util.js +13 -1
  377. package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
  378. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/utils.js +0 -10
@@ -14,6 +14,9 @@ const {
14
14
  hasEfdRetries,
15
15
  shouldSkipEfdRetry,
16
16
  } = require('../../dd-trace/src/ci-visibility/efd-retry-policy')
17
+ const {
18
+ getDynamicAtrRetryCount,
19
+ } = require('../../dd-trace/src/ci-visibility/dynamic-atr-retries')
17
20
  const {
18
21
  TEST_STATUS,
19
22
  setRumTestTags,
@@ -86,6 +89,7 @@ const {
86
89
  getPullRequestBaseBranch,
87
90
  TEST_FINAL_STATUS,
88
91
  getTestOptimizationRequestResults,
92
+ setExpectedEmptyTestSessionTags,
89
93
  } = require('../../dd-trace/src/plugins/util/test')
90
94
  const { ORIGIN_KEY, COMPONENT } = require('../../dd-trace/src/constants')
91
95
  const { RESOURCE_NAME } = require('../../../ext/tags')
@@ -229,8 +233,13 @@ function getTestScreenshots (cypressTest, attemptIndex, specScreenshots) {
229
233
  return specScreenshots.filter(screenshot => isScreenshotForTestAttempt(screenshot, titleParts, attemptIndex))
230
234
  }
231
235
 
232
- function getSessionStatus (summary) {
233
- if (summary.totalFailed !== undefined && summary.totalFailed > 0) {
236
+ function getSessionStatus (summary, testSuiteStatuses) {
237
+ if (!summary) {
238
+ if (testSuiteStatuses.has('fail')) return 'fail'
239
+ if (testSuiteStatuses.has('skip') && !testSuiteStatuses.has('pass')) return 'skip'
240
+ return 'pass'
241
+ }
242
+ if (summary.status === 'failed' || summary.failures > 0 || summary.totalFailed > 0) {
234
243
  return 'fail'
235
244
  }
236
245
  if (summary.totalSkipped !== undefined && summary.totalSkipped === summary.totalTests) {
@@ -378,33 +387,10 @@ function getSuiteStatus (suiteStats) {
378
387
  return 'pass'
379
388
  }
380
389
 
381
- function getMatchingCypressTest (cypressTests, testName, attemptIndex, testStatus, preferIndexedMatch = false) {
382
- let matchingTestByIndex
383
- let matchingTestByStatus
384
- let matchingTestIndex = 0
385
-
386
- for (const cypressTest of cypressTests) {
387
- if (cypressTest.title.join(' ') !== testName) {
388
- continue
389
- }
390
-
391
- if (matchingTestIndex === attemptIndex) {
392
- matchingTestByIndex = cypressTest
393
- }
394
- matchingTestIndex++
395
-
396
- if (!matchingTestByStatus && CYPRESS_STATUS_TO_TEST_STATUS[cypressTest.state] === testStatus) {
397
- matchingTestByStatus = cypressTest
398
- }
399
- }
400
-
401
- return preferIndexedMatch
402
- ? matchingTestByIndex || matchingTestByStatus
403
- : matchingTestByStatus || matchingTestByIndex
404
- }
405
-
406
390
  function isCypressHookFailure (cypressTest) {
407
- return CYPRESS_STATUS_TO_TEST_STATUS[cypressTest.state] === 'fail' &&
391
+ // Duplicate titles can leave the aggregate state passed even when the final attempt has a hook failure.
392
+ const lastAttempt = cypressTest.attempts?.at(-1)
393
+ return (cypressTest.state === 'failed' || lastAttempt?.state === 'failed') &&
408
394
  /\bhook\b/.test(String(cypressTest.displayError || ''))
409
395
  }
410
396
 
@@ -415,7 +401,12 @@ const FINAL_STATUS_RETRY_KIND = {
415
401
  atf: 'atf',
416
402
  }
417
403
 
418
- function getFinalStatusRetryKind ({ finishedTest, finishedTestAttempts, flakyTestRetriesCount }) {
404
+ function getFinalStatusRetryKind ({
405
+ finishedTest,
406
+ finishedTestAttempts,
407
+ flakyTestRetriesCount,
408
+ isDynamicAtrEnabled,
409
+ }) {
419
410
  // Infer retry kind from the executions we actually saw so ATR enabled with
420
411
  // a retry count of 0 is still treated as a single final execution.
421
412
  if (finishedTest.isAttemptToFix) {
@@ -426,7 +417,7 @@ function getFinalStatusRetryKind ({ finishedTest, finishedTestAttempts, flakyTes
426
417
  return FINAL_STATUS_RETRY_KIND.efd
427
418
  }
428
419
 
429
- if (finishedTestAttempts.length > 1 && flakyTestRetriesCount > 0) {
420
+ if (finishedTestAttempts.length > 1 && (isDynamicAtrEnabled || flakyTestRetriesCount > 0)) {
430
421
  return FINAL_STATUS_RETRY_KIND.atr
431
422
  }
432
423
 
@@ -436,7 +427,7 @@ function getFinalStatusRetryKind ({ finishedTest, finishedTestAttempts, flakyTes
436
427
  function getFinalStatus ({
437
428
  status,
438
429
  retryKind,
439
- hasFailedAllRetries,
430
+ hasFailedAllAttempts,
440
431
  hasPassedAllAtfRetries,
441
432
  isQuarantined,
442
433
  isDisabled,
@@ -450,7 +441,7 @@ function getFinalStatus ({
450
441
  case FINAL_STATUS_RETRY_KIND.atr:
451
442
  case FINAL_STATUS_RETRY_KIND.efd:
452
443
  // These modes report the aggregate result across attempts.
453
- return hasFailedAllRetries ? 'fail' : 'pass'
444
+ return hasFailedAllAttempts ? 'fail' : 'pass'
454
445
  case FINAL_STATUS_RETRY_KIND.atf:
455
446
  // Attempt-to-fix only passes if every execution passed.
456
447
  return hasPassedAllAtfRetries ? 'pass' : 'fail'
@@ -464,6 +455,8 @@ class CypressPlugin {
464
455
  testEnvironmentMetadata = getTestEnvironmentMetadata(TEST_FRAMEWORK_NAME)
465
456
 
466
457
  finishedTestsByFile = {}
458
+ hasTestsReported = false
459
+ testSuiteStatuses = new Set()
467
460
  testStatuses = {}
468
461
  hasLibraryConfiguration = false
469
462
  isItrEnabled = false
@@ -473,6 +466,9 @@ class CypressPlugin {
473
466
  isCoverageReportUploadEnabled = false
474
467
  isFlakyTestRetriesEnabled = false
475
468
  flakyTestRetriesCount = 0
469
+ isDynamicAtrEnabled = false
470
+ dynamicAtrBuckets = undefined
471
+ dynamicAtrRetryCountByTest = new Map()
476
472
  isEarlyFlakeDetectionEnabled = false
477
473
  isEarlyFlakeDetectionFaulty = false
478
474
  isKnownTestsEnabled = false
@@ -550,11 +546,12 @@ class CypressPlugin {
550
546
  * Resets state that is scoped to a single Cypress run so the singleton plugin
551
547
  * can be reused safely across multiple programmatic cypress.run() calls.
552
548
  *
553
- * @returns {void}
554
549
  */
555
550
  resetRunState () {
556
551
  this._isInit = false
557
552
  this.finishedTestsByFile = {}
553
+ this.hasTestsReported = false
554
+ this.testSuiteStatuses = new Set()
558
555
  this.testStatuses = {}
559
556
  this.hasLibraryConfiguration = false
560
557
  this.isItrEnabled = false
@@ -564,6 +561,9 @@ class CypressPlugin {
564
561
  this.isCoverageReportUploadEnabled = false
565
562
  this.isFlakyTestRetriesEnabled = false
566
563
  this.flakyTestRetriesCount = 0
564
+ this.isDynamicAtrEnabled = false
565
+ this.dynamicAtrBuckets = undefined
566
+ this.dynamicAtrRetryCountByTest = new Map()
567
567
  this.isEarlyFlakeDetectionEnabled = false
568
568
  this.isEarlyFlakeDetectionFaulty = false
569
569
  this.isKnownTestsEnabled = false
@@ -630,7 +630,6 @@ class CypressPlugin {
630
630
  *
631
631
  * @param {string} traceId - Test trace id used for the upload
632
632
  * @param {Promise<string|undefined>} uploadPromise - Promise resolving to the upload outcome
633
- * @returns {void}
634
633
  */
635
634
  addScreenshotUploadPromise (traceId, uploadPromise) {
636
635
  const uploadPromises = this.screenshotUploadPromisesByTraceId.get(traceId)
@@ -659,7 +658,6 @@ class CypressPlugin {
659
658
  * Cancels screenshot work that must not outlive an errored after:spec finalization boundary.
660
659
  *
661
660
  * @param {Error} error - Error that triggered finalization
662
- * @returns {void}
663
661
  */
664
662
  abortPendingScreenshotUploads (error) {
665
663
  for (const controller of this.screenshotUploadAbortControllers) controller.abort(error)
@@ -673,7 +671,6 @@ class CypressPlugin {
673
671
  * start/finish. Captured at session span creation so it shares the same
674
672
  * epoch as the trace without reaching into span internals.
675
673
  *
676
- * @returns {number}
677
674
  */
678
675
  _now () {
679
676
  return this._timeOrigin + performance.now() - this._perfOrigin
@@ -682,7 +679,6 @@ class CypressPlugin {
682
679
  /**
683
680
  * Returns the directory used to normalize coverage file names.
684
681
  *
685
- * @returns {string}
686
682
  */
687
683
  getCoverageRootDir () {
688
684
  return this.repositoryRoot || this.rootDir || process.cwd()
@@ -691,7 +687,6 @@ class CypressPlugin {
691
687
  /**
692
688
  * Returns whether skipped test coverage should be backfilled into the session coverage map.
693
689
  *
694
- * @returns {boolean}
695
690
  */
696
691
  shouldBackfillSkippedCoverage () {
697
692
  return this.isItrEnabled &&
@@ -704,7 +699,6 @@ class CypressPlugin {
704
699
  * Adds a test's Istanbul coverage to the aggregated session coverage map.
705
700
  *
706
701
  * @param {object} coverage
707
- * @returns {void}
708
702
  */
709
703
  addTestSessionCoverage (coverage) {
710
704
  mergeCoverage(coverage, this.testSessionCoverageMap)
@@ -713,7 +707,6 @@ class CypressPlugin {
713
707
  /**
714
708
  * Applies backend skipped-test coverage to the aggregated session coverage map.
715
709
  *
716
- * @returns {boolean}
717
710
  */
718
711
  applySkippedCoverageToTestSessionCoverage () {
719
712
  if (!this.shouldBackfillSkippedCoverage()) {
@@ -756,7 +749,6 @@ class CypressPlugin {
756
749
  /**
757
750
  * Uploads executable-line coverage for the test session when backend configuration enables it.
758
751
  *
759
- * @returns {void}
760
752
  */
761
753
  reportTestSessionCoverage () {
762
754
  const exporter = this.tracer._tracer._exporter
@@ -785,7 +777,6 @@ class CypressPlugin {
785
777
  * @param {object} cypressConfig - Cypress resolved config
786
778
  * @param {object} tracer - dd-trace proxy tracer
787
779
  * @param {object} testOptimizationConfig - Test Optimization config
788
- * @returns {void}
789
780
  */
790
781
  warnIfMisconfiguredTestFailureScreenshots (cypressConfig, tracer, testOptimizationConfig) {
791
782
  if (!testOptimizationConfig.DD_TEST_FAILURE_SCREENSHOTS_ENABLED) {
@@ -816,7 +807,6 @@ class CypressPlugin {
816
807
  * @param {object} cypressConfig - Cypress resolved config
817
808
  * @param {object} tracer - dd-trace proxy tracer
818
809
  * @param {object} testOptimizationConfig - Test Optimization config
819
- * @returns {void}
820
810
  */
821
811
  warnIfMisconfiguredTestFailureVideos (cypressConfig, tracer, testOptimizationConfig) {
822
812
  if (!testOptimizationConfig.DD_TEST_FAILURE_VIDEOS_ENABLED) return
@@ -897,6 +887,8 @@ class CypressPlugin {
897
887
  earlyFlakeDetectionFaultyThreshold,
898
888
  isFlakyTestRetriesEnabled,
899
889
  flakyTestRetriesCount,
890
+ isDynamicAtrEnabled,
891
+ dynamicAtrBuckets,
900
892
  isKnownTestsEnabled,
901
893
  isTestManagementEnabled,
902
894
  testManagementAttemptToFixRetries,
@@ -914,13 +906,26 @@ class CypressPlugin {
914
906
  if (isFlakyTestRetriesEnabled && this.isTestIsolationEnabled) {
915
907
  this.isFlakyTestRetriesEnabled = true
916
908
  this.flakyTestRetriesCount = flakyTestRetriesCount ?? 0
909
+ this.isDynamicAtrEnabled = isDynamicAtrEnabled ?? false
910
+ this.dynamicAtrBuckets = dynamicAtrBuckets
917
911
  if (typeof this.cypressConfig.retries === 'number') {
918
912
  this.cypressConfig.retries = {
919
913
  openMode: this.cypressConfig.retries,
920
914
  runMode: this.cypressConfig.retries,
921
915
  }
922
916
  }
923
- this.cypressConfig.retries.runMode = this.flakyTestRetriesCount
917
+ // Dynamic ATR starts at the maximum budget, then narrows each test
918
+ // after its initial duration is known.
919
+ if (this.isDynamicAtrEnabled) {
920
+ this.cypressConfig.retries.runMode = Math.max(
921
+ 1,
922
+ this.dynamicAtrBuckets
923
+ ? Math.max(...this.dynamicAtrBuckets)
924
+ : this.earlyFlakeDetectionRetryPolicy.schedulingRetryCount
925
+ )
926
+ } else {
927
+ this.cypressConfig.retries.runMode = this.flakyTestRetriesCount
928
+ }
924
929
  } else {
925
930
  this.flakyTestRetriesCount = 0
926
931
  }
@@ -962,7 +967,6 @@ class CypressPlugin {
962
967
  * @param {string} testSuite
963
968
  * @param {string} testName
964
969
  * @param {number | undefined} duration
965
- * @returns {number}
966
970
  */
967
971
  setEfdRetryCountForTest (testSuite, testName, duration) {
968
972
  if (!this.efdRetryCountByTest[testSuite]) {
@@ -979,19 +983,51 @@ class CypressPlugin {
979
983
  return retryCount
980
984
  }
981
985
 
986
+ /**
987
+ * Stores the dynamic ATR retry count for a test after its first execution duration is known.
988
+ *
989
+ * @param {string} testSuite
990
+ * @param {string} testId
991
+ * @param {number | undefined} duration
992
+ */
993
+ setDynamicAtrRetryCountForTest (testSuite, testId, duration) {
994
+ if (!this.dynamicAtrRetryCountByTest) {
995
+ this.dynamicAtrRetryCountByTest = new Map()
996
+ }
997
+ let retryCountByTestId = this.dynamicAtrRetryCountByTest.get(testSuite)
998
+ if (!retryCountByTestId) {
999
+ retryCountByTestId = new Map()
1000
+ this.dynamicAtrRetryCountByTest.set(testSuite, retryCountByTestId)
1001
+ }
1002
+ const retryCount = getDynamicAtrRetryCount(
1003
+ duration ?? 0,
1004
+ this.earlyFlakeDetectionRetryPolicy,
1005
+ this.dynamicAtrBuckets
1006
+ )
1007
+ retryCountByTestId.set(testId, retryCount)
1008
+ return retryCount
1009
+ }
1010
+
982
1011
  /**
983
1012
  * Returns whether an EFD retry clone is beyond the selected retry count and should be discarded.
984
1013
  *
985
1014
  * @param {string} testSuite
986
1015
  * @param {string} testName
987
1016
  * @param {number} efdRetryIndex
988
- * @returns {boolean}
989
1017
  */
990
1018
  shouldSkipEfdRetry (testSuite, testName, efdRetryIndex) {
991
1019
  const testSuiteRetries = this.efdRetryCountByTest[testSuite]
992
1020
  return shouldSkipEfdRetry(efdRetryIndex, testSuiteRetries?.[testName])
993
1021
  }
994
1022
 
1023
+ /**
1024
+ * @param {string} testSuite
1025
+ * @param {string} testId
1026
+ */
1027
+ getDynamicAtrRetryCountForTest (testSuite, testId) {
1028
+ return this.dynamicAtrRetryCountByTest.get(testSuite)?.get(testId)
1029
+ }
1030
+
995
1031
  getTestSuiteSpan ({ testSuite, testSuiteAbsolutePath }) {
996
1032
  const testSuiteSpanMetadata = {
997
1033
  ...getTestSuiteCommonTags(this.command, this.frameworkVersion, testSuite, TEST_FRAMEWORK_NAME),
@@ -1340,12 +1376,22 @@ class CypressPlugin {
1340
1376
  */
1341
1377
  #finalizeRun (suiteStats, error, hasPendingVideoSpans = false) {
1342
1378
  if (this.testSessionSpan && this.testModuleSpan) {
1343
- const testStatus = error ? 'fail' : getSessionStatus(suiteStats)
1379
+ const testStatus = error ? 'fail' : getSessionStatus(suiteStats, this.testSuiteStatuses)
1380
+ const hasNoTests = suiteStats?.totalTests === 0 ||
1381
+ (suiteStats?.totalTests === undefined && !this.hasTestsReported)
1344
1382
  const hasBackfilledCoverage = this.applySkippedCoverageToTestSessionCoverage()
1345
1383
  const testCodeCoverageLinesTotal = this.getTestCodeCoverageLinesTotal(hasBackfilledCoverage)
1346
1384
 
1347
1385
  this.testModuleSpan.setTag(TEST_STATUS, testStatus)
1348
1386
  this.testSessionSpan.setTag(TEST_STATUS, testStatus)
1387
+ if (testStatus !== 'fail' && hasNoTests) {
1388
+ setExpectedEmptyTestSessionTags(
1389
+ this.testSessionSpan,
1390
+ this.testModuleSpan,
1391
+ 'No tests were executed',
1392
+ 'zero_tests'
1393
+ )
1394
+ }
1349
1395
  if (error) {
1350
1396
  this.testModuleSpan.setTag('error', error)
1351
1397
  this.testSessionSpan.setTag('error', error)
@@ -1434,7 +1480,6 @@ class CypressPlugin {
1434
1480
  * Uploads failure screenshots as soon as Cypress creates them.
1435
1481
  *
1436
1482
  * @param {object} details - Cypress screenshot details
1437
- * @returns {void}
1438
1483
  */
1439
1484
  afterScreenshot (details) {
1440
1485
  const lastFailedTestSpan = this.lastFinishedTest?.testStatus === 'fail'
@@ -1460,8 +1505,9 @@ class CypressPlugin {
1460
1505
  }
1461
1506
 
1462
1507
  afterSpec (spec, results, error) {
1463
- const { tests, stats, screenshots, video } = results || {}
1508
+ const { tests, stats, screenshots, video, error: resultError } = results || {}
1464
1509
  const cypressTests = tests || []
1510
+ if (cypressTests.length > 0) this.hasTestsReported = true
1465
1511
  const specScreenshots = screenshots || []
1466
1512
  const finishedTests = this.finishedTestsByFile[spec.relative] || []
1467
1513
  const screenshotUploadPromises = []
@@ -1540,33 +1586,41 @@ class CypressPlugin {
1540
1586
  // Cypress will report the last run test as failed, but we don't know that yet at `dd:afterEach`
1541
1587
  let latestError
1542
1588
 
1543
- const finishedTestsByTestName = finishedTests.reduce((acc, finishedTest) => {
1544
- if (!acc[finishedTest.testName]) {
1545
- acc[finishedTest.testName] = []
1589
+ // Cypress preserves IDs across retry clones, so duplicate titles remain independent.
1590
+ const finishedTestsByTest = new Map()
1591
+ for (const finishedTest of finishedTests) {
1592
+ const testIdentifier = finishedTest.testId ?? finishedTest.testName
1593
+ let finishedTestAttempts = finishedTestsByTest.get(testIdentifier)
1594
+ if (!finishedTestAttempts) {
1595
+ finishedTestAttempts = []
1596
+ finishedTestsByTest.set(testIdentifier, finishedTestAttempts)
1546
1597
  }
1547
- acc[finishedTest.testName].push(finishedTest)
1548
- return acc
1549
- }, {})
1598
+ finishedTestAttempts.push(finishedTest)
1599
+ }
1550
1600
 
1551
- for (const [testName, finishedTestAttempts] of Object.entries(finishedTestsByTestName)) {
1601
+ const matchedCypressTests = new Set()
1602
+ for (const finishedTestAttempts of finishedTestsByTest.values()) {
1603
+ const { testName } = finishedTestAttempts[0]
1604
+ // Cypress reports one result per original runnable, including Datadog-managed clones.
1605
+ // Public results omit runnable IDs but retain declaration order.
1606
+ const cypressTest = cypressTests.find(test =>
1607
+ test.title.join(' ') === testName && !matchedCypressTests.has(test)
1608
+ )
1609
+ matchedCypressTests.add(cypressTest)
1552
1610
  for (const [attemptIndex, finishedTest] of finishedTestAttempts.entries()) {
1553
1611
  // We can check if this is the last attempt regardless of the retry mechanism
1554
1612
  const isLastAttempt = attemptIndex === finishedTestAttempts.length - 1
1555
1613
  const isDatadogManagedAttempt = finishedTest.isEfdManagedTest || finishedTest.isAttemptToFix
1556
- const cypressTest = isDatadogManagedAttempt
1557
- ? getMatchingCypressTest(cypressTests, testName, attemptIndex, finishedTest.testStatus, isLastAttempt) ||
1558
- cypressTests.find(test => test.title.join(' ') === testName)
1559
- : cypressTests.find(test => test.title.join(' ') === testName)
1560
1614
  if (!cypressTest) {
1561
1615
  continue
1562
1616
  }
1563
1617
  // finishedTests can include multiple tests with the same name if they have been retried
1564
1618
  // by early flake detection. Cypress is unaware of this so .attempts does not necessarily have
1565
1619
  // the same length as `finishedTestAttempts`
1566
- const shouldUseCapturedStatus = isDatadogManagedAttempt && !(isLastAttempt && isCypressHookFailure(cypressTest))
1567
- let cypressTestStatus = shouldUseCapturedStatus
1568
- ? finishedTest.testStatus
1569
- : CYPRESS_STATUS_TO_TEST_STATUS[cypressTest.state]
1620
+ let cypressTestStatus = CYPRESS_STATUS_TO_TEST_STATUS[cypressTest.state]
1621
+ if (isDatadogManagedAttempt) {
1622
+ cypressTestStatus = isLastAttempt && isCypressHookFailure(cypressTest) ? 'fail' : finishedTest.testStatus
1623
+ }
1570
1624
  if (!finishedTest.isEfdManagedTest && !finishedTest.isAttemptToFix &&
1571
1625
  cypressTest.attempts && cypressTest.attempts[attemptIndex]) {
1572
1626
  cypressTestStatus = CYPRESS_STATUS_TO_TEST_STATUS[cypressTest.attempts[attemptIndex].state]
@@ -1648,9 +1702,22 @@ class CypressPlugin {
1648
1702
  finishedTest,
1649
1703
  finishedTestAttempts,
1650
1704
  flakyTestRetriesCount: this.flakyTestRetriesCount,
1705
+ isDynamicAtrEnabled: this.isDynamicAtrEnabled,
1651
1706
  })
1652
1707
 
1653
- const hasFailedAllRetries = testSpanTags[TEST_HAS_FAILED_ALL_RETRIES] === 'true'
1708
+ let hasFailedAllAttempts = testSpanTags[TEST_HAS_FAILED_ALL_RETRIES] === 'true'
1709
+ if (retryKind === FINAL_STATUS_RETRY_KIND.atr) {
1710
+ // Late hooks can change every attempt after dd:afterEach has captured its status.
1711
+ hasFailedAllAttempts = finishedTestAttempts.every(attempt =>
1712
+ attempt.testSpan.context().getTag(TEST_STATUS) === 'fail'
1713
+ )
1714
+ const atrRetryCount = this.isDynamicAtrEnabled
1715
+ ? this.getDynamicAtrRetryCountForTest(spec.relative, finishedTest.testId)
1716
+ : this.flakyTestRetriesCount
1717
+ // An aborted run can fail without using the entire selected retry budget.
1718
+ const hasFailedAllRetries = hasFailedAllAttempts && finishedTestAttempts.length > atrRetryCount
1719
+ finishedTest.testSpan.setTag(TEST_HAS_FAILED_ALL_RETRIES, hasFailedAllRetries ? 'true' : undefined)
1720
+ }
1654
1721
  const hasPassedAllAtfRetries =
1655
1722
  testSpanTags[TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED] === 'true'
1656
1723
  const isQuarantined = testSpanTags[TEST_MANAGEMENT_IS_QUARANTINED] === 'true'
@@ -1659,7 +1726,7 @@ class CypressPlugin {
1659
1726
  const finalStatus = getFinalStatus({
1660
1727
  status: cypressTestStatus,
1661
1728
  retryKind,
1662
- hasFailedAllRetries,
1729
+ hasFailedAllAttempts,
1663
1730
  hasPassedAllAtfRetries,
1664
1731
  isQuarantined,
1665
1732
  isDisabled,
@@ -1683,7 +1750,12 @@ class CypressPlugin {
1683
1750
  }
1684
1751
 
1685
1752
  const testSuiteFinishTime = this._now()
1686
- const suiteFailed = error || latestError || getSuiteStatus(stats) === 'fail'
1753
+ const suiteError = error || resultError || latestError
1754
+ const suiteStatus = suiteError ||
1755
+ cypressTests.some(test => CYPRESS_STATUS_TO_TEST_STATUS[test.state] === 'fail')
1756
+ ? 'fail'
1757
+ : getSuiteStatus(stats)
1758
+ this.testSuiteStatuses.add(suiteStatus)
1687
1759
  const testSuiteSpan = this.testSuiteSpan
1688
1760
  const uploadOptions = {
1689
1761
  filePath: video,
@@ -1694,10 +1766,10 @@ class CypressPlugin {
1694
1766
  ? testSuiteSpan.context().toSpanId()
1695
1767
  : undefined,
1696
1768
  }
1697
- const shouldUploadVideo = suiteFailed && this.#canUploadTestSuiteVideo(uploadOptions)
1769
+ const shouldUploadVideo = suiteStatus === 'fail' && this.#canUploadTestSuiteVideo(uploadOptions)
1698
1770
  if (testSuiteSpan) {
1699
- testSuiteSpan.setTag(TEST_STATUS, error ? 'fail' : getSuiteStatus(stats))
1700
- if (error || latestError) testSuiteSpan.setTag('error', error || latestError)
1771
+ testSuiteSpan.setTag(TEST_STATUS, suiteStatus)
1772
+ if (suiteError) testSuiteSpan.setTag('error', suiteError)
1701
1773
  this.testSuiteSpan = null
1702
1774
  }
1703
1775
 
@@ -1838,7 +1910,6 @@ class CypressPlugin {
1838
1910
  * @param {string|undefined} options.filePath - Cypress video path
1839
1911
  * @param {string|undefined} options.testSessionId - Test session id
1840
1912
  * @param {string|undefined} options.testSuiteId - Test suite id
1841
- * @returns {boolean}
1842
1913
  */
1843
1914
  #canUploadTestSuiteVideo ({ filePath, testSessionId, testSuiteId }) {
1844
1915
  const exporter = this.tracer?._tracer?._exporter
@@ -1936,7 +2007,14 @@ class CypressPlugin {
1936
2007
 
1937
2008
  getTasks () {
1938
2009
  return {
1939
- 'dd:testSuiteStart': ({ testSuite, testSuiteAbsolutePath }) => {
2010
+ 'dd:testSuiteStart': ({ testSuite, testSuiteAbsolutePath, isTextTerminal: browserIsTextTerminal }) => {
2011
+ // Cypress 6 omits the execution mode from the Node plugin configuration.
2012
+ const isTextTerminal = this.cypressConfig.isTextTerminal ?? browserIsTextTerminal
2013
+ if (!isTextTerminal) {
2014
+ this.isFlakyTestRetriesEnabled = false
2015
+ this.isDynamicAtrEnabled = false
2016
+ this.flakyTestRetriesCount = 0
2017
+ }
1940
2018
  const suitePayload = {
1941
2019
  isEarlyFlakeDetectionEnabled:
1942
2020
  this.isEarlyFlakeDetectionEnabled && hasEfdRetries(this.earlyFlakeDetectionRetryPolicy),
@@ -1950,6 +2028,8 @@ class CypressPlugin {
1950
2028
  isModifiedTest: this.getIsTestModified(testSuiteAbsolutePath),
1951
2029
  repositoryRoot: this.repositoryRoot,
1952
2030
  isTestIsolationEnabled: this.isTestIsolationEnabled,
2031
+ isDynamicAtrEnabled: this.isDynamicAtrEnabled,
2032
+ isTextTerminal,
1953
2033
  rumFlushWaitMillis: this.rumFlushWaitMillis,
1954
2034
  rumTestExecutionIdCookieName: RUM_TEST_EXECUTION_ID_COOKIE_NAME,
1955
2035
  }
@@ -1958,6 +2038,7 @@ class CypressPlugin {
1958
2038
  return suitePayload
1959
2039
  },
1960
2040
  'dd:beforeEach': (test) => {
2041
+ this.hasTestsReported = true
1961
2042
  const { testId, testName, testSuite, isEfdRetry, efdRetryIndex } = test
1962
2043
  if (isEfdRetry && this.shouldSkipEfdRetry(testSuite, testName, efdRetryIndex)) {
1963
2044
  return { shouldSkip: true, shouldDiscard: true }
@@ -2016,6 +2097,7 @@ class CypressPlugin {
2016
2097
  testSourceStack,
2017
2098
  testSuite,
2018
2099
  testSuiteAbsolutePath,
2100
+ testId,
2019
2101
  testName,
2020
2102
  testItTitle,
2021
2103
  isNew,
@@ -2064,12 +2146,23 @@ class CypressPlugin {
2064
2146
  this.activeTestSpan.setTag(TEST_EARLY_FLAKE_ABORT_REASON, 'slow')
2065
2147
  }
2066
2148
  }
2149
+ // Dynamic ATR: after the first attempt, compute the duration-based retry budget.
2150
+ if (
2151
+ this.isDynamicAtrEnabled &&
2152
+ this.isFlakyTestRetriesEnabled &&
2153
+ !isAttemptToFix &&
2154
+ !isEfdRetry &&
2155
+ !isEfdManagedTest &&
2156
+ this.getDynamicAtrRetryCountForTest(testSuite, testId) === undefined
2157
+ ) {
2158
+ this.setDynamicAtrRetryCountForTest(testSuite, testId, duration)
2159
+ }
2067
2160
  if (didAbortSlowEfdRetries && testStatus === 'skip' && !error && duration > 0) {
2068
2161
  testStatus = 'pass'
2069
2162
  }
2070
2163
  this.activeTestSpan.setTag(TEST_STATUS, testStatus)
2071
2164
 
2072
- const testIdentifier = `${testSuite}\0${testName}`
2165
+ const testIdentifier = `${testSuite}\0${testId ?? testName}`
2073
2166
  let testStatuses = this.testStatuses[testIdentifier]
2074
2167
  if (testStatuses) {
2075
2168
  testStatuses.push(testStatus)
@@ -2160,8 +2253,10 @@ class CypressPlugin {
2160
2253
  })
2161
2254
  }
2162
2255
  // ATR: set TEST_HAS_FAILED_ALL_RETRIES when all auto test retries were exhausted and every attempt failed
2256
+ const dynamicAtrRetryCount = this.getDynamicAtrRetryCountForTest(testSuite, testId)
2257
+ const atrRetryCount = this.isDynamicAtrEnabled ? dynamicAtrRetryCount : this.flakyTestRetriesCount
2163
2258
  if (this.isFlakyTestRetriesEnabled && !isAttemptToFix && !isEfdRetry &&
2164
- this.flakyTestRetriesCount > 0 && testStatuses.length === this.flakyTestRetriesCount + 1 &&
2259
+ atrRetryCount > 0 && testStatuses.length === atrRetryCount + 1 &&
2165
2260
  testStatuses.every(status => status === 'fail')) {
2166
2261
  this.activeTestSpan.setTag(TEST_HAS_FAILED_ALL_RETRIES, 'true')
2167
2262
  }
@@ -2201,6 +2296,7 @@ class CypressPlugin {
2201
2296
  }
2202
2297
 
2203
2298
  const finishedTest = {
2299
+ testId,
2204
2300
  testName,
2205
2301
  testStatus,
2206
2302
  finishTime: this._now(),
@@ -2227,7 +2323,7 @@ class CypressPlugin {
2227
2323
  })
2228
2324
  this.activeTestSpan = null
2229
2325
 
2230
- return null
2326
+ return dynamicAtrRetryCount === undefined ? null : { dynamicAtrRetryCount }
2231
2327
  },
2232
2328
  'dd:addTags': (tags) => {
2233
2329
  if (this.activeTestSpan) {
@@ -19,9 +19,6 @@ function runUserHandler (handler) {
19
19
  return userHandlerContext.run(true, handler)
20
20
  }
21
21
 
22
- /**
23
- * @returns {boolean} whether a managed finalizer owns the current lifecycle event
24
- */
25
22
  function shouldDeferLegacyFinalization () {
26
23
  return userHandlerContext.getStore() === true
27
24
  }
@@ -15,7 +15,6 @@ const SOURCE_MAP_CACHE = new Map()
15
15
  /**
16
16
  * Whether a file path references JavaScript.
17
17
  * @param {string} absoluteFilePath
18
- * @returns {boolean}
19
18
  */
20
19
  function isJavaScriptFile (absoluteFilePath) {
21
20
  return absoluteFilePath.endsWith('.js') || absoluteFilePath.endsWith('.cjs') || absoluteFilePath.endsWith('.mjs')
@@ -25,7 +24,6 @@ function isJavaScriptFile (absoluteFilePath) {
25
24
  * Decide whether invocationDetails line can be trusted as final source line.
26
25
  * @param {string} absoluteFilePath
27
26
  * @param {number} testSourceLine
28
- * @returns {boolean}
29
27
  */
30
28
  function shouldTrustInvocationDetailsLine (absoluteFilePath, testSourceLine) {
31
29
  if (!Number.isInteger(testSourceLine) || testSourceLine < 1) return false
@@ -38,7 +36,6 @@ function shouldTrustInvocationDetailsLine (absoluteFilePath, testSourceLine) {
38
36
  * Decode one VLQ-encoded integer from `str` at `cursor.pos`, advancing the cursor in place.
39
37
  * @param {string} str
40
38
  * @param {{ pos: number }} cursor
41
- * @returns {number}
42
39
  */
43
40
  function decodeVLQ (str, cursor) {
44
41
  let result = 0
@@ -243,7 +240,6 @@ function templateBodyToRegExp (templateBody) {
243
240
  * Count 1-indexed line number for a character index in `content`.
244
241
  * @param {string} content
245
242
  * @param {number} endIndex
246
- * @returns {number}
247
243
  */
248
244
  function lineNumberForIndex (content, endIndex) {
249
245
  let line = 1