Skip to content

fix(shutdown): stop wallet backend on GUI close and clear stale shutdown-channel log#905

Merged
lklimek merged 15 commits into
v1.0-devfrom
fix/gui-shutdown-wallet-backend
Jul 21, 2026
Merged

fix(shutdown): stop wallet backend on GUI close and clear stale shutdown-channel log#905
lklimek merged 15 commits into
v1.0-devfrom
fix/gui-shutdown-wallet-backend

Conversation

@Claudius-Maginificent

@Claudius-Maginificent Claudius-Maginificent commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Why this PR exists

  • Problem: On GUI close, DET never stops the wallet backend (SPV client / platform-wallet coordinators) before tearing down — it's simply abandoned at process exit. Separately, a stale oneshot-channel poll logs a misleading warning on every clean shutdown.
  • What breaks without it: Launch DET, pick "Just Explore", let SPV start syncing, close the window via a real title-bar/WM close. Every single clean close logs WARN dash_evo_tool::app: Shutdown channel closed unexpectedly (possible panic) even though nothing panicked — confusing when triaging a real shutdown issue. More substantively, the wallet backend's SPV client/coordinators are never explicitly asked to shut down through the app's own shutdown path, relying instead on whatever happens at process death rather than a deterministic teardown.
  • Blocking relationship: none.

What was done

  • src/app.rs: GUI close now awaits WalletBackend::shutdown() for every initialized network context (including one that finishes initializing mid-shutdown via an in-flight network switch) before the viewport actually closes, bounded by the existing shutdown timeout. The shutdown_receiver oneshot is consumed exactly once (cleared once resolved) so a later frame can't re-poll an already-drained channel and log a false "possible panic" warning.
  • src/backend_task/mod.rs: closes a related race where an in-flight network-switch task could create/publish a new backend context after shutdown had already begun.
  • A shutdown_started latch is set on the very first shutdown attempt (graceful or force-close) and never cleared, so on_exit()'s force-close guard blocks fallback re-entry on every branch — clean, panicked, or deadline-exceeded — not only after a clean finish. This prevents a second close signal from racing wallet-backend teardown against a still-running first attempt.
  • forget_all_secrets() is now also called again after the bounded wallet-shutdown wait resolves, including the timeout path, so a backend task that re-caches a secret mid-wait is still cleared before exit.
  • SwitchNetwork now registers its wallet-backend context before its slow network call resolves, racing that call against the shutdown cancellation token — an in-flight network switch is discoverable to the shutdown teardown pass instead of being invisible to it.
  • Incidental cleanup: removed the now-dead blocking TaskManager::shutdown(), pruned completed blocking-task tracking entries instead of letting them grow unbounded for the app session's lifetime, and centralized the shutdown budget constant instead of duplicating its arithmetic.
  • Out of scope: the upstream platform-wallet coordinator-thread join race (discarded JoinHandles, quiesce() not waiting for actual thread exit) is tracked separately at feat(platform-wallet)!: shared ThreadRegistry for coordinator lifecycle + shutdown UAF/data-loss fixes platform#3954 — this PR makes DET correctly ask the wallet backend to shut down with a bounded wait, but can't fully close that upstream race until the fix there lands.

Testing

  • cargo fmt --all -- --check — clean
  • cargo clippy --all-features --all-targets -- -D warnings — clean
  • cargo test app:: --all-features — 35 passed, 0 failed
  • cargo test backend_task:: --all-features — 374 passed, 0 failed
  • cargo test utils::tasks:: --all-features — 5 passed, 0 failed
  • Manual GUI verification against the exact commit this fix is based on (3b32bed2, the commit v1.0.0-weekly.20260717 was built from): closed via a real ICCCM WM_DELETE_WINDOW request (not a forced X11 destroy) with a fresh isolated data directory. Confirmed via logs that both the crash-safety and the log-line regression are resolved — no panics, and the shutdown sequence now shows SPV/wallet-backend components tearing down in order (SyncCoordinator → per-task shutdown → peer network manager → storage flush) before the viewport closes.

Breaking changes

None.

Checklist

  • Builds clean
  • Clippy clean (-D warnings)
  • Formatted (cargo fmt --all)
  • Manually verified against a real window-close event
  • Automated regression tests added for the shutdown-race fixes (second_exit_after_async_attempt_does_not_repeat_wallet_teardown, wallet_shutdown_clears_secrets_again_after_teardown_timeout, switch_network_registers_wired_backend_before_cancellation_teardown)

Attribution

🤖 Co-authored by Claudius the Magnificent AI Agent

Summary by CodeRabbit

  • Bug Fixes
    • Improved coordinated app shutdown with a hard deadline, including safe handling of late/deduplicated network context registration.
    • Ensured SPV startup wiring occurs before cancellation teardown, with correct wallet secret clearing when shutdown is in progress or times out.
    • Updated viewport close behavior to reflect shutdown completion, with a timed fallback when needed.
  • Reliability
    • Hardened task shutdown using an admission barrier that blocks new work and reports degraded teardown on timeout.
    • Added shutdown-aware MCP dispatch behavior (in-flight completes; new requests are rejected) with expanded test coverage.

…own-channel log

Await every initialized wallet backend within the bounded GUI shutdown flow, including contexts completed by an in-flight network switch, and consume terminal shutdown receivers exactly once.

The platform-wallet coordinator thread join race remains tracked upstream in dashpay/platform#3954 and is not fixed here.

Co-Authored-By: OpenAI Codex GPT-5 <noreply@openai.com>
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The shutdown path now uses admission barriers, coordinated async teardown, typed outcomes, wallet-backend timeouts, context collection during cancellation, and hard-deadline viewport handling. Network switching and MCP dispatch participate in the shared shutdown lifecycle.

Changes

Shutdown and task lifecycle

Layer / File(s) Summary
Task registration and shutdown barrier
src/utils/tasks.rs
TaskManager rejects late registrations, tracks ordinary and blocking work, joins tasks with timeouts, and reports typed outcomes.
Coordinated application shutdown
src/app.rs, CHANGELOG.md
AppState drains results, collects contexts, clears secrets, shuts down wallet backends, signals outcomes, and enforces a hard deadline.
Tracked backend dispatch
src/mcp/dispatch.rs, src/mcp/server.rs, src/backend_task/mod.rs, src/backend_task/error.rs
MCP and managed requests use tracked execution, reject work during shutdown, and coordinate backend teardown.
Cancellation-aware network switching
src/backend_task/mod.rs, src/mcp/tools/network.rs
Network switching reports wired contexts before SPV, handles cancellation during startup, and shuts down affected backends.
Shutdown-aware task call sites
src/context/wallet_lifecycle/*, src/app.rs
Existing task submissions explicitly discard updated spawn results.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MCP
  participant TaskManager
  participant AppContext
  participant WalletBackend
  MCP->>TaskManager: register tracked dispatch
  TaskManager->>AppContext: run backend task
  AppContext-->>MCP: return task result and lifecycle tail
  TaskManager-->>MCP: complete tracked dispatch
  MCP->>WalletBackend: shut down outgoing backend
Loading

Possibly related PRs

Suggested labels: claudius-review

Suggested reviewers: lklimek

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main shutdown changes: wallet backend teardown on GUI close and the related log cleanup.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/gui-shutdown-wallet-backend

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@lklimek
lklimek marked this pull request as ready for review July 17, 2026 11:15
@thepastaclaw

thepastaclaw commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

🕓 Ready for review — 38 ahead in queue (commit 7603be6)
Queue position: 39/39

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preliminary review — Codex only

The new shutdown flow correctly consumes the terminal receiver and handles GUI network-switch results, but it does not yet guarantee that every wallet backend is stopped. Embedded MCP can own an active context outside the GUI registry, and TaskManager can accept a delayed task registration after shutdown has already drained its JoinSet. Both gaps can recreate the nondeterministic teardown this PR is intended to fix.

Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (completed), gpt-5.6-sol — rust-quality (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 2 blocking

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `src/app.rs`:
- [BLOCKING] src/app.rs:1840-1845: Include the active MCP context in wallet-backend shutdown
  With the `mcp` feature enabled, the `network_switch` tool publishes its newly created context directly to `mcp_app_context` through `DashMcpService::swap_context`. That context is neither inserted into `network_contexts` nor returned through the GUI task-result receiver, so an MCP-initiated switch completed before GUI exit leaves the active context absent from this shutdown snapshot. The tool shuts down the outgoing backend before swapping, which means the omitted MCP context is precisely the backend still running at exit. Clone the shared ArcSwap before spawning shutdown, load its final value after the tracked MCP server has drained, and add it to the context set with pointer-based deduplication.
- [BLOCKING] src/app.rs:1848-1860: Task shutdown is not a registration barrier
  Waiting for `subtasks.shutdown_async()` does not guarantee that every previously submitted task has been joined or aborted. `TaskManager::spawn_sync` records the name synchronously but launches an untracked wrapper that acquires the JoinSet mutex later; if shutdown acquires and drains that mutex first, the wrapper can register its future only after `shutdown_async()` resolves. A delayed `spawn_backend_init` then runs without checking the cancellation token and can create or start a wallet backend after this code has collected and shut down the known backends. Make task submission synchronously register or reserve the task before returning, or introduce a closed state that atomically rejects registration once shutdown begins.

Comment thread src/app.rs Outdated
Comment thread src/app.rs

@lklimek lklimek left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated grumpy-review — PR #905

Reviewed at fdeeacd2 (unchanged since review; no findings dropped as already-fixed).

The headline: this PR does not yet fully deliver its stated purpose

The PR body states the problem without qualification — "On GUI close, DET never stops the wallet backend ... it's simply abandoned at process exit" — and claims that "GUI close now awaits WalletBackend::shutdown() for every initialized network context." Two independent reviewers traced the actual call chains rather than trusting the description, and that claim does not hold in three verified cases:

  1. MCP-created contexts are structurally invisible to the shutdown sweep — not a race, but true under every timing once an MCP client has called network_switch. This independently corroborates @thepastaclaw's already-open thread and is left there rather than duplicated here.
  2. The TaskManager registration barrier is not atomic, so a wallet-touching task can wire and start a backend after the sweep has already collected and shut down every known backend — the exact class of race the PR claims to have closed, via call sites the SwitchNetwork guard doesn't cover. Also left on @thepastaclaw's existing thread.
  3. on_exit's force-close fallback still never calls WalletBackend::shutdown() — posted inline below. The PR's own new comment names this path as reachable, and the 'Out of scope' section does not carve it out.

Because the 'Out of scope' section names only the upstream platform-wallet coordinator-thread join race (dashpay/platform#3954), the remaining gaps read as claimed-closed when they are not. Either close them, or explicitly narrow the title/description and file tracked follow-ups.

What's genuinely good here

  • The common GUI-close path is now correct: existing contexts are snapshotted up front, and an in-flight GUI-driven SwitchNetwork context is correctly observed via the shared channel before the shutdown task settles.
  • The stale-log fix is soundshutdown_receiver is consumed via .take() exactly once, so a later frame hits the new None => true arm instead of re-triggering the false "possible panic" warning. A real sender drop/panic still reaches the Closed warning, so the cleanup doesn't hide genuine failures.
  • WalletBackend::shutdown() is documented idempotent, so the deliberate double-invocation between the SwitchNetwork check and the aggregate sweep is safe by design — that overlap is not a bug.
  • The sweep genuinely awaits each future rather than merely signalling stop.
  • Call-tree walk found no stale callers of any changed/new signature.
  • cargo clippy --all-features --all-targets -- -D warnings (clean) and cargo test --lib app:: (30/30) were independently reproduced, not taken from the PR's self-report.
  • The upstream dashpay/platform#3954 limitation is accurately disclosed.

Findings dropped as duplicates

Two blocking findings (the MCP-context blind spot and the TaskManager registration race) duplicate open @thepastaclaw threads and are not re-posted as new comments — each has a reply on its existing thread adding only what's genuinely new (root-cause mechanism, a second uncovered call site, and the secret-session lifetime angle).

Suggested action: request changes before merge — the fixes are narrow and well-scoped; no redesign needed.

🤖 Co-authored by Claudius the Magnificent AI Agent — automated grumpy-review (Claude trio-equivalent + Codex Sol)

Comment thread src/app.rs Outdated
Comment thread src/app.rs
Comment thread src/app.rs Outdated
Comment thread src/app.rs Outdated
Close task registration before draining managed work, include the final MCP
context, clear remembered secrets, and bound both graceful and fallback wallet
backend shutdown paths.

Co-Authored-By: OpenAI Codex GPT-5 <noreply@openai.com>

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preliminary review — Codex only

The latest delta fixes both prior blockers: shutdown now captures the final MCP context after managed task shutdown, and TaskManager closes registration atomically before taking its JoinSet. One cumulative blocking gap remains: timing out and aborting the tracked join watchers does not stop their already-running spawn_blocking backend operations, so wallet work can continue concurrently with wallet-backend teardown.

Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (completed), gpt-5.6-sol — rust-quality (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 1 blocking

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `src/utils/tasks.rs`:
- [BLOCKING] src/utils/tasks.rs:204-205: Aborting join watchers does not stop backend work
  After SHUTDOWN_TIMEOUT expires, shutdown_inner aborts the remaining JoinSet entries and allows shutdown_async to report completion. The GUI entries named backend_task_join_watcher only await JoinHandles created by spawn_blocking in src/app.rs; once those blocking operations have started, aborting or dropping their JoinHandles cannot stop them. AppState then advances to shutdown_wallet_backends, so a slow wallet-touching run_backend_task operation can continue using, wiring, or writing through the same backend while its secrets are cleared and its storage is being shut down. Track actual completion of the blocking operations and wait for them to reach a terminal state, or add cooperative per-operation cancellation that reaches a terminal state before wallet teardown begins.

Comment thread src/utils/tasks.rs

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preliminary review — Codex only

The new-push delta merges v1.0-dev changes and does not modify the shutdown machinery, so the remaining blocker is still present at the exact head. The PR fixes the task-registration barrier and final MCP-context collection, but after the task timeout it can still begin wallet-backend teardown while an already-running blocking backend operation continues. The three focused shutdown tests pass, but none exercises this timeout and detached-operation behavior.

Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (completed), gpt-5.6-sol — rust-quality (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 1 blocking

1 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

lklimek and others added 2 commits July 18, 2026 16:25
…down

Backend tasks run inside tokio::spawn_blocking closures wrapped by an
abortable async watcher. On shutdown timeout, aborting the watcher only
cancelled the cancellable wrapper — the underlying spawn_blocking closure
cannot be forcibly stopped and kept running, unobserved, while wallet
backend secrets were cleared and storage torn down underneath it.

TaskManager now tracks blocking-task completion via a Shared future kept
independent of the abortable watcher, so shutdown can genuinely await real
completion (bounded by a new blocking-task timeout) instead of an abortable
wrapper. Both the async shutdown path and the on_exit force-close fallback
route through the same two-phase wait before shutdown_wallet_backends runs.
A still-running blocking task past the bound now reports a distinct
degraded ShutdownOutcome::BackendTasksTimedOut instead of silently
proceeding as if nothing were wrong. shutdown_hard_deadline() extended to
cover both phases.

Addresses PR #905 review thread PRRT_kwDOM8GK3c6R6sht.

Co-Authored-By: OpenAI Codex GPT-5 <noreply@openai.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…d in review

- Latch `shutdown_started` at the first close attempt (graceful or
  force-close) so on_exit()'s guard blocks fallback re-entry on every
  branch, not only the clean-finish path -- stops a second close signal
  from racing wallet teardown against a still-running first attempt
  (SEC-001).
- Call forget_all_secrets() again after the bounded wallet-shutdown wait
  resolves, including the timeout branch, so a backend task that
  re-caches a secret mid-wait is still cleared before exit (SEC-002).
- Register a SwitchNetwork-created wallet backend before its slow
  network call resolves, and race that call against shutdown's
  cancellation token, so an in-flight network switch is discoverable to
  teardown instead of being invisible to it (CODE-003).
- Prune completed blocking-task entries, drop dead
  TaskManager::shutdown(), centralize the shutdown budget constant, and
  add a CHANGELOG entry (non-blocking cleanup from the same review).

Adds regression tests for all three fixes; cargo fmt/clippy/tests all
clean (verified independently, not from the fixing agent's own report).

Co-Authored-By: Codex Sol <noreply@openai.com>

<sub>🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent</sub>

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preliminary review — Codex only

The latest commits fix the ordinary watcher-abort race, MCP-context collection, and task-registration barrier. One blocking race remains: after blocking work times out, both shutdown paths begin wallet teardown while non-cancellable backend work is still running. This is a preliminary Codex-only checkpoint; no Sonnet coverage is claimed.

Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (completed), gpt-5.6-sol — rust-quality (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 1 blocking

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `src/app.rs`:
- [BLOCKING] src/app.rs:1993-2004: Backend-task timeout still permits concurrent wallet teardown
  `TaskShutdownOutcome::BackendTasksTimedOut` means at least one non-cancellable `spawn_blocking` closure remains active after the two bounded waits, but this code calls `finish_wallet_shutdown()` before inspecting that outcome. Those closures run wallet-touching backend operations that can still be signing, updating storage, or using coordinators, while wallet shutdown clears their secrets and calls `WalletBackend::shutdown()` on the same resources. The blocking fallback repeats this ordering at lines 2039-2055. A network switch also stores its new backend before `bootstrap_loaded_wallets()` finishes, but does not publish `NetworkContextRegistered` until that bootstrap returns, so a timed-out switch can remain absent from the collected teardown contexts. Do not start wallet teardown after `BackendTasksTimedOut`; either wait for actual terminal completion, or make every backend operation cooperatively cancel and acknowledge termination before teardown. If the bounded timeout must force process exit, skip shared wallet teardown on that degraded branch.

Comment thread src/app.rs Outdated
lklimek and others added 4 commits July 20, 2026 11:03
The merge of origin/v1.0-dev (904ba0b) auto-merged src/app.rs cleanly at
the text level, but left a semantic break: v1.0-dev's new test
`panicking_scheduled_vote_sweep_clears_in_progress_guard` (added in #902)
called `forward_backend_task_join_error(join_handle, ...)`, passing the raw
`JoinHandle` — the pre-#905 signature. This branch's shutdown-race work
changed the function to take an already-awaited `Result<(), JoinError>`
(so the join can be observed via `tokio::select!` alongside shutdown), which
every other call site in this file was updated for except this one new test
that didn't exist when the signature changed.

Add the missing `.await`, matching the two sibling tests immediately above
and below it. No behavioral change to production code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The commented-out ShutdownReport check and the ShieldedShutdownIncomplete
bucket TODOs referenced platform-pr3968 (rs-platform-wallet-storage, an
unrelated SQLite persistence PR). The actual upstream work that restores
these types is the ThreadRegistry/shutdown-report PR, platform#3954.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/wallet_backend/mod.rs (1)

1148-1150: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the redundant import.

WalletTransactionHistoryError is already imported at the module level (line 153). This local import is redundant and will trigger an unused_imports warning under cargo clippy. As per coding guidelines, code should pass all clippy checks without warnings.

♻️ Proposed refactor to remove the import
     fn hydrate_persisted_transactions(
         &self,
         wallet_id: &WalletId,
     ) -> Result<PersistedTransactionHydration, TaskError> {
-        use crate::backend_task::error::WalletTransactionHistoryError;
         use dash_sdk::dpp::dashcore::hashes::Hash;
         use platform_wallet::changeset::PlatformWalletPersistence;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/wallet_backend/mod.rs` around lines 1148 - 1150, Remove the redundant
local WalletTransactionHistoryError import from the function returning
PersistedTransactionHydration, and rely on the existing module-level import.
Keep the Hash import and surrounding logic unchanged.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/tasks.rs`:
- Around line 123-170: Update spawn_blocking_sync so the on_join observer
remains awaited during shutdown instead of being dropped with state.tasks.
Ensure completion results from the blocking task continue reaching on_join,
including forward_backend_task_join_error and task_result_sender, while
preserving the existing completion-handle tracking and shutdown behavior.

---

Nitpick comments:
In `@src/wallet_backend/mod.rs`:
- Around line 1148-1150: Remove the redundant local
WalletTransactionHistoryError import from the function returning
PersistedTransactionHydration, and rely on the existing module-level import.
Keep the Hash import and surrounding logic unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5b5631c2-47e5-44eb-8575-e833afd31b29

📥 Commits

Reviewing files that changed from the base of the PR and between 3848372 and 625e08b.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • src/app.rs
  • src/backend_task/mod.rs
  • src/utils/tasks.rs
  • src/wallet_backend/mod.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app.rs

Comment thread src/utils/tasks.rs
@lklimek lklimek added the claudius-review Triggers automated code review using claudius plugin, runs as a CI job label Jul 20, 2026

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preliminary review — Codex only

The PR adds bounded wallet-backend teardown, but three shutdown-barrier gaps still allow wallet resources to be cleared or shut down while backend work remains active. The revised blocking-task tracker also loses late panic reporting when its ordinary observer is aborted, so the PR requires changes before merge.

Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — rust-quality (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 3 blocking | 🟡 1 suggestion(s)

1 additional finding(s) omitted (not in diff).

1 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `src/utils/tasks.rs`:
- [BLOCKING] src/utils/tasks.rs:107-109: Rejected descendant registration detaches admitted work
  When shutdown closes registration, `spawn_sync()` drops the supplied future. `await_managed_network_request_with_timeout()` transfers a timed-out request's `JoinHandle` into such a reaper future at `src/backend_task/mod.rs:97`; if registration is rejected, dropping that handle detaches the still-running request. The admitted outer backend task can then finish and let `TaskManager` report `Complete` while its request continues using the wallet backend. Registration rejection must return ownership so the caller can abort or await the request, or descendants created by admitted work must remain tracked through shutdown.
- [SUGGESTION] src/utils/tasks.rs:158-167: Shutdown can discard late blocking-task panic reports
  The blocking closure's completion and its `on_join` callback have different lifetimes. After the ordinary-task timeout, `tasks.shutdown()` aborts the observer that owns `on_join`; if the blocking closure then finishes during the blocking-task phase, `shutdown_blocking_tasks()` treats the shared completion as ready but never takes its stored `JoinError`. A backend closure that panics during this interval can therefore produce a `Complete` shutdown outcome without reaching `forward_backend_task_join_error` or the task-result channel. Keep error observation attached to the tracked completion, or make the blocking shutdown phase consume the result and execute the callback.

In `src/mcp/dispatch.rs`:
- [BLOCKING] src/mcp/dispatch.rs:25-32: MCP backend operations remain outside the shutdown barrier
  Embedded MCP requests execute backend operations through a raw `tokio::task::spawn_blocking`, while `TaskManager` tracks only the enclosing HTTP server future. Cancellation or the ordinary-task timeout can drop the request's join handle without stopping its non-cancellable closure, after which the PR's new shutdown path loads the MCP context and tears down its wallet backend. MCP payments, withdrawals, shielded operations, and other backend tasks can therefore overlap wallet teardown. Register MCP dispatch work with the real-completion barrier used by GUI backend tasks, or add an equivalent in-flight request barrier that completes before wallet teardown.

Comment thread src/utils/tasks.rs Outdated
Comment thread src/utils/tasks.rs
Track timed network requests and MCP backend work before wallet teardown, and skip secret clearing whenever managed work fails to drain.

Co-Authored-By: OpenAI Codex <noreply@openai.com>
@Claudius-Maginificent

Copy link
Copy Markdown
Collaborator Author

Pushed fixes for the 3 blocking shutdown-race findings, plus the diagnostics-loss nit:

  • Wallet teardown (finish_wallet_shutdown) now gated on TaskShutdownOutcome::Complete in both the async and blocking shutdown paths.
  • spawn_sync's timeout-reaper registration no longer silently detaches a still-running request from TaskManager tracking.
  • MCP dispatch now routes through the tracked spawn_blocking_sync instead of a raw spawn_blocking, so it's included in shutdown draining.
  • Late JoinErrors from aborted blocking tasks are now consumed/logged instead of silently dropped.

Commit: 38dbb789

🤖 Co-authored by Claudius the Magnificent AI Agent

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preliminary review — Codex only

The current head fixes the wallet-teardown ordering and rejected descendant-registration defects. Two shutdown-barrier gaps remain: the MCP network-switch handler performs context publication and outgoing teardown after its tracked dispatch completes, and the join observer can consume a panic result before an abortable callback finishes.

Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (failed), gpt-5.6-sol — rust-quality (failed), gpt-5.6-sol — general (completed), gpt-5.6-sol — rust-quality (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 1 blocking | 🟡 1 suggestion(s)

1 additional finding(s) omitted (not in diff).

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `src/mcp/tools/network.rs`:
- [BLOCKING] src/mcp/tools/network.rs:247-250: MCP network switch leaves its final lifecycle work outside the barrier
  `dispatch_task()` tracks only `BackendTask::SwitchNetwork`. Once that task returns the newly created context, the handler separately awaits shutdown of the outgoing backend and then publishes the new context through `swap_context()`. The MCP dispatch uses a deliberately dropped task-result receiver, so the task's earlier `NetworkContextRegistered` result cannot register the new context with GUI shutdown. If shutdown cancels or times out the MCP request during this tail, `TaskManager` can report `Complete` while `finish_wallet_shutdown()` still sees the old context in the MCP `ArcSwap`; the newly initialized backend then misses explicit teardown. Keep outgoing teardown and context publication within tracked work, or publish/register the new context before the tracked dispatch can complete.

In `src/utils/tasks.rs`:
- [SUGGESTION] src/utils/tasks.rs:214-220: Shutdown can still discard a pending join-error callback
  The ordinary observer removes the stored join result with `take()` before awaiting `on_join`. If the ordinary shutdown deadline expires after that removal but before the callback completes, `tasks.shutdown()` aborts the observer. The tracked phase then sees a completed task with no stored result and can return `Complete`, even though the typed panic report or other callback side effect was discarded. The new regression test covers completion after the observer has already been aborted, but not this consume-before-callback-completion interval. Keep the result available until `on_join` completes, or track callback completion as part of the shutdown barrier.

Comment thread src/utils/tasks.rs Outdated
@Claudius-Maginificent

Copy link
Copy Markdown
Collaborator Author

Ran a comment-verification pass on this PR. One note: thepastaclaw's latest review (2026-07-21T03:37:05Z, head 38dbb789) describes a blocking finding in src/mcp/tools/network.rs:247-250 that doesn't appear to have a corresponding inline review thread, so flagging it here directly:

MCP network switch leaves its final lifecycle work outside the shutdown barrier. dispatch_task() only tracks BackendTask::SwitchNetwork; once that returns NetworkContextCreated, the handler (src/mcp/tools/network.rs:234-250) separately awaits the outgoing wallet backend's shutdown and then calls service.swap_context(context) — both after the tracked dispatch has already completed. Confirmed by reading the current code: if an app shutdown lands during that tail (before swap_context runs), TaskManager can report Complete while the MCP service's ArcSwap still holds the old context, so finish_wallet_shutdown() never sees — and never explicitly tears down — the newly installed backend.

The one existing inline thread (tasks.rs consume-before-callback race) was also verified still open — replied there directly.

🤖 Co-authored by Claudius the Magnificent AI Agent

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claudius grumpy-review — PR #905 (shutdown/wallet-backend teardown)

I set my crew of three loose on this — security, structural, and adversarial-QA — and, credit where it's due, this is a tidy piece of concurrency work. The shutdown state machine, the registration barrier, the bounded 55s viewport deadline, and the network-switch TOCTOU fix all survived a full call-tree walk and a live test run (utils::tasks 8/8, app::shutdown_tests 8/8, genuinely executed — I don't take "trust me" for an answer). The removed blocking TaskManager::shutdown left zero orphaned callers. Nicely done.

Verdict: not blocking, but one Medium worth your attention.

  • 🟡 1 Medium — the degraded BackendTasksTimedOut / TaskManagerFailed shutdown branches skip forget_all_secrets, contradicting this PR's own CHANGELOG promise of unconditional secret clearing. Inline comment on src/app.rs. Cheap, safe fix (decouple the sync secret-clear from the coordinator-joining shutdown()), or reword the CHANGELOG. The headless src/mcp/server.rs path shares the omission.
  • 6 Lowspawn_tracked_sync/register_tracked_completion gate mismatch dropping on_join in a narrow shutdown race; duplicated prologue between the async and blocking shutdown drivers; the undocumented double forget_all_secrets; a tautological deadline test; and a call-tree consistency note. All optional polish — noted here but not posted individually per Medium-and-above policy.

One prior review thread (src/utils/tasks.rs — the .take()-before-on_join abort window) remains legitimately open; I re-verified it against HEAD and replied there. Not approving while that and the Medium stand.

Full severity-ranked report with reproductions and code snippets was generated alongside this review.

🤖 Co-authored by Claudius the Magnificent AI Agent — automated grumpy-review (Claude trio: security-engineer + project-reviewer + qa-engineer)
📊 View full HTML review report

Comment thread src/app.rs
Comment on lines +2135 to +2141
match task_shutdown_outcome {
Some(TaskShutdownOutcome::Complete) => wallet_shutdown.await,
Some(TaskShutdownOutcome::BackendTasksTimedOut) => {
ShutdownOutcome::BackendTasksTimedOut
}
None => ShutdownOutcome::TaskManagerFailed,
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium: the degraded shutdown branches skip forget_all_secrets, quietly breaking this PR's own CHANGELOG promise

Independently flagged by two of my reviewers (security + QA), and it holds up on inspection. finish_shutdown_after_tasks runs the wallet-teardown future — the only caller of forget_all_secrets() on the exit path — solely on TaskShutdownOutcome::Complete. On BackendTasksTimedOut and None/TaskManagerFailed it returns early and clears nothing.

That branch is reachable in practice, not just in theory: graceful_shutdown_budget() is 20s (2× SHUTDOWN_TIMEOUT), while backend network calls routinely run up to NETWORK_REQUEST_TIMEOUT = 90s. A user closing the app while a slow token/contract/network task is still in flight lands here — and SecretAccess::forget_all (src/wallet_backend/secret_access.rs:656-663) is a synchronous, I/O-free RwLock::write().clear() with no dependency on any backend task finishing, so there's no good reason to gate it behind the tracked-join phase. Both start_async_shutdown and run_blocking_shutdown_fallback share this function, so both paths inherit the gap — and backend_task_timeout_skips_wallet_teardown asserts teardown_calls == 0 for exactly this outcome, enshrining it.

Meanwhile CHANGELOG.md (### Fixed) promises, unconditionally, that closing the app "finishes wallet activity and clears in-memory secrets." The code doesn't, on these branches. The Zeroizing drop backstop still fires at process teardown, so this is a widened plaintext-in-memory window rather than a permanent leak — hence Medium, not High — but for a wallet it's worth closing.

Recommendation: split the teardown. Run forget_all_secrets() on every collected context unconditionally (safe to run alongside a stuck/aborted task — it only clears the session cache; any in-flight op holds its own op-scoped Zeroizing copy), and keep the coordinator-joining backend.shutdown() gated on Complete. The deliberate choice to skip shutdown() on the degraded branch (avoiding teardown of resources still in use) is fine to keep — only the cheap secret clear needs decoupling. If the skip is genuinely intended, reword the CHANGELOG so it stops promising unconditional clearing. The sibling headless path shutdown_app_context_wallet_backend (src/mcp/server.rs:16-33) has the same omission and deserves the same fix.

🤖 Co-authored by Claudius the Magnificent AI Agent — automated grumpy-review (security + project + QA trio)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-verified against current HEAD (26cb9d6d + local merge of v1.0-dev + a CI compile fix, not yet pushed): still valid, not addressed.

finish_shutdown_after_tasks (src/app.rs) still routes forget_all_secrets() exclusively through finish_wallet_shutdown, which only runs on TaskShutdownOutcome::Complete. The BackendTasksTimedOut and None (TaskManagerFailed) branches return early with no secret clearing — confirmed by the backend_task_timeout_skips_wallet_teardown test itself, which asserts teardown_calls == 0 for that outcome. The commit that landed since your review (26cb9d6d, "close remaining barrier gaps") fixed the join-error-callback and MCP network-switch barrier gaps but didn't touch this one.

Leaving unresolved — the recommended split (unconditional forget_all_secrets() on every collected context, backend.shutdown() still gated on Complete) hasn't been implemented yet. Out of scope for this pass (CI-fix + comment triage only); tracking as a follow-up.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7603be6c.

finish_shutdown_after_tasks now calls forget_all_secrets() on every collected wallet backend unconditionally, before branching on the outcome — only the full coordinator backend.shutdown() join stays gated on Complete. Applies to both start_async_shutdown and run_blocking_shutdown_fallback. New regression tests (backend_task_timeout_forgets_secrets_without_wallet_teardown, task_manager_failure_forgets_secrets_without_wallet_teardown) assert secrets are cleared with zero coordinator-shutdown calls on both degraded outcomes.

@github-actions github-actions Bot removed the claudius-review Triggers automated code review using claudius plugin, runs as a CI job label Jul 21, 2026
Keep join-error callbacks and MCP network-switch lifecycle work inside the bounded shutdown barrier.

Co-Authored-By: OpenAI Codex GPT-5 <noreply@openai.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mcp/server.rs`:
- Around line 11-31: Update shutdown_app_context_wallet_backend so the
BackendTasksTimedOut and Err(_) branches synchronously clear wallet secrets via
the backend’s existing forget-all-secrets operation before logging and skipping
the potentially blocking backend.shutdown() call; retain the Complete branch’s
normal async teardown.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 968cd1fa-7dc4-4783-b005-987901b457db

📥 Commits

Reviewing files that changed from the base of the PR and between 625e08b and 26cb9d6.

📒 Files selected for processing (13)
  • src/app.rs
  • src/backend_task/error.rs
  • src/backend_task/mod.rs
  • src/bin/det_cli/headless.rs
  • src/context/wallet_lifecycle/bootstrap.rs
  • src/context/wallet_lifecycle/registration.rs
  • src/context/wallet_lifecycle/removal.rs
  • src/context/wallet_lifecycle/spv.rs
  • src/context/wallet_lifecycle/unlock.rs
  • src/mcp/dispatch.rs
  • src/mcp/server.rs
  • src/mcp/tools/network.rs
  • src/utils/tasks.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/utils/tasks.rs
  • src/app.rs

Comment thread src/mcp/server.rs
lklimek and others added 2 commits July 21, 2026 10:28
The base-branch merge and this PR's NetworkContextRegistered handler
both landed changes to AppState without a textual conflict, but the
handler referenced a `self.secret_prompt_host` field that never
existed — the Arc<dyn SecretPrompt> built in AppState::new() was only
installed on the initial network contexts and then dropped. This broke
compilation (E0609) for both the Test Suite and Clippy CI jobs.

Store the host as an AppState field so contexts registered later (via
an in-flight network switch surviving into NetworkContextRegistered)
can also have the secret prompt installed on them.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Claudius-Maginificent

Copy link
Copy Markdown
Collaborator Author

Merged origin/v1.0-dev in and fixed the CI break:

  • Root cause: v1.0-dev and this branch each touched AppState independently with no textual conflict, but the NetworkContextRegistered handler referenced self.secret_prompt_host — a field that never existed. The Arc<dyn SecretPrompt> built in AppState::new() was only installed on the initial network contexts, then dropped. This broke both Test Suite and Clippy (E0609).
  • Fix: store the host as an AppState field (a3a8da6e) so later-registered contexts can also have it installed.
  • Verified: cargo build, cargo clippy --all-features -- -D warnings (bin), cargo test --all-features --workspace --no-run (full compile), and targeted runs of the shutdown/secret-prompt/network-chooser test suites all green locally before pushing.

Also ran a comment-verification pass (fresh fetch, re-checked against current HEAD):

  • Resolved thepastaclaw's "pending join-error callback" finding (src/utils/tasks.rs) — genuinely fixed by 26cb9d6d's tracked callback_completion + new regression test. Thread resolved.
  • Two findings remain open, unaddressed by commits since they were raised — replied on both threads:
    • src/app.rs finish_shutdown_after_tasks: degraded shutdown outcomes (BackendTasksTimedOut, TaskManagerFailed) still skip forget_all_secrets() entirely — only the Complete branch clears secrets. backend_task_timeout_skips_wallet_teardown itself asserts zero teardown calls for the timeout case.
    • src/mcp/server.rs shutdown_app_context_wallet_backend: same gap in the standalone MCP shutdown helper.

Both are pre-existing findings, not regressions from this push — flagging for a follow-up rather than blocking on them here.

🤖 Co-authored by Claudius the Magnificent AI Agent

Two independent reviewers (CodeRabbit and a Claude Code automated
review) found that finish_shutdown_after_tasks (src/app.rs) and
shutdown_app_context_wallet_backend (src/mcp/server.rs) only cleared
session-cached wallet secrets on the Complete outcome. On
BackendTasksTimedOut or a failed task manager, the wallet-backend
Arc<AppContext> set was collected and then dropped unpolled, so
forget_all_secrets() never ran — contradicting this PR's own
CHANGELOG entry promising secrets are cleared on close.

Split the two concerns: forget_all_secrets() now runs unconditionally
on every collected wallet backend regardless of outcome (cheap,
synchronous, no dependency on any task finishing), while the full
coordinator shutdown() join stays gated on Complete only, since
backend tasks may still be using those coordinators on a degraded
outcome. Applies to both the async and blocking-fallback GUI shutdown
paths, and to the standalone MCP shutdown helper.

Adds regression tests proving secrets are forgotten with zero
coordinator-shutdown calls on both degraded outcomes, in both
src/app.rs::shutdown_tests and the new src/mcp/server.rs::tests.

Co-Authored-By: Codex Sol <noreply@openai.com>
@Claudius-Maginificent

Copy link
Copy Markdown
Collaborator Author

Implemented the fix for both remaining open findings (degraded-shutdown outcomes skipping forget_all_secrets()) in 7603be6c:

  • finish_shutdown_after_tasks (src/app.rs) now unconditionally forgets secrets on every collected wallet backend before branching on the task-shutdown outcome; the full coordinator backend.shutdown() join stays gated on Complete only, since backend tasks may still be actively using those coordinators on a degraded outcome. Applies to both the async and blocking-fallback shutdown paths.
  • shutdown_app_context_wallet_backend (src/mcp/server.rs) gets the same treatment via a new mockable StandaloneShutdownWalletBackend seam, per CodeRabbit's suggested shape.
  • New regression tests in both files assert secrets are cleared with zero coordinator-shutdown calls on both degraded outcomes.

Verified independently (isolated build/target-dir, not reused from the implementing pass): cargo clippy --all-features --bin dash-evo-tool -- -D warnings clean, and all 5 new + 5 pre-existing shutdown_tests/mcp::server::tests pass by name.

Replied on both threads; left them for the original reviewers/human to resolve.

🤖 Co-authored by Claudius the Magnificent AI Agent

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
CHANGELOG.md (1)

365-369: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use “afterward” for American English.

Change “afterwards” on Line 369 to “afterward.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 365 - 369, Update the changelog wording in the
onboarding entry to use the American English spelling “afterward” instead of
“afterwards,” without changing the surrounding content.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@CHANGELOG.md`:
- Around line 365-369: Update the changelog wording in the onboarding entry to
use the American English spelling “afterward” instead of “afterwards,” without
changing the surrounding content.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4afe8960-3079-422b-8ea5-f6736745b6bb

📥 Commits

Reviewing files that changed from the base of the PR and between 26cb9d6 and 7603be6.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • src/app.rs
  • src/backend_task/error.rs
  • src/backend_task/mod.rs
  • src/mcp/server.rs
  • src/mcp/tools/network.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/backend_task/error.rs
  • src/mcp/tools/network.rs
  • src/backend_task/mod.rs
  • src/app.rs

@Claudius-Maginificent

Copy link
Copy Markdown
Collaborator Author

Ran a fresh /grumpy-review (security + project-consistency + QA, independent) against the two commits this session added (177aea3d..7603be6c) that hadn't been reviewed yet.

Verdict: no blockers. 6 non-blocking findings survive dedup (1 MEDIUM, 4 LOW, 1 INFO) — polish and hardening on an otherwise sound fix, not regressions:

  • MEDIUM: mcp/server.rs's new Complete-outcome secret-forget branch has zero test coverage (the two new tests only cover the degraded outcomes).
  • LOW ×4: undocumented "why unconditional forget" invariant (risk of future regression), a duplicated ShutdownWalletBackend-shaped trait between app.rs/mcp/server.rs, an untested triple-forget-call composition on the real Complete path, and the inherent (documented, pre-existing-class, narrower-than-before) residual window where a degraded shutdown doesn't get a second-chance secret clear.
  • INFO: clean call-tree walk, no broken callers from the signature changes.

Full report: /data/artifacts/dash-evo-tool/2026-07-21/pr905-grumpy-review-7603be6c.md

Treating these as optional follow-up rather than blocking this PR further — happy to implement any of them on request.

🤖 Co-authored by Claudius the Magnificent AI Agent

@lklimek
lklimek merged commit 5d225f2 into v1.0-dev Jul 21, 2026
5 checks passed
@lklimek
lklimek deleted the fix/gui-shutdown-wallet-backend branch July 21, 2026 12:34
orchardpaytl pushed a commit to orchardpaytl/orchardpay that referenced this pull request Jul 21, 2026
Brings in: shutdown fix (dashpay#905), duplicate-DPNS-name error message
(dashpay#915), startup banner clearing (dashpay#916), nav pointer cursor + tooltips
and wallet-less masternode indication (dashpay#917), onboarding disconnected-
banner suppression (dashpay#907), masternode dialog/nav/passphrase fixes
(dashpay#913), DAPI auto-refresh during pre-1.0 migration (dashpay#908), "Add
Receiving Address" wiring + its test hardening (dashpay#914, dashpay#920), and a CI
timeout bump (dashpay#912). dashpay#906 (shielded re-enable) was already pulled in
individually last session, so its squashed commit merged as a no-op.

Conflicts (6 files) were rebrand-naming overlaps (dash_evo_tool::  vs
orchardpay::  imports) plus one real merge in left_panel.rs, where
OrchardPay's green-icon tint had to combine with upstream's new nav
tooltip. Also fixed 5 files upstream's auto-merged (non-conflicting)
additions left un-rebranded: a stray DASH_EVO_DATA_DIR_LOCK/env-var
name in a new app.rs test, and dash_evo_tool:: references in three
kittest test files.

Added tooltip strings for OrchardPay's own nav entries (OrchardPay,
DashPay) so the new every_nav_entry_has_a_tooltip test covers them —
upstream's version only knows its own nav items. Fixed the new
nav_label_hover_shows_pointer_cursor kittest test: OrchardPay's nav
rail carries two more always-visible entries than upstream's, pushing
"Settings" below the scrollable list's default-size visible viewport;
scroll it into view first, matching what a real user would do.

Verified: cargo check (both feature modes), cargo clippy --all-features
--all-targets -- -D warnings, cargo fmt --all, cargo test --all-features
--workspace (2066 lib + 257 kittest + doc tests, 0 failed), all clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants