From 0b1261c54973777c818c7a51d79673311494140c Mon Sep 17 00:00:00 2001 From: Tony Cebzanov Date: Sun, 12 Apr 2026 23:41:42 -0400 Subject: [PATCH] Preserve source compat and document retry-after field change Add a non-canonical 8-arg SendMessageResult constructor that delegates to the canonical form with null retry-after. This keeps source compatibility for any downstream code that constructs the record directly (tests, mocks) without changing the canonical shape. Records permit additional constructors alongside the canonical one. Document the retryAfterSeconds meaning change in the CHANGELOG. The field was previously populated only for proof-required failures; it is now populated whenever the server sends a Retry-After header. The canonical proof-required discriminator is still token != null. Co-Authored-By: Claude Opus 4.6 (1M context) --- CHANGELOG.md | 4 +++ .../signal/manager/api/SendMessageResult.java | 26 +++++++++++++++++++ .../manager/api/SendMessageResultTest.java | 14 ++++++++++ 3 files changed, 44 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index af02c08d..44478806 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Changed + +- Send message results now surface server-advised retry time for plain rate-limit (HTTP 413) failures, not only for proof-required challenges. The `retryAfterSeconds` field in JSON-RPC `SendMessageResult` is populated whenever the server sends a `Retry-After` header. The canonical way to distinguish proof-required failures remains `token != null`. Text output includes "retry after N seconds" when known. + ## [0.14.2] - 2026-04-04 ### Added diff --git a/lib/src/main/java/org/asamk/signal/manager/api/SendMessageResult.java b/lib/src/main/java/org/asamk/signal/manager/api/SendMessageResult.java index 081a7873..82b83aa9 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/SendMessageResult.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/SendMessageResult.java @@ -15,6 +15,32 @@ public record SendMessageResult( Long rateLimitRetryAfterSeconds ) { + /** + * Source-compatible constructor for callers built against the pre-retry-after record shape. + * Delegates to the canonical constructor with a null retry-after, which is the correct value + * for any result not produced by {@link #from}. + */ + public SendMessageResult( + RecipientAddress address, + boolean isSuccess, + boolean isNetworkFailure, + boolean isUnregisteredFailure, + boolean isIdentityFailure, + boolean isRateLimitFailure, + ProofRequiredException proofRequiredFailure, + boolean isInvalidPreKeyFailure + ) { + this(address, + isSuccess, + isNetworkFailure, + isUnregisteredFailure, + isIdentityFailure, + isRateLimitFailure, + proofRequiredFailure, + isInvalidPreKeyFailure, + null); + } + public static SendMessageResult unregisteredFailure(RecipientAddress address) { return new SendMessageResult(address, false, false, true, false, false, null, false, null); } diff --git a/lib/src/test/java/org/asamk/signal/manager/api/SendMessageResultTest.java b/lib/src/test/java/org/asamk/signal/manager/api/SendMessageResultTest.java index fd5b2b93..b4a4bf4e 100644 --- a/lib/src/test/java/org/asamk/signal/manager/api/SendMessageResultTest.java +++ b/lib/src/test/java/org/asamk/signal/manager/api/SendMessageResultTest.java @@ -3,6 +3,7 @@ package org.asamk.signal.manager.api; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; class SendMessageResultTest { @@ -21,4 +22,17 @@ class SendMessageResultTest { assertEquals(2L, SendMessageResult.millisToCeilingSeconds(1500L)); assertEquals(60L, SendMessageResult.millisToCeilingSeconds(60_000L)); } + + /** + * Source-compat: callers built against the pre-retry-after record shape use the 8-arg + * constructor. It must continue to compile and produce a record with a null retry-after. + */ + @Test + @SuppressWarnings("deprecation") + void legacyEightArgConstructorPreservesSourceCompat() { + var result = new SendMessageResult(new RecipientAddress(null, null, "+15551234567", null), + true, false, false, false, false, null, false); + + assertNull(result.rateLimitRetryAfterSeconds()); + } }