Repository navigation
Conversation
…-broadcast-outcome
There was a problem hiding this comment.
detekt found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
Regtest APKDownload bitkit-dev-debug universal APK (expires in 30 days). |
This comment has been minimized.
This comment has been minimized.
|
I pushed 6966111 with the scoped review fixes: original-send follow-up, exact-observation acknowledgement, running-process Accepted persistence repair, verified Shop proof delivery after guard replacement, and original transfer accounting. The visibility component test now states its actual coverage. The source batch passed 71 focused tests. Process loss before Accepted is durable still leaves the attempt guarded. This PR remains draft while corrected node artifacts, consumer validation and current native journeys are pending. |
|
I pushed ae0be37 with the hardware Shop proof correction. A Core txid is retained only as the original lookup candidate; proof and Success require fresh observation of that exact outgoing transaction in the original wallet. Identity/request/wallet context is captured, preparation failures block dispatch, and pending proof work cannot start another payment. The frozen batch passed 58 focused tests, including the guard, wrong-identity, inbound/mismatched lookup and original-context regressions. The hardware journey spec is parsed but unrun; physical hardware and native fault fixtures remain explicit QA gaps. This remains draft while both apps validate the published rc68 dependency and current native fixed/Max journeys. Prior rc67 media is labelled historical. |
|
I pushed 9de645a with the final hardware Shop guards and the production rc68 dependency pin. A candidate-save failure or a Core exception with no returned txid keeps the started request protected after dismissal/reopening. Shop Sent activity now requires fresh exact outgoing observation and durable local follow-up in the original wallet. The affected run passed 95 tests and app/test APK builds. The actual installed APK embeds the published rc68 native bytes; funded fixed 1,000-sat and Max 98,749-sat native sends passed, and both exact UI transaction IDs were independently observed on the backend. Current Preview replaces the historical accepted-send media. Controlled native refusal/response-loss and hardware Shop execution remain unrun; their QA entries remain explicit. No recovery scope was added. |
jvsena42
left a comment
There was a problem hiding this comment.
Two HIGH, one MEDIUM and two LOW inline. I reviewed this as a funds change. The refusal lockout and the legacy-proof gap are shared with synonymdev/bitkit-ios#844.
Checked and clean:
- No failure is reported for a tx that broadcast:
NodeException/NodeNotSetuprelease the guard only before dispatch in rc.68, and everything else keeps the guard. - Success is shown only on
Accepted. The replays at :4018/:4172 are for the same request with its original txid. HW Shop needs a fresh exact observation. admitblocks the samerequestId/orderId, and Lightning proof association is refused while an on-chain attempt exists.- Pending is persisted before dispatch.
- Old backups decode with the new field defaulting to false, and newer backups decode on older builds via
ignoreUnknownKeys. - The Keychain change is storage-only, with no seed material.
- The rc.66 → rc.68 bump carries the broadcast-result API.
Pre-existing: RBF/CPFP remain fire-and-forget.
Also LOW: the new toasts at TransferViewModel.kt:394/436 are hardcoded English.
|
Two independent reviews. needs changing before merge
worth doing, does not block
nits
|
|
Published cd07c3c. I rejected unsigned active backup attempts that could leave a restored wallet permanently blocked, and kept recovery Pending when acceptance exists only in memory after a failed write. The retry preserves the original transaction and does not authorize another payment. Both defects were reproduced before correction; local build, unit tests and lint completed. The dispatch-boundary, contact-attribution and fresh-wallet Shop restore findings remain open, alongside device and merchant acceptance. This PR stays draft. @codex review |
|
Codex Review: Didn't find any major issues. 🎉 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
|
Published 964ef89. I fixed restored-payment contact attribution so recovery preserves the user's durable manual detachment instead of reattaching the original contact or blocking completion. The regression reproduced the unwanted reattachment before correction; local build, unit tests and lint completed. The dispatch-boundary finding and fresh-wallet Shop restoration remain open, together with device and funded merchant acceptance. This PR stays draft. @codex review |
|
Codex Review: Didn't find any major issues. You're on a roll. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 964ef89f16
ℹ️ 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".
| @@ -868,17 +891,12 @@ class AppViewModel @Inject constructor( | |||
|
|
|||
| private fun handlePaykitOnchainPaymentResolution(resolution: PaykitOnchainPaymentProofResolution) { | |||
| if (!PubkyPublicKeyFormat.matches(pubkyRepo.publicKey.value, resolution.identity)) return | |||
There was a problem hiding this comment.
Reprocess resolutions when the matching identity becomes active
If reconciliation publishes a resolution while pubkyRepo.publicKey is temporarily null or points to another profile, this return leaves the resolution in the repository flow, but nothing retries it when the matching identity becomes active. onchainPaymentResolutions is a StateFlow, duplicate publication keeps the same list without re-emitting, and identity activation can additionally clear the list, so a completed hardware payment is never added to resolvedHardwarePayments and a software completion never updates the current send/contact state. Observe the identity together with the resolution list or explicitly replay retained resolutions after activation.
Useful? React with 👍 / 👎.
|
Pushed 7ec4d56. I kept acceptance recovered after a broadcast error Pending until the exact winner is durably saved. This addresses the retained-only success finding. Local verification: Android build, unit tests and lint completed; the new regression failed before the fix and passes afterward. Funded Shop acceptance remains unrun. @codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7ec4d56753
ℹ️ 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".
| proofs[index] = verified | ||
| return persistAndSubmit(listOf(verified), proofs) | ||
| } | ||
| submitReady(proof) |
There was a problem hiding this comment.
Rebuild hardware activity before submitting a restored proof
When a wallet backup restores a hardware proof with onchainAcceptanceVerified == true, this branch submits and removes the proof without calling observeExactTransaction(), which is also the only path that recreates and verifies the local sent activity. Because wallet and activity backup categories upload independently, the restored wallet envelope can be newer than the activity envelope; in that case the app publishes payment success and discards its retryable proof while the corresponding activity is still absent. Verify or recreate the hardware activity before submitting an already-verified restored proof.
Useful? React with 👍 / 👎.
| lightningRepo.lightningState.map { it.nodeLifecycleState.isRunning() }.distinctUntilChanged() | ||
| .collect { running -> if (running) resumeAcceptedFunding() } |
There was a problem hiding this comment.
Retry accepted funding after connectivity recovers
If an accepted transfer still needs its paid-order/local follow-up and fetchOrders() fails because Blocktank is temporarily unreachable, the only automatic retries installed here are another node-running transition or an on-chain event. Once the node is already running and the transaction event has already been consumed—for example, restoring an already-confirmed transfer while the API is offline—network recovery triggers neither, so the accepted attempt remains incomplete and blocks subsequent software sends until a process restart or manual order flow. Observe connectivity recovery or otherwise schedule a retry after this failure.
Useful? React with 👍 / 👎.
|
Pushed 2836a9b. I fixed hardware Shop recovery after a broadcast timeout: exact transaction observation clears the retained send guard and opens Success with the original payment details, without requiring a returned Core result or another send. Local verification: Android build, unit tests and lint completed. The regression failed before the fix; it also checks original request/payer/amount, unrelated observations and admission of the next send. Funded hardware/merchant validation remains unrun. @codex review |
|
Codex Review: Didn't find any major issues. More of your lovely PRs please. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
|
Pushed 3ca8a30. I made restore reject an accepted replacement transaction whose backup omits that candidate’s fee rate, preventing installation of a payment guard that cannot complete. The original candidate can still use its original fee rate; a valid replacement preserves its own rate. Local verification: Android build, unit tests and lint completed. The new regression failed before the fix; accepted restore fixtures now include the winning replacement rate. Funded Shop/hardware acceptance remains unrun. @codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3ca8a3093f
ℹ️ 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".
| walletIndex = walletIndex, | ||
| transferContext = transferContext, | ||
| payerIdentity = payerIdentity, | ||
| preparationPending = requestId != null, |
There was a problem hiding this comment.
Recover unsigned guards after process death
If the process dies after this persistence and before retainPreparedReceipt() finishes, an ordinary send or transfer restarts with a durable blocking attempt but no inputs or candidate txid. retryOriginal() rejects that state, while the only restart cleanup (releaseInterruptedShopPreparation) requires preparationPending, a requestId, and a Shop proof, so these non-Shop attempts permanently block every later software on-chain send. The backup deferral fixes remote snapshots but does not repair this local keychain state; all definitely unsigned, non-restored attempts need a restart-safe cleanup path.
Useful? React with 👍 / 👎.
| ).also { | ||
| persist(it) | ||
| inFlightPreparations -= attemptId | ||
| if (!isRecovery) firstSubmissions += attemptId |
There was a problem hiding this comment.
Persist whether a prepared software candidate was dispatched
If the process dies after the signed receipt is persisted here but before broadcastPreparedCandidate() reaches prepared.broadcast(), the only proof that this candidate was never submitted is lost with the process-local firstSubmissions set. After restart the candidate cannot be cleared as definitely unsent; for a Shop request or transfer whose payment/order deadline has since expired, every recovery attempt fails authorization before dispatch and the retained guard permanently blocks all later software sends. Persist a recoverable pre-dispatch phase or the exact signed transaction instead of relying on this in-memory marker.
Useful? React with 👍 / 👎.
|
I pushed 96a9230 to reject an active on-chain backup without its original local follow-up context. Restore now fails before installing a guard that cannot finish the payment, addressing the missing-context finding. Local verification: model restore and wallet restore regressions reproduced the gap before the fix; build, unit tests and lint passed after the fix. Funded Shop checkout validation remains unrun. @codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 96a9230e8e
ℹ️ 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".
| backupFollowup = ActiveOnchainAttemptBackup.Followup( | ||
| feeSats = "0", | ||
| tags = tags, | ||
| createdAtMillis = nowMillis(clock).toString(), | ||
| channelId = channelId, |
There was a problem hiding this comment.
Capture the contact in the active follow-up context
For an ordinary on-chain payment initiated from a contact, admit() creates every backupFollowup without the contact and no later production path populates it. If the wallet snapshot is uploaded before the separately launched contact-assignment write or its independently uploaded activity backup, restoring the accepted attempt recreates the Sent activity without attribution because finishOnchainSendLocally() can restore only followup.contact. Pass the selected contact into this durable follow-up context when admitting the send.
Useful? React with 👍 / 👎.
| attempt: OnchainSendAttempt?, | ||
| ): Boolean { | ||
| if (proof.onchainWalletId != WalletScope.default) return reconcileHardwareOnchainProof(proof) | ||
| if (!attempt.matchesPositiveShopProof(proof)) return false |
There was a problem hiding this comment.
Preserve reconciliation for pre-upgrade on-chain proofs
Existing installations can contain a software on-chain proof written by the previous version with paymentStarted == true, a null paymentIdentifier, and only onchainMatchingTransactionIdsBeforeAttempt for identifying the eventual transaction. Such a record has no OnchainSendAttempt, so this check now rejects it unconditionally, whereas the removed reconciliation path searched the wallet by its original address and amount while excluding the saved baseline. After upgrading, an already-broadcast payment can therefore never produce or deliver its proof and the started record permanently blocks the request; retain a verified legacy lookup or migrate these records before requiring an active attempt.
Useful? React with 👍 / 👎.
|
I pushed 9f73e83 to resume payment follow-up from the merged local guard after wallet restore. An older unresolved snapshot no longer hides acceptance already retained locally. Recovery remains tied to the original attempt and wallet. Local verification: the stale-snapshot regression failed before correction; build, unit tests and lint passed after the fix. Funded Shop checkout validation remains unrun. @codex review |
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
|
I pushed f616693 to clear the blocked new confirmation’s captured contact context before recovery of an older payment. Pending retains the older operation’s original request, and later completion cannot assign the new recipient’s contact to its transaction. Local verification: the contact-attribution regression failed before correction; build, unit tests and lint passed after the fix. Funded Shop checkout validation remains unrun. @codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f6166930f9
ℹ️ 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".
| paykitPaymentProofRepo.onchainPaymentResolutions.value | ||
| .firstOrNull { it.requestId == incomingPaymentRequest.id } | ||
| .firstOrNull { it.requestId == unresolvedRequestId } | ||
| ?.let(::handlePaykitOnchainPaymentResolution) | ||
| if (uncertainOnchainPaymentRequestId == null) return | ||
| setSendEffect( | ||
| SendEffect.NavigateToPending( | ||
| paymentHash = incomingPaymentRequest.paymentRequestId, | ||
| amount = amount.toLong(), | ||
| observeResolution = false, | ||
| ) | ||
| showUnresolvedOnchainSend( |
There was a problem hiding this comment.
Stop after consuming an existing payment resolution
When the exact Shop resolution is already present by the time an uncertain send reaches this branch, handlePaykitOnchainPaymentResolution clears the uncertainty and queues PaymentSuccess, but execution then unconditionally calls showUnresolvedOnchainSend, restores the uncertain request ID, and queues Pending as well. This can leave an already accepted payment displayed as unresolved; return when the matching resolution was consumed before presenting Pending.
Useful? React with 👍 / 👎.
| val unresolvedRequestId = if (previous != null) previous.requestId else incomingPaymentRequest?.id | ||
| uncertainOnchainPaymentRequestId = unresolvedRequestId |
There was a problem hiding this comment.
Bind recovery UI to the older Shop request
When Shop request B is blocked by an unresolved Shop request A, this routes Pending using A's request ID while SendUiState.incomingPaymentRequestId remains B. If A resolves afterward, handlePaykitOnchainPaymentResolution consumes the resolution but refuses success because the state still names B, and SendPendingViewModel deliberately does not observe request-bound attempts, so the screen remains Pending after A's proof completes. Update the displayed request context to A or otherwise deliver A's exact resolution to this Pending route.
Useful? React with 👍 / 👎.
Closes #1211
Twin: synonymdev/bitkit-ios#844
Refs:
Description
Hardware Shop payments persist the signed receipt and original private boundary before endpoint consumption. Interrupted unsigned software preparations release the saved boundary before removing their proof.
0.1.0-rc69with LDK0.7.0-rc.70, retaining original payment guards, captured proof app IDs and cross-platform backup state.Required for Bitkit 2.6.0 Shop support. Open for review so app and native dependency reviews can proceed in parallel. Dependency approval, remaining feedback and funded Paykit/server acceptance are still required before merging. The merged broadcast-result API is extended by LDK rc70 so the original signed transaction ID, actual inputs and recipient amount are durable before submission.
0.7.0-rc.70prepared-send bindings; independent Maven resolution and current built APK native bytes were verified; earlier rc69 installation was verified before the backup follow-up.Why
Required for Shop support in Bitkit 2.6.0: buyers must be able to tell whether an on-chain payment was accepted and recover an uncertain checkout without paying twice.
These are release acceptance requirements. The app PRs include the selected Paykit updates for 2.6.0. Final validation must pay a Shop order with these app builds and verify that the merchant receives the payment proof and the order becomes paid on the existing Shop server.
Out of Scope
Design
N/A — no design available for the new unresolved-send state.
Preview
Prepared-send Pending preview before the backup follow-up: actual published rc69 native preparation in a funded regtest wallet, with Unknown injected before broadcasting. This shows the retained 1,000-sat original receipt and explicit retry action; it does not reproduce backend refusal or response loss.
Historical rc68 candidate before the current feedback batch: fixed 1,000-sat and Max 98,749-sat regtest sends using the actual published and resolved LDK package. Both exact transaction IDs matched native Accepted logs and independent backend observation.
Earlier Pending preview at 0ef4613: synthetic component UI only, with dummy transaction IDs/refusal text and mocked fiat value. It shows refusal copy, a selectable candidate ID and local Details without success; it does not reproduce backend refusal or persistent reopening.
QA Notes
Current master integration
0.1.0-rc69from the merged Paykit PR; LDK remains0.7.0-rc.70.Private hardware cleanup (b71aff7)
Hardware dispatch-state recovery (91351de)
Hardware authorization recovery (3925ef2)
PaykitPaymentProofRepoTest,HwSendViewModelTestandAppViewModelSendFlowTest; the authorization-boundary backup regression reproduced the missing receipt before correction. Local verification: affected checks and Android build completed; physical hardware and fresh-wallet Shop VSS acceptance remain unrun.Current review corrections at 59df4f8 / 5843da2: direct-send fallback validates original attempt and wallet; hardware Shop Pending retains its result until proof completion. Missing proof app IDs remain readable and retained, and cannot be submitted with invented provenance. Focused repository, hardware-send and send-flow checks and the app build completed. Physical hardware proof-save failure, remote restore and final Shop order/proof checkout remain unvalidated.
Journeys
onchain-original-payment-retry.xml— Pending → approve fee and normal payment authentication → retry the same recipient amount and input set; persist both candidates, keep uncertainty guarded and finish only the accepted/observed winner. Spec parsed; current funded retry journey remains unrun.shop-onchain-proof.xml— linked issuer and funded Bridge hardware wallet: exact original transaction and delivered proof, with no new signing/payment while observation is pending. Spec parsed; native hardware journey unrun.onchain-accepted-result.xml— accepted fixed-amount and send-all finish local activity and expose distinct exact transaction IDs in Details.Manual Tests
Automated Checks
updated
AppViewModelSendFlowTest.kt— recovering an older blocked payment never assigns the new recipient’s contact to it.updated
BackupRepoTest.kt— an older unresolved backup resumes retained local acceptance after original context is restored, without requiring another transaction event.updated
ActiveOnchainAttemptBackupTest.ktandBackupRepoTest.kt— missing original follow-up context rejects restore before installing a blocking payment guard.updated
ActiveOnchainAttemptBackupTest.kt,BackupRepoTest.ktandOnchainSendAttemptStoreTest.kt— accepted replacement backups require the winning candidate’s fee rate; missing/partial maps fail restore, valid replacement rates and original-candidate fallback remain supported.updated
HwSendViewModelTest.kt— exact-wallet completion after a hardware Shop broadcast timeout clears the retained send guard and preserves the original amount/request/payer; unrelated observations cannot clear it. Build, unit and lint checks completed; the funded hardware journey remains unrun.updated
LightningRepoTest.kt— a retained accepted result after a broadcast failure stays Pending while durable repair fails, including after reopening; no second native send is prepared.updated
ActivityServiceTest.kt— accepted-payment restoration preserves a deliberately removed contact and allows local follow-up to finish. The previous behavior reattached the original contact in the regression. Local verification: Debug build, unit tests and lint. Device and merchant acceptance remain outstanding.updated
ActiveOnchainAttemptBackupTest.ktandLightningRepoTest.kt— unsigned backup attempts are rejected; retry preserves Pending when the accepted winner is not durable, without authorizing or dispatching another payment. Both defects reproduced before correction. Local verification: Debug build, unit tests and lint. Fresh-wallet Shop restoration and funded merchant acceptance remain outstanding.ran
PaykitPaymentProofRepoTest.ktandHwSendViewModelTest.ktregressions: definite software preparation failure retains the proof until its original private boundary is released; a restored signed hardware receipt blocks ordinary and other-request signing from the same wallet. Required local build, unit tests and lint passed at bcc22b1.ran
LightningRepoTest.ktandActivityRepoTest.ktregressions: failed accepted-outcome persistence and failed repair stay Pending across restart; contact-assignment retries finish marker cleanup and replacement propagation. Required local build, unit tests and lint passed at 4306d22.updated
HwSendViewModelTest.ktandPaykitPaymentProofRepoTest.kt— signed hardware Shop receipts survive encoded backup/repository restoration; explicit authorized retry broadcasts the original bytes without another signature. Wrong payer/wallet/address/amount cannot load the receipt. Restoration itself does not broadcast or prove acceptance.Hardware Shop connectivity failure retains its signed payment across cancellation and explicit retry, with one signature and the same original payer/request. The regression failed before correction; affected hardware-send/proof tests, app build and changed-line static analysis completed. Physical hardware remains unrun.
Non-connectivity hardware Shop broadcast errors also retain the original signed payment through cancellation and retry. The invalid-transaction regression failed before correction; affected hardware-send/proof checks, app build and changed-line static analysis completed. Physical hardware remains unrun.
added
BackupRepoTest.kt— unsigned ordinary sends and transfers defer the entire wallet snapshot before any remote write.added
HwSendViewModelTest.kt— save denial and storage exceptions preserve the signed payment across cancellation and retry it without signing again.added
OnchainSendCoordinatorTest.kt— accepted retry storage failure stays Pending with the original candidate family after restart.added
TransferViewModelTest.kt— changed funding address, client balance or service fee cannot complete the retained transfer or trigger another send.updated
OnchainSendAttemptStoreTest.kt— repeated restore retains an imported operation’s progressed fee and completion; changed payer or recipient is rejected, and a first import without follow-up context remains guarded.updated
ActivityRepoTest.kt— a failed Core contact write leaves the durable manual-detachment marker intact. Both new regressions failed before correction.updated
OnchainBackupRestoreDeviceTest.kt— verifies the remote wallet payload contains the accepted attempt, deletes its local attempt record and checks it is absent, then restores the original wallet, transaction, amount, exact inputs, candidate IDs and completed follow-up from VSS. Corrected device replay passed. The earlier completed-attempt replay was a false positive because backups excluded its completed receipt. This remains an ordinary-payment test on the same wallet, not fresh-wallet Shop request/proof recovery.ran repaired shared-state Paykit device fixtures at 5f800c2: app/test APK compilation and drawer/Pending component checks passed on Android 16, with exact installed app APK bytes verified. Removed duplicate profile arguments and obsolete settings dependencies. These are component checks, not funded PIN/recovery or merchant checkout.
updated
PaymentDeadlineSubmissionTest.kt,AppViewModelSendFlowTest.kt— queue-time expiry, expiry after immutable preparation, and exact original hardware cancellation with no release after dispatch.ran local JVM suite and detekt against Paykit rc65 and hosted LDK rc70; current funded device, hardware and Shop checkout journeys remain unrun. Detekt retains its existing
ignoreFailures=trueconfiguration.ran native rc70 consumer compilation and broadcast-outcome/recovery checks against the hosted Maven artifact with local Maven repositories excluded.
updated
OnchainSendAttemptStoreTest.kt,PaykitPaymentProofRepoTest.kt— durable admission precedes request consumption; failed writes preserve request details; restart cleanup preserves live, legacy and signed attempts, and proof-removal failure retains the guard.added
ActiveOnchainAttemptBackupTest.kt, updatedPaykitPaymentStateBackupTest.kt,BackupRepoTest.kt— shared golden wire, wallet/network/proof rejection and guard-before-proof restore.added
OnchainSendCoordinatorTest.kt— exact original amount/input retries, original winner races, payer change and UInt32 fee bounds.added
OnchainSendAttemptStoreTest.kt— serialized admission, durable guards, outcome persistence and exact transaction observation.added
SendPendingScreenTest.kt— refusal/candidate visibility and enabled local Details callback while remaining Pending; component checks do not reload durable state.updated
LightningRepoTest.kt,LightningServiceTest.kt— explicit accepted/rejected/unknown mapping and pre-dispatch boundaries.updated
AppViewModelSendFlowTest.kt,PaykitPaymentProofRepoTest.kt,TransferViewModelTest.kt— proven pre-admission errors, accepted follow-up failures, request protection and original hardware proof identity.updated
AppViewModelSendFlowTest.kt— permission denial, captured request/identity across asynchronous hardware authorization, and started-proof preservation after retry denial/cancellation.updated
TransferViewModelTest.kt— fresh Accepted and resumed Accepted/Observed funding retain one order/send and paid-success navigation after local activity failure; failed funding persistence retains the original order without success.updated
TransferRepoTest.kt,SendPendingViewModelTest.kt— startup/event funding resumption, partial storage idempotency and original-wallet Details without acceptance inference.updated
HwWalletRepoTest.kt,HwSendViewModelTest.kt,ActivityRepoTest.kt— exact outgoing original-account observation, Sent activity durability and one native broadcast while proof completion is pending.removed
PaykitOnchainPaymentProofLookupTest.kt— address/amount matching no longer establishes that an interrupted attempt was accepted.ran remote dependency validation with Maven local excluded —
0.7.0-rc.68resolved AAR SHA-2560cee2079291260aea12bf60ac9c8af8f459d9f24c3327d4cb021e5686035aa2f, identical to the published canonical artifact.Recovery completion and identity (7984a64)
Restart-safe Shop preparation (5a07a0f)
Historical validation before the shared-state Paykit integration
Local verification at 56398e3: master b29956a was integrated without manual edits; compilation and 484 focused tests passed (0 failures/errors/skips). Published rc68 AAR identity was verified with Maven local excluded. Detekt completed with
ignoreFailures=trueand 577 reported findings; it is not warning-free. All finding locations map to existing parent lines, which does not prove identical prior structural findings. Full-suite, device, native-fault and physical-hardware checks were not repeated; heavy hosted integration CI remains deferred to release.Earlier verification at 62c32cc: compilation and 470 focused tests passed (0 failures/errors) against unchanged published rc68, with Maven local excluded. The identity-switch-during-authorization regression failed before the captured identity/context checks and passes now; captured callbacks cannot authorize a replacement request. No device, native fault, physical hardware or contact-deletion journey was run on this merged source.
Earlier verification at 6c75463: compilation and 169 focused tests passed (0 failures/errors). All three new duplicate-funding regressions failed on the preceding production source by funding a second order; the persistence-failure regression remained fail closed. Maven local was excluded and the resolved AAR hash matches unchanged published rc68. No device or storage-fault journey was run for this fix.
Earlier verification at 0ef4613: compile, 3,079 unit tests (0 failures/errors/skips), app/test APK builds and two emulator component tests passed. Startup funding and pre-admission regressions failed before their fixes. Detekt exited successfully with
ignoreFailures: 570 findings remained, none on added or changed feedback lines. The installed APK’s native library matched rc68. Full-suite, Detekt and device checks were not repeated for 6c75463 or 62c32cc.Prior rc68 validation: 95 affected tests and funded fixed-amount/Max native journeys passed with independently verified exact backend transactions. Those native journeys were not repeated for this batch. Controlled native refusal, response-loss, storage-fault and hardware Shop journeys remain unrun; the new Preview is synthetic component coverage only.
Current integration verification at d252bcb: 925 focused tests passed; strengthened Shop rerun (203 cases), 96 Jade/Paykit integration tests and 13 emulator component tests passed. The regression for acknowledgement without durable original Shop activity failed on old behavior and passes after repair. Exact request/txid mismatches and identity switching cannot deliver or acknowledge another proof, and recovery never broadcasts. Test API integration repairs and final test-only formatting compiled successfully. Detekt exits successfully with ignoreFailures=true; existing findings remain, so it is not warning-free. Component refusal screens use synthetic fixtures, not a real native refusal. Final matched release-pair Shop, response-loss and physical hardware validation remain required.
Feedback verification at 5f7839a: both new pre-dispatch regression cases failed before the fix; 334 affected send-flow tests and compilation passed afterward. Detekt completed with existing findings and none on added lines. No devices or native fault fixtures were used in this batch; final recovery and release-pair validation remain outstanding.
Current recovery and backup verification: 307 affected checks passed against the published remote rc69 AAR before backup additions. Then 57 focused backup/metadata checks passed, including shared wire round-trip, wallet binding, original proof authorization/completion and restore ordering. The final UInt32 fee-boundary regression failed before its correction and passed afterward, along with current app/test APK builds. These overlapping counts are not additive. Built app native bytes match the hosted rc69 arm64 library; the current backup batch has not been installed or driven on a device. Detekt exited with
ignoreFailures=true: one changed-line complexity finding remains, zero changed-line formatting findings. Hosted Maven publication completed successfully. Earlier funded preparation and Pending/fee/PIN observations seeded uncertainty before submission; they do not prove backend refusal, response loss or a successful retry. Current funded fixed/Max retry, independent Android native VSS vector, physical hardware and final Shop release-pair QA remain unrun.Pending UI verification at 15f45fa: 16 focused JVM checks and 3 emulator component checks passed, along with app/test APK builds. The preceding view model failed the exact observed-successor regression; the preceding error layout failed the non-overlap assertion. Detekt exited successfully with ignoreFailures=true and no changed-line findings; existing findings remain. Component checks use synthetic state. Funded auto-navigation on this UI batch has not been repeated.
Native rc69 validation on preceding production head152b43d: five native fixture checks passed with installed hosted package bytes. A fixed1,000-sat retry with withheld backend acknowledgements remained Pending until independent exact successor observation and durable local completion. Native transport repeated the same transaction; no distinct second payment was observed. Max retained99,890sats and exactinputs: a higher fee failed before broadcast, then original-fee retry succeeded. Original uncertainty was seeded before the first broadcast, so this does not prove process-death recovery after initial dispatch. Native VSS derivation vectors passed. Physical hardware, native refusal and final production Shop merchant pairing remain unrun.
Published 5f8e105:
Validation: four regressions failed against the previous production behavior. 209 focused tests passed; final overlapping 31-case and 62-case checks passed, alongside app/test APK builds against published rc69 and detekt. Lint reported existing findings with zero introduced-line findings. Physical hardware, live backup restore and final selected-version Shop checkout remain unrun. Draft status remains unchanged.
Published 6c1a9cb: added the Pending observation device integration fixture. Two checks passed using the current production APK and published rc69. The shared backup reader preserved the original wallet, inputs and candidate family; injected exact-positive observation completed the production Pending callback with the original txid and amount. The fixture restored its original saved operation afterward. This validates the store/ViewModel/screen callback, not a native event, full-app success route, remote VSS restore or merchant checkout.
Lint/detekt and fixture APK compilation completed. Full accepted funding/VSS device restore, authenticated hardware Shop rejection, physical hardware and final merchant pairing remain unrun. Five new review findings are being addressed; draft status was retained at that validation point.
Published 66d32dd: preparation cancellation releases only an empty pre-dispatch guard; completing an older payment does not present the blocked new send as successful; uncertain transfer funding opens the original recovery surface; each candidate retains its authorized fee rate; proof reconciliation avoids the reversed attempt/proof lock order. The original order, payer, amount and exact inputs remain protected.
Validation: 96 focused tests passed, with meaningful prior-behavior failures for cancellation, misleading navigation, transfer routing, fee metadata, shared restore and lock ordering. App/test APK builds passed against published rc69. Detekt completed with 515 existing findings and zero introduced-line findings (
ignoreFailures=true). The shared optional candidate fee-rate map passed the same golden vector as iOS. Current transfer recovery device routing/PIN, funded restore, physical hardware and final selected-version merchant checkout remain outstanding.Published c7745fc: Accepted successors use the actual signed transaction input/prevout fee instead of the original fee. Missing or invalid evidence keeps follow-up guarded; verified fee/rate repair also updates an existing activity placeholder.
Validation: 174 affected JVM tests passed (0 failures/errors/skips), including exact previous-output calculation, missing/substituted inputs, invalid values and arithmetic overflow. The earlier stale-fee regression failed before the writer fix. Current transfer/PIN/device validation, four new review findings and final selected-version Shop checkout remain outstanding.
Published d3f3bec: both retry fallback paths verify original attempt and wallet identity. The prior behavior failed the later-winner regression; all 17 coordinator tests passed afterward. Three remaining review findings and current device/release-pair validation remain outstanding.
Published b9cf568: restored shared/iOS contact attribution no longer prevents completion of an accepted payment. The original contact fills only an empty activity contact; later edits remain unchanged. A failed contact write retains the payment guard.
Validation: the shared golden backup failed acknowledgement before the fix. All 175 affected JVM tests passed afterward (13 attempt-store, 159 send-repository, 3 activity tests; no failures/errors/skips), including contact write failure and later-edit preservation. Two remaining findings concern pre-prepare proof crash ordering and transfer Pending completion. Both apps still need matching rc70 consumer and current funded/Shop validation.
Published df05937: transfer Pending now observes durable completion of its exact original order, wallet, input set and candidate family, then opens the funded order. Accepted funding stays Pending until local follow-up is saved, and this navigation does not dispatch another payment.
Validation: the stale transfer Pending regression failed before the fix. Compilation and all 3,465 JVM tests passed before formatting; the final 355 affected tests and detekt passed after formatting. Detekt has 577 existing findings with zero findings on introduced lines (
ignoreFailures=true). No device or merchant checkout was run for this batch.The signed receipt and private boundary are persisted before hardware endpoint consumption. Fresh-wallet Shop request/proof recovery, current expiry device coverage, physical hardware and final merchant order/proof checkout remain outstanding; this PR remained draft at that validation point.
Original retry deadline verification (6686f9a)
Original input validation (fea3f42)
Funded Android payment-PIN verification (fea3f42, native rc70, Paykit rc65)
Real acknowledgement-loss recovery (2cb41e0, native rc70, Paykit rc65)
First-submission expiry (875a3cb)
Current-head device component verification at875a3cb7: rebuilt and installed APK identity verified;
SendPendingScreenTest.ktandDrawerMenuWidgetsTest.ktran on Android emulator. This covers uncertainty presentation, guarded retry controls and exact-candidate Details availability; it does not certify funded expiry/replacement, remote restore, hardware or merchant proof/order completion. Those acceptance checks remain open.Original-winner recovery accounting (a6ddeb0)
Restart-safe hardware expiry cleanup (d463af9)
Current validation gaps: the rc65 SDK fresh-grant remote request fixture and same-wallet ordinary-payment remote VSS restore passed. Fresh-wallet Shop request/proof recovery, funded channel recovery, current expiry device coverage, physical hardware and final merchant order/proof checkout remain unvalidated.
Payment storage recovery (8f4b85e)
Retained hardware completion (2592aa2)
Prior private payment boundary (e38369f)
Unsent private preparation cleanup (5214de9)
PaykitPaymentProofRepoTest,AppViewModelSendFlowTest, private payment and backup regressions, dev app build and changed-line formatting checks.Retained private payment version (08d35b7)
PaykitPaymentProofRepoTest.kt— restored signed receipts consume their saved private version before retry; failed private storage blocks dispatch, existing consumption remains valid, and another order cannot reuse the same contact while its signed payment is retained.