Skip to content

Backlog triage: unsolved issues ranked by agent-handoff safety #1275

Description

@jvsena42

Context

A triage pass compared all 124 then-open issues against master (cc1023ac), reading the current code and the fixing commits, and driving a Pixel_9 emulator where the flow was observable. 13 issues turned out to be already fixed or stale and were closed; regression pins for those landed in #1274.

This issue collects what is left, split by how safely it can be handed to a coding agent running with little or no supervision. Each row names the exact file and the shape of the change, so a task can be cut from it directly. Nothing here is a new bug report — every item links an existing issue.

The point of the split is that "small diff" and "safe for an agent" are not the same thing. Tier A items have one obvious correct implementation. Tier B items are still bounded but have a failure mode worth a human look. Everything in the last section should not go to an unsupervised agent, and the reason is stated.


Tier A — mechanical, one obvious implementation

Self-contained, unit-testable, no product or design decision left open. Each mirrors a pattern that already exists in the repo.

Issue Change Where
#809 Transfer-to-savings success returns to the Spending details screen instead of Home. Replace popBackStack<Routes.TransferRoot>(inclusive = true) with navigateToHome() — the sibling external-node flow already does this (a13842243), and iOS calls navigation.reset(). ContentView.kt:940-947
#1110 Channel details hardcodes 24h time. DatePattern.CHANNEL_DETAILS = "MMM d, yyyy, HH:mm"; route it through the existing UiDateStyle.pattern(is24Hour) + LocalIs24HourFormat machinery that the activity list already uses (the #677 fix). ChannelDetailScreen.kt:588-604, ext/DateTime.kt:264
#1042 A successful retry keeps the failed attempt's amount. The existing-row branch copies only updatedAt/status/contact; add value, fee, preimage, message, which are already on payment/kind. CoreService.kt:748-753
#1167 Three Core restore slices share one runCatching, so one failure silently drops the rest. Split into three runSuspendCatching blocks with per-slice Logger.error and an aggregate failure result. ActivityRepo.kt:985-989
#1139 Contact activity cross-filters boost ids between wallets: getTxIdsInBoostTxIds() is called once with the default wallet. ActivityListViewModel.kt:238-242 already does the per-wallet version — copy it. (The wallet-scope half of this issue is already fixed by c95160a6b.) ActivityRepo.kt:462
#622 Pull-to-refresh does not re-fetch FX rates. Add currencyRepo.triggerRefresh() to the existing onRefresh lambda; CurrencyRepo.refresh() already guards re-entrancy with isRefreshing. HomeScreen.kt:286-290
#558 The number pad stores the grouped text as raw input, so "100 000 000" is 11 chars against a 10-char cap and further digits are refused; deletes also waste presses on separators. Strip SATS_GROUPING_SEPARATOR when assigning rawInputText at the three sites. AmountInputViewModel.kt:147-152, 170-176, 193
#638 The "also required for payments" label runs under the Switch in longer locales. Add Modifier.weight(1f) to the BodyMSB, keep the Switch intrinsic. PinResultScreen.kt:100-117
#630 Tag length is uncapped, so arbitrarily long tags reach metadata and backups. Add a TAG_MAX_LENGTH constant and .take() in the tag inputs, mirroring DEVICE_LABEL_MAX_LENGTH = 50 and BIO_MAX_LENGTH = 160. (The chip rendering half is already fixed by a78783249.) AddTagScreen.kt:120-136, components/AddTagSheet.kt:76
#1177 Electrum connection failures discard the probe's specific cause. Branch on the ElectrumProbeError subclass, add the strings alphabetically, keep the generic fallback. Moving the mapping into the ViewModel would also make it unit-testable. ElectrumConfigScreen.kt:70-77
#894 Design-confirmed: the Coin selection frame has no Auto row — the sheet goes nav bar → divider → UTXO rows. Autopilot vs manual is the existing Settings > Advanced > Coin selection preference, and the frame's own note says the sheet is only shown when that preference is manual. Remove auto_select_row. SendCoinSelectionScreen.kt:115-133; Figma 46920:148767
#422 Design-confirmed: three fixed ordered suggestion sets, one per wallet state, 4 cards max, and "when a card is removed the next in the set is promoted". Empty wallet: Buy, Spend, Support, Back Up, Secure, Profile, Hardware, Invite. On-chain: Back Up, Secure, Spend, Support, Profile, Hardware, Invite, Buy. Spending: Quickpay, Get Paid, Hardware, Shop, Profile, Support, Invite, Buy. Implement the sets verbatim. SuggestionsRepo.kt:32-49, 72-105; Figma 46920:147832/147833/147834
#634 Design-confirmed: the Incorrect-word note reads "To correct for a mistake, the user can simply tap either the word in red or the button for that word to toggle the button back to the off-state." So: tapping the red word in the list must also clear it, and there is no overwrite semantics. Today only re-tapping the same chip works, and any other tap hits a bare return. ConfirmMnemonicScreen.kt:74-100; Figma 46920:148017, note 46920:145482

Tier B — bounded, but check the failure mode

Small and localized, but each has a way to be subtly wrong. Fine for an agent that writes the test first; worth a human skim on review.

Issue Change Watch out for
#1251 Trezor powered off shows a blank "Unknown error". handleFailure has branches for cancellation, passphrase, device-busy, firmware, connectivity, timeout — but none for device-unavailable, so the raw AppError falls to else -> ToastEventBus.send(error). Add the branch in both the send and transfer when blocks, and give TrezorRepo a typed error instead of the bare AppError. Two call sites (HwSendViewModel.kt:269-306 and TransferViewModel.kt:1290); missing one leaves half the bug.
#901 Self-payment shows "Insufficient Spending". Add a guard comparing the decoded invoice's payee pubkey against lightningRepo.getNodeId() before the existing checks, plus one string. Must run before the canSend check or the wrong toast still wins.
#896 Pasting a partial mnemonic fills field 1 and then blocks editing: handlePastedWords only acts on exactly 12 or 24 words, so a fragment is dropped while the text field keeps it locally. Spread N words from the focused index. The field holds its own TextFieldValue; fixing only the ViewModel leaves the stuck-text symptom.
#797 A tx that confirms without being seen in the mempool produces no received-payment sheet — Command.from maps only PaymentReceived and OnchainTransactionReceived. Extend it to the confirmed event and route handleOnchainTransactionConfirmed through notifyPaymentReceived. Must not double-notify after a normal mempool-first receive; the existing seen/claim dedupe in the handler is what prevents it, so test both orders.
#804 The critical-update check is emitted on a no-replay SharedFlow whose only collector lives under walletExists, so it is dropped during onboarding. Give it replay = 1 (or hold it in a StateFlow) and collect above the onboarding/main split. Env.isDebug short-circuits the check, so it cannot be exercised on a dev build.
#724 PIN is only required at process start; there is no lifecycle re-lock anywhere. Add a background hook calling resetIsAuthenticatedState(). Must not re-lock while an in-app biometric prompt, the system share sheet, or the Trezor USB permission dialog is foregrounded — that is the whole risk of this one.
#631 Rapid month taps in the activity date-range sheet cancel each other's Animatables and can strand the grid at alpha = 0 / offsetX = ±1000f. Serialize through a Mutex and clear isAnimating in a finally after joining the children. The current isAnimating guard does not serialize because the children are unjoined — re-adding the same guard shape fixes nothing.
#614 The transfer banner can stick when an order is fulfilled-then-closed: syncTransferStates only settles on channel-ready or EXPIRED. Widen the settle condition. Widening too far hides genuinely pending transfers; pair with the DeriveBalanceStateUseCaseTest case.
#616 "Failed to load UTXOs" with no retry — one listSpendableOutputs() call, and executeWhenNodeRunning means a not-yet-running node lands here too. Add a bounded retry and an error/retry state. Needs a real retry affordance, not just a longer wait.
#845 LightningRepo.start wraps the whole startup in runCatching, so a CancellationException after start() returns is swallowed and latches ErrorStarting. Switch to a rethrowing form and rework getStatus(). Repro tests already exist on origin/fix/stuck-node-state-845 (7699a98e5) — port them rather than writing new ones.
#1125 restartNode() calls start(shouldRetry = false), so the first transient failure is terminal. Allow the bounded retry on the restart path. Touches node lifecycle; keep the retry bounded and review toast suppression.
#1093 Residual from the Paykit hardening: PubkyRepo.initialize returns early on an ensureServiceInitialized() throw before _sessionRestorationFailed is set, so identity failures produce no toast and no re-auth prompt. Set the flag on that path. Only the early-return half is agent-sized. Widening canDeferStaleSession to other error contexts needs SDK-owner input — leave it.
#869 Wiping a wallet leaves RN_PENDING_BLOCKTANK_ORDER_IDS_KEY behind, so the retry loop keeps flashing the status icon. WipeWalletUseCase calls only markMigrationChecked(); expose and call the existing clearPersistedMigrationData(). Also chunk the un-chunked blocktank.orders(orderIds = …) call. The icon-debounce half of this issue changes user-visible health semantics — do not bundle it.
#876 The receive sheet's starting tab is correct now (ef9067646), but LaunchedEffect(canCreateLightningInvoice, …) still animates to AUTO when that flag flips true asynchronously on open. Guard the effect with an "already on default" flag. Needs an on-device look to confirm; the dumps do not show the animation.
#715 22 Bitrefill gift-card categories are hardcoded English literals. Add the strings alphabetically and change the enum field to @StringRes Int, resolving at the 2 call sites. Mechanical, but do not localize acronyms (repo rule).
#417 The LNURL-pay comment is sent to the server and then dropped — savePreActivityMetadata has no comment parameter. Add a nullable field through the repo + Room entity and render it in the existing note section. Needs a Room migration; that is the only reason this is not Tier A.
#633 Design-confirmed spec: screen 375 wide, card at x=32 width 311, inner padding 32 all round, two 107.5-wide columns with a 32 gutter, rows 22 high on a 30px pitch. Apply the spec so long words stop wrapping. The file states row height but no explicit overflow rule, so truncate-vs-shrink is still a judgement call — ask before picking. Figma 46920:147925.

Tier C — test and dependency work only

Issue Change
#1193 Flaky unit tests: QuickPayRepoTest builds a real file-backed CacheStore, so virtual-time timeouts race real IO. Extract an interface (or inject DataStore<AppCacheData>) and supply an in-memory fake. Test-only, no production behaviour change; failure mode is a red build.
#843 Branch-and-Bound coin selection fails on a fragmented wallet. Fixed upstream in ldk-node 348197b (PR #109), which is not in the pinned 0.7.0-rc.66. The change here is a version bump — but it needs a published artifact and a full on-chain/Lightning regression run, so treat the bump as the easy part.

Do NOT hand these to an unsupervised agent

Listed so nobody has to re-derive why.

Blocked upstream or cross-repo — the fix is not in this repo:

Duplicates unmerged work — landing the existing PR is the action, not a second implementation:

Money-movement or funds-safety decisions:

Root cause not yet identified — an agent would be guessing:

Design decision still open:

Scope, not difficulty:


Suggested first batch

If you want to start small, Tier A #809, #1110, #622 and #638 are each a handful of lines with an obvious test, touch no money paths, and between them cover navigation, formatting, data refresh and layout — enough to see whether the pipeline works before handing over anything larger.

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions