Skip to content

v6.4.0 proposal - #9368

Merged
juan-fernandez merged 35 commits into
v6.xfrom
v6.4.0-proposal
Jul 16, 2026
Merged

v6.4.0 proposal#9368
juan-fernandez merged 35 commits into
v6.xfrom
v6.4.0-proposal

Conversation

@dd-octo-sts

@dd-octo-sts dd-octo-sts Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Features

  • electron: Ship dd-trace-electron package with reduced dependencies #8948
  • General: Trace core-API HTTP/2 servers #9138
  • graphql: Trace Apollo Federation entity resolvers and skip the health-check #9134
  • Test Optimization: Add EFD retry count override #9344
  • Test Optimization: Diagnose and fix Jest suite skipping #9339

Fixes

  • aws-sdk: Record kinesis DSM checkpoint only when context ships #9183
  • graphql: Skip Apollo health checks in Mercurius #9363
  • LLM Observability: Replace Object.create(span) with delegating wrapper to preserve OTel span private-field access #9152
  • proxy: Retain feature modules across tracing reconfiguration #9331
  • Test Optimization: Isolate retry status by spec #9340
  • Test Optimization: Preserve zero EFD retry budgets #9341
  • Test Optimization: Prevent negative test durations #9380
  • Test Optimization: Resolve disabled git upload immediately #9338
  • Test Optimization: Support cucumber 13.1 results #9370
  • Test Optimization: Wait for all worker writers #9349

Performance

  • graphql: Reuse filtered variables across resolve spans #9225

Internal (CI, Testing, Benchmarking)

  • AppSec: Select mongodb version by Node.js runtime in plugin tests #9322
  • ci: Set 16 retries for dd-sts-action #9374
  • Dependencies: Bump bullmq #9350
  • Dependencies: Bump pnpm #9365
  • Dependencies: Bump protobufjs from 8.6.5 to 8.7.0 in /vendor in the vendor-minor-and-patch-dependencies group across 1 directory #9325
  • express: Exercise loopback public entry #9291
  • express: Trace middleware via layer prototype dispatch #9067
  • General: Make no-traces timeout test deterministic #9372
  • General: Prepare lint and Vitest for TypeScript 7 #9345
  • General: Preserve coverage from custom plugin jobs #9386
  • General: Reject when no matching trace arrives before the timeout #9177
  • General: Select latest unversioned dependency range #9352
  • LLM Observability: Centralize session_id injection in handleLLMObsInjection #9353
  • LLM Observability: Cover compatible SDK provider version matrix #9332
  • Test Optimization: Assert complete run payloads #9358
  • Test Optimization: Make STS API key fetch non-fatal #9320
  • undici: Force proxy tunnel in CONNECT regression test #9271

dependabot Bot and others added 17 commits July 15, 2026 05:47
…ndor-minor-and-patch-dependencies group across 1 directory (#9325)

Bumps the vendor-minor-and-patch-dependencies group with 1 update in the /vendor directory: [protobufjs](https://github.com/protobufjs/protobuf.js).


Updates `protobufjs` from 8.6.5 to 8.7.0
- [Release notes](https://github.com/protobufjs/protobuf.js/releases)
- [Changelog](https://github.com/protobufjs/protobuf.js/blob/master/CHANGELOG.md)
- [Commits](protobufjs/protobuf.js@protobufjs-v8.6.5...protobufjs-v8.7.0)

---
updated-dependencies:
- dependency-name: protobufjs
  dependency-version: 8.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: vendor-minor-and-patch-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
If the OIDC token exchange fails due to a transient infrastructure
issue, jobs were failing before tests even ran. With continue-on-error,
ci/init.js gracefully skips reporting when DD_API_KEY is absent and the
tests still execute normally.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* perf(graphql): reuse filtered variables across resolve spans

The graphql.resolve variable tags ran the user-supplied config.variables
filter once for every instrumented field that carries arguments, even though
graphql coerces variableValues once per execute and hands the same object to
every resolver. Memoize the filtered result against the last-seen
variableValues object so the filter runs once per operation.

The cache is a single { key, value } slot compared by identity, not a WeakMap.
graphql hands every resolver in one execute the same variableValues object, so
the common case is a bare `===` hit with no per-operation allocation. A nested
execute() sharing the same object contextValue reuses the outer rootCtx but
carries its own variableValues; the identity compare recomputes for it and the
later inner fields reuse the slot, so each field's tags stay correct. A
regression test covers that nested case.

Microbenchmark (Node v26.3.1, V8 14.6, n=2M x 7 trials, drop best+worst),
per-operation cost of rootCtx setup + N arg-bearing field filters:

  1 field,  1 object:  baseline  53 ns  weakmap 73 ns (+37%)  slot 54 ns (+2%)
  3 fields, 1 object:  baseline 163 ns  weakmap 82 ns (-49%)  slot 56 ns (-65%)
  10 fields,1 object:  baseline 519 ns  weakmap 113 ns(-78%)  slot 61 ns (-88%)
  3 fields, 2 objects: baseline 160 ns  weakmap 147 ns(-8%)   slot 114 ns(-29%)
  10 fields,2 objects: baseline 506 ns  weakmap 177 ns(-65%)  slot 124 ns(-75%)

A WeakMap regresses the single-field common case (its allocation costs more
than one filter call); the identity slot wins in every scenario.

* test(graphql): exercise the memoized variables filter across sibling fields

A single operation selecting two argument-bearing fields is the only shape that
reaches the cached return in #filterVariables; every prior variables test picks
one field and only ever hits the miss path. Assert both sibling resolve spans
draw their own tags from the one shared filtered object and that the filter runs
once for the resolve path rather than per field.
…health-check (#9134)

* fix(graphql): trace resolvers reached through unions and interfaces

The resolver-wrapping traversal only descended through lists and non-nulls, so
it never reached object types referenced solely as union members or interface
implementations. graphql resolves the concrete type at runtime, so an Apollo
Federation subgraph (whose entity types are reachable only through the synthetic
`_Entity` union returned by `_entities`) produced no graphql.resolve spans for
those fields.

Descend into union members via getTypes() and interface implementations via
schema.getPossibleTypes(), keyed off the realm-agnostic `Symbol.toStringTag`
discriminator so an interface without an explicit resolveType is still covered.
patchedTypes keeps the walk one-time per type, so cyclic abstract types
terminate and there is no per-resolve cost.

Fixes: #1057

* fix(graphql): skip the Apollo Federation health-check operation

Apollo Gateway's polling subgraph health check sends a fixed
`query __ApolloServiceHealthCheck__ { __typename }` on every poll interval,
burying real traffic under health-check noise. Skip that named operation by
exact name before span creation. The skip is unconditional because the name is
spec-reserved (the `__` prefix) and the operation carries no user input, so
there is nothing for AppSec or IAST to inspect and no legitimate operation to
collide with. The gateway's other probe, the anonymous startup
`{ __typename }` query, is left alone on purpose: it fires only on startup and
schema update, so it is not a source of recurring noise.

Fixes: #1057

* fix(graphql): harden federation health-check skip and interface walk

1. The health-check skip matched the reserved operation name alone. Since
   operation names are client-controlled, a request naming itself
   `__ApolloServiceHealthCheck__` while selecting a real field (or using a
   mutation, or adding selections beside `__typename`) was silently dropped
   from tracing and from the AppSec/IAST resolver channels. Confirm the
   gateway's exact spec-fixed shape (`query __ApolloServiceHealthCheck__
   { __typename }`) before skipping so the reserved name can't become a
   tracing/security bypass.
2. `getPossibleTypes` is schema-specific, but the interface-implementation
   descent shared the global `patchedTypes` guard. Two schemas reusing one
   interface instance meant the first schema's walk marked the interface and
   the second schema's implementations were never wrapped, so their resolvers
   went untraced. Key the interface descent per (schema, interface) instead.

* fix(graphql): wrap resolvers per schema when types are shared

The resolver-wrapping walk terminated on a global per-type guard, but the
walk is schema-dependent: union members and interface implementations are
read through the schema (getTypes / getPossibleTypes) and differ between
schemas. Two schemas sharing any type on the path to an abstract type — a
reused root Query, a shared interface — meant the first schema's walk marked
that type, and the second schema's walk returned at it before reaching its
own members or implementations, leaving those resolvers untraced.

Key the walk's visited set per (schema, type) so each schema runs its own
full traversal. Resolver wrapping is already idempotent via patchedResolvers,
so re-walking a type shared across schemas never double-wraps a resolver.

Fixes: #1057

* fix(graphql): skip parse and validate spans for the health-check

The health-check skip only suppressed the execute and resolver spans, so a
gateway poll still emitted graphql.parse and graphql.validate. graphql runs
both before execute, so every cold poll (and every poll on servers without a
document cache, e.g. graphql-yoga) left two heartbeat spans a customer's
operation filter would flag.

Detect the poll from the raw query string at parse — the only input parse has —
and mark the produced document so validate and execute skip it too. Apollo
Server caches parsed+validated documents in its documentStore and reuses the
same document object across polls, so a warm poll reaches execute with the
already-marked document; when a health-check document reaches execute without
ever passing through the instrumented parse (pre-populated cache, hand-built
document), the operation-shape check remains the backstop.

Fixes: #1057

* fix(graphql): require exact Apollo health-check documents

Health-check operation names and parsed documents are caller-controlled. Requiring Apollo's complete constant shape keeps transformed or multi-operation documents, and operations with variables or directives, on the traced AppSec and IAST path.
Cypress full titles omit the spec path, so equal titles in separate files shared retry history and produced incorrect final status.
This prevents coverage, logs, or telemetry payloads from being lost when traces flush before their IPC sends complete.
* chore(deps-dev): update sonarjs for TypeScript 7

SonarJS 4.1 reads compiler enums removed in TypeScript 7 and crashes before ESLint can run.

* test(vitest): use the sandboxed TypeScript compiler

Vitest 3 resolves a bare tsc command from the inherited npm PATH, which made sandboxed typechecks use the repository compiler instead of their pinned dependency.
* refactor(express): trace middleware via layer prototype dispatch

Middleware tracing replaced `layer.handle` with a wrapper and re-exposed the
user handler through an enumerable `_datadog_orig` back-reference, the only
property loopback's `_findLayerByHandler` could follow to tag a layer with its
phase. That ties the tracer to loopback's private reflection heuristic, where
the property name and its enumerability are both load-bearing.

Wrap the host `Layer` prototype dispatch (`handle_request`/`handle_error`, and
`handleRequest`/`handleError` on router >=2) and read per-layer metadata from a
WeakMap, leaving `layer.handle` the user's function. loopback's first lookup
(`layer.handle === handler`) then matches with no tracer-specific contract, so
the back-reference, the `express-async-errors` `__handle` branch, and the
`_name` write-back onto the user handler are no longer needed. A synchronous
throw or a rejected promise becomes `next(error)` in the host dispatch, so the
wrapped `next` captures both without a tracer-side try/catch.

Refs: #9062

* fix(express): trace middleware on express <4.3.0 (no prototype dispatch)

express <4.3.0 has no `Layer.prototype.handle_request`/`handle_error`; the
router invokes `layer.handle` directly, so wrapping the prototype traced
nothing and dropped middleware, route-handler, and code-origin spans there.
Replace `layer.handle` in place (arity preserved so the host still routes error
handlers) when the layer exposes no dispatch method. express 4.3.0+, express 5,
the router package, and loopback keep `handle` pristine via the prototype wraps.

Also point the router-helper spec at the renamed `setLayerMeta` helper.

* test(router): cover express-async-errors on prototype-dispatch hosts

express-async-errors redefines `handle` as a getter/setter that stores the
wrapped handler in `__handle` and patches `handle` only, never `handle_request`.
On express 4.3.0+ the tracer's prototype-dispatch wrap therefore has to survive
that patch, the arity gate has to read the real 3-arg handler, and a rejected
async handler has to reach the wrapped `next` as `next(error)`. Pin that path so
a regression surfaces here instead of in a downstream tracer test.

* fix(express): restore error publishing for throwing middleware on express <4.6.0

On express <4.6.0 the router has no `Layer` prototype dispatch: it runs
`layer.handle` directly and, on a synchronous throw, catches outside the layer
and calls its own `next(error)` — never the wrapped `next` the tracer installed.
The prototype-dispatch rewrite dropped the legacy handle wrap's catch, so a
throwing middleware or route handler no longer published `middleware:error` /
`middleware:next` / `middleware:finish`: the span lost its error tag and lingered
on the stack until request finish.

Restore the catch in `wrapLegacyHandle` to publish error/next/finish and rethrow,
mirroring `wrapNext`. The prototype hosts (express >=4.6.0, express 5, router)
already route the throw through the wrapped next, so only the legacy path needs it.

Also correct the version boundary in the surrounding comments: `handle_request`
landed in express 4.6.0, not 4.3.0, so the legacy path covers `>=4.0.0 <4.6.0`.

Refs: #9067 (comment)

* fix(express): publish middleware next/finish once per continuation

A handler that calls `next()` and then rejects (`async (req, res, next) => {
next(); await bg() }` where `bg()` rejects) makes the host invoke the same
wrapped `next` twice: the clean `next()` finishes and pops the middleware span,
then the host's rejection pass calls `next(error)` again. Since the middleware
stack is already empty, that second pass tagged the error on the parent span,
inventing a request-level error the middleware never surfaced.

Guard the wrapped continuation so its error/next/finish publishes fire at most
once per dispatch; the second call still forwards to the host chain untouched.

Add the missing JSDoc on `hasLayerDispatch`.
…ies (#8948)

* chore(electron): add electron package exclusion config

* chore(electron): add electron package generation script and initial package.electron.json

Adds scripts/generate-electron-package.js to automatically generate a
version of package.json with excluded optional dependencies for the
dd-trace-electron package variant. Supports --check flag for CI validation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(electron): wire electron package verify into lint

* chore(electron): add electron publish script

* docs(electron): document Dependabot behavior for package.electron.json

* chore(electron): move generation to publish time, add release jobs, gitignore generated file

* feat(electron): add Electron entrypoint and make OpenFeature self-registering

Adds Tracer.registerFeature() / NoopProxy.registerNoop() so subsystems
can opt into the tracer without being hardcoded in proxy.js. OpenFeature
uses this via a new register.js that self-registers on require.

The Electron entrypoint (index.electron.js) simply omits that require,
so OpenFeature and its native dep (@datadog/openfeature-node-server) are
absent from the Electron build with no conditional logic in the core.
index.js delegates to index.electron.js after calling register.js,
keeping both entrypoints in sync with zero duplication.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(proxy): adapt spec to OpenFeature self-registration

OpenFeature is no longer hardcoded in proxy.js so the test now calls
registerFeature() explicitly with the mocked modules instead of passing
them through proxyquire.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(electron): extract bootstrap into shared module

Both index.js and index.electron.js now require ./src/bootstrap directly
rather than one depending on the other. index.js remains the only
entrypoint that registers OpenFeature.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(electron): use src/index.js in bootstrap to respect DD_TRACE_ENABLED

bootstrap.js was requiring ./proxy directly, bypassing src/index.js which
handles DD_TRACE_ENABLED=false and Jest worker environments by returning
the noop proxy instead. This caused global._ddtrace to always be the full
Tracer in contexts where it should be the noop.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(plugins): evict src/bootstrap from require cache on tracer rebuild

The agent test helper clears specific module cache entries before
rebuilding the tracer. src/bootstrap.js was not in the eviction list,
so after global._ddtrace was deleted the cached bootstrap module still
exported the stale (deleted) proxy instance instead of re-running
initialization.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: add CODEOWNERS entries for electron entrypoints and release workflow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(electron): fix abort.integration telemetry missing with OpenFeature

Requiring openfeature/register.js from index.js previously loaded
proxy.js as a side-effect (to call Tracer.registerFeature), which
transitively loaded datadog-instrumentations/register.js. That module
registers logAbortedIntegrations with beforeExitHandlers, but at that
point the global symbol was not yet set up by bootstrap.js, so the
optional-chaining silently no-oped and the handler was never registered.

Introduce a feature-registry module that openfeature/register.js pushes
to directly without requiring proxy.js. proxy.js and noop/proxy.js read
from it at class-definition time (after the global symbol is set up by
bootstrap.js). This keeps all initialization gated on !global._ddtrace.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: add CODEOWNERS entries for bootstrap and feature-registry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci(electron): refactor release jobs for electron package

Fix broken `needs: publish-latest` reference by renaming to
`publish-electron` with `needs: publish`. Drop the v5.x branch
guard since the job already only runs when publish succeeds
(which itself is gated to release branch pushes via setup).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(electron): address Codex review findings

- Pass computed npm dist-tag to electron publish so maintenance
  branches don't erroneously move the latest tag
- Make electron publish idempotent: skip if the version is already
  on the registry, matching the behaviour of the regular publish step
- Exclude oxc-parser from the electron package (native bindings)
- Restore @DataDog/libdatadog exclusion; crashtracking is not
  supported in Electron — wrap its start() in a local try/catch so
  a missing libdatadog doesn't abort tracer initialization

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
undici 8.7.0 (nodejs/undici#5116) changed the default so a plain HTTP request
through an HTTP proxy forwards an absolute-form request instead of tunneling
via CONNECT. The ProxyAgent CONNECT-span regression test then sees no CONNECT
request at all and fails asserting a finished CONNECT span. Passing
proxyTunnel: true restores the tunnel; the option is a no-op on undici < 6.22.0,
where CONNECT was always used.

Refs: nodejs/undici#5116
Bumps the cloud-and-messaging group with 1 update in the /packages/dd-trace/test/plugins/versions directory: [bullmq](https://github.com/taskforcesh/bullmq).


Updates `bullmq` from 5.80.1 to 5.80.2
- [Release notes](https://github.com/taskforcesh/bullmq/releases)
- [Commits](taskforcesh/bullmq@v5.80.1...v5.80.2)

---
updated-dependencies:
- dependency-name: bullmq
  dependency-version: 5.80.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: cloud-and-messaging
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…9183)

* fix(aws-sdk): record kinesis DSM checkpoint only when context ships

When a Kinesis record exceeds the 1 MiB cap, injectToMessage bailed after
setDSMCheckpoint had already run: it recorded a produce checkpoint, advanced the
pathway context, and tagged pathway.hash on the span, yet params.Data was never
written so nothing shipped on the wire. The producer left a dangling pathway edge
no consumer completes and a span tagged with a hash for a message it never sent.

Gate on the trace-context payload before setDSMCheckpoint so a record we cannot
ship records no checkpoint, advances no pathway, and tags no hash. The bounded
dd-pathway-ctx-base64 bytes are added after the gate; they cannot realistically
tip a record that already cleared 1 MiB with room for them.

EventBridge shares this checkpoint-before-gate pattern and is tracked separately
in #8476; this change is Kinesis-only.

* refactor(aws-sdk): track message injection with a boolean, drop isEmpty

The kinesis, sqs, and sns producers decided whether to attach `_datadog`
by re-scanning the freshly built `ddInfo` carrier with an `isEmpty`
for-in helper. A local `injected` flag set at each population site
carries the same fact without the per-send rescan or the shared helper,
and matches `DsmPathwayCodec.encode`'s own `!dataStreamsContext.hash`
guard on the sns path so an empty pathway context no longer counts as
injected.

Replace the faked kinesis inject-to-message spec — an
`Object.create(Kinesis.prototype)` instance with a stubbed tracer — with
a real agent-loaded regression in kinesis.dsm.spec.js: a record that
only clears the 1 MiB cap before the trace context is attached must
record no produce checkpoint, asserted through the `putRecord` span
carrying no `pathway.hash`. Drop the sqs unit case that asserted a
carrier state (`injectTraceContext` true, `inject` a no-op) no real
caller reaches.

* refactor(core): return whether inject wrote anything into the carrier

`Tracer.inject` and every propagator now report whether they wrote any
context, so the AWS SDK messaging producers stop attaching an empty
`_datadog` message attribute when nothing was injected. Previously they
assumed a write happened whenever injection was attempted, which shipped an
empty carrier under `DD_TRACE_PROPAGATION_STYLE_INJECT=none` and whenever a
disabled-APM-tracing (standalone ASM) trace was stripped after injection.

The standalone ASM strip runs on the `dd-trace:span:inject` channel after the
propagator writes, so the text_map propagator re-checks the `_dd.p.ts` trace
tag when APM tracing is disabled to keep the returned value truthful without
rescanning the carrier.

* test: align inject test doubles with the boolean carrier-write return

`Tracer.inject` now reports whether it wrote context into the carrier, and the
AWS SDK producers read that instead of rescanning with `isEmpty`. Four
expectations still modelled the old `undefined` return and failed in CI:

1. sqs-inject-to-message: stubs mutate the carrier but returned `undefined`, so
   the producer dropped `_datadog`; return `true` from the writing stubs and
   `false` from the no-op default.
2. dd-trace-api: `inject` forwards its return through the public API, now
   `false` for the empty test args; assert `false`.
3. pathway: type the no-hash `encode` argument concretely to clear
   jsdoc/reject-any-type.
4. kinesis.dsm: `assert.match(resource, /^putRecord/)` clears
   eslint-prefer-assert-match.

* fix(aws-sdk): reserve the DSM pathway field before the kinesis size gate

The size gate ran on the trace-context payload before DsmPathwayCodec.encode
appended the fixed-size dd-pathway-ctx-base64 field. A record sitting within 55
bytes of the 1 MiB cap cleared the gate, recorded a checkpoint, and then wrote an
over-cap params.Data that Kinesis rejects, failing the user's putRecord. Reserve
the pathway field's bytes in the gate so a record that only fits without it
records no checkpoint and never ships over the cap.

* fix(types): mirror inject boolean return in the v5 type surface

Tracer.inject now reports whether it wrote context into the carrier, and
index.d.ts was updated to return boolean. index.d.v5.ts still declared
void. inject exists on v5 and this return is not v6-only, so the v5
release type swap (scripts/release/swap-v5-types.js) would ship a stale
void declaration and hide the return value from v5 TypeScript users even
though the runtime provides it. Mirror the signature and JSDoc so the two
public surfaces diverge only by the intended v6 cleanups.

Refs: #9183 (comment)

* fix(types): keep public inject void on v5/v6, expose boolean on v7

The prior commit widened Tracer.inject's declared return from void to
boolean across the public surface. That is a breaking TypeScript change:
under strict mode `const x: void = tracer.inject(...)` and returning
`tracer.inject(...)` from a void-typed function stop compiling. It must
not ship on a shipping major.

The runtime already returns the boolean and the internal AWS SDK
producers consume it through the unwrapped DatadogTracer (a plugin's
`this.tracer` resolves to `_tracer._tracer`, and the DSM checkpointer
holds that inner tracer directly), never through the public proxy. So
the boolean stays an internal signal regardless of what the public
`.d.ts` promises.

Freeze the contract per major:

1. index.d.v5.ts and the new index.d.v6.ts declare `inject(): void` —
   the current shipping majors keep their contract.
2. index.d.ts (master is 7.0.0-pre) declares `inject(): boolean` as the
   next-major public API, documented in MIGRATING.md under 6.0 to 7.0.

Generalize the release type swap: swap-v5-types.js only handled v5, so a
v6 release would publish the v7 index.d.ts. Rename it to
swap-legacy-types.js and pick index.d.v<major>.ts by the release major;
the newest major has no frozen file and is a no-op. Adding a future
frozen surface is now a single file drop. The .v<major>.ts files stay
out of the npm `files` array by design — the swap copies the chosen one
over index.d.ts at pack time, so only index.d.ts ships.

Refs: #9183 (comment)

* fix(propagation): return lazily created carriers

Standalone ASM can remove trace headers while leaving baggage in the carrier. A boolean result reported false for that non-empty carrier, causing AWS messaging producers to drop valid context. Return the carrier internally after its first write while keeping the public tracer API void at the proxy boundary.

Kinesis limits cover Data plus PartitionKey. Include both before recording a DSM checkpoint and allow records at the exact default limit.

No-write injection measured 11.96-12.21 ns eager vs 6.92-6.98 ns lazy; one write in eight measured 29.30-29.46 ns vs 26.09-26.66 ns on Node 24.18.0 / V8 13.6.233.17, 5M iterations x 7 trials with best and worst dropped.
* feat(http2): trace core-API HTTP/2 servers

A server using the raw stream API (`createServer().on('stream', ...)`) produced
no server span, because the instrumentation only hooked the compatibility
`request` event. This adapts the `Http2Stream` and its pseudo-header map into the
minimal req/res shape the shared web lifecycle consumes, so the core path now
gets the same span, context propagation, and header tagging as the compatibility
path.

A compatibility server emits both `request` and `stream` for every request, so
the `stream` branch only creates a span when the server has no `request`
listener; otherwise the request would be double-instrumented.

Fixes: #312

* fix(http2): default core-stream status to 200 when no response was sent

A core-API stream aborted before `stream.respond()` runs (client RST, server
`stream.close(code)`, a throwing handler) has an empty `stream.sentHeaders`, so
the adapter reported `res.statusCode` as `undefined`. `web.js` then ran
`validateStatus(undefined)`, which is falsy, tagged the span as an error, and
dropped the `http.status_code` tag — diverging from the compatibility path,
whose `Http2ServerResponse.statusCode` defaults to 200 for the same abort. The
adapter now falls back to 200 so both paths agree.

Drive-by fix:

* Pin the stream-adapter req/res shape with a `@typedef` naming the `web.js` /
  `url.js` / `ip_extractor.js` fields it must satisfy, so a new read added there
  fails the type check instead of silently resolving to `undefined` on the core
  path only.
* Record at `bindEmit` that finish is single-sourced from the stream's one
  `close` event, which is why the `!req.stream` idempotency-guard bypass in
  `web.js` is harmless here.

Fixes: #312

* fix(http2): keep the server span active for mixed stream/request servers

A server that registers both a raw `stream` listener and a compatibility
`request` listener emits a single `stream` event whose internal listener
synthesizes the `request`. The previous gate created the span only on the
synthesized `request`, which fires nested in one stream listener, so the
application's own `stream` listener ran with no active span and any child
spans or handler duration it produced were lost.

1. Such mixed servers now create the span from the `stream` event, keeping
   it active across the application's stream listener; the synthesized
   `request` reuses it instead of creating a second span. A request-only
   server still traces on `request` so the compatibility response keeps its
   richer req/res, and the per-request cost stays a single `WeakSet.has`.
2. The `with configured headers` test reconfigured the plugin with a second
   `agent.load` nested under the suite that already loaded it, starting a
   second mock agent and leaking the first server's handle; it now reloads
   in place so a single agent runs.

Drive-by fix:

* Correct the stream-adapter `@typedef`: `res.statusCode` is the numeric
  `:status` pseudo-header, and `res.getHeader` can return a string array.

* fix(http2): hand mixed-server requests the real req/res via an adopt channel

A server with both a raw `stream` listener and a compatibility `request`
listener creates its span from the `stream` event using a throwaway adapter.
The synthesized `request` off the same stream then found no context, so a
user's `request` handler calling `web.setRoute`/`web.setFramework` never
reached the span and the finish `hooks.request` received the adapter instead
of the real `Http2ServerRequest`/`Http2ServerResponse`.

The instrumentation now publishes `apm:http2:server:request:adopt` with the
real req/res, and the plugin points the stream-backed context at them. The
join key is the shared `Http2Stream`: `web.linkContextToStream` keys the
context on the stream so the second request resolves to the first's span. That
key is written only for mixed servers (`ctx.adoptable`), so the common
single-listener request pays no extra per-request map write.

* fix(http2): do not trace gRPC-owned HTTP/2 servers

@grpc/grpc-js builds its transport on a core Node `Http2Server` and registers
a raw `stream` listener with no `request` listener. The re-enabled http2
server instrumentation traces exactly that shape, so every gRPC call gained a
`web.request` span on top of its `grpc.server` span, and because the stream
event fires before gRPC's handler, `web.request` became the top frame.

The gRPC instrumentation now marks the server it owns and the http2
instrumentation skips any marked server, so a gRPC call keeps a single span
with gRPC as the top frame. Suppression is unconditional: disabling gRPC
tracing does not resurrect these as `web.request` spans, since a gRPC call over
HTTP/2 has no meaningful HTTP request/response semantics (`:path` is
`/pkg.Svc/Method`, status is always 200 + trailers) and surfacing it as one
would surprise a user who turned gRPC off.

The mark is a module-local `Symbol` on the server instance, read once per emit
behind the existing `hasSubscribers` gate (~1.6 ns; a WeakSet lookup measured
~3.5x slower and needs a shared mutable container across the two
instrumentations). It is set from `_setupHandlers`, the single server-creation
funnel present across the supported range — the newer `createHttp2Server` does
not exist on older versions — and it runs at bind time, before any request
reaches the wrapped `emit`.

* test(grpc): connect non-gRPC probe over IPv4

Linux runners resolve localhost to ::1, but the gRPC fixture listens on IPv4, so the probe failed before reaching the server.

* test(http2): cover stream handler crash path

A synchronous throw from a core stream handler terminates the process, so exercise it in a forked fixture and let NYC collect the child coverage instead of excluding the error path.
…#9177)

* test(agent): reject when no matching trace arrives before the timeout

An `assertSomeTraces` / `expectSomeSpan` expectation whose span never
arrives left the returned promise unsettled: the rejection timeout only
fired when errors had accumulated, so with zero payloads the callback did
nothing and the spec hung until Mocha's 5s per-test timeout killed it with
a generic "Timeout of 5000ms exceeded" instead of failing at the intended
1s window with the real cause.

The rejection timeout now always settles the promise: the accumulated
first/aggregate error when a payload matched but assertions failed, and
otherwise a fresh error naming the timeout window so a missing span points
the reader at "no matching trace received within <timeoutMs>ms".

* test(agent): add assertNoTraces and give slow spans room after timeout reject

Rejecting the assertSomeTraces promise at its timeout broke tests that relied on
the previous never-settling behaviour:

1. "Should not be traced" cases registered an expectation that must never match,
   left the promise unawaited, and passed via a separate setTimeout(done). The
   reject now fires into that path, calling done() twice or surfacing a stray
   "No matching trace". A new assertNoTraces resolves when nothing matches before
   the timeout and rejects only when a forbidden trace arrives; the negative
   sites move to it.
2. Positive tests whose span legitimately lands after 1s (restify <5 uncaught
   exceptions ~5s, the openai/anthropic dead-baseURL retry backoff, kafka
   consumer delivery, aws-sdk cold connect, the http Node-20 timeout cases) now
   set an explicit timeoutMs. openai/anthropic instead drop retries with
   maxRetries: 0 since the endpoint is dead on purpose. The LLMObs harness gets a
   longer window because every call is a real VCR round-trip.
3. mongodb-core's BigInt test returns done() early on the version that throws
   synchronously; the assertion now registers only once the command starts, so
   no expectation is left to reject afterwards.

* test(agent): fail loudly on leaked trace expectations

An assertSomeTraces expectation that is armed but never consumed can keep its rejection timer running after the test ends. The timer then rejects a promise nobody awaits a whole timeout window later, surfacing as an unhandled rejection on an unrelated test.

1. Each expectation promise carries a cancel() that disarms its timer and drops the handler; the consumer that armed it cancels it in its own teardown.
2. The framework reset() disarms every still-armed expectation, then throws to fail the just-finished test by name. Bare subscribe() handlers have no timer and are never counted.
3. The invalid-type SDK test no longer races getEvents() against a timeout, which abandoned a poll loop that kept draining span requests and starving later tests.

* test(agent): drop settled handlers and fix the leaks the guard exposed

This PR's teardown leak guard counts any handler left in the set as armed, but
runCallbackAgainstTraces kept its handler on the timeout and rejectFirst settle
paths, so the guard rejected expectations it had already settled. Drop the
handler on every settle path.

With the guard trustworthy, three specs leaked real expectations:

1. aws-sdk sqs: timeoutMs sat on `.catch()` rather than assertSomeTraces, so the
   suppressed-consumer expectation ran on the 1000ms default and stayed armed past
   the 250ms done().
2. google-cloud-pubsub dsm and index: the DSM checkpoint expectations were never
   awaited. Register before publishing, then await, and read the expected pathway
   hash little-endian to match DataStreamsProcessor's readBigUInt64LE decode.

* test(aws-sdk): make the disabling tests deterministic

`should allow disabling a specific service` and its sqs consumer-span-kind sibling
paired two fire-and-forget assertSomeTraces expectations on a 100ms window with a
fixed setTimeout(done, 250) asserting a match counter. On a cold localstack the
enabled request's span lands after the 100ms window, so its expectation times out,
the counter stays 0, and the guard asserts 0 !== 1.

Assert the disabled request's absence with assertNoTraces and await the enabled
request's assertSomeTraces, which is what assertNoTraces documents in place of a
bare assertSomeTraces plus a separate setTimeout(done, …).

* test(claude-agent-sdk): give the agentic-call assertion room under the timeout

This PR makes assertSomeTraces reject at its timeout instead of waiting out the
mocha deadline. The full-agentic-call test registers the expectation, then spawns
the claude subprocess and runs several steps before the trace flushes, which takes
longer than the 1000ms default, so the expectation rejected before the trace ever
arrived. Opt into a 10s timeoutMs and raise the block's mocha timeout to 15s.
Bumps the test-versions group with 1 update in the /packages/dd-trace/test/plugins/versions directory: [pnpm](https://github.com/pnpm/pnpm/tree/HEAD/pnpm11/pnpm).


Updates `pnpm` from 11.11.0 to 11.12.0
- [Release notes](https://github.com/pnpm/pnpm/releases)
- [Changelog](https://github.com/pnpm/pnpm/blob/main/pnpm11/pnpm/CHANGELOG.md)
- [Commits](https://github.com/pnpm/pnpm/commits/v11.12.0/pnpm11/pnpm)

---
updated-dependencies:
- dependency-name: pnpm
  dependency-version: 11.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: test-versions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…with 1 update (#9367)

Bumps the gh-actions-packages group with 1 update in the / directory: [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action).
Bumps the gh-actions-packages group with 1 update in the /.github/workflows directory: [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action).


Updates `slackapi/slack-github-action` from 3.0.3 to 3.0.4
- [Release notes](https://github.com/slackapi/slack-github-action/releases)
- [Changelog](https://github.com/slackapi/slack-github-action/blob/main/CHANGELOG.md)
- [Commits](slackapi/slack-github-action@45a88b9...fc46ded)

Updates `slackapi/slack-github-action` from 3.0.3 to 3.0.4
- [Release notes](https://github.com/slackapi/slack-github-action/releases)
- [Changelog](https://github.com/slackapi/slack-github-action/blob/main/CHANGELOG.md)
- [Commits](slackapi/slack-github-action@45a88b9...fc46ded)

---
updated-dependencies:
- dependency-name: slackapi/slack-github-action
  dependency-version: 3.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: gh-actions-packages
- dependency-name: slackapi/slack-github-action
  dependency-version: 3.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: gh-actions-packages
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
@dd-octo-sts

dd-octo-sts Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Overall package size

Self size: 6.77 MB
Deduped: 7.43 MB
No deduping: 7.43 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.3.1 | 122.62 kB | 438.86 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Jul 15, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🔄 Datadog retried 1 test - 1 passed on retry View in Datadog

🎯 Code Coverage (details)
Patch Coverage: 99.74%
Overall Coverage: 96.87%

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 77b0d3b | Docs | Datadog PR Page | Give us feedback!

BridgeAR and others added 11 commits July 16, 2026 05:52
Assertions that resolved on a valid prefix could miss duplicate or late payloads emitted before the child finished. Apply the existing post-exit drain collector to repeated-run, finalization, and retry contracts, and make its timing tests deterministic.
Disabling git upload left readiness unresolved, so settings requests waited for the 60-second fallback.
Falsy fallback logic replaced an explicit zero retry budget with defaults, scheduling retries the backend disabled.
Clamp short failed-test durations at zero and cover the regression through a real Vitest integration run.

Co-authored-by: Ruben Bridgewater <ruben.bridgewater@datadoghq.com>
Node does not guarantee that Date.now() reports the full delay when a setTimeout callback runs, so the exact 200 ms lower bound occasionally observed 199 ms. Advancing fake timers across the 199/200 ms boundary pins the contract without depending on scheduler timing.
Apollo Gateway reaches the Mercurius request boundary before the graphql-js hooks, so each poll still emitted a graphql.request span after its nested spans were suppressed. Match the same exact fixed query at that boundary so health-check-shaped user operations remain traced.
)

Remote configuration that disables and re-enables tracing could leave OpenFeature consumers bound to an orphaned provider and leave AI Guard integrations unsubscribed. Preserve lazily initialized feature modules across reconfiguration and re-enable their integrations when tracing resumes.

Co-authored-by: Bo Stendal Sørensen <bo@stendal-sorensen.net>
Co-authored-by: Sameeran Kunche <sameeran.kunche@datadoghq.com
BridgeAR added 3 commits July 16, 2026 05:52
* test(ai): cover compatible SDK provider version matrix

* test(ai): use latest compatible ESM dependencies
Real applications load LoopBack through its public entry once during bootstrap. Keep that path in the compatibility test and give its eager initialization ten seconds without repeating the work for every case.
Runtime-gated declarations could leave the first active range as the unversioned target even when a newer compatible range was also active.
@dd-octo-sts
dd-octo-sts Bot force-pushed the v6.4.0-proposal branch from 6b315e2 to bd293ef Compare July 16, 2026 05:52
@pr-commenter

pr-commenter Bot commented Jul 16, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-07-16 11:27:54

Comparing candidate commit 77b0d3b in PR branch v6.4.0-proposal with baseline commit a20ae3c in branch v6.x.

📊 Benchmarking dashboard

Found 0 performance improvements and 0 performance regressions! Performance is the same for 2314 metrics, 44 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

Unstable benchmarks

These benchmarks have a confidence interval too wide to call a change; treat them as noise rather than signal.

scenario:appsec-appsec-enabled-24

  • unstable execution_time [-203.587ms; +215.833ms] or [-7.627%; +8.085%]

scenario:appsec-appsec-enabled-26

  • unstable execution_time [-236.310ms; +229.459ms] or [-9.286%; +9.017%]

scenario:appsec-appsec-enabled-with-attacks-24

  • unstable execution_time [-158.585ms; +167.075ms] or [-5.138%; +5.413%]

scenario:appsec-appsec-enabled-with-attacks-26

  • unstable execution_time [-189219.092µs; +188125.325µs] or [-6.498%; +6.461%]

scenario:appsec-control-20

  • unstable execution_time [-130.952ms; +127.704ms] or [-7.981%; +7.783%]

scenario:appsec-control-24

  • unstable execution_time [-105.494ms; +124.023ms] or [-8.554%; +10.057%]

scenario:appsec-control-26

  • unstable execution_time [-126.226ms; +122.104ms] or [-10.167%; +9.835%]

scenario:appsec-iast-no-vulnerability-iast-enabled-always-active-20

  • unstable execution_time [-17.476ms; +10.246ms] or [-6.724%; +3.942%]

scenario:appsec-iast-no-vulnerability-iast-enabled-default-config-20

  • unstable execution_time [-10.575ms; +19.854ms] or [-4.105%; +7.706%]

scenario:appsec-iast-with-vulnerability-control-20

  • unstable execution_time [-31521.421µs; +32763.488µs] or [-5.759%; +5.986%]

scenario:debugger-line-probe-with-snapshot-default-24

  • unstable cpu_user_time [-1893.661ms; +391.488ms] or [-22.415%; +4.634%]
  • unstable execution_time [-1889.268ms; +404.658ms] or [-20.624%; +4.417%]
  • unstable instructions [-16.1G instructions; +3.2G instructions] or [-23.381%; +4.599%]
  • unstable throughput [-87.959op/s; +530.129op/s] or [-2.449%; +14.760%]

scenario:debugger-line-probe-with-snapshot-default-26

  • unstable cpu_user_time [-2295.480ms; +740.207ms] or [-24.045%; +7.754%]
  • unstable execution_time [-2366.996ms; +819.268ms] or [-23.007%; +7.963%]
  • unstable instructions [-20.3G instructions; +6.6G instructions] or [-25.467%; +8.218%]
  • unstable throughput [-166.756op/s; +453.729op/s] or [-5.164%; +14.052%]

scenario:debugger-line-probe-with-snapshot-minimal-24

  • unstable cpu_user_time [-1726.074ms; +565.704ms] or [-20.907%; +6.852%]
  • unstable execution_time [-1741.190ms; +566.186ms] or [-19.381%; +6.302%]
  • unstable instructions [-14.7G instructions; +4.7G instructions] or [-21.761%; +7.004%]
  • unstable throughput [-154.486op/s; +469.145op/s] or [-4.216%; +12.802%]

scenario:debugger-line-probe-with-snapshot-minimal-26

  • unstable cpu_user_time [-2300.675ms; +721.137ms] or [-24.106%; +7.556%]
  • unstable execution_time [-2310.828ms; +707.569ms] or [-22.454%; +6.876%]
  • unstable instructions [-20.3G instructions; +6.5G instructions] or [-25.501%; +8.203%]
  • unstable throughput [-136.453op/s; +462.152op/s] or [-4.239%; +14.358%]

scenario:debugger-line-probe-without-snapshot-24

  • unstable cpu_user_time [-1507.579ms; +486.602ms] or [-18.493%; +5.969%]
  • unstable execution_time [-1501.584ms; +499.325ms] or [-16.937%; +5.632%]
  • unstable instructions [-12.8G instructions; +4.1G instructions] or [-19.206%; +6.165%]
  • unstable throughput [-146.067op/s; +430.990op/s] or [-3.954%; +11.668%]

scenario:dogstatsd-with-tags-20

  • unstable cpu_user_time [-368.369ms; +300.075ms] or [-7.840%; +6.386%]
  • unstable execution_time [-365.905ms; +295.807ms] or [-7.660%; +6.192%]
  • unstable throughput [-93360.884op/s; +128583.644op/s] or [-5.306%; +7.308%]

scenario:plugin-aws-sdk-lambda-inject-with-context-24

  • unstable cpu_user_time [-252.687ms; +194.141ms] or [-6.578%; +5.054%]
  • unstable execution_time [-251.722ms; +192.896ms] or [-6.508%; +4.987%]
  • unstable throughput [-23441.982op/s; +32100.828op/s] or [-4.503%; +6.167%]

scenario:plugin-graphql-long-with-depth-off-20

  • unstable max_rss_usage [-6253.899KB; +8013.328KB] or [-4.823%; +6.179%]

scenario:plugin-graphql-long-with-depth-on-max-20

  • unstable cpu_user_time [-728.662ms; +742.910ms] or [-5.679%; +5.790%]
  • unstable execution_time [-725.951ms; +753.586ms] or [-5.535%; +5.746%]
  • unstable throughput [-3.462op/s; +3.335op/s] or [-5.640%; +5.433%]

scenario:plugin-pg-service-24

  • unstable cpu_usage_percentage [-9.577%; +5.904%]
  • unstable execution_time [-169.800ms; +264.546ms] or [-10.073%; +15.693%]
  • unstable throughput [-372822.780op/s; +240071.926op/s] or [-10.315%; +6.642%]

scenario:test-optimization-large-suite-20

  • unstable max_rss_usage [-5179.004KB; +3383.671KB] or [-6.463%; +4.222%]

@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.74205% with 3 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (v6.x@a20ae3c). Learn more about missing BASE report.

Files with missing lines Patch % Lines
...ty/intelligent-test-runner/get-skippable-suites.js 94.54% 3 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             v6.x    #9368   +/-   ##
=======================================
  Coverage        ?   96.90%           
=======================================
  Files           ?      923           
  Lines           ?   123011           
  Branches        ?    21338           
=======================================
  Hits            ?   119202           
  Misses          ?     3809           
  Partials        ?        0           
Flag Coverage Δ
aiguard 53.65% <66.08%> (?)
aiguard-integration 57.09% <73.26%> (?)
apm-bucket-0 55.02% <65.74%> (?)
apm-bucket-1 58.89% <70.79%> (?)
apm-bucket-2 58.12% <85.74%> (?)
apm-bucket-3 55.50% <65.74%> (?)
apm-capabilities-tracing 60.66% <60.13%> (?)
apm-integrations-aerospike 53.03% <65.74%> (?)
apm-integrations-confluentinc-kafka-javascript 57.21% <77.50%> (?)
apm-integrations-couchbase 53.40% <65.74%> (?)
apm-integrations-http 58.04% <56.53%> (?)
apm-integrations-kafkajs 57.86% <77.50%> (?)
apm-integrations-next 54.29% <54.25%> (?)
apm-integrations-prisma 54.28% <65.74%> (?)
appsec 68.84% <60.63%> (?)
appsec-express_fastify_graphql 65.72% <69.09%> (?)
appsec-integration 51.93% <62.01%> (?)
appsec-kafka_ldapjs_lodash 59.16% <76.12%> (?)
appsec-mongodb-core_mongoose_mysql 62.40% <79.67%> (?)
appsec-next 52.85% <50.89%> (?)
appsec-node-serialize_passport_postgres 62.03% <79.67%> (?)
appsec-sourcing_stripe_template 60.42% <73.23%> (?)
debugger 65.68% <56.89%> (?)
instrumentations-bucket-0 48.87% <59.74%> (?)
instrumentations-bucket-1 55.08% <67.20%> (?)
instrumentations-bucket-10 56.70% <66.19%> (?)
instrumentations-bucket-11 48.87% <65.74%> (?)
instrumentations-bucket-12 49.04% <76.10%> (?)
instrumentations-bucket-13 48.81% <65.74%> (?)
instrumentations-bucket-2 50.02% <73.84%> (?)
instrumentations-bucket-3 53.99% <68.81%> (?)
instrumentations-bucket-4 49.29% <65.74%> (?)
instrumentations-bucket-5 53.13% <53.79%> (?)
instrumentations-bucket-6 55.72% <76.12%> (?)
instrumentations-bucket-7 53.62% <54.25%> (?)
instrumentations-bucket-8 54.76% <67.20%> (?)
instrumentations-bucket-9 56.18% <66.19%> (?)
instrumentations-instrumentation-couchbase 48.27% <66.43%> (?)
instrumentations-integration-esbuild 34.04% <40.34%> (?)
llmobs-ai_anthropic_bedrock 57.80% <60.34%> (?)
llmobs-bucket-1 57.13% <70.13%> (?)
llmobs-openai 57.53% <77.59%> (?)
llmobs-sdk 60.08% <80.60%> (?)
llmobs-vertex-ai 54.35% <67.55%> (?)
openfeature 54.71% <64.96%> (?)
openfeature-unit 49.94% <69.96%> (?)
platform-core_esbuild_instrumentations-misc 38.52% <46.92%> (?)
platform-integration 62.32% <61.75%> (?)
platform-shimmer_unit-guardrails_webpack 37.18% <42.03%> (?)
plugins-bucket-0 53.29% <57.50%> (?)
plugins-bucket-1 55.22% <71.48%> (?)
plugins-bucket-11 57.66% <69.65%> (?)
plugins-bucket-18 57.18% <63.79%> (?)
plugins-bucket-19 55.46% <68.16%> (?)
plugins-bucket-20 57.70% <78.07%> (?)
plugins-bucket-4 53.87% <54.25%> (?)
plugins-bullmq_cassandra_cookie 57.50% <77.50%> (?)
plugins-cookie-parser_crypto_dd-trace-api 52.42% <66.43%> (?)
plugins-fetch_fs_generic-pool 54.70% <56.53%> (?)
plugins-google-cloud-pubsub_grpc_handlebars 59.95% <64.75%> (?)
plugins-hapi_hono_ioredis 55.89% <54.25%> (?)
plugins-jest_knex_langgraph 51.79% <68.06%> (?)
plugins-ldapjs_light-my-request_limitd-client 53.54% <65.74%> (?)
plugins-lodash_mariadb_memcached 54.33% <65.74%> (?)
plugins-moleculer_mongodb_mongodb-core 57.43% <76.12%> (?)
plugins-mongoose_multer_mysql 54.82% <65.74%> (?)
plugins-mysql2_nats_node-serialize 56.36% <76.12%> (?)
plugins-opensearch_passport-http_pino 55.22% <78.20%> (?)
plugins-postgres_process_pug 54.41% <65.74%> (?)
plugins-redis_router_sequelize 57.20% <74.63%> (?)
plugins-test-and-upstream-rhea_undici_url 57.07% <51.62%> (?)
plugins-valkey_vm_winston 53.97% <68.16%> (?)
plugins-ws 54.92% <76.47%> (?)
profiling 58.29% <50.71%> (?)
serverless-aws-sdk-aws-sdk 50.76% <55.37%> (?)
serverless-aws-sdk-bedrockruntime 50.75% <52.01%> (?)
serverless-aws-sdk-client 52.12% <68.80%> (?)
serverless-aws-sdk-dynamodb 51.80% <52.01%> (?)
serverless-aws-sdk-eventbridge 46.44% <58.20%> (?)
serverless-aws-sdk-kinesis 54.79% <62.82%> (?)
serverless-aws-sdk-lambda 52.87% <57.50%> (?)
serverless-aws-sdk-s3 51.58% <52.01%> (?)
serverless-aws-sdk-serverless-peer-service 54.81% <65.75%> (?)
serverless-aws-sdk-sns 55.54% <60.98%> (?)
serverless-aws-sdk-sqs 55.99% <59.52%> (?)
serverless-aws-sdk-stepfunctions 51.35% <57.50%> (?)
serverless-aws-sdk-util 48.53% <66.43%> (?)
serverless-bucket-0 55.11% <59.91%> (?)
serverless-bucket-1 56.06% <60.63%> (?)
test-optimization-cucumber 72.99% <75.20%> (?)
test-optimization-cypress 66.37% <67.77%> (?)
test-optimization-jest 74.37% <79.55%> (?)
test-optimization-mocha 74.73% <75.68%> (?)
test-optimization-playwright-playwright-atr 61.44% <55.36%> (?)
test-optimization-playwright-playwright-efd 61.85% <55.98%> (?)
test-optimization-playwright-playwright-final-status 61.61% <55.36%> (?)
test-optimization-playwright-playwright-impacted-tests 61.33% <55.36%> (?)
test-optimization-playwright-playwright-reporting 61.21% <55.36%> (?)
test-optimization-playwright-playwright-test-management 62.17% <55.36%> (?)
test-optimization-playwright-playwright-test-span 61.30% <55.36%> (?)
test-optimization-selenium 60.74% <67.08%> (?)
test-optimization-testopt 59.25% <65.68%> (?)
test-optimization-vitest 71.30% <57.81%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@juan-fernandez
juan-fernandez marked this pull request as ready for review July 16, 2026 11:11
@juan-fernandez
juan-fernandez requested review from a team as code owners July 16, 2026 11:11
@juan-fernandez
juan-fernandez requested review from bojbrook, dd-oleksii, khanayan123 and sameerank and removed request for a team July 16, 2026 11:11
aperezfals and others added 2 commits July 16, 2026 11:11
…rve OTel span private-field access (#9152)

* fix(ai): replace Object.create(span) with delegating wrapper to preserve OTel span private-field access

* fix(ai): replace Object.create(span) with delegating wrapper to preserve OTel span private-field access and chaining

* test(ai): replace exported wrapTracer unit tests with E2E regression in index.spec.js

* fix(ai): replace Object.create(span) with delegating wrapper to preserve OTel span private-field access

* fix(ai): replace Object.create(span) with delegating wrapper to preserve OTel span private-field access and chaining

* test(ai): replace exported wrapTracer unit tests with E2E regression in index.spec.js

* test(ai): eslint ignore non used statusCode var
@dd-octo-sts
dd-octo-sts Bot force-pushed the v6.4.0-proposal branch from bd293ef to 77b0d3b Compare July 16, 2026 11:11

@datadog-datadog-prod-us1-2 datadog-datadog-prod-us1-2 Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Datadog Autotest: PASS

More details

Validated 7 distinct risk areas across the release bundle. The DsmPathwayCodec.encode now returns its carrier (previously void), and the existing DSM callers in amqplib/bullmq/kafkajs/pubsub/rhea discard the return value — they remain correct via side-effects. All adversarial scenarios for kinesis size-gating, vitest negative duration, worker flush counter, EFD zero retry budget, Apollo health-check skipping, per-schema walkedTypes, and Jest suite-path fallback passed cleanly.

Was this helpful? React 👍 or 👎

📊 Validated against 22 scenarios · Open Bits AI session

🤖 Datadog Autotest · Commit bd293ef · What is Autotest? · Any feedback? Reach out in #autotest

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bd293ef219

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

injectedCarrier = this
._injectTraceparent(spanContext, injectedCarrier ?? carrier, injectTraceContext) ?? injectedCarrier

if (injectedCarrier === undefined) return

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Publish inject subscribers even when built-ins add no carrier

When callers provide an existing carrier but the configured propagation styles do not write any built-in headers (for example DD_TRACE_PROPAGATION_STYLE_INJECT=none or baggage-only with no baggage), this early return prevents dd-trace:span:inject subscribers from running. LLMObs relies on that channel to append _dd.p.llmobs_* values to x-datadog-tags even when the carrier starts empty, so those contexts stop propagating in those configurations; consider publishing to subscribers with the provided carrier before deciding nothing was injected.

Useful? React with 👍 / 👎.

@@ -0,0 +1,3 @@
'use strict'

module.exports = require('./src/bootstrap')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Register feature noops before bootstrapping electron

This electron entry point bypasses packages/dd-trace/index.js, so src/openfeature/register never runs before bootstrap constructs the singleton. Because both NoopProxy and the real proxy copy entries from feature-registry only in their constructors, dd-trace-electron instances end up without the public openfeature noop/provider path even though the shared typings still expose tracer.openfeature; require the register module here (or from bootstrap) before constructing the proxy.

Useful? React with 👍 / 👎.

let tags = existing || ''
if (parentId) tags += `${tags ? ',' : ''}${PROPAGATED_PARENT_ID_KEY}=${parentId}`
if (mlApp) tags += `${tags ? ',' : ''}${PROPAGATED_ML_APP_KEY}=${mlApp}`
if (sessionId) tags += `${tags ? ',' : ''}${PROPAGATED_SESSION_ID_KEY}=${sessionId}`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate session IDs before appending x-datadog-tags

When an LLMObs session ID contains a comma or non-ASCII character, this writes it directly into x-datadog-tags without the validation/length checks used by the normal trace-tag injector. Downstream extraction splits this header on commas and aborts extraction if any tag pair is invalid, so one user-supplied session ID can make the receiving service drop all propagated Datadog trace tags from the header; skip or sanitize invalid session IDs before appending them.

Useful? React with 👍 / 👎.

@juan-fernandez
juan-fernandez merged commit af7a705 into v6.x Jul 16, 2026
807 checks passed
@juan-fernandez
juan-fernandez deleted the v6.4.0-proposal branch July 16, 2026 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants