StoreKit2 Repro Notes: the latest renewal appears in Transaction.unfinished after restore (2026-04-05)
1. Issue Summary
In the current project, during a normal cold launch:
Transaction.latest(for:) returns a value for the weekly subscription
Transaction.all returns the full subscription history chain
Transaction.unfinished is empty
However, after tapping Restore Purchases and calling AppStore.sync(), one "latest renewal" transaction appears in Transaction.unfinished.
This behavior looks more like a system-side replay triggered by AppStore.sync() than a consistently unfinished transaction during a normal launch.
2. Affected Product
Product:
do.i.iapc.vip.week
Transaction chain characteristics:
All transactions belong to the same auto-renewable subscription chain
originalTransactionID = 2000001143446796
The transaction that appears in unfinished is usually the latest or last renewal in the chain
3. Current Code Path
During app startup:
loadProducts()
Debug snapshot for Transaction.latest(for:)
Debug snapshot for Transaction.all
Scan Transaction.unfinished
refreshEntitlements()
During restore purchases:
Call AppStore.sync()
Scan Transaction.unfinished
refreshEntitlements()
4. Preconditions
A Sandbox test account is used
The weekly subscription do.i.iapc.vip.week already has multiple historical renewal transactions
The subscription is already expired, so entitlements = 0 during a normal launch
The issue is easier to reproduce on an iOS 26.4 device
The issue was not consistently reproduced on another iOS 18.2 device
5. Reproduction Steps
Path A: Normal cold launch
Launch the app
Observe the logs:
LatestTransaction snapshot
AllTransaction snapshot summary
unfinished processing result
Observed result:
latest has a value
all contains the full history chain
unfinishedHandledCount = 0
Path B: Tap Restore Purchases
Launch the app
Tap Restore Purchases
Trigger AppStore.sync()
Observe the logs:
restore started
unfinished processing started
unfinished transaction received
Observed result:
After restore, one "latest renewal" transaction appears in unfinished
That same transaction does not necessarily appear during a normal cold launch
6. Expected Result
If a transaction has already been successfully finished in the past, it should not appear again as unfinished after Restore Purchases.
A stricter expectation is:
During a normal cold launch, unfinished = 0
After tapping Restore Purchases, unfinished should still remain 0
7. Actual Result
Actual behavior:
Normal cold launch: unfinished = 0
After Restore Purchases: one "latest renewal" transaction appears again in unfinished
This suggests that AppStore.sync() may replay the most recent historical subscription transaction.
8. Current Assessment
Based on the current logs, the issue is more likely to be:
Related to AppStore.sync() / StoreKit / Sandbox replay behavior on the system side
Easier to reproduce on iOS 26.4
Less likely to be caused by a persistent app-side bug where finish() is missed during a normal startup flow
Reasons:
During a normal launch, unfinished = 0
The behavior is inconsistent across devices and OS versions, even with the same Sandbox account
latest, all, and unfinished can be clearly separated during a normal cold launch
9. Suggested Engineering Position
Suggested wording for internal or external communication:
In the iOS 26.4 + Sandbox environment, calling AppStore.sync() may cause StoreKit to replay the latest historical subscription transaction into Transaction.unfinished. Since the same transaction does not necessarily appear during a normal cold launch, the issue currently looks more like a system/environment-specific behavior difference than an app-side bug where finish() is consistently missed during the regular startup path.
10. Additional Evidence That Can Be Collected
If this needs to be escalated to the team or to Apple, the following would strengthen the report:
Full log comparison before and after tapping Restore Purchases
The same transactionId compared between normal launch and post-restore behavior
Cross-device comparison on different iOS versions
A minimal reproducible sample project and Sandbox test record
0
0
47