fix: pass AtProtoClient's clock to its XRPC transport #188
No reviewers
Labels
No labels
breaking-change
bug
documentation
duplicate
enhancement
good first issue
help wanted
performance
question
wontfix
No milestone
No project
No assignees
4 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Grandiras/ATProto.NET!188
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "issue-187-client-clock"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #187.
AtProtoClient's internal constructor, the one tests use to inject a clock, gave that clock only toSessionManager. TheXrpcClientit built keptTimeProvider.System. So the 429 retry delays and theRetry-After/RateLimit-Resetarithmetic ignored the injected clock. The public constructor passesTimeProvider.Systemeither way, so production behaviour is unchanged.Changes
AtProtoClient: setTimeProvider = timeProviderin theXrpcClientinitializer, next toUserAgentandRateLimit.XrpcClientRateLimitTests.AtProtoClient_BacksOffOnItsClock: two 429s withoutRetry-After, then 200. The client's clock must see the 1 s and 2 s back-off, within the 10 % jitter.VideoUploadTests.UploadVideoAsync_BacksOffExponentiallygoes throughAtProtoClient(client.Bsky.Video) instead of hand-building anXrpcClient+VideoClient. This drops the workaround and the comment #186 added to explain it.TestSupport/InstantTimeProvider.cs, so both tests can use it.Verification
dotnet buildpasses with 0 warnings.tests/ATProtoNet.Tests: 5001 passed, 5 skipped.AtProtoClienta non-system clock. None of them hits a 429 path, so the failure looks like an unrelated timing-sensitive test.Note
Open PR #185 (debloat pass D) rewrites the same constructor and still has this gap. Whichever merges second gets a small conflict at the
new XrpcClient(...) { … }initializer; keep theTimeProvider = timeProviderline.🤖 Generated with Claude Code
🤖 Reviewing this PR — the review will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the review runs.
⏳ Held on the OpenCode Go window — the 5-hour window is at 0% (the bot holds at 95%).
This continues automatically after the window resets (2026-09-27T22:33:43.301Z) — nothing to re-trigger.
@claude-reviewer
🤖 Reviewing this PR — follow along in the action run; the reply will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the task runs.
✅ Verdict: approve — no blocking issues found.
One-line fix:
TimeProvider = timeProvideradded to theXrpcClientobject initializer inAtProtoClient's internal test constructor, next toUserAgent/RateLimit. This is exactly the gap described — the public constructor already forwardsTimeProvider.Systemdown the same path, so production behavior is unchanged, and only the injectable-clock test constructor was affected.The new
XrpcClientRateLimitTests.AtProtoClient_BacksOffOnItsClocktest correctly exercises the fix end-to-end throughAtProtoClient.QueryAsync, asserting the 1s/2s exponential back-off (with the documented 10% jitter tolerance) lands on the injectedInstantTimeProviderrather than the system clock.The
VideoUploadTests.UploadVideoAsync_BacksOffExponentiallyrework is a clean simplification: it now goes throughclient.Bsky.Videoinstead of hand-assemblingXrpcClient+VideoClient, which is possible precisely because the fix now plumbs the clock through the public-facing constructor path. Moving the privateManualTime/InstantTimeProviderclock toTestSupport/InstantTimeProvider.csfor reuse is a reasonable, minimal refactor with no behavior change (the class body is copied verbatim).The CHANGELOG entry is correctly placed under
Fixedin[Unreleased], references #187, and matches the required bullet style. No correctness or security issues found; this is a good, tightly-scoped fix.⏱ 0m 49s · 12 turns · tokens: 25.9k in / 3.6k out (+533.0k cache-read)
📜 Full session transcript