Skip to content

Add getRateLimitStatus JSON-RPC method#2023

Open
tonycpsu wants to merge 2 commits intoAsamK:masterfrom
tonycpsu:get-rate-limit-status
Open

Add getRateLimitStatus JSON-RPC method#2023
tonycpsu wants to merge 2 commits intoAsamK:masterfrom
tonycpsu:get-rate-limit-status

Conversation

@tonycpsu
Copy link
Copy Markdown
Contributor

Summary

Adds a read-only getRateLimitStatus JSON-RPC method returning the most recent rate-limit state observed from send results. Callers can check whether the account is currently rate-limited without triggering a send and without having to track state themselves.

Complements the recent retry-after work (#2016) and distinct captcha-rejected error code (#2021) by closing the loop: send results report rate-limit deltas, this method reports current rate-limit level.

Motivation

Today there is no way to query rate-limit state without attempting a send and inspecting the per-recipient result. That pattern forces clients to either:

  1. Track state themselves in memory (lost on client restart).
  2. Issue a "canary" send just to probe state (wasteful, counts against the limit it's probing).

getRateLimitStatus resolves this by exposing internal state the Manager already observes as sends pass through it.

Behavior

State is tracked in-memory on the Manager:

  • Updated whenever a SendMessageResult reports a rate-limit failure.
  • Cleared after a successful submitRateLimitRecaptchaChallenge.
  • Auto-expires: when the current time is past the retry-after deadline, getRateLimitStatus() returns active=false (and clears the stale snapshot), so callers don't need to compare timestamps themselves.

JSON-RPC response shape

{
  "active": false,
  "proofRequired": false
}
{
  "active": true,
  "proofRequired": false,
  "retryAfterSeconds": 3420,
  "expiresAtEpochSeconds": 1713283000
}
{
  "active": true,
  "proofRequired": true,
  "retryAfterSeconds": 86000,
  "challengeToken": "abc123...",
  "expiresAtEpochSeconds": 1713366000
}

retryAfterSeconds, challengeToken, and expiresAtEpochSeconds are omitted from the JSON when null (non-active case, or non-proof-required for token).

Use cases

  • Admin UIs displaying current rate-limit state on load
  • Monitoring/alerting (poll for active rate limits)
  • Clients that restart and would otherwise lose tracked state

D-Bus

DbusManagerImpl implements the new Manager method as a stub returning inactive(). Exposing this state over D-Bus is intentionally out of scope for this PR — D-Bus clients already observe rate-limit state via send results and don't have the restart-resilience use case in the same way.

Files

  • lib/.../api/RateLimitStatus.java — new API record
  • lib/.../Manager.java — new interface method
  • lib/.../internal/ManagerImpl.java — state tracking + snapshot computation, hooked into toSendMessageResult and the captcha-submit path
  • src/.../commands/GetRateLimitStatusCommand.java — new JSON-RPC/CLI command
  • src/.../commands/Commands.java — command registration
  • src/.../dbus/DbusManagerImpl.java — stub implementation
  • src/test/.../SubscribeCallEventsTest.java — update existing StubManager to implement the new method

🤖 Generated with Claude Code

tonycpsu and others added 2 commits April 16, 2026 08:26
Adds a read-only query returning the most recent rate-limit state
observed from send results. Callers can check whether the account is
currently rate-limited, how long until retry, and whether a captcha
challenge is required — without having to trigger a send and inspect
the response, and without having to reconstruct state themselves.

Useful for:
- Admin UIs that want to display current rate-limit state on load
- Monitoring/alerting (poll for active rate limits)
- Clients that restart and would otherwise lose tracked state

The status is tracked in-memory on the Manager: updated whenever a
SendMessageResult reports a rate-limit failure, cleared after a
successful captcha submission, and auto-expires when the retry-after
window elapses (getRateLimitStatus returns active=false once the
current time is past expiresAtEpochSeconds).

JSON-RPC response shape:
{
  "active": bool,
  "proofRequired": bool,
  "retryAfterSeconds": long,    // omitted if not active
  "challengeToken": string,      // omitted unless proofRequired
  "expiresAtEpochSeconds": long  // omitted if not active
}

D-Bus is not updated to expose this state; DbusManagerImpl returns
inactive as a stub since D-Bus clients already observe rate-limit state
via send results.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

1 participant