diff --git a/CHANGELOG.md b/CHANGELOG.md
index a4642ea..6a35a47 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,61 @@ All notable changes to the AxonFlow Java SDK will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [8.0.0] - 2026-05-08 — Decision history API + telemetry simplification
+
+**Major release.** The headline feature is the new decision-history client
+API: `listDecisions` for paging through recorded decisions, plus a
+runnable example showing the full record → list → explain audit flow.
+Bundled into a major because the v8 line also tightens the telemetry
+contract — see `Removed` at the bottom of this entry for that.
+
+### Added
+
+- **`listDecisions(ListDecisionsOptions opts)` client method.** Pages
+ over recorded decision history from the orchestrator, mirroring `GET
+ /api/v1/decisions`. Companion to the v7.4.0 `getDecisionExplain`
+ method — callers can now both list and drill in. See
+ `examples/list-decisions/`.
+- **`examples/explain-decision/`** end-to-end runnable example covering
+ the full decision audit flow: record → list → explain.
+
+### Migration guide (v7 → v8)
+
+- **`AxonFlowConfig.Builder.telemetry(Boolean)` removed.** Code that
+ called `.telemetry(true)` or `.telemetry(false)` on the builder will
+ fail to compile. Migration: remove the call from your builder chain.
+ If you were using it to disable telemetry, set
+ `AXONFLOW_TELEMETRY=off` in the environment instead — that's the
+ sole opt-out lever as of v8. If you were using it to force-enable,
+ the default is now ON for every mode so the override is no longer
+ needed.
+- **`AxonFlowConfig.getTelemetry()` removed.** Code reading the
+ override field will fail to compile. Same migration: drop the call
+ site; `AXONFLOW_TELEMETRY=off` is the only telemetry knob.
+- **`TelemetryReporter.isEnabled` and `TelemetryReporter.sendPing`
+ signatures simplified.** Both methods previously took the
+ `(mode, configOverride, hasCredentials, ...)` parameter shape from
+ the v7 mode-and-override gate. v8 collapses to a single env-var
+ signal: `isEnabled(String axonflowTelemetry)` and
+ `sendPing(String mode, String sdkEndpoint, boolean debug, ...)`.
+ Application code does not call these directly; only test harnesses
+ that exercise the testability surface need to update.
+
+### Removed
+
+- **`AxonFlowConfig.Builder.telemetry(Boolean)` builder method** (was
+ `Builder telemetry(Boolean)`) and **`AxonFlowConfig.getTelemetry()`**
+ accessor. `AXONFLOW_TELEMETRY=off` is now the sole opt-out path. Tests
+ that need to defend against contaminated dev environments should
+ pass `null` to the testability `axonflowTelemetry` parameter or set
+ `AXONFLOW_TELEMETRY=` (empty) at the test level.
+- **Sandbox-mode silent telemetry suppression.** Sandbox-mode clients
+ (constructed via `Mode.SANDBOX`) now fire telemetry on the same
+ heartbeat schedule as production-mode clients. Pings are tagged
+ `stream="sandbox"` so analytics can distinguish dev pings from
+ production heartbeat — see the checkpoint-service
+ `IsValidIncomingStream` allowlist for the wire-side gate.
+
## [7.1.0] - 2026-05-06 — X-Axonflow-Client header + scope-aware license validation
**Companion release to platform v7.7.0.** The Java SDK now sends an
diff --git a/README.md b/README.md
index 18a9efc..0a0a6d5 100644
--- a/README.md
+++ b/README.md
@@ -47,14 +47,14 @@ Three short videos covering different angles of the platform:
{@code null} means use the default behavior (ON for production, OFF for sandbox). {@code - * Boolean.TRUE} forces telemetry on, {@code Boolean.FALSE} forces it off. - * - * @return the telemetry override, or null for default behavior - */ - public Boolean getTelemetry() { - return telemetry; - } - public static Builder builder() { return new Builder(); } @@ -370,7 +356,6 @@ public static final class Builder { private RetryConfig retryConfig; private CacheConfig cacheConfig; private String userAgent; - private Boolean telemetry; private Builder() {} @@ -533,23 +518,6 @@ public Builder userAgent(String userAgent) { return this; } - /** - * Sets the telemetry override. - * - *
{@code null} (default) uses the mode-based default: ON for production, OFF for sandbox. - * {@code Boolean.TRUE} forces telemetry on, {@code Boolean.FALSE} forces it off. - * - *
Telemetry can also be disabled globally via environment variable - * {@code AXONFLOW_TELEMETRY=off}. - * - * @param telemetry true to enable, false to disable, null for default behavior - * @return this builder - */ - public Builder telemetry(Boolean telemetry) { - this.telemetry = telemetry; - return this; - } - /** * Builds the configuration. * diff --git a/src/main/java/com/getaxonflow/sdk/telemetry/TelemetryReporter.java b/src/main/java/com/getaxonflow/sdk/telemetry/TelemetryReporter.java index 2fe0687..181b398 100644 --- a/src/main/java/com/getaxonflow/sdk/telemetry/TelemetryReporter.java +++ b/src/main/java/com/getaxonflow/sdk/telemetry/TelemetryReporter.java @@ -41,14 +41,12 @@ *
Telemetry is completely anonymous and contains no user data, only SDK version, runtime * environment, and deployment mode information. * - *
Telemetry can be disabled via: - * - *
By default, telemetry is OFF in sandbox mode and ON in production mode. + *
{@code AXONFLOW_TELEMETRY=off} in the environment is the SOLE opt-out path as of v8.0. The + * v7.x {@code telemetry(Boolean)} config-builder override has been removed; the previous silent + * suppression of sandbox-mode pings has also been removed. Sandbox-mode pings now fire on the + * same heartbeat schedule as production-mode pings, tagged {@code stream="sandbox"} in the + * payload so analytics can distinguish dev/test pings from production heartbeat (the wire-side + * allowlist is enforced by the checkpoint service — see {@code IsValidIncomingStream}). */ public class TelemetryReporter { @@ -67,25 +65,17 @@ public class TelemetryReporter { private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); /** - * Sends an anonymous telemetry ping asynchronously (fire-and-forget). + * Sends an anonymous telemetry ping synchronously (blocks until the round-trip completes). * * @param mode the deployment mode (e.g. "production", "sandbox") * @param sdkEndpoint the configured SDK endpoint, used to detect platform version via /health - * @param telemetryEnabled config override for telemetry (null = use default based on mode) * @param debug whether debug logging is enabled */ - public static void sendPing( - String mode, - String sdkEndpoint, - Boolean telemetryEnabled, - boolean debug, - boolean hasCredentials) { + public static void sendPing(String mode, String sdkEndpoint, boolean debug) { sendPing( mode, sdkEndpoint, - telemetryEnabled, debug, - hasCredentials, System.getenv("AXONFLOW_TELEMETRY"), System.getenv("AXONFLOW_CHECKPOINT_URL")); } @@ -94,12 +84,10 @@ public static void sendPing( static void sendPing( String mode, String sdkEndpoint, - Boolean telemetryEnabled, boolean debug, - boolean hasCredentials, String axonflowTelemetry, String checkpointUrl) { - if (!isEnabled(mode, telemetryEnabled, hasCredentials, axonflowTelemetry)) { + if (!isEnabled(axonflowTelemetry)) { if (debug) { logger.debug("Telemetry is disabled, skipping ping"); } @@ -178,43 +166,28 @@ public static boolean sendPingNow( } /** - * Determines whether telemetry is enabled based on environment and config. + * Determines whether telemetry is enabled. * - *
Priority order: + *
{@code AXONFLOW_TELEMETRY=off} in the environment is the SOLE opt-out path as of v8.0. + * Telemetry is otherwise ON by default, regardless of mode (sandbox / production / anything + * else). Sandbox-mode pings are tagged {@code stream="sandbox"} in the payload so analytics + * can still distinguish them — see {@link #buildPayload}. * - *
Historical context: v7.x supported a {@code Boolean configOverride} parameter and a + * {@code mode != "sandbox"} default-suppression rule. Both were removed in v8.0 to leave a + * single, ops-controlled opt-out lever and avoid silent suppression that masks real adoption + * signal. See CHANGELOG v8.0.0. * *
{@code DO_NOT_TRACK} is intentionally NOT honored. It is commonly inherited from host * tools and developer environments (CLIs like Codex and Claude Code inject it unconditionally), * which makes it an unreliable expression of user intent for AxonFlow telemetry. * - * @param mode the deployment mode - * @param configOverride explicit config override (null = use default) - * @param hasCredentials whether the client has credentials (kept for API compat, no longer used - * in default logic) + * @param axonflowTelemetry value of {@code AXONFLOW_TELEMETRY} env var (null = unset) * @return true if telemetry should be sent */ - public static boolean isEnabled(String mode, Boolean configOverride, boolean hasCredentials) { - return isEnabled( - mode, configOverride, hasCredentials, System.getenv("AXONFLOW_TELEMETRY")); - } - - /** Package-private for testing. Accepts env var values as parameters. */ - public static boolean isEnabled( - String mode, Boolean configOverride, boolean hasCredentials, String axonflowTelemetry) { - if (axonflowTelemetry != null && "off".equalsIgnoreCase(axonflowTelemetry.trim())) { - return false; - } - if (configOverride != null) { - return configOverride; - } - // Default: ON everywhere except sandbox mode. - return !"sandbox".equals(mode); + public static boolean isEnabled(String axonflowTelemetry) { + // AXONFLOW_TELEMETRY=off is the SOLE opt-out path. + return !(axonflowTelemetry != null && "off".equalsIgnoreCase(axonflowTelemetry.trim())); } /** Builds the JSON payload for the telemetry ping. */ @@ -245,6 +218,15 @@ static String buildPayload(String mode, String platformVersion, String endpointT root.put("instance_id", UUID.randomUUID().toString()); + // Stream classifier: sandbox-mode clients self-tag so analytics can distinguish dev/test + // pings from production. Production-mode (and other modes) omit the field entirely so the + // server defaults to "heartbeat" — preserving byte-identical wire shape relative to v7.x + // for the production-mode case. See CHANGELOG v8.0.0 and checkpoint-service + // IsValidIncomingStream. + if ("sandbox".equals(mode)) { + root.put("stream", "sandbox"); + } + return mapper.writeValueAsString(root); } catch (Exception e) { // Fallback minimal payload diff --git a/src/test/java/com/getaxonflow/sdk/telemetry/TelemetryReporterShortLivedTest.java b/src/test/java/com/getaxonflow/sdk/telemetry/TelemetryReporterShortLivedTest.java index 41d13ca..9437015 100644 --- a/src/test/java/com/getaxonflow/sdk/telemetry/TelemetryReporterShortLivedTest.java +++ b/src/test/java/com/getaxonflow/sdk/telemetry/TelemetryReporterShortLivedTest.java @@ -64,8 +64,6 @@ void sendPingBlocksUntilRoundTripCompletes(WireMockRuntimeInfo info) { TelemetryReporter.sendPing( "production", "", // empty SDK endpoint: skip /health probe so we measure only the POST - Boolean.TRUE, - false, false, null, // AXONFLOW_TELEMETRY checkpointUrl); diff --git a/src/test/java/com/getaxonflow/sdk/telemetry/TelemetryReporterTest.java b/src/test/java/com/getaxonflow/sdk/telemetry/TelemetryReporterTest.java index 0477c3c..7142533 100644 --- a/src/test/java/com/getaxonflow/sdk/telemetry/TelemetryReporterTest.java +++ b/src/test/java/com/getaxonflow/sdk/telemetry/TelemetryReporterTest.java @@ -33,58 +33,29 @@ class TelemetryReporterTest { private final ObjectMapper objectMapper = new ObjectMapper(); - // --- isEnabled tests (using the 4-arg package-private method) --- - // DO_NOT_TRACK is intentionally NOT honored; the 4-arg overload only takes - // AXONFLOW_TELEMETRY. The DNT-related tests below pin that new invariant. + // --- isEnabled tests --- + // v8: AXONFLOW_TELEMETRY=off is the SOLE opt-out signal. The v7.x mode-based default + // suppression and the Boolean configOverride parameter were both removed. + // DO_NOT_TRACK is intentionally NOT honored. @Test - @DisplayName("should disable telemetry when AXONFLOW_TELEMETRY=off") + @DisplayName("AXONFLOW_TELEMETRY=off disables telemetry") void testTelemetryDisabledByAxonflowEnv() { - assertThat(TelemetryReporter.isEnabled("production", null, true, "off")).isFalse(); - assertThat(TelemetryReporter.isEnabled("production", null, true, "OFF")).isFalse(); - assertThat(TelemetryReporter.isEnabled("production", Boolean.TRUE, true, "off")).isFalse(); + assertThat(TelemetryReporter.isEnabled("off")).isFalse(); + assertThat(TelemetryReporter.isEnabled("OFF")).isFalse(); + assertThat(TelemetryReporter.isEnabled(" off ")).isFalse(); } @Test - @DisplayName("should default telemetry OFF for sandbox mode") - void testTelemetryDefaultOffForSandbox() { - assertThat(TelemetryReporter.isEnabled("sandbox", null, true, null)).isFalse(); - } - - @Test - @DisplayName("should default telemetry ON for production mode with credentials") - void testTelemetryDefaultOnForProductionWithCredentials() { - assertThat(TelemetryReporter.isEnabled("production", null, true, null)).isTrue(); - } - - @Test - @DisplayName("should default telemetry ON for production mode even without credentials") - void testTelemetryDefaultOnForProductionWithoutCredentials() { - assertThat(TelemetryReporter.isEnabled("production", null, false, null)).isTrue(); - } - - @Test - @DisplayName("should default telemetry ON for enterprise mode with credentials") - void testTelemetryDefaultOnForEnterpriseWithCredentials() { - assertThat(TelemetryReporter.isEnabled("enterprise", null, true, null)).isTrue(); - } - - @Test - @DisplayName("should allow config override to enable telemetry in sandbox") - void testTelemetryConfigOverrideEnable() { - assertThat(TelemetryReporter.isEnabled("sandbox", Boolean.TRUE, false, null)).isTrue(); - } - - @Test - @DisplayName("should allow config override to disable telemetry in production") - void testTelemetryConfigOverrideDisable() { - assertThat(TelemetryReporter.isEnabled("production", Boolean.FALSE, true, null)).isFalse(); - } - - @Test - @DisplayName("AXONFLOW_TELEMETRY=off takes precedence over config override") - void testAxonflowTelemetryPrecedence() { - assertThat(TelemetryReporter.isEnabled("production", Boolean.TRUE, true, "off")).isFalse(); + @DisplayName("v8: telemetry is ON by default for every mode (no env opt-out)") + void testTelemetryOnByDefault() { + // null env (unset) → telemetry is ON. The mode-specific suppression + // that used to disable sandbox-mode pings was removed in v8 — sandbox + // pings now fire and are tagged stream="sandbox" in the payload. + assertThat(TelemetryReporter.isEnabled(null)).isTrue(); + assertThat(TelemetryReporter.isEnabled("")).isTrue(); + assertThat(TelemetryReporter.isEnabled("on")).isTrue(); + assertThat(TelemetryReporter.isEnabled("anything-not-off")).isTrue(); } // --- Payload format test --- @@ -110,6 +81,10 @@ void testPayloadFormat() throws Exception { // instance_id should be a valid UUID format assertThat(root.get("instance_id").asText()) .matches("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); + // v8: production-mode payloads OMIT the `stream` field entirely so the wire shape is + // byte-identical to v7.x for the production-mode case. The server defaults empty/missing + // to "heartbeat". + assertThat(root.has("stream")).isFalse(); } @Test @@ -120,6 +95,33 @@ void testPayloadModeReflection() throws Exception { assertThat(root.get("deployment_mode").asText()).isEqualTo("sandbox"); } + @Test + @DisplayName("v8: sandbox-mode payload carries stream=\"sandbox\"") + void testPayloadStreamTagSandbox() throws Exception { + String payload = TelemetryReporter.buildPayload("sandbox", null); + JsonNode root = objectMapper.readTree(payload); + assertThat(root.get("stream")).isNotNull(); + assertThat(root.get("stream").asText()).isEqualTo("sandbox"); + } + + @Test + @DisplayName("v8: production-mode payload omits the stream field") + void testPayloadStreamTagProductionOmitted() throws Exception { + String payload = TelemetryReporter.buildPayload("production", null); + JsonNode root = objectMapper.readTree(payload); + assertThat(root.has("stream")).isFalse(); + } + + @Test + @DisplayName("v8: enterprise / staging / empty modes also omit the stream field") + void testPayloadStreamTagOtherModesOmitted() throws Exception { + for (String mode : new String[] {"enterprise", "staging", "", "unknown-mode"}) { + String payload = TelemetryReporter.buildPayload(mode, null); + JsonNode root = objectMapper.readTree(payload); + assertThat(root.has("stream")).as("mode=%s should omit stream", mode).isFalse(); + } + } + // --- HTTP integration tests --- @Test @@ -129,13 +131,11 @@ void testCustomEndpoint(WireMockRuntimeInfo wmRuntimeInfo) throws Exception { String customUrl = wmRuntimeInfo.getHttpBaseUrl() + "/v1/ping"; - // Call sendPing with custom checkpoint URL, no env opt-outs, with credentials + // Call sendPing with custom checkpoint URL, no env opt-outs TelemetryReporter.sendPing( "production", "http://localhost:8080", - Boolean.TRUE, false, - true, // hasCredentials null, // axonflowTelemetry customUrl // checkpointUrl ); @@ -156,6 +156,8 @@ void testCustomEndpoint(WireMockRuntimeInfo wmRuntimeInfo) throws Exception { assertThat(body.get("sdk_version").asText()).isEqualTo(AxonFlowConfig.SDK_VERSION); assertThat(body.get("deployment_mode").asText()).isEqualTo("production"); assertThat(body.get("instance_id").asText()).isNotEmpty(); + // production-mode payloads still omit stream on the wire. + assertThat(body.has("stream")).isFalse(); } @Test @@ -168,9 +170,7 @@ void testNoRequestWhenDisabled(WireMockRuntimeInfo wmRuntimeInfo) throws Excepti TelemetryReporter.sendPing( "production", "http://localhost:8080", - null, false, - true, // hasCredentials "off", // axonflowTelemetry = canonical opt-out customUrl); @@ -180,13 +180,13 @@ void testNoRequestWhenDisabled(WireMockRuntimeInfo wmRuntimeInfo) throws Excepti } @Test - @DisplayName("should STILL send ping when only DO_NOT_TRACK=1 is set in process env (DNT no longer honored)") + @DisplayName("should STILL send ping when only DO_NOT_TRACK=1 is set (DNT no longer honored)") void testRequestSentEvenWithDoNotTrackInProcessEnv(WireMockRuntimeInfo wmRuntimeInfo) throws Exception { // Note: this test passes axonflowTelemetry=null, which is what the public // sendPing wrapper would supply if DO_NOT_TRACK=1 were the only env signal. - // After the DNT removal, the SDK no longer reads DO_NOT_TRACK at all, so a - // null axonflowTelemetry means "no opt-out env" and telemetry should fire. + // The SDK does not read DO_NOT_TRACK at all, so a null axonflowTelemetry + // means "no opt-out env" and telemetry should fire. stubFor(post("/v1/ping").willReturn(ok())); String customUrl = wmRuntimeInfo.getHttpBaseUrl() + "/v1/ping"; @@ -194,9 +194,7 @@ void testRequestSentEvenWithDoNotTrackInProcessEnv(WireMockRuntimeInfo wmRuntime TelemetryReporter.sendPing( "production", "http://localhost:8080", - null, false, - true, // hasCredentials null, // axonflowTelemetry = not set, telemetry should fire customUrl); @@ -214,9 +212,7 @@ void testSilentFailure() { TelemetryReporter.sendPing( "production", "http://localhost:8080", - null, false, - true, // hasCredentials null, "http://127.0.0.1:1" // port 1 - connection refused ); @@ -228,29 +224,13 @@ void testSilentFailure() { } @Test - @DisplayName("should not send ping in sandbox mode without explicit enable") - void testSandboxModeDefaultOff(WireMockRuntimeInfo wmRuntimeInfo) throws Exception { - stubFor(post("/v1/ping").willReturn(ok())); - - String customUrl = wmRuntimeInfo.getHttpBaseUrl() + "/v1/ping"; - - TelemetryReporter.sendPing( - "sandbox", - "http://localhost:8080", - null, // no override - false, - true, // hasCredentials - null, - customUrl); - - Thread.sleep(1000); - - verify(exactly(0), postRequestedFor(urlEqualTo("/v1/ping"))); - } - - @Test - @DisplayName("should send ping in sandbox mode when explicitly enabled via config") - void testSandboxModeExplicitEnable(WireMockRuntimeInfo wmRuntimeInfo) throws Exception { + @DisplayName( + "v8: ping fires in sandbox mode AND payload carries stream=\"sandbox\"") + void shouldFirePingWithStreamSandboxInSandboxMode(WireMockRuntimeInfo wmRuntimeInfo) + throws Exception { + // v8 contract: sandbox-mode clients fire telemetry (v7 silently suppressed them) and + // tag their payload with stream="sandbox" so analytics can distinguish dev/test pings + // from production heartbeat. This is the headline behavioral flip. stubFor(post("/v1/ping").willReturn(ok())); String customUrl = wmRuntimeInfo.getHttpBaseUrl() + "/v1/ping"; @@ -258,15 +238,21 @@ void testSandboxModeExplicitEnable(WireMockRuntimeInfo wmRuntimeInfo) throws Exc TelemetryReporter.sendPing( "sandbox", "http://localhost:8080", - Boolean.TRUE, // explicit enable false, - false, // hasCredentials (doesn't matter with explicit override) - null, + null, // no env opt-out customUrl); Thread.sleep(2000); + // Both the ping fires AND the stream tag is on the wire. verify(exactly(1), postRequestedFor(urlEqualTo("/v1/ping"))); + + var requests = WireMock.findAll(postRequestedFor(urlEqualTo("/v1/ping"))); + assertThat(requests).hasSize(1); + JsonNode body = objectMapper.readTree(requests.get(0).getBodyAsString()); + assertThat(body.get("deployment_mode").asText()).isEqualTo("sandbox"); + assertThat(body.get("stream")).isNotNull(); + assertThat(body.get("stream").asText()).isEqualTo("sandbox"); } @Test @@ -276,13 +262,10 @@ void testProductionModeWithoutCredentials(WireMockRuntimeInfo wmRuntimeInfo) thr String customUrl = wmRuntimeInfo.getHttpBaseUrl() + "/v1/ping"; - // telemetryEnabled=true: explicit enable for this test TelemetryReporter.sendPing( "production", "http://localhost:8080", - Boolean.TRUE, false, - false, // no credentials — no longer affects default null, customUrl); @@ -319,26 +302,10 @@ void testUniqueInstanceId() throws Exception { assertThat(id2).isNotEqualTo(id3); } - @Test - @DisplayName("config false in production should skip POST even with credentials") - void testConfigDisableInProduction(WireMockRuntimeInfo wmRuntimeInfo) throws Exception { - stubFor(post("/v1/ping").willReturn(ok())); - - String customUrl = wmRuntimeInfo.getHttpBaseUrl() + "/v1/ping"; - - TelemetryReporter.sendPing( - "production", - "http://localhost:8080", - Boolean.FALSE, // config override disables - false, - true, // hasCredentials (would normally enable) - null, - customUrl); - - Thread.sleep(1000); - - verify(exactly(0), postRequestedFor(urlEqualTo("/v1/ping"))); - } + // testConfigDisableInProduction and testSandboxModeDefaultOff were removed in v8.0 along + // with the AxonFlowConfig.telemetry(Boolean) builder method and the mode-based default + // suppression. AXONFLOW_TELEMETRY=off is the SOLE opt-out path; programmatic suppression + // is no longer supported. See CHANGELOG v8.0.0. @Test @DisplayName("should silently handle server timeout without crashing") @@ -353,9 +320,7 @@ void testSilentFailureOnTimeout(WireMockRuntimeInfo wmRuntimeInfo) { TelemetryReporter.sendPing( "production", "http://localhost:8080", - null, false, - true, // hasCredentials null, customUrl); @@ -372,15 +337,12 @@ void testNon200ResponseNoCrash(WireMockRuntimeInfo wmRuntimeInfo) { String customUrl = wmRuntimeInfo.getHttpBaseUrl() + "/v1/ping"; - // telemetryEnabled=true: explicit enable for this test assertThatCode( () -> { TelemetryReporter.sendPing( "production", "http://localhost:8080", - Boolean.TRUE, false, - true, // hasCredentials null, customUrl); @@ -394,7 +356,7 @@ void testNon200ResponseNoCrash(WireMockRuntimeInfo wmRuntimeInfo) { } @Test - @DisplayName("AXONFLOW_TELEMETRY=off should skip POST even with credentials in production") + @DisplayName("AXONFLOW_TELEMETRY=off should skip POST in production") void testAxonflowTelemetrySkipsPost(WireMockRuntimeInfo wmRuntimeInfo) throws Exception { stubFor(post("/v1/ping").willReturn(ok())); @@ -403,9 +365,7 @@ void testAxonflowTelemetrySkipsPost(WireMockRuntimeInfo wmRuntimeInfo) throws Ex TelemetryReporter.sendPing( "production", "http://localhost:8080", - null, false, - true, // hasCredentials "off", // AXONFLOW_TELEMETRY=off customUrl); @@ -421,15 +381,12 @@ void testPayloadDeploymentModeEnterprise(WireMockRuntimeInfo wmRuntimeInfo) thro String customUrl = wmRuntimeInfo.getHttpBaseUrl() + "/v1/ping"; - // telemetryEnabled=true: explicit enable for this test // Use localhost:1 so detectPlatformVersion gets immediate connection-refused // (localhost:8080 may have a running service that returns a version) TelemetryReporter.sendPing( "enterprise", "http://localhost:1", - Boolean.TRUE, false, - true, // hasCredentials null, customUrl); @@ -456,5 +413,7 @@ void testPayloadDeploymentModeEnterprise(WireMockRuntimeInfo wmRuntimeInfo) thro assertThat(body.get("features").isArray()).isTrue(); assertThat(body.get("instance_id").asText()) .matches("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); + // enterprise mode is not "sandbox", so stream is omitted + assertThat(body.has("stream")).isFalse(); } }