Repository navigation
fix: keep a pending pubky sign-in link when another link opens - #987
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 13d02ef3cf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
[Medium impact] The change is limited to Bitkit's incoming-link and approval-sheet flow. Fix the approval replacement marker before merging so a receipt cannot release the held payment early. Findings
SummaryKeeps a pending Pubky sign-in ahead of another link and resumes the held link when approval closes.
Diagram%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Sign-in and another link arrive] --> B[Keep sign-in pending]
B --> C[Hold latest other link]
C --> D[Open approval or schedule replacement]
D --> E[Approval closes]
E --> F[Promote and route held link]
D --> G[Receipt arrives during replacement delay]
G --> H[Pending approval marker cleared]
H --> I[Held link routes before approval]
Reviews (1) · Last reviewed commit: "fix: keep a pending pubky sign-in link w..." · Reviewed by Greptile |
|
Pushed 1b4fad8, answering the Codex and Greptile findings:
|
talosmachina
left a comment
There was a problem hiding this comment.
1 finding (1 P2). Keeps a pending Pubky sign-in link when another link arrives, holding the second link in a follow-up slot until the sign-in is handled and its Authorize sheet closes. Reviewed 13d02ef, full tier, reasoned from the code and CI (iOS does not build on this reviewer's Linux host, so no simulator run).
What I checked, and 4 candidates I ruled out
Read in full: the diff; AppViewModel.retainDeepLink / routePendingDeepLinkIfReady / promoteDeepLinkAfterPubkyAuthIfIdle; SheetViewModel.showSheet / hideSheet / hideSheetBeforePerforming; MainNavView deep-link onChange/task hooks and handleDeepLink; PubkyAuthApprovalSheet dismiss paths; AppScene onOpenURL / DeepLinkRouter delivery.
Call sites traced: retainDeepLink (3 in AppScene), isPubkyAuthApprovalShownOrPending, showSheet(.pubkyAuthApproval).
CI: validate and detect-changes green; Run Tests, Run Integration Tests and build-local still pending at review time.
Ruled out
- Cold-start duplicate delivery parks the sign-in link in the follow-up slot: the duplicate has
pending == url, so it falls through to the plain assignment, andlastRoutedDeepLinkstill swallows a re-delivery after routing. - Held link stranded when the sign-in link fails to parse or shows a toast instead of the sheet:
routePendingDeepLinkIfReadypromotes the follow-up afterhandlerreturns, and thependingDeepLinkURLonChangeroutes it. replacingSheetIDleft stale: it is cleared in bothshowSheetbranches, andhideSheetBeforePerformingnever sets it.- Newer sign-in link while the Authorize sheet is open: sign-in links bypass the hold, so a newer one still replaces the open sheet through
showSheet, as before. - Cold reader: the finding stood, rated P2.
Merge confidence: 3/5, CI was still running when I reviewed, and the finding has not been checked on a device.
ben-kaufman
left a comment
There was a problem hiding this comment.
Reviewed 1b4fad8 and the existing sheet-dismissal and replacement fixes. No blocking code findings. The routing and regression tests cover sign-in priority, follow-up replacement, and the intervening-sheet case. SwiftFormat passes on all four changed Swift files. Hosted unit, integration, and build checks pass, while E2E is still queued. App and device tests were not rerun locally, so this approval does not mark the pending E2E gate complete.
jvsena42
left a comment
There was a problem hiding this comment.
Approving at 1b4fad8, with two LOWs inline. This round was reviewed on Opus because Fable credits ran out.
Checked and clean against synonymdev/bitkit-android#1547:
- Two slots, and both orders on the PIN screen work (
retainDeepLink243-253). A payment link waits behind an open or pending Authorize sheet. The newest link wins in each slot. - No silent drop beyond newest-wins. A held link is promoted after the handler returns, so a sign-in that ends in a toast still releases it.
.task(id: canHandleDeepLinks)re-runs after a relock, and a node-gated link waits for the node. - Dismissal: Cancel, OK and swipe all clear
activeSheetConfiguration. A newer sign-in over an open sheet setsreplacingSheetIDfirst. ThepresentationIDpinning from #966 is untouched. - No queue growth (one URL per slot). A held contact link is re-checked against the session.
Device gate: 1b4fad8 — signin-with-second-link.xml: 6/6 cases pass on the iPhone 17 Pro simulator (PIN on, staging regtest):
| Case | Close | Send after close | Routes |
|---|---|---|---|
sign-in then bitcoin: on PIN |
Cancel | 0.75 s | 1 |
bitcoin: then sign-in on PIN |
swipe | 0.79 s | 1 |
bitcoin: over open Authorize |
swipe | 0.77 s | 1 |
second sign-in over open Authorize, then bitcoin: |
Cancel (newer sheet shown first) | 0.72 s | 1 |
second sign-in and bitcoin: inside the 0.7 s replacement |
Cancel | 0.73 s | 1 |
bitcoin: over open Authorize |
Authorize → PIN → OK | 0.74 s | 1 |
Send always opened on Amount with 10 000 sats. No held link routed while an Authorize sheet was up.
perf: 0.72–0.79 s from close to Send. l10n: no UI text changed.
Each LOW can be fixed here or moved to a follow-up issue. Reply on the thread with which one.
|
These are outside this PR's scope and need no change here. 1. QuickPay runs on any 2. Authorize sometimes hangs on "Authorizing…". Nothing is logged, the relay never receives the approval, and the sheet cannot be dismissed. It hung in 4 of 6 attempts on this head and 1 of 3 on master, alongside 3. An incoming-transaction sheet replaces an open Authorize sheet and drops the sign-in request. While Authorize was open, a received on-chain transaction (an old channel sweep) called The sign-in request was lost with no user action, and the held payment link then opened Send. This sheet replacement predates this PR. Suggested follow-up in bitkit-ios: give |
@jvsena42 filed both: #992 (QuickPay on a link that crossed the PIN lock, 3.0.0, which also covers the inline LOW) and #993 (Authorize hanging on "Authorizing…" during a busy session restore, 3.0.5, linked to #984 and pubky/paykit-rs#197). |
|
Pushed 28be264, which closes #992 here: a payment link that crossed the PIN lock, on its own or held behind a sign-in link, now opens for review instead of QuickPay, as on Android. |
jvsena42
left a comment
There was a problem hiding this comment.
Re-approving at 28be264 ("open locked payment links for review instead of quickpay"), with one new LOW inline. This round was reviewed on Opus because Fable credits ran out.
- My QuickPay LOW is fixed, and the fix goes further.
retainDeepLink(url, whileLocked: settings.pinEnabled && !isPinVerified)marks every link that arrives while the PIN screen is up, matching the condition that showsAuthCheck(AppScene.swift:868). That also covers alightning:link alone crossing the lock, the out-of-scope case from my earlier comment, now #992. A link delivered while unlocked over an open Authorize sheet is not marked, matching Android. A marked link still opens the Send review (Confirm, Amount or LNURL).QuickPaySpendStore.canApplyis untouched. - My journey-wording LOW moved to #994.
Device gate: 28be264 — on the iPhone 17 Pro simulator, PIN on, QuickPay on ($5), a Lightning channel, and 1 811-sat invoices:
| Case | Result |
|---|---|
lightning: then sign-in on the PIN screen, PIN, Cancel |
Authorize first, then Send Confirm (Swipe To Pay), not QuickPay |
sign-in then lightning: on the PIN screen, Authorize → PIN → OK |
Send Confirm, not QuickPay |
lightning: alone on the PIN screen, unlock |
Send Confirm, not QuickPay |
unlocked with Authorize open, lightning: |
QuickPays after Cancel (spending 51 769 → 49 958) |
| after the previous row, Scan › Paste a fresh invoice | QuickPays (53 580 → 51 769), so no stale suppression |
signin-with-second-link.xml |
all three parts pass |
perf: not relevant. l10n: no UI text changed.
The LOW can be fixed here or moved to a follow-up issue. Reply on the thread with which one.
ben-kaufman
left a comment
There was a problem hiding this comment.
Reviewed 4891907, including both commits since my previous approval. No new material findings. Locked payment links open for review instead of QuickPay, and the in-flight counter preserves suppression during concurrent routing. All 29 focused Pubky routing, payment navigation, and sheet tests pass locally. SwiftFormat and whitespace checks pass.
The full CI unit rerun and E2E check are still pending. I did not rerun the funded Pubky device journey locally. This approval does not mark those checks complete.
|
Pushed ee3e45f: merged master (e96c4a7) into this branch, with no conflicts and no change to this PR's own diff. Run Tests failed three times on 4891907, each time on a different test this PR does not touch ( |
Closes #985
Closes #992
Refs:
This PR keeps a pending Pubky sign-in link when another link opens Bitkit before the sign-in is handled. The later link now opens after the sign-in, as on Android, instead of replacing it.
Description
AppViewModelkept one pending deep link and overwrote it. A sign-in link now keeps that slot, and another link waits in one follow-up slot that opens once the sign-in is handled and its Authorize sheet closes. A newer link replaces the one in that slot, and a newer sign-in link still replaces an older one.SheetViewModelnow records which sheet is being shown after a replacement, andMainNavViewroutes the held link once the Authorize sheet has closed and its 0.7 s replacement delay has passed.lightning:link under the QuickPay threshold opened on the PIN screen was QuickPaid right after unlock, and a link held behind a sign-in would have been QuickPaid after the Authorize sheet closed.AppScenemarks links that arrive while the PIN screen is up, andPaymentNavigationHelper.shouldUseQuickpayskips QuickPay while such a link routes.Out of Scope
AppViewModel: two non-sign-in links opened while the app cannot route them still keep only the latest, as before.Design
N/A — no UI changes.
Preview
N/A — no new UI; the sheets open in a different order.
QA Notes
Journeys
signin-with-second-link.xml— a payment link opened on the PIN screen in either order, or over the open Authorize sheet, opens only after the sign-in sheet closes (port of the Android journey)Manual Tests
N/A
Automated Checks
PubkyAuthURLSchemeTests.swift— a pending sign-in link routes before a later link in either order; a link waits until the open Authorize sheet closes, and a newer one replaces it; a newer sign-in link replaces an older pending one; the pending Authorize sheet stays tracked when another sheet shows during its replacement; links that crossed the PIN lock route without QuickPay, unlocked links keep it