From 4b03777cf65e334e6bafa5bf8a2d07ef989447e7 Mon Sep 17 00:00:00 2001 From: Douglas Q Hawkins Date: Thu, 22 Oct 2026 19:26:11 -0400 Subject: [PATCH 1/3] Add @CorrectnessContract and @Confined @CorrectnessContract marks a rule code must follow, where a violation is a bug rather than a tradeoff. Unlike @PerfContract it has no suppression: code that needs to break the rule shows the contract is wrong for that type. @Confined is the first such contract. It declares where an instance stays valid: only during the call it was passed into (CALL), or only in the frame that obtained it, completed on every path before that frame exits (FRAME). For an AutoCloseable FRAME type, completion means a try-with-resources. Its checker contract is written for AI review, like the perf contracts; no static checker enforces it yet. Co-Authored-By: Claude Opus 5.5 --- .github/CODEOWNERS | 1 + .../datadog/correctnesscontract/Confined.java | 63 +++++++++++++++++++ .../CorrectnessContract.java | 28 +++++++++ 3 files changed, 92 insertions(+) create mode 100644 internal-api/src/main/java/datadog/correctnesscontract/Confined.java create mode 100644 internal-api/src/main/java/datadog/correctnesscontract/CorrectnessContract.java diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ee8c267c77d..948488a48f9 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -87,6 +87,7 @@ /internal-api/src/*/*/datadog/trace/api/env/ @DataDog/apm-java /internal-api/src/*/*/datadog/trace/api/flare/ @DataDog/apm-java /internal-api/src/*/*/datadog/trace/api/function/ @DataDog/apm-java +/internal-api/src/*/*/datadog/correctnesscontract/ @DataDog/apm-java /internal-api/src/*/*/datadog/perfcontract/ @DataDog/apm-java /internal-api/src/*/*/datadog/trace/api/intake/ @DataDog/apm-java /internal-api/src/*/*/datadog/trace/api/logging/ @DataDog/apm-java diff --git a/internal-api/src/main/java/datadog/correctnesscontract/Confined.java b/internal-api/src/main/java/datadog/correctnesscontract/Confined.java new file mode 100644 index 00000000000..6ad2db116dc --- /dev/null +++ b/internal-api/src/main/java/datadog/correctnesscontract/Confined.java @@ -0,0 +1,63 @@ +package datadog.correctnesscontract; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Declares where an instance of the annotated type remains valid. Using an instance outside its + * {@link Extent} is a bug: the type relies on that confinement for its own correctness, for example + * by completing through an unsynchronized flag or by carrying state that is only meaningful during + * one call. + * + *

Extents are ordered from narrowest to widest: {@link Extent#CALL}, then {@link Extent#FRAME}. + * Both imply the instance is never used from another thread. An unannotated type is unconfined. + * + *

This marker changes no runtime behavior. The checker contract below guides AI review; no + * static checker currently enforces it. As a {@link CorrectnessContract}, it has no exemption. + * + *

Compare {@link datadog.trace.api.function.NoEscape}, which says an instance should not + * be retained, for performance. A confined instance must not be retained. + * + *

Checker contract. Applies to production source sets. Tests and benchmarks that misuse a + * type deliberately, to verify its behavior, are outside the rule. + * + *

+ */ +@Documented +@CorrectnessContract +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.TYPE) +public @interface Confined { + + /** The extent instances of the annotated type are confined to. */ + Extent value(); + + /** Where a confined instance remains valid, from narrowest to widest. */ + enum Extent { + /** Valid only for the duration of the call it was passed into. */ + CALL, + + /** + * Valid only in the frame that obtained it and the calls that frame makes, and completed on + * every path before that frame exits. + */ + FRAME + } +} diff --git a/internal-api/src/main/java/datadog/correctnesscontract/CorrectnessContract.java b/internal-api/src/main/java/datadog/correctnesscontract/CorrectnessContract.java new file mode 100644 index 00000000000..e0c0901de51 --- /dev/null +++ b/internal-api/src/main/java/datadog/correctnesscontract/CorrectnessContract.java @@ -0,0 +1,28 @@ +package datadog.correctnesscontract; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks an annotation as a correctness contract for documentation and static analysis. A + * correctness contract states a rule that code must follow, in the RFC 2119 sense: a violation is a + * bug, not a tradeoff. Contract annotations change no runtime behavior. + * + *

Unlike {@link datadog.perfcontract.PerfContract}, a correctness contract has no suppression. A + * declaration that needs to break the rule shows that the contract is wrong for its type; change + * the annotation rather than exempting the use. A {@link datadog.perfcontract.SuppressPerfContract} + * that names a correctness contract is invalid, since every class in its {@code value} must be a + * perf contract. + * + *

Tools use this meta-annotation to discover contracts. This annotation defines no rule itself. + * + *

{@link RetentionPolicy#CLASS} lets tools discover contracts in dependency class files without + * exposing them through runtime reflection. + */ +@Documented +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.ANNOTATION_TYPE) +public @interface CorrectnessContract {} From 3ac5d1288ded0eb1f8058bf76dfabefbf6ad765d Mon Sep 17 00:00:00 2001 From: Douglas Q Hawkins Date: Thu, 22 Oct 2026 19:26:15 -0400 Subject: [PATCH 2/3] Confine Reservation to its frame and the retry lease to its call A reservation completes through an unsynchronized flag and leaks a unit of capacity if it is neither filled nor closed, so it is confined to the frame that reserved it and used in a try-with-resources. The RetryQueue handed to RetryStrategy.onFailure carries the failed item's attempt count, so it is valid only during that call. Co-Authored-By: Claude Opus 5.5 --- .../java/datadog/common/queue/BaseWorkQueue.java | 2 +- .../main/java/datadog/common/queue/Reservation.java | 12 +++++++++--- .../main/java/datadog/common/queue/RetryQueue.java | 7 ++++++- .../main/java/datadog/common/queue/WorkQueue.java | 4 ++-- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/utils/queue-utils/src/main/java/datadog/common/queue/BaseWorkQueue.java b/utils/queue-utils/src/main/java/datadog/common/queue/BaseWorkQueue.java index 7a0de8b5cfc..3cfc539c2d5 100644 --- a/utils/queue-utils/src/main/java/datadog/common/queue/BaseWorkQueue.java +++ b/utils/queue-utils/src/main/java/datadog/common/queue/BaseWorkQueue.java @@ -375,7 +375,7 @@ public void fill(T element) { @Override public void close() { - // Reservation confines fill and close to the reserving thread, so a plain flag suffices. + // Reservation confines fill and close to the reserving frame, so a plain flag suffices. if (!done) { done = true; queue.releasePlace(); diff --git a/utils/queue-utils/src/main/java/datadog/common/queue/Reservation.java b/utils/queue-utils/src/main/java/datadog/common/queue/Reservation.java index add79a425d6..9b72611719e 100644 --- a/utils/queue-utils/src/main/java/datadog/common/queue/Reservation.java +++ b/utils/queue-utils/src/main/java/datadog/common/queue/Reservation.java @@ -1,5 +1,9 @@ package datadog.common.queue; +import static datadog.correctnesscontract.Confined.Extent.FRAME; + +import datadog.correctnesscontract.Confined; + /** * A claimed place in a {@link WorkQueue}, for a caller whose work between claiming and filling * cannot be expressed as a {@link Producer}. @@ -10,9 +14,10 @@ * quietly and permanently, which is why this is an {@link AutoCloseable} meant for * try-with-resources. * - *

A reservation is confined to the thread that reserved it: only that thread may fill or close - * it. Completion is not synchronized, so filling or closing from another thread can store two - * elements against one place, or store an element whose place was already given back. + *

A reservation is confined to the frame that reserved it: fill or close it there, in a + * try-with-resources, and never from another thread. Completion is not synchronized, so filling or + * closing from another thread can store two elements against one place, or store an element whose + * place was already given back. * *

A refused claim is a reservation too, rather than a {@code null}, and one that quietly * discards whatever is filled into it. Nothing about the failed path throws, so the shortest @@ -35,6 +40,7 @@ * } * } */ +@Confined(FRAME) public interface Reservation extends AutoCloseable { /** diff --git a/utils/queue-utils/src/main/java/datadog/common/queue/RetryQueue.java b/utils/queue-utils/src/main/java/datadog/common/queue/RetryQueue.java index b10fba899dd..02d837384f5 100644 --- a/utils/queue-utils/src/main/java/datadog/common/queue/RetryQueue.java +++ b/utils/queue-utils/src/main/java/datadog/common/queue/RetryQueue.java @@ -1,13 +1,18 @@ package datadog.common.queue; +import static datadog.correctnesscontract.Confined.Extent.CALL; + +import datadog.correctnesscontract.Confined; import javax.annotation.Nonnull; /** * The capability to resubmit work after a consumer failure. * *

Only obtainable inside {@link RetryStrategy#onFailure}, never from a plain consumer, so - * re-enqueue-after-failure stays visibly distinct from ordinary admission. + * re-enqueue-after-failure stays visibly distinct from ordinary admission. Valid only during that + * call: it carries the failed item's attempt count, which a later or different use would misreport. */ +@Confined(CALL) public interface RetryQueue { /** * Resubmits the failed item. diff --git a/utils/queue-utils/src/main/java/datadog/common/queue/WorkQueue.java b/utils/queue-utils/src/main/java/datadog/common/queue/WorkQueue.java index d4c60e695eb..bd59e3365c2 100644 --- a/utils/queue-utils/src/main/java/datadog/common/queue/WorkQueue.java +++ b/utils/queue-utils/src/main/java/datadog/common/queue/WorkQueue.java @@ -144,8 +144,8 @@ int tryPutBatch( * *

The reservation holds no position in the backing. Its element joins the queue when filled, * so an open reservation does not block consumers. Use try-with-resources to release unfilled - * reservations; abandoning one permanently consumes its capacity. Keep the reservation on the - * reserving thread. + * reservations; abandoning one permanently consumes its capacity. Keep the reservation in the + * reserving frame. * *

A refused claim returns a non-null reservation that ignores fill. Check {@link * Reservation#granted()} before building the element. From b017adaa29e89c2bfab0df56239ea3e18ff57d18 Mon Sep 17 00:00:00 2001 From: Douglas Q Hawkins Date: Thu, 22 Oct 2026 19:48:15 -0400 Subject: [PATCH 3/3] Place the correctness contract annotations in datadog.contract Follows #12998, which gathers the contract annotations into one package. The links to PerfContract and SuppressPerfContract keep their current package until that change reaches this branch. Co-Authored-By: Claude Opus 5.5 --- .github/CODEOWNERS | 2 +- .../datadog/{correctnesscontract => contract}/Confined.java | 2 +- .../CorrectnessContract.java | 2 +- .../src/main/java/datadog/common/queue/Reservation.java | 4 ++-- .../src/main/java/datadog/common/queue/RetryQueue.java | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) rename internal-api/src/main/java/datadog/{correctnesscontract => contract}/Confined.java (98%) rename internal-api/src/main/java/datadog/{correctnesscontract => contract}/CorrectnessContract.java (97%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 948488a48f9..ef153a68d22 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -87,7 +87,7 @@ /internal-api/src/*/*/datadog/trace/api/env/ @DataDog/apm-java /internal-api/src/*/*/datadog/trace/api/flare/ @DataDog/apm-java /internal-api/src/*/*/datadog/trace/api/function/ @DataDog/apm-java -/internal-api/src/*/*/datadog/correctnesscontract/ @DataDog/apm-java +/internal-api/src/*/*/datadog/contract/ @DataDog/apm-java /internal-api/src/*/*/datadog/perfcontract/ @DataDog/apm-java /internal-api/src/*/*/datadog/trace/api/intake/ @DataDog/apm-java /internal-api/src/*/*/datadog/trace/api/logging/ @DataDog/apm-java diff --git a/internal-api/src/main/java/datadog/correctnesscontract/Confined.java b/internal-api/src/main/java/datadog/contract/Confined.java similarity index 98% rename from internal-api/src/main/java/datadog/correctnesscontract/Confined.java rename to internal-api/src/main/java/datadog/contract/Confined.java index 6ad2db116dc..b5611fb991a 100644 --- a/internal-api/src/main/java/datadog/correctnesscontract/Confined.java +++ b/internal-api/src/main/java/datadog/contract/Confined.java @@ -1,4 +1,4 @@ -package datadog.correctnesscontract; +package datadog.contract; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; diff --git a/internal-api/src/main/java/datadog/correctnesscontract/CorrectnessContract.java b/internal-api/src/main/java/datadog/contract/CorrectnessContract.java similarity index 97% rename from internal-api/src/main/java/datadog/correctnesscontract/CorrectnessContract.java rename to internal-api/src/main/java/datadog/contract/CorrectnessContract.java index e0c0901de51..fe95392cdce 100644 --- a/internal-api/src/main/java/datadog/correctnesscontract/CorrectnessContract.java +++ b/internal-api/src/main/java/datadog/contract/CorrectnessContract.java @@ -1,4 +1,4 @@ -package datadog.correctnesscontract; +package datadog.contract; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; diff --git a/utils/queue-utils/src/main/java/datadog/common/queue/Reservation.java b/utils/queue-utils/src/main/java/datadog/common/queue/Reservation.java index 9b72611719e..e5328c1c66d 100644 --- a/utils/queue-utils/src/main/java/datadog/common/queue/Reservation.java +++ b/utils/queue-utils/src/main/java/datadog/common/queue/Reservation.java @@ -1,8 +1,8 @@ package datadog.common.queue; -import static datadog.correctnesscontract.Confined.Extent.FRAME; +import static datadog.contract.Confined.Extent.FRAME; -import datadog.correctnesscontract.Confined; +import datadog.contract.Confined; /** * A claimed place in a {@link WorkQueue}, for a caller whose work between claiming and filling diff --git a/utils/queue-utils/src/main/java/datadog/common/queue/RetryQueue.java b/utils/queue-utils/src/main/java/datadog/common/queue/RetryQueue.java index 02d837384f5..e5b9884efbd 100644 --- a/utils/queue-utils/src/main/java/datadog/common/queue/RetryQueue.java +++ b/utils/queue-utils/src/main/java/datadog/common/queue/RetryQueue.java @@ -1,8 +1,8 @@ package datadog.common.queue; -import static datadog.correctnesscontract.Confined.Extent.CALL; +import static datadog.contract.Confined.Extent.CALL; -import datadog.correctnesscontract.Confined; +import datadog.contract.Confined; import javax.annotation.Nonnull; /**