Uh oh!
There was an error while loading. Please reload this page.
skill(apm-integrations): additional rules from recent HTTP-category PR reviews - #11927
Conversation
Five rules distilled from HTTP-client and HTTP-server PR reviews (feign #11709, commons-httpclient #11717, sparkjava #11708) that were NOT covered by the R13-R33 additions in #11760. - advice-class.md: async double-span (do not wrap an async client with advice when the sync delegate is already instrumented; produces two spans per request). Source: @ValentinZakharov on PR #11709. - advice-class.md: HelperMethods refactor anti-pattern (do not extract advice logic into a per-instrumentation helper class just to shorten the advice body — inline unless genuinely shared). Source: @ygree on PR #11717. - instrumenter-module.md: regeneration must preserve every override the master version has — not just super(...), but also defaultEnabled(), helperClassNames(), contextStore(), orderPriority(), etc. Source: Codex reviews on PRs #11709 and #11708 (recurring pattern). - instrumenter-module.md: scan dd-java-agent/instrumentation/$framework/ before generating; do not create parallel duplicate modules. Source: @PerfectSlayer's historical review on #10941, still an unencoded gap. - muzzle.md: base testImplementation dep version must match the module's declared minimum, not the latest — extends the existing latestDep parity rule to base tests. Source: @PerfectSlayer on PR #11708. 3 files, +44 lines. No changes to existing rules. Reviewers: @mcculls (skill hygiene, reviewed #11760), @PerfectSlayer (HTTP domain, contributed rules from #10941 + #11708).
Adds 9 rules across 5 files based on extended audit of PR #11708 (sparkjava), PR #11709 (feign), and the sparkjava CI-fix commit history: - context-tracking: CompletableFuture cancellation preservation (codex, #11709) - advice-class: framework-inside-framework span identity (codex, #11708) - advice-class: no non-constant static fields in advice (CI-fix commit f6d1263) - tests: 5 test-hygiene rules (PerfectSlayer, #11708) — no Thread.sleep, static server field, shared test bases, ForkedTest justification, no default jvmArgs - supported-configurations: registry type correctness (CI-fix commits 53836a0, 48a84c0) - instrumenter-module: helperClassNames() for enrichment helpers (CI-fix commit 2c372a3)
…ture Reconciles two conflicting maintainer positions on the constructor pattern: - Stuart McCulloch (PR #11760 comment 3552616459) — new instrumentations should adopt the version-alias pattern - Valentin Zakharov (PR #11709 comment 3532152120) — single-module frameworks should pass one name; extra names mint DD_TRACE_<NAME>_ENABLED flags with no counterpart to gate against The empirical convention in dd-trace-java confirms Valentin's rule for single-module frameworks (feign, freemarker, liberty, sparkjava all pass one name; freemarker and liberty do so even with real version siblings) and McCulloch's rule for frameworks with real sibling versions (okhttp shipping okhttp-2.0 and okhttp-3.0 with a shared 'okhttp' group flag). Also fixes the previous jedis example which claimed 'jedis-3.0' alias but the shipping jedis-3.0 module actually passes super("jedis", "redis").
This comment has been minimized.
This comment has been minimized.
🟢 Java Benchmark SLOs — All performance SLOs passed
PR vs. master results
Commit: Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion. |
Behaviour check — how the current draft affects generated outputUpdate (2026-07-13 pm) — original findings retracted. After posting this comment I extracted the compile-step agent trace and discovered the blind regens did NOT actually load the draft skill content in this PR. The toolkit's skill-loader first-match preferred the target repo's in-tree Preserving the original observations below for the record, but with corrections: Two candidates:
Static-verification results — corrected classification:
Corrected reading: the rule content in this PR is unchanged and still worth reviewing on its merits. The empirical validation evidence in my original comment is retracted pending a re-run against a properly-loaded skill. I'm setting up that re-run now on an async-category cycle (rxjava-3.0) with the skill correctly loaded via a target-repo branch that has the draft in-tree; results will follow if useful. Sorry for the noise on the earlier reading. |
There was a problem hiding this comment.
Pull request overview
Extends the canonical apm-integrations skill reference docs with additional rules extracted from recent HTTP-category review/CI feedback, and refines guidance around integration naming via super(...) based on version-sibling structure.
Changes:
- Adds “test hygiene” rules for instrumentation tests (deterministic waits, embedded server lifecycle, base-class factoring, forked-test justification, avoiding default JVM args).
- Adds registry population guidance for
metadata/supported-configurations.json(required_ENABLEDentries, analytics key shapes, common mistakes). - Expands integration authoring guidance around module discovery,
super(...)naming choices, async wrapper double-span avoidance,CompletableFuturecancellation preservation, and advice-class constraints.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
.agents/skills/apm-integrations/references/tests.md | Adds test-hygiene rules intended to reduce flakiness and CI cost. |
.agents/skills/apm-integrations/references/supported-configurations.md | Adds common-mistake guidance for correctly registering new configuration entries. |
.agents/skills/apm-integrations/references/muzzle.md | Adds a rule tying test dependency versions to declared module ranges/min versions. |
.agents/skills/apm-integrations/references/instrumenter-module.md | Adds “scan first” guidance, reconciles super(...) naming rules, and adds helper declaration guidance. |
.agents/skills/apm-integrations/references/context-tracking.md | Adds guidance to preserve cancellation semantics for async return types. |
.agents/skills/apm-integrations/references/advice-class.md | Adds rules for async double-span avoidance, helper-method anti-pattern, framework-in-framework enrichment, and advice static-field constraints. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
7 findings, all verified against master:
- tests.md: waitForTraces(N) waits for >=N (not exactly N) with 20s
bounded timeout per ListWriter.java
- supported-configurations.md: fix internal contradiction — registry
uses "decimal" (rates) and "int" (counts), NOT "double"/"integer"
(matches canonical guidance earlier in same doc, line 52)
- instrumenter-module.md: replace non-existent super("feign") example
with freemarker (real, verifiable); replace misleading single-name
list with an accurate one; add sparkjava-2.3 counter-example
explaining why super("sparkjava","sparkjava-2.4") uses the -2.4
alias despite living in the -2.3/ directory (compile against 2.3,
test against 2.4 for JettyHandler)
- muzzle.md: reframe testImplementation=min as default preference,
not absolute rule; document justified deviation with sparkjava-2.3
build.gradle as the canonical example
- context-tracking.md: reframe CompletableFuture pattern to emphasize
that the correct (non-reassigning) pattern does NOT require
@Advice.Return(readOnly=false); only add readOnly=false if you
have a documented reason to substitute the return value
- advice-class.md: S1 framework-in-framework example now includes
the null-check on activeSpan(), matching sparkjava's
RoutesInstrumentation.java:52-55 (withRoute() does not guard)
Copilot's citations were checked against master before applying.…tent - Reword "regenerating an existing module" as "rewriting or refactoring" — the guidance applies whenever an existing module is being changed, not just to automated regeneration flows. - Remove the "Rationale traceable to reviewer comments (PR/comment IDs)" footnote. That attribution belongs in commit messages and PR descriptions, not in the shipping skill; readers of the skill just need the rule.
Hi! 👋 Thanks for your pull request! 🎉 To help us review it, please make sure to:
If you need help, please check our contributing guidelines. |
There was a problem hiding this comment.
More details
Documentation-only PR extending APM integration guidance with rules from recent reviewer feedback. All code examples verified against actual module implementations (sparkjava-2.3, jedis, okhttp, freemarker, liberty); naming reconciliation is empirically grounded and consistent; cross-references validated. No executable code changes — no regressions possible.
🤖 Datadog Autotest · Commit 04a0719 · What is Autotest? · Any feedback? Reach out in #autotest
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:04a07191ee
ℹ️ 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".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Four findings, all P2, all verified against master: - advice-class.md (framework-in-framework): narrow the rule to route-only enrichers (SparkJava). JAX-RS annotations and Ratpack legitimately create handler/controller spans in addition to the outer server span (jax-rs-annotations-2.0/JaxRsAnnotationsInstrumentation.java:128; ratpack-1.5/TracingHandler.java:41). Original blanket wording would cause future JAX-RS/Ratpack instrumentation to drop expected child spans. - advice-class.md (async wrapper): completion-only propagation is not enough when the sync delegate runs on a worker thread — the sync client's advice creates its span BEFORE the future completes. Document the two supported approaches: (1) rely on executor instrumentation, or (2) reactivate around the delegate submission via a shared wrapper. Reference java-concurrent-1.8's existing patterns. - context-tracking.md (CompletableFuture): the CORRECT example was itself wrong on two counts caught by Codex: (a) missing onThrowable = Throwable.class means the exit advice skips when the instrumented method throws before returning the future — any span started on enter would leak (b) used a lambda body, which the "no lambdas in advice methods" rule in advice-class.md:111 explicitly forbids — lambdas compile to synthetic classes that are not helper-injected Rewrite the CORRECT example with @Advice.Thrown handling, a named BiConsumer helper (ClientCompletionCallback) instead of a lambda, and helperClassNames() implications.
Automated integration-authoring pass on rxjava-3.0, produced against the draft skill in #11927 (which was in-tree on the target checkout at generation time — using the skill-loading precedence fix from the 2026-07-13 HTTP cycle correction). Reference for #11927 reviewers to see concrete output the current skill draft produces. Not intended to be merged as-is. Base: master @ 05671ce (rebased from original bd134f3; the original branch inherited a stash-merge revert of #11852 during eval branch setup that dropped DD_TRACE_ROBOLECTRIC_ENABLED from metadata plus 172 unrelated files. This rebased version cherry-picks ONLY the rxjava-3.0 module output onto current master, preserving all unrelated upstream changes.) Cost: \$43.23, wall time ~3.5h, reviewer approved with 0 todos remaining. Diff scope: dd-java-agent/instrumentation/rxjava/rxjava-3.0/ only. Metadata: no change (all rxjava3 entries already present on master).
…skill Automated integration-authoring pass on reactor-core-3.1, produced against the draft skill in #11927. Reference for #11927 reviewers to see concrete output the current skill draft produces. Not intended to be merged as-is. Base: master @ 05671ce (rebased from original 2e1d2b9; the original branch inherited a stash-merge revert of #11852 during eval branch setup that dropped DD_TRACE_ROBOLECTRIC_ENABLED from metadata plus 172 unrelated files. This rebased version cherry-picks ONLY the reactor-core-3.1 module output onto current master, preserving all unrelated upstream changes.) Cost: \$13, reviewer approved with 0 todos remaining. Diff scope: dd-java-agent/instrumentation/reactor-core-3.1/ only. Metadata: no change (all reactor entries already present on master). Note: the toolkit reorganized the package layout from 'datadog.trace.instrumentation.reactor.core' (master) to 'datadog.trace.instrumentation.reactorcore' (eval). This is a regen-preservation Rule #2 concern; documented for reviewer consideration.
/merge |
View all feedbacks in Devflow UI.
The expected merge time in
Build pipeline has failing jobs for 3b64d3e: What to do next?
DetailsSince those jobs are not marked as being allowed to fail, the pipeline will most likely fail. |
Uh oh!
There was an error while loading. Please reload this page.
/merge |
View all feedbacks in Devflow UI.
The expected merge time in
DDCI pipeline didn't start (sourcing_failed)... Please retry. DDCI Change Request: |
Uh oh!
There was an error while loading. Please reload this page.
/merge |
View all feedbacks in Devflow UI.
The expected merge time in
Build pipeline has failing jobs for 9e3b9f0:
What to do next?
DetailsSince those jobs are not marked as being allowed to fail, the pipeline will most likely fail. |
Uh oh!
There was an error while loading. Please reload this page.
/merge |
View all feedbacks in Devflow UI.
The expected merge time in
Build pipeline has failing jobs for 8605c11:
What to do next?
DetailsSince those jobs are not marked as being allowed to fail, the pipeline will most likely fail. |
Uh oh!
There was an error while loading. Please reload this page.
sarahchen6
commented
Jul 16, 2026
/merge |
View all feedbacks in Devflow UI.
The expected merge time in
|
Uh oh!
There was an error while loading. Please reload this page.
…fix only Reverts part of 75b06bb. Renaming super("cassandra") -> super("cassandra-toolkit") to unblock check-instrumentation-naming was wrong: integration names are public config API, and this codebase already has a documented rule against silently renaming them (see docs/eval-research/hypotheses/cassandra.md on the toolkit repo, quoting PR #11927: "read the existing module's super(...) and copy it verbatim... renaming one silently breaks customer DD_TRACE_*_ENABLED settings"). Also inconsistent with how prior research cycles (HTTP, async) handled analogous name matches -- match the real name, document the collision as the finding, don't invent a workaround name to unblock CI. The directory move (cassandra/ -> cassandra/cassandra-4.0/) stays -- that's a pure naming-convention fix with no integration-identity implications. The super("cassandra") collision with master's real datastax-cassandra/datastax-cassandra-4.0/ module is restored and remains the R-DB-1 research finding, unfixed, same as before this branch's CI-triage pass touched it. Verified locally: - `./gradlew :dd-java-agent:instrumentation:checkInstrumentationNaming` -- BUILD SUCCESSFUL - `./gradlew :dd-java-agent:verifyAgentJarIntegrations` -- BUILD SUCCESSFUL Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
Extends the
add-apm-integrationsskill with additional rules derived from reviewer feedback and CI-fix commits across recent HTTP-category PRs (#11708 sparkjava-2.3, #11709 feign-10.8, #11717 commons-httpclient-2.0). Also reconciles a conflict between two maintainer positions onsuper(...)naming.Follow-on to #11760.
What's added
Rules from reviewer comments (in the referenced PRs):
advice-class.md)advice-class.md)advice-class.md)HTTP_RESOURCE_DECORATOR.withRoute(...)— do NOT create a new span,Decorator, orAgentScope. Null-checkactiveSpan()first.CompletableFuture(context-tracking.md)future = future.whenComplete(...)—whenCompleteproduces a dependent stage, and cancelling that stage does not cancel the original requesttests.md)Thread.sleep(); embedded servers asstaticfields, not per-test; shared scaffolding in a base class;ForkedTestrequires a justified isolation reason; no defaultjvmArgsin test tasksinstrumenter-module.md)super(...),defaultEnabled(),helperClassNames(),contextStore(),orderPriority(),muzzleDirective()) — silent loss ofdefaultEnabled()=falseon an opt-in integration ships it on by defaultinstrumenter-module.md)dd-java-agent/instrumentation/$framework/$framework-$version/, list the parent directory to check for existing coverage; do not create parallel duplicate modulestestImplementationversion (muzzle.md)build.gradleheader comment)Rules from CI-fix commit history on #11708:
advice-class.md*Advice.java(muzzle contract — advice methods are inlined and non-constant statics get pulled into every callsite)supported-configurations.mdboolean,int(NOTinteger),decimal(NOTdouble),string,array,map. Everysuper(...)name needs a matching_ENABLEDentry; every_ANALYTICS_SAMPLE_RATEneeds a matching_ANALYTICS_ENABLED.instrumenter-module.mdhelperClassNames()— otherwise the target classloader lacks it and the advice throwsNoClassDefFoundErrorat runtimesuper(...)naming reconciliation (instrumenter-module.md)Two maintainer positions were in tension:
super("jedis", "jedis-3.0")).DD_TRACE_<NAME>_ENABLEDflag with no counterpart to gate against.Empirical check of the codebase: single-name is the norm even for versioned modules —
freemarker-2.3.9+freemarker-2.3.24bothsuper("freemarker");liberty-20.0+liberty-23.0bothsuper("liberty"). The multi-name form appears when frameworks have real cross-version group switches:okhttp(super("okhttp", "okhttp-3")becauseokhttp-2.0/sibling exists).Also worth noting: the prior skill example for the version-alias pattern used
super("jedis", "jedis-3.0"), but the shippingjedis-3.0module actually usessuper("jedis", "redis"), andDD_TRACE_JEDIS_3_0_ENABLEDdoes not exist inmetadata/supported-configurations.json.Resolution: encode as conditional guidance — pass ONE name unless multiple version-specific sibling directories genuinely exist.
sparkjava-2.3'ssuper("sparkjava", "sparkjava-2.4")is included as a nuanced counter-example (the-2.4alias reflects the version exercised by tests, not the directory name — see thebuild.gradleheader comment on that module).Both maintainer positions are correct in their respective situations; the reconciled guidance in this PR distinguishes them explicitly.
Files changed
.agents/skills/apm-integrations/references/advice-class.md.agents/skills/apm-integrations/references/context-tracking.md.agents/skills/apm-integrations/references/instrumenter-module.md.agents/skills/apm-integrations/references/muzzle.md.agents/skills/apm-integrations/references/supported-configurations.md.agents/skills/apm-integrations/references/tests.mdNot in scope
.agents/skills/apm-integrations/references/.