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,7 @@ const {
14
14
  hasEfdRetries,
15
15
  shouldSkipEfdRetry,
16
16
  } = require('../../dd-trace/src/ci-visibility/efd-retry-policy')
17
+ const { getDynamicAtrRetryCount } = require('../../dd-trace/src/ci-visibility/dynamic-atr-retries')
17
18
  const {
18
19
  parseAnnotations,
19
20
  getTestSuitePath,
@@ -65,6 +66,7 @@ const testPageGotoCh = channel('ci:playwright:test:page-goto')
65
66
 
66
67
  const dispatcherRunCh = tracingChannel('orchestrion:playwright:Dispatcher_run')
67
68
  const dispatcherCreateWorkerCh = tracingChannel('orchestrion:playwright:Dispatcher_createWorker')
69
+ const filterForShardCh = tracingChannel('orchestrion:playwright:filterForShard')
68
70
  const processHostStartRunnerCh = tracingChannel('orchestrion:playwright:ProcessHost_startRunner')
69
71
  const createRootSuiteCh = tracingChannel('orchestrion:playwright:createRootSuite')
70
72
  const artifactsRecorderScreenshotPathCh =
@@ -112,6 +114,8 @@ let isEarlyFlakeDetectionFaulty = false
112
114
  let earlyFlakeDetectionFaultyThreshold = 0
113
115
  let isFlakyTestRetriesEnabled = false
114
116
  let flakyTestRetriesCount = 0
117
+ let isDynamicAtrEnabled = false
118
+ let dynamicAtrBuckets
115
119
  let knownTests = {}
116
120
  let isTestManagementTestsEnabled = false
117
121
  let testManagementAttemptToFixRetries = 0
@@ -121,6 +125,9 @@ let modifiedFiles = {}
121
125
  let playwrightRunSummary
122
126
  let recordedTestOptimizationExecutions = new Set()
123
127
  let testsReportedInGenerateSummary = new Set()
128
+ let reportedTestExecutions = new WeakMap()
129
+ let hasTestsAssignedToShard = false
130
+ let hasTestsBeforeSharding = false
124
131
  const newTestsWithDynamicNames = new Set()
125
132
  const attemptToFixExecutions = new Map()
126
133
  const loggedAttemptToFixTests = new Set()
@@ -131,6 +138,8 @@ const efdRetryTestsById = new Map()
131
138
  const efdScheduledOriginalTestKeys = new Set()
132
139
  const efdStartedOriginalTestKeys = new Set()
133
140
  const efdSlowAbortedTests = new Set()
141
+ const dynamicAtrRetryCountByTestKey = new Map()
142
+ const automaticRetryProjects = new Set()
134
143
  const ddPropertiesByTestId = new Map()
135
144
  const ddPropertiesRequestsByTestId = new Map()
136
145
  const disabledTestIds = new Set()
@@ -159,7 +168,6 @@ const automaticFailureVideoPaths = new Set()
159
168
  * Returns whether Playwright's internal screenshot recorder created an attachment.
160
169
  *
161
170
  * @param {object} attachment - Playwright attachment payload
162
- * @returns {boolean}
163
171
  */
164
172
  function isAutomaticFailureScreenshotAttachment (attachment) {
165
173
  return typeof attachment?.path === 'string' && automaticFailureScreenshotPaths.delete(attachment.path)
@@ -169,7 +177,6 @@ function isAutomaticFailureScreenshotAttachment (attachment) {
169
177
  * Returns whether Playwright's internal video recorder created an attachment.
170
178
  *
171
179
  * @param {object} attachment - Playwright attachment payload
172
- * @returns {boolean}
173
180
  */
174
181
  function isAutomaticFailureVideoAttachment (attachment) {
175
182
  return typeof attachment?.path === 'string' && automaticFailureVideoPaths.delete(attachment.path)
@@ -230,7 +237,6 @@ function getTestRepeatEachKey (test) {
230
237
 
231
238
  /**
232
239
  * @param {object} test
233
- * @returns {string}
234
240
  */
235
241
  function getTestEfdKey (test) {
236
242
  const projectKey = getTestProjectKey(test)
@@ -263,9 +269,6 @@ function registerEfdRetryTest (test) {
263
269
  })
264
270
  }
265
271
 
266
- /**
267
- * @returns {boolean}
268
- */
269
272
  function shouldRunEarlyFlakeDetection () {
270
273
  return isEarlyFlakeDetectionEnabled && hasEfdRetries(earlyFlakeDetectionRetryPolicy)
271
274
  }
@@ -389,7 +392,6 @@ function sendDdPropertiesToWorkerWhenAvailable (workerProcess, testId) {
389
392
 
390
393
  /**
391
394
  * @param {object} test
392
- * @returns {boolean}
393
395
  */
394
396
  function shouldRequestEfdRetryCount (test) {
395
397
  // The main process remains the source of truth. repeatEachIndex is only used as
@@ -519,6 +521,8 @@ function getTestsBySuiteFromTestsById (testsById) {
519
521
  }
520
522
 
521
523
  function getPlaywrightConfig (playwrightRunner) {
524
+ if (!playwrightRunner) return {}
525
+
522
526
  try {
523
527
  return playwrightRunner._configLoader.fullConfig()
524
528
  } catch {
@@ -558,7 +562,6 @@ function getProjectsFromRunner (runner, configArg) {
558
562
  * Returns whether at least one Playwright project captures automatic screenshots for failed tests.
559
563
  *
560
564
  * @param {Array<object>} projects - Playwright projects with resolved use options
561
- * @returns {boolean} Whether failure screenshot capture is enabled
562
565
  */
563
566
  function isFailureScreenshotCaptureEnabled (projects) {
564
567
  for (const project of projects) {
@@ -575,7 +578,6 @@ function isFailureScreenshotCaptureEnabled (projects) {
575
578
  * Returns whether at least one Playwright project records videos that can be retained for failures.
576
579
  *
577
580
  * @param {Array<object>} projects - Playwright projects with resolved use options
578
- * @returns {boolean} Whether video capture is enabled
579
581
  */
580
582
  function isFailureVideoCaptureEnabled (projects) {
581
583
  for (const project of projects) {
@@ -599,14 +601,19 @@ function getProjectsFromDispatcher (dispatcher) {
599
601
  return dispatcher._loader?.fullConfig()?.projects
600
602
  }
601
603
 
602
- function getBrowserNameFromProjects (projects, test) {
604
+ /**
605
+ * Resolves the configured project by Playwright's unique ID or legacy index.
606
+ * @param {object[]} projects
607
+ * @param {object} test
608
+ */
609
+ function getTestProject (projects, test) {
603
610
  if (!projects || !test) {
604
611
  return null
605
612
  }
606
613
  const { _projectIndex, _projectId: testProjectId } = test
607
614
 
608
615
  if (_projectIndex !== undefined) {
609
- return projects[_projectIndex]?.name
616
+ return projects[_projectIndex]
610
617
  }
611
618
 
612
619
  return projects.find(({ __projectId, _id, name }) => {
@@ -617,7 +624,12 @@ function getBrowserNameFromProjects (projects, test) {
617
624
  return _id === testProjectId
618
625
  }
619
626
  return name === testProjectId
620
- })?.name
627
+ })
628
+ }
629
+
630
+ function getBrowserNameFromProjects (projects, test) {
631
+ const project = getTestProject(projects, test)
632
+ return project && project.name
621
633
  }
622
634
 
623
635
  function formatTestHookError (error, hookType, isTimeout) {
@@ -671,8 +683,8 @@ function getTestByTestId (dispatcher, testId) {
671
683
  // Inspired by https://github.com/microsoft/playwright/blob/2b77ed4d7aafa85a600caa0b0d101b72c8437eeb/packages/playwright/src/reporters/base.ts#L293
672
684
  // We can't use test.outcome() directly because it's set on follow up handlers:
673
685
  // our `testEndHandler` is called before the outcome is set.
674
- function testWillRetry (test, testStatus) {
675
- return testStatus === 'fail' && test.results.length <= test.retries
686
+ function testWillRetry (test, status, expectedStatus = test.expectedStatus) {
687
+ return status !== 'skipped' && status !== expectedStatus && test.results.length <= test.retries
676
688
  }
677
689
 
678
690
  function getFinalStatus ({
@@ -682,7 +694,6 @@ function getFinalStatus ({
682
694
  isAtrRetry,
683
695
  isEfdManagedTest,
684
696
  isAttemptToFix,
685
- hasFailedAllRetries,
686
697
  hasFailedAttemptToFixRetries,
687
698
  hasPassedAnyEfdAttempt,
688
699
  testStatus,
@@ -694,7 +705,7 @@ function getFinalStatus ({
694
705
  return 'skip'
695
706
  }
696
707
  if (isAtrRetry) {
697
- return hasFailedAllRetries ? 'fail' : 'pass'
708
+ return testStatus
698
709
  }
699
710
  if (isEfdManagedTest) {
700
711
  return hasPassedAnyEfdAttempt ? 'pass' : 'fail'
@@ -705,6 +716,17 @@ function getFinalStatus ({
705
716
  return testStatus
706
717
  }
707
718
 
719
+ /**
720
+ * Reports whether another test in the serial group can trigger this test to run again.
721
+ * @param {object} test
722
+ */
723
+ function isSerialTest (test) {
724
+ for (let suite = test.parent; suite; suite = suite.parent) {
725
+ if (suite._parallelMode === 'serial') return true
726
+ }
727
+ return false
728
+ }
729
+
708
730
  function getTestFullname (test) {
709
731
  let parent = test.parent
710
732
  const names = [test.title]
@@ -789,7 +811,6 @@ function testBeginHandler (test, browserName, shouldCreateTestSpan) {
789
811
  *
790
812
  * @param {object} test
791
813
  * @param {string} testSuiteAbsolutePath
792
- * @returns {void}
793
814
  */
794
815
  function recordSkippedTestOptimizationExecution (test, testSuiteAbsolutePath) {
795
816
  if (recordedTestOptimizationExecutions.has(test) ||
@@ -852,6 +873,37 @@ function finishTestSuiteIfDone (testSuiteAbsolutePath, projects) {
852
873
  }
853
874
  }
854
875
 
876
+ /**
877
+ * Checks whether a test inherits the retry limit assigned by Test Optimization.
878
+ * @param {object} test
879
+ * @param {object[]} projects
880
+ */
881
+ function hasAutomaticRetries (test, projects) {
882
+ if (!automaticRetryProjects.has(getTestProject(projects, test))) return false
883
+ for (let suite = test.parent; suite; suite = suite.parent) {
884
+ if (suite._retries !== undefined) return false
885
+ }
886
+ return true
887
+ }
888
+
889
+ /**
890
+ * Records a completed test in its suite and removes it from pending executions.
891
+ * @param {object} test
892
+ * @param {string} testStatus
893
+ * @param {object} [error]
894
+ */
895
+ function recordFinalTestStatus (test, testStatus, error) {
896
+ const testSuiteAbsolutePath = test._requireFile
897
+ if (testSuiteToTestStatuses.has(testSuiteAbsolutePath)) {
898
+ testSuiteToTestStatuses.get(testSuiteAbsolutePath).push(testStatus)
899
+ } else {
900
+ testSuiteToTestStatuses.set(testSuiteAbsolutePath, [testStatus])
901
+ }
902
+ if (error) addErrorToTestSuite(testSuiteAbsolutePath, error)
903
+ remainingTestsByFile[testSuiteAbsolutePath] = remainingTestsByFile[testSuiteAbsolutePath]
904
+ .filter(currentTest => currentTest !== test)
905
+ }
906
+
855
907
  function testEndHandler ({
856
908
  test,
857
909
  annotations,
@@ -860,6 +912,9 @@ function testEndHandler ({
860
912
  isTimeout,
861
913
  shouldCreateTestSpan,
862
914
  projects,
915
+ testDuration,
916
+ testResultStatus,
917
+ expectedStatus = test.expectedStatus,
863
918
  }) {
864
919
  const {
865
920
  _requireFile: testSuiteAbsolutePath,
@@ -892,19 +947,23 @@ function testEndHandler ({
892
947
 
893
948
  const isEfdManagedTest = isTestEfdManaged(test)
894
949
  const testFqn = getTestFullyQualifiedName(test)
895
- const testStatusKey = isEfdManagedTest ? getTestEfdKey(test) : testFqn
950
+ // Dynamic ATR budgets and retry status must be isolated per Playwright project.
951
+ const testStatusKey = (isEfdManagedTest || isDynamicAtrEnabled) ? getTestEfdKey(test) : testFqn
896
952
  const testStatuses = testsToTestStatuses.get(testStatusKey) || []
897
953
 
898
954
  if (testStatuses.length === 0) {
899
- testsToTestStatuses.set(testStatusKey, [testStatus])
955
+ testsToTestStatuses.set(testStatusKey, testStatuses)
900
956
  if (test._ddIsNew && DYNAMIC_NAME_RE.test(getTestFullname(test))) {
901
957
  newTestsWithDynamicNames.add(`${getTestSuitePath(test._requireFile, rootDir)} › ${getTestFullname(test)}`)
902
958
  }
903
- } else {
904
- testStatuses.push(testStatus)
959
+ }
960
+ testStatuses.push(testStatus)
961
+ if (testStatus === 'pass' || testStatus === 'fail') {
962
+ reportedTestExecutions.set(test, { status: testStatus, error })
905
963
  }
906
964
 
907
965
  const testEfdKey = getTestEfdKey(test)
966
+ const dynamicAtrTestKey = testEfdKey
908
967
  if (isEfdManagedTest && !test._ddIsEfdRetry && !efdRetryCountByTestKey.has(testEfdKey)) {
909
968
  const testResult = results.at(-1)
910
969
  const duration = testResult?.duration > 0 ? testResult.duration : performance.now() - test._ddStartTime
@@ -916,6 +975,23 @@ function testEndHandler ({
916
975
  }
917
976
 
918
977
  const testProperties = getTestProperties(test)
978
+ if (
979
+ isDynamicAtrEnabled &&
980
+ isFlakyTestRetriesEnabled &&
981
+ !testProperties.attemptToFix &&
982
+ !test._ddIsEfdRetry &&
983
+ !isEfdManagedTest &&
984
+ hasAutomaticRetries(test, projects) &&
985
+ !dynamicAtrRetryCountByTestKey.has(dynamicAtrTestKey)
986
+ ) {
987
+ const testResult = results.at(-1)
988
+ const duration = testDuration ??
989
+ (testResult?.duration > 0 ? testResult.duration : performance.now() - test._ddStartTime)
990
+ const retryCount = getDynamicAtrRetryCount(duration, earlyFlakeDetectionRetryPolicy, dynamicAtrBuckets)
991
+ dynamicAtrRetryCountByTestKey.set(dynamicAtrTestKey, retryCount)
992
+ // Serial groups may skip this test before its first actual execution.
993
+ test.retries = (testResult?.retry ?? 0) + retryCount
994
+ }
919
995
  const hasRecordedTestOptimizationExecution = recordedTestOptimizationExecutions.has(test)
920
996
 
921
997
  if (!hasRecordedTestOptimizationExecution) {
@@ -968,34 +1044,40 @@ function testEndHandler ({
968
1044
  test._ddHasFailedAllRetries = true
969
1045
  }
970
1046
 
971
- // ATR: set _ddHasFailedAllRetries when all auto test retries were exhausted and every attempt failed
1047
+ const willRetry = testWillRetry(test, testResultStatus, expectedStatus)
1048
+
1049
+ // ATR: use the effective native limit for tests with explicit Playwright retries.
1050
+ const atrRetryCount = isDynamicAtrEnabled
1051
+ ? dynamicAtrRetryCountByTestKey.get(dynamicAtrTestKey) ?? test.retries
1052
+ : flakyTestRetriesCount
972
1053
  if (isFlakyTestRetriesEnabled && !testProperties.attemptToFix && !test._ddIsEfdRetry &&
973
1054
  !(test._ddIsNew || test._ddIsModified) &&
974
- flakyTestRetriesCount != null && flakyTestRetriesCount > 0 &&
975
- testStatuses.length === flakyTestRetriesCount + 1 &&
1055
+ atrRetryCount != null && atrRetryCount > 0 &&
1056
+ !willRetry && testResultStatus !== expectedStatus &&
976
1057
  testStatuses.every(status => status === 'fail')) {
977
1058
  test._ddHasFailedAllRetries = true
978
1059
  }
979
1060
 
980
- const willRetry = testWillRetry(test, testStatus)
981
-
982
- // this handles tests that do not go through the worker process (because they're skipped)
1061
+ // Legacy Playwright also creates executed test spans in the main process.
983
1062
  if (shouldCreateTestSpan) {
984
1063
  const testResult = results.at(-1)
985
1064
  const testCtx = testToCtx.get(test)
1065
+ const retryTestId = testStatus !== 'skip' && !isEfdManagedTest &&
1066
+ !test._ddIsAttemptToFix && test.retries > 0
1067
+ ? test.id ?? test._id
1068
+ : undefined
986
1069
  const isAtrRetry = testResult?.retry > 0 &&
987
1070
  isFlakyTestRetriesEnabled &&
988
1071
  !test._ddIsAttemptToFix &&
989
1072
  !test._ddIsEfdRetry
990
1073
 
991
1074
  const finalStatus = getFinalStatus({
992
- isFinalExecution: !willRetry,
1075
+ isFinalExecution: retryTestId !== undefined || !willRetry,
993
1076
  isDisabled: test._ddIsDisabled,
994
1077
  isQuarantined: test._ddIsQuarantined,
995
1078
  isAtrRetry,
996
1079
  isEfdManagedTest,
997
1080
  isAttemptToFix: test._ddIsAttemptToFix,
998
- hasFailedAllRetries: test._ddHasFailedAllRetries,
999
1081
  hasFailedAttemptToFixRetries: test._ddHasFailedAttemptToFixRetries,
1000
1082
  hasPassedAnyEfdAttempt: testStatuses.includes('pass'),
1001
1083
  testStatus,
@@ -1021,28 +1103,15 @@ function testEndHandler ({
1021
1103
  isAtrRetry,
1022
1104
  isModified: test._ddIsModified,
1023
1105
  finalStatus,
1106
+ retryTestId,
1107
+ deferFinalStatus: willRetry,
1024
1108
  earlyFlakeAbortReason: efdSlowAbortedTests.has(testEfdKey) ? 'slow' : undefined,
1025
1109
  ...testCtx.currentStore,
1026
1110
  })
1027
1111
  }
1028
1112
  }
1029
1113
 
1030
- if (!willRetry) {
1031
- if (testSuiteToTestStatuses.has(testSuiteAbsolutePath)) {
1032
- testSuiteToTestStatuses.get(testSuiteAbsolutePath).push(testStatus)
1033
- } else {
1034
- testSuiteToTestStatuses.set(testSuiteAbsolutePath, [testStatus])
1035
- }
1036
-
1037
- if (error) {
1038
- addErrorToTestSuite(testSuiteAbsolutePath, error)
1039
- }
1040
- }
1041
-
1042
- if (!willRetry) {
1043
- remainingTestsByFile[testSuiteAbsolutePath] = remainingTestsByFile[testSuiteAbsolutePath]
1044
- .filter(currentTest => currentTest !== test)
1045
- }
1114
+ if (!willRetry) recordFinalTestStatus(test, testStatus, error)
1046
1115
 
1047
1116
  finishTestSuiteIfDone(testSuiteAbsolutePath, projects)
1048
1117
  }
@@ -1050,10 +1119,35 @@ function testEndHandler ({
1050
1119
  function dispatcherRunWrapper (run) {
1051
1120
  return function (...args) {
1052
1121
  remainingTestsByFile = getTestsBySuiteFromTestsById(this._testById)
1122
+ for (const tests of Object.values(remainingTestsByFile)) {
1123
+ if (tests.length > 0) {
1124
+ hasTestsAssignedToShard = true
1125
+ break
1126
+ }
1127
+ }
1053
1128
  return run.apply(this, args)
1054
1129
  }
1055
1130
  }
1056
1131
 
1132
+ function recordTestsBeforeSharding (testGroups) {
1133
+ hasTestsBeforeSharding = testGroups.some(group => group.tests.length > 0)
1134
+ }
1135
+
1136
+ function testGroupsHook (testGroupsPackage) {
1137
+ const filterForShard = testGroupsPackage.filterForShard
1138
+ const wrappedFilterForShard = function (...args) {
1139
+ recordTestsBeforeSharding(args.at(-1))
1140
+ return filterForShard.apply(this, args)
1141
+ }
1142
+
1143
+ return new Proxy(testGroupsPackage, {
1144
+ get (target, prop, receiver) {
1145
+ if (prop === 'filterForShard') return wrappedFilterForShard
1146
+ return Reflect.get(target, prop, receiver)
1147
+ },
1148
+ })
1149
+ }
1150
+
1057
1151
  function deferEfdRetryGroups (testGroups) {
1058
1152
  const groupsWithOriginalTests = []
1059
1153
  const efdRetryOnlyGroups = []
@@ -1090,6 +1184,13 @@ function deferEfdRetryGroups (testGroups) {
1090
1184
  function prepareDispatcherRun (dispatcher, args) {
1091
1185
  let testGroups = args[0]
1092
1186
 
1187
+ for (const group of testGroups) {
1188
+ if (group.tests.length > 0) {
1189
+ hasTestsAssignedToShard = true
1190
+ break
1191
+ }
1192
+ }
1193
+
1093
1194
  // Filter out disabled tests from testGroups before they get scheduled,
1094
1195
  // unless they have attemptToFix (in which case they should still run and be retried)
1095
1196
  if (isTestManagementTestsEnabled) {
@@ -1177,7 +1278,7 @@ function onDispatcherCreateWorker (dispatcher, worker) {
1177
1278
  videos.push(attachment)
1178
1279
  }
1179
1280
  })
1180
- worker.on('testEnd', ({ testId, status, errors, annotations }) => {
1281
+ worker.on('testEnd', ({ testId, status, errors, annotations, duration, expectedStatus }) => {
1181
1282
  const test = getTestByTestId(dispatcher, testId)
1182
1283
  if (!test) return
1183
1284
 
@@ -1196,6 +1297,9 @@ function onDispatcherCreateWorker (dispatcher, worker) {
1196
1297
  isTimeout,
1197
1298
  shouldCreateTestSpan,
1198
1299
  projects,
1300
+ testDuration: duration,
1301
+ testResultStatus: status,
1302
+ expectedStatus,
1199
1303
  }
1200
1304
  )
1201
1305
  const testResult = test.results.at(-1)
@@ -1241,10 +1345,16 @@ function onDispatcherCreateWorker (dispatcher, worker) {
1241
1345
  } else if (test._ddIsAttemptToFix) {
1242
1346
  isFinalExecution = !!(test._ddHasPassedAttemptToFixRetries || test._ddHasFailedAttemptToFixRetries)
1243
1347
  } else {
1244
- isFinalExecution = !testWillRetry(test, testStatus)
1348
+ isFinalExecution = !testWillRetry(test, status, expectedStatus)
1245
1349
  }
1246
1350
 
1351
+ const retryTestId = !isEfdManagedTest && !test._ddIsAttemptToFix && test.retries > 0 ? test.id : undefined
1352
+ const deferFinalStatus = retryTestId !== undefined &&
1353
+ (!isFinalExecution || (isSerialTest(test) && test.results.length <= test.retries))
1354
+
1247
1355
  const ddProperties = {
1356
+ _ddRetryTestId: retryTestId,
1357
+ _ddDeferFinalStatus: deferFinalStatus,
1248
1358
  _ddIsDisabled: test._ddIsDisabled,
1249
1359
  _ddIsQuarantined: test._ddIsQuarantined,
1250
1360
  _ddIsAttemptToFix: test._ddIsAttemptToFix,
@@ -1295,6 +1405,7 @@ function dispatcherHook (dispatcherExport) {
1295
1405
  test,
1296
1406
  annotations: params.annotations,
1297
1407
  testStatus: STATUS_TO_TEST_STATUS[testResult.status],
1408
+ testResultStatus: testResult.status,
1298
1409
  error: testResult.error,
1299
1410
  isTimeout,
1300
1411
  shouldCreateTestSpan: true,
@@ -1321,9 +1432,32 @@ function dispatcherHookNew (dispatcherExport, runWrapper) {
1321
1432
  function runAllTestsWrapper (runAllTests, playwrightVersion) {
1322
1433
  // Config parameter is only available from >=1.55.0
1323
1434
  return async function (config) {
1435
+ // A later run must not inherit ATR settings when configuration fails or the plugin is disabled.
1436
+ isFlakyTestRetriesEnabled = false
1437
+ flakyTestRetriesCount = 0
1438
+ isDynamicAtrEnabled = false
1439
+ dynamicAtrBuckets = undefined
1440
+ if (!libraryConfigurationCh.hasSubscribers) {
1441
+ // Instrumentation hooks still run when the plugin is disabled between runs.
1442
+ isKnownTestsEnabled = false
1443
+ isEarlyFlakeDetectionEnabled = false
1444
+ isTestManagementTestsEnabled = false
1445
+ isImpactedTestsEnabled = false
1446
+ knownTests = {}
1447
+ testManagementTests = {}
1448
+ modifiedFiles = {}
1449
+ return runAllTests.apply(this, arguments)
1450
+ }
1451
+
1452
+ testsToTestStatuses.clear()
1453
+ reportedTestExecutions = new WeakMap()
1454
+ dynamicAtrRetryCountByTestKey.clear()
1455
+ automaticRetryProjects.clear()
1324
1456
  reporterError = undefined
1325
1457
  hasReporterError = false
1326
1458
  playwrightRunSummary = undefined
1459
+ hasTestsAssignedToShard = false
1460
+ hasTestsBeforeSharding = false
1327
1461
  let restoreReporterConsoleError
1328
1462
  if (satisfies(playwrightVersion, '>=1.60.0') && config?.config) {
1329
1463
  const DatadogPlaywrightReporter = require('./playwright-reporter')
@@ -1333,6 +1467,8 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1333
1467
  config.config.reporter.unshift([require.resolve('./playwright-reporter')])
1334
1468
  }
1335
1469
  }
1470
+ const runnerConfig = getPlaywrightConfig(this)
1471
+ const playwrightConfig = config?.config || runnerConfig.config || runnerConfig
1336
1472
  rootDir = getRootDir(this, config)
1337
1473
  const projects = getProjectsFromRunner(this, config)
1338
1474
  const isFailureScreenshotEnabled = isFailureScreenshotCaptureEnabled(projects)
@@ -1361,6 +1497,8 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1361
1497
  earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold
1362
1498
  isFlakyTestRetriesEnabled = libraryConfig.isFlakyTestRetriesEnabled
1363
1499
  flakyTestRetriesCount = libraryConfig.flakyTestRetriesCount
1500
+ isDynamicAtrEnabled = libraryConfig.isDynamicAtrEnabled
1501
+ dynamicAtrBuckets = libraryConfig.dynamicAtrBuckets
1364
1502
  isTestManagementTestsEnabled = libraryConfig.isTestManagementEnabled
1365
1503
  testManagementAttemptToFixRetries = libraryConfig.testManagementAttemptToFixRetries
1366
1504
  isImpactedTestsEnabled = libraryConfig.isImpactedTestsEnabled
@@ -1447,11 +1585,23 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1447
1585
  // ATR and `--retries` are now compatible with Test Management.
1448
1586
  // Test Management tests have their retries set to 0 at the test level,
1449
1587
  // preventing them from being retried by ATR or `--retries`.
1450
- const shouldSetATRRetries = isFlakyTestRetriesEnabled && flakyTestRetriesCount > 0
1588
+ const shouldSetATRRetries = isFlakyTestRetriesEnabled &&
1589
+ (isDynamicAtrEnabled || flakyTestRetriesCount > 0)
1590
+ const projectsWithAutomaticRetries = []
1451
1591
  if (shouldSetATRRetries) {
1592
+ // Dynamic ATR starts at the maximum budget, then narrows each test after
1593
+ // its initial duration is known.
1594
+ const maximumDynamicAtrRetries = dynamicAtrBuckets
1595
+ ? Math.max(...dynamicAtrBuckets)
1596
+ : earlyFlakeDetectionRetryPolicy.schedulingRetryCount
1597
+ const atrRetries = isDynamicAtrEnabled
1598
+ ? Math.max(1, maximumDynamicAtrRetries)
1599
+ : flakyTestRetriesCount
1452
1600
  for (const project of projects) {
1453
1601
  if (project.retries === 0) { // Only if it hasn't been set by the user
1454
- project.retries = flakyTestRetriesCount
1602
+ projectsWithAutomaticRetries.push(project)
1603
+ automaticRetryProjects.add(project)
1604
+ project.retries = atrRetries
1455
1605
  }
1456
1606
  }
1457
1607
  }
@@ -1475,6 +1625,9 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1475
1625
  hasReporterError = false
1476
1626
  throw error
1477
1627
  } finally {
1628
+ for (const project of projectsWithAutomaticRetries) {
1629
+ project.retries = 0
1630
+ }
1478
1631
  restoreReporterConsoleError?.()
1479
1632
  }
1480
1633
 
@@ -1486,6 +1639,14 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1486
1639
  // there were tests that did not go through `testBegin` or `testEnd`,
1487
1640
  // because they were skipped
1488
1641
  for (const test of tests) {
1642
+ const lastExecution = reportedTestExecutions.get(test)
1643
+ if (lastExecution) {
1644
+ // Preserve a reported execution whose retry was canceled. Playwright can
1645
+ // also synthesize failed results after hook errors without emitting testEnd.
1646
+ recordFinalTestStatus(test, lastExecution.status, lastExecution.error)
1647
+ finishTestSuiteIfDone(test._requireFile, projects)
1648
+ continue
1649
+ }
1489
1650
  const alreadyReported = testsReportedInGenerateSummary.has(test)
1490
1651
  const browser = getBrowserNameFromProjects(projects, test)
1491
1652
  testBeginHandler(test, browser, !alreadyReported)
@@ -1493,6 +1654,7 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1493
1654
  test,
1494
1655
  annotations: [],
1495
1656
  testStatus: 'skip',
1657
+ testResultStatus: 'skipped',
1496
1658
  error: null,
1497
1659
  isTimeout: false,
1498
1660
  shouldCreateTestSpan: !alreadyReported,
@@ -1520,8 +1682,14 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1520
1682
  const finalStatus = hasReporterError
1521
1683
  ? 'fail'
1522
1684
  : (preventedToFail ? 'pass' : STATUS_TO_TEST_STATUS[sessionStatus])
1685
+ const isExpectedEmptyShard = finalStatus === 'pass' &&
1686
+ Boolean(playwrightConfig.shard) &&
1687
+ hasTestsBeforeSharding &&
1688
+ !hasTestsAssignedToShard &&
1689
+ testsReportedInGenerateSummary.size === 0
1523
1690
  await getChannelPromise(testSessionFinishCh, {
1524
- status: finalStatus,
1691
+ status: isExpectedEmptyShard ? 'skip' : finalStatus,
1692
+ isExpectedEmptyShard,
1525
1693
  error: finalizationError,
1526
1694
  isEarlyFlakeDetectionEnabled,
1527
1695
  isEarlyFlakeDetectionFaulty,
@@ -1537,6 +1705,8 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1537
1705
  playwrightRunSummary = undefined
1538
1706
  recordedTestOptimizationExecutions = new Set()
1539
1707
  testsReportedInGenerateSummary = new Set()
1708
+ hasTestsAssignedToShard = false
1709
+ hasTestsBeforeSharding = false
1540
1710
  efdManagedTestKeys.clear()
1541
1711
  efdRetryCountByTestKey.clear()
1542
1712
  efdRetryCountRequestsByTestKey.clear()
@@ -1693,6 +1863,12 @@ dispatcherCreateWorkerCh.subscribe({
1693
1863
  },
1694
1864
  })
1695
1865
 
1866
+ filterForShardCh.subscribe({
1867
+ start (ctx) {
1868
+ recordTestsBeforeSharding(ctx.arguments.at(-1))
1869
+ },
1870
+ })
1871
+
1696
1872
  processHostStartRunnerCh.subscribe({
1697
1873
  start (ctx) {
1698
1874
  prepareProcessHostStartRunner(ctx.self)
@@ -1734,7 +1910,6 @@ reporterRunSummaryCh.subscribe((runSummary) => {
1734
1910
  * Records a reporter failure even when the reporter throws a falsy value.
1735
1911
  *
1736
1912
  * @param {unknown} error
1737
- * @returns {void}
1738
1913
  */
1739
1914
  function recordReporterError (error) {
1740
1915
  if (hasReporterError) return
@@ -1756,7 +1931,6 @@ function recordReporterError (error) {
1756
1931
  * Records a path created by Playwright's automatic screenshot recorder.
1757
1932
  *
1758
1933
  * @param {object} ctx - Orchestrion context
1759
- * @returns {void}
1760
1934
  */
1761
1935
  function recordAutomaticFailureScreenshotPath (ctx) {
1762
1936
  if (isFailureScreenshotUploadEnabled &&
@@ -1770,7 +1944,6 @@ function recordAutomaticFailureScreenshotPath (ctx) {
1770
1944
  * Records only the destination used by Playwright's automatic video recorder.
1771
1945
  *
1772
1946
  * @param {object} ctx - Orchestrion context
1773
- * @returns {void}
1774
1947
  */
1775
1948
  function recordAutomaticFailureVideoPath (ctx) {
1776
1949
  const video = ctx.arguments?.[0]
@@ -1868,6 +2041,12 @@ addHook({
1868
2041
  versions: ['>=1.38.0 <1.60.0'],
1869
2042
  }, (dispatcher) => dispatcherHookNew(dispatcher, dispatcherRunWrapperNew))
1870
2043
 
2044
+ addHook({
2045
+ name: 'playwright',
2046
+ file: 'lib/runner/testGroups.js',
2047
+ versions: ['>=1.38.0 <1.60.0'],
2048
+ }, testGroupsHook)
2049
+
1871
2050
  addHook({
1872
2051
  name: 'playwright',
1873
2052
  file: 'lib/common/suiteUtils.js',
@@ -2460,14 +2639,16 @@ function instrumentWorkerMainMethods (workerMain) {
2460
2639
  })
2461
2640
  await Promise.race([ddPropertiesPromise, ddPropertiesTimeoutPromise])
2462
2641
 
2642
+ const retryTestId = test._ddRetryTestId
2463
2643
  const finalStatus = getFinalStatus({
2464
- isFinalExecution: test._ddIsFinalExecution,
2644
+ // Retain a candidate final status while a native retry is possible. The main
2645
+ // process removes it when another execution arrives, or keeps it if retries stop.
2646
+ isFinalExecution: retryTestId !== undefined || test._ddIsFinalExecution,
2465
2647
  isDisabled: test._ddIsDisabled,
2466
2648
  isQuarantined: test._ddIsQuarantined,
2467
2649
  isAtrRetry: test._ddIsAtrRetry,
2468
2650
  isEfdManagedTest: test._ddIsEfdManagedTest,
2469
2651
  isAttemptToFix: test._ddIsAttemptToFix,
2470
- hasFailedAllRetries: test._ddHasFailedAllRetries,
2471
2652
  hasFailedAttemptToFixRetries: test._ddHasFailedAttemptToFixRetries,
2472
2653
  hasPassedAnyEfdAttempt: test._ddHasPassedAnyEfdAttempt,
2473
2654
  testStatus: STATUS_TO_TEST_STATUS[status],
@@ -2475,6 +2656,8 @@ function instrumentWorkerMainMethods (workerMain) {
2475
2656
 
2476
2657
  await getChannelPromise(testFinishCh, {
2477
2658
  testStatus: STATUS_TO_TEST_STATUS[status],
2659
+ retryTestId,
2660
+ deferFinalStatus: test._ddDeferFinalStatus,
2478
2661
  steps: steps.filter(step => step.testId === testId),
2479
2662
  error,
2480
2663
  extraTags: annotationTags,
@@ -0,0 +1,7 @@
1
+ 'use strict'
2
+
3
+ const { addHook, getHooks } = require('./helpers/instrument')
4
+
5
+ for (const hook of getHooks('postgres').values()) {
6
+ addHook(hook, exports => exports)
7
+ }