Repository navigation
[Bug]: Clock skew silently defers initial subscription payment after Subscribed success #1621
Description
What happened?
When the subscriber clock is four minutes behind the issuer, a newly created USD subscription settling 1:1 in USDT can be accepted without starting its first payment. Both platforms route a successfully accepted subscription with no currently due period to the generic Subscribed success screen. There is no explanation on that success screen that the first payment has not been sent and is deferred until the payer clock reaches the issuer's start timestamp. Later refresh produces the first payment request, which can look like another trigger after the successful swipe.
This report concerns clock-skew handling and the unexplained deferred first payment. It does not claim a duplicate charge or a second subscription. The original Android-to-iOS observation had one confirmed 1 USDT payment.
Expected behavior
Make acceptance and first-payment status explicit when time disagreement defers the initial payment. Show that payment has not been sent and when it becomes due, or provide an actionable clock warning where a trusted time comparison is available. Preserve intentionally future-dated subscription semantics; do not pay every future period early or weaken payment authorization.
Steps to Reproduce
Controlled service-level case, using real production subscription logic and mocked SDK transport:
- Create a monthly proposal with
startsAt = anchor = 2027-01-15T08:00:00Z, amount1 usd, fixedusdt: 1conversion and USDT-Arbitrum endpoint only. - Set the payer's injected wall clock to
2027-01-15T07:56:00Zand refresh the proposed subscription. - Accept it. Check the active subscription, returned due request and pending requests.
- Advance the payer clock by 239 seconds, refresh, then advance one more second and refresh twice.
- Repeat with an aligned payer clock as control and at both the PR head and pinned base revision.
The UI routing is source-verified; this is not presented as a new device recording or an SDK transport integration test. No real wallet payment is required by the controlled case.
Logs / Screenshots / Recordings
Controlled production-repository cases passed on both revisions, two selected tests per revision (aligned and payer −240 seconds), zero failures.
| Payer clock | On acceptance | After 239 seconds | At 240 seconds | Repeated refresh |
|---|---|---|---|---|
| Aligned | First due request returned; one pending period | — | — | Still one pending period |
| 240 seconds behind | Active subscription; no due request; zero pending | Zero pending | One pending first period | Still exactly one pending period |
Same results on the PR head and pinned base: pre-existing behavior, not introduced by #1568. These cases establish the delayed-due-request mechanism; the generic success-screen routing is independently source-verified.
Focused cases extend PaykitPaymentRequestRepoSubscriptionTest in isolated archives only. The unchanged production code is used, with the same proposal and clock inputs on both revisions. The case checks acceptance, the initial empty due queue under skew, the boundary at +240 seconds, exactly one pending first period after repeated refreshes, and absence of payment proofs in the transport fixture.
No recording of this specific clock-skew sequence is available. The separate amount-input recording belongs to Android #1616 / iOS #1044 and is not evidence for this report.
Bitkit Version
Original installed QA build / observation context: 2.5.0 (190), devDebug / local REGTEST, USDT enabled.
Controlled cases use Debug unit-test targets with mocked SDK transport and injected clocks; they do not connect to a chain/backend.
- PR head:
19e3a31127bb11420480055ec071221cc6b8fe79. - Pinned PR base:
3cdc79c5826c143774c3aa039a065768874ee1d0.
Device / OS
Original observation: Pixel 6 Android 13 emulator, paired with iPhone 17 Pro iOS 26.0. Controlled reproduction: JVM production-repository tests with injected clocks.
Reproducibility
Controlled skew scenario reproduced once on each revision; aligned control also passed on each (four selected tests total). Original user-observed sequence occurred once; no UI repeat rate is claimed.
Additional context
The time gate itself is consistent with a genuinely scheduled future start. The bug is the ambiguous success/deferred-payment experience when a start intended as immediate is still in the future on the payer's clock.
Duplicate search covered both repositories, open and closed issues, for clock, time skew, subscription payment/success/future, stale payment request and payment delayed. Android #1534 (post-send reappearance) and iOS #982 (stale actionable request after payment) concern a request after a payment; this case has no initial payment yet. Existing standard USDT second-confirmation reports Android #1540 / iOS #981 are also a different sequence.
Original Android emulator drift was independently measured. Local clock synchronization is an environment mitigation and does not resolve this application behavior. No proof has established that clock skew caused every UI event in the original manual session.
Companion report: synonymdev/bitkit-ios#1049.
Activity
ovitrif commentedon Oct 20, 2026
Triage: milestone 3.1.0. The first payment still goes out once the payer's clock reaches the start time, and no duplicate charge occurs, so it does not block 3.0.1. The report says iOS behaves the same; there is no bitkit-ios issue for it yet.
ovitrif commentedon Oct 20, 2026
Twin: synonymdev/bitkit-ios#1049.