Skip to content

refactor: remove unused Insight API and show_in_ui config fields#597

Merged
lklimek merged 3 commits into
v1.0-devfrom
claude/remove-insight-api-VvsdM
Feb 18, 2026
Merged

refactor: remove unused Insight API and show_in_ui config fields#597
lklimek merged 3 commits into
v1.0-devfrom
claude/remove-insight-api-VvsdM

Conversation

@lklimek
Copy link
Copy Markdown
Contributor

@lklimek lklimek commented Feb 17, 2026

Removes unused insight_api_url and show_in_ui fields from NetworkConfig, along with related serialization, environment variable examples, and tests. Simplifies configuration initialization by eliminating dead settings.

Summary by CodeRabbit

  • Chores
    • Removed Insight API configuration options from environment files and app network settings.
    • Simplified configuration initialization and related test setup by eliminating those settings.

The `insight_api_url` field in `NetworkConfig` and its associated
`insight_api_uri()` method were never used in production code (both
marked `#[allow(dead_code)]`). Remove the field, method, config
entries, env example lines, and related tests.

https://claude.ai/code/session_01HWPmCJHT8KTZGP9bFiksjn
The `show_in_ui` field was defined on `NetworkConfig` and serialized in
`save()`, but never read by any production code to control network
visibility. Remove the field, its serialization, env example lines,
and test references.

https://claude.ai/code/session_01HWPmCJHT8KTZGP9bFiksjn
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 17, 2026

📝 Walkthrough

Walkthrough

This change removes Insight API fields (insight_api_url, show_in_ui) from the configuration and environment examples, updates save/validation logic and tests to the reduced NetworkConfig shape, and adjusts related test environment setup and one import in the UI module.

Changes

Cohort / File(s) Summary
Core configuration
.env.example, src/config.rs
Deleted *_insight_api_url and *_show_in_ui environment keys and removed insight_api_url and show_in_ui fields from NetworkConfig; updated save/write and validation logic to omit these fields.
Test updates
src/spv/tests.rs, src/ui/tokens/tokens_screen/mod.rs
Removed construction and environment setup references to the removed fields in test helpers and test environment variable initialization.
UI import tweak
src/ui/wallets/wallets_screen/dialogs.rs
Adjusted imports to explicitly include Color32; no behavioral changes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Poem

🐰 I hopped through configs, tidy and spry,
Two fields dropped softly — out they fly.
Env lines cleared, tests hopped along,
A leaner layout, neat and strong.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 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 change: removing unused Insight API and show_in_ui configuration fields across multiple files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/remove-insight-api-VvsdM

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
src/config.rs (3)

80-133: Consider extracting repeated .map_err boilerplate in save().

Every writeln! call in the closure chains the same .map_err(|e| ConfigError::LoadError(e.to_string())). A small helper (or a From<std::io::Error> impl on ConfigError) would reduce noise and make future field additions less error-prone. Pre-existing pattern, so fine to defer.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/config.rs` around lines 80 - 133, The closure write_network_config inside
save() repeats .map_err(|e| ConfigError::LoadError(e.to_string())) on every
writeln!; extract that boilerplate by adding a small helper (e.g., a function
like map_io_err or write_env_line) or implement From<std::io::Error> for
ConfigError so you can simply use ? after writeln! calls; update the writeln!
invocations in write_network_config to call the helper or rely on the From impl
and ? to remove repeated .map_err(...) occurrences while keeping the same
ConfigError::LoadError semantics.

294-302: is_valid() is still marked #[allow(dead_code)] — verify if it's used now or plan to use it.

If the method is still unused in production code, consider either removing it (consistent with the cleanup spirit of this PR) or adding a concrete call site. If it's kept for future validation, the current annotation is fine.

#!/bin/bash
# Check if is_valid() is called anywhere outside tests
rg -n --type=rust 'is_valid\(\)' -g '!**/test*' -g '!**/mod.rs'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/config.rs` around lines 294 - 302, The method NetworkConfig::is_valid()
is still annotated with #[allow(dead_code)]; either remove the unused method for
cleanup or wire it up where config validation occurs. Locate the impl
NetworkConfig::is_valid method and either delete it if not referenced, or remove
the attribute and add a call (e.g., in your configuration load/validation flow
such as the config loader/initializer function) to check and handle invalid
configs (logging/error-return) so the method is actually exercised.

533-566: Save-format test only covers mainnet — consider extending coverage.

The test_save_format_contains_expected_env_vars test builds a Config with both mainnet and testnet (line 539), but the simulated output block (lines 547–559) only formats and asserts the mainnet section. This means testnet env-var formatting is untested here. Consider adding assertions for TESTNET_ lines as well, or dropping the unused testnet_config from the test fixture to avoid giving a false sense of coverage.

This is pre-existing and not introduced by this PR, so feel free to defer.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/config.rs` around lines 533 - 566, The test
test_save_format_contains_expected_env_vars constructs a Config with
testnet_config but only formats and asserts MAINNET_ env lines, leaving TESTNET_
formatting untested; either remove the unused testnet_config from the Config
fixture or expand the simulated output/assertions to include TESTNET_ lines
(e.g., mirror the MAINNET formatting block and add asserts for
TESTNET_dapi_addresses, TESTNET_core_rpc_port, TESTNET_core_rpc_user,
TESTNET_core_rpc_password, and TESTNET_core_zmq_endpoint) so the test accurately
reflects coverage of the Config save-format logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/config.rs`:
- Around line 80-133: The closure write_network_config inside save() repeats
.map_err(|e| ConfigError::LoadError(e.to_string())) on every writeln!; extract
that boilerplate by adding a small helper (e.g., a function like map_io_err or
write_env_line) or implement From<std::io::Error> for ConfigError so you can
simply use ? after writeln! calls; update the writeln! invocations in
write_network_config to call the helper or rely on the From impl and ? to remove
repeated .map_err(...) occurrences while keeping the same ConfigError::LoadError
semantics.
- Around line 294-302: The method NetworkConfig::is_valid() is still annotated
with #[allow(dead_code)]; either remove the unused method for cleanup or wire it
up where config validation occurs. Locate the impl NetworkConfig::is_valid
method and either delete it if not referenced, or remove the attribute and add a
call (e.g., in your configuration load/validation flow such as the config
loader/initializer function) to check and handle invalid configs
(logging/error-return) so the method is actually exercised.
- Around line 533-566: The test test_save_format_contains_expected_env_vars
constructs a Config with testnet_config but only formats and asserts MAINNET_
env lines, leaving TESTNET_ formatting untested; either remove the unused
testnet_config from the Config fixture or expand the simulated output/assertions
to include TESTNET_ lines (e.g., mirror the MAINNET formatting block and add
asserts for TESTNET_dapi_addresses, TESTNET_core_rpc_port,
TESTNET_core_rpc_user, TESTNET_core_rpc_password, and TESTNET_core_zmq_endpoint)
so the test accurately reflects coverage of the Config save-format logic.

@lklimek lklimek changed the title refactor: remove unused Insight API references refactor: remove unused Insight API and show_in_ui references Feb 17, 2026
@lklimek lklimek changed the title refactor: remove unused Insight API and show_in_ui references refactor: remove unused Insight API and show_in_ui config fields Feb 17, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/ui/wallets/wallets_screen/dialogs.rs (1)

19-19: Hardcoded Color32::from_rgb is inconsistent with the DashColors theme used everywhere else in this file.

The import is needed because line 171 uses Color32::from_rgb(255, 100, 100) directly. Every other error/status colour in this file is sourced from DashColors (e.g. DashColors::ERROR on line 196, DashColors::DANGER_RED on line 738, DashColors::error_color(dark_mode) on line 925). Additionally, render_send_dialog is the only render method that never reads dark_mode, so the hardcoded value also ignores theme awareness.

♻️ Proposed fix — align with `DashColors` and add `dark_mode` awareness
 use egui::{Color32, Frame, Margin, RichText, TextureOptions};

The import of Color32 would then no longer be needed at all for this path:

-use egui::{Color32, Frame, Margin, RichText, TextureOptions};
+use egui::{Frame, Margin, RichText, TextureOptions};

In render_send_dialog, add dark_mode near the top of the closure (same pattern as the other dialogs) and replace the hardcoded colour:

+        let dark_mode = ctx.style().visuals.dark_mode;
         // ...
         if let Some(error) = &self.send_dialog.address_error {
-            ui.colored_label(Color32::from_rgb(255, 100, 100), error);
+            ui.colored_label(DashColors::error_color(dark_mode), error);
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/wallets/wallets_screen/dialogs.rs` at line 19, The render_send_dialog
function uses a hardcoded Color32::from_rgb(255,100,100) and doesn't read theme;
update render_send_dialog to determine dark_mode (same pattern used in other
render_* dialogs) and replace the hardcoded color with
DashColors::error_color(dark_mode) (or DashColors::ERROR/DANGER_RED if a
non-theme variant is preferred) so the error/status colour respects the
DashColors theme; after this change remove the now-unused Color32 import from
the use list.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/ui/wallets/wallets_screen/dialogs.rs`:
- Line 19: The render_send_dialog function uses a hardcoded
Color32::from_rgb(255,100,100) and doesn't read theme; update render_send_dialog
to determine dark_mode (same pattern used in other render_* dialogs) and replace
the hardcoded color with DashColors::error_color(dark_mode) (or
DashColors::ERROR/DANGER_RED if a non-theme variant is preferred) so the
error/status colour respects the DashColors theme; after this change remove the
now-unused Color32 import from the use list.

@lklimek lklimek requested a review from shumkov February 18, 2026 11:23
@lklimek lklimek merged commit 152be4f into v1.0-dev Feb 18, 2026
6 checks passed
@lklimek lklimek deleted the claude/remove-insight-api-VvsdM branch February 18, 2026 13:07
lklimek added a commit that referenced this pull request Feb 18, 2026
* refactor: remove unused Insight API references

The `insight_api_url` field in `NetworkConfig` and its associated
`insight_api_uri()` method were never used in production code (both
marked `#[allow(dead_code)]`). Remove the field, method, config
entries, env example lines, and related tests.

https://claude.ai/code/session_01HWPmCJHT8KTZGP9bFiksjn

* refactor: remove unused `show_in_ui` field from NetworkConfig

The `show_in_ui` field was defined on `NetworkConfig` and serialized in
`save()`, but never read by any production code to control network
visibility. Remove the field, its serialization, env example lines,
and test references.

https://claude.ai/code/session_01HWPmCJHT8KTZGP9bFiksjn

* fix: add missing `Color32` import in wallet dialogs

https://claude.ai/code/session_01HWPmCJHT8KTZGP9bFiksjn

---------

Co-authored-by: Claude <noreply@anthropic.com>
lklimek added a commit that referenced this pull request Feb 23, 2026
…601)

* docs: add unified message display design documents

Add UX specification, technical architecture, and HTML mockup for the
MessageBanner component that will replace the ~50 ad-hoc error/message
display implementations across screens with a single reusable component.

Key design decisions:
- Per-screen MessageBanner with show()/set_message() API
- All colors via DashColors (zero hardcoded Color32 values)
- 4 severity levels: Error, Warning, Success, Info
- Auto-dismiss for Success/Info (5s), persistent for Error/Warning
- Follows Component Design Pattern conventions (private fields, builder, show)
- No changes to BackendTask/TaskResult/AppState architecture

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

* feat: add MessageType::Warning

* chore: initial implementation

* chore: docs

* chore: self review

* refactor(context): replace RwLock<Sdk> with ArcSwap<Sdk> (#600)

* refactor(context): replace RwLock<Sdk> with ArcSwap<Sdk>

Sdk is internally thread-safe (Arc, ArcSwapOption, atomics) and all
methods take &self. The RwLock was adding unnecessary contention across
backend tasks.

Using ArcSwap instead of plain Sdk because reinit_core_client_and_sdk()
needs to atomically swap the entire Sdk instance when config changes.
ArcSwap provides lock-free reads with atomic swap for the rare write.

Suggested-by: lklimek

* fix: address CodeRabbit review findings for ArcSwap migration

- Fix import ordering: move arc_swap::ArcSwap before crossbeam_channel
- Remove redundant SDK loads in load_identity_from_wallet, register_dpns_name,
  and load_identity — use the sdk parameter already passed to these functions
- Fix stale TODO referencing removed sdk.read().unwrap() API
- Rename sdk_guard → sdk in transfer, withdraw_from_identity, and
  refresh_loaded_identities_dpns_names (no longer lock guards)
- Pass &sdk to run_platform_info_task from dispatch site instead of
  reloading internally
- Fix leftover sdk.write() call in context_provider.rs (RwLock remnant)
- Add missing Color32 import in wallets dialogs

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

* refactor: address remaining CodeRabbit review feedback on ArcSwap migration

- Move SDK load outside for loop in refresh_loaded_identities_dpns_names.rs
  so it's loaded once for the batch instead of on each iteration
- Update stale TODO comment in default_platform_version() to reflect that
  this is a free function with no sdk access

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

* refactor: consolidate double read-lock on spv_context_provider

Clone the SPV provider in a single lock acquisition, then bind app
context on the clone instead of locking twice.

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

---------

Co-authored-by: PastaClaw <thepastaclaw@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: remove unused Insight API and show_in_ui config fields (#597)

* refactor: remove unused Insight API references

The `insight_api_url` field in `NetworkConfig` and its associated
`insight_api_uri()` method were never used in production code (both
marked `#[allow(dead_code)]`). Remove the field, method, config
entries, env example lines, and related tests.

https://claude.ai/code/session_01HWPmCJHT8KTZGP9bFiksjn

* refactor: remove unused `show_in_ui` field from NetworkConfig

The `show_in_ui` field was defined on `NetworkConfig` and serialized in
`save()`, but never read by any production code to control network
visibility. Remove the field, its serialization, env example lines,
and test references.

https://claude.ai/code/session_01HWPmCJHT8KTZGP9bFiksjn

* fix: add missing `Color32` import in wallet dialogs

https://claude.ai/code/session_01HWPmCJHT8KTZGP9bFiksjn

---------

Co-authored-by: Claude <noreply@anthropic.com>

* build: add Flatpak packaging and CI workflow (#589)

* build: remove snap version

* build: add Flatpak packaging and CI workflow

Add Flatpak build manifest, desktop entry, AppStream metadata, and
GitHub Actions workflow for building and distributing Flatpak bundles.
Uses freedesktop 25.08 runtime with rust-stable and llvm21 extensions.
No application source code changes required - works in SPV mode by default.

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

* build: address review findings for Flatpak packaging

- Pin GitHub Actions to commit SHAs for supply chain security
- Upgrade softprops/action-gh-release from v1 to v2.2.2
- Remove redundant --socket=x11 (fallback-x11 suffices)
- Remove duplicate tag trigger preventing double builds on release
- Remove duplicate env vars inherited from top-level build-options
- Add Flatpak build artifacts to .gitignore
- Add bugtracker URL to AppStream metainfo
- Remove deprecated <categories> from metainfo (use .desktop instead)
- Add Terminal=false and Keywords to desktop entry
- Add disk space check after SDK install in CI
- Rename artifact to include architecture suffix

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

* build: simplify CI workflows for Linux-only releases

- Remove "Free disk space" step from flatpak and release workflows
- Remove Windows and macOS builds from release workflow
- Use "ubuntu" runner image instead of pinned versions
- Clean up unused matrix.ext references

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

* build: attach to existing releases instead of creating new ones

- Replace release-creating job with attach-to-release (only on release event)
- Add 14-day retention for build artifacts
- On tag push or workflow_dispatch, only upload artifacts (no release)

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

* revert: restore release.yml to original v1.0-dev version

The release workflow changes were out of scope for the Flatpak PR.

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

* fix: address CodeRabbit review comments

- Fix CRLF line endings in Flatpak manifest (convert to LF)
- Set app_id on ViewportBuilder to match desktop StartupWMClass
- Use --locked flag for reproducible cargo builds in Flatpak
- Rename --repo=repo to --repo=flatpak-repo to match .gitignore
- Add architecture note for protoc x86_64 binary

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

* docs: add Flatpak install instructions to README

Add a dedicated section for installing via Flatpak on Linux,
clarify that prerequisites are only needed for building from source,
and rename "Installation" to "Build from Source" for clarity.

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

* fix: match StartupWMClass to Flatpak app_id

Use reverse-DNS format org.dash.DashEvoTool to match the
Wayland app_id set via ViewportBuilder::with_app_id().

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

* fix: use ** glob for branch trigger to match feat/flatpak

Single * doesn't match path separators in GitHub Actions branch filters.

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

* feat: add aarch64 Flatpak build and caching to CI

- Add matrix strategy for parallel x86_64 and aarch64 builds
- Patch protoc URL/sha256 per architecture at build time
- Cache .flatpak-builder directory keyed on arch + manifest + lockfile
- Pin actions/cache to SHA

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

* fix: convert desktop and metainfo files to LF line endings

Flatpak builder validates desktop files and rejects CRLF line endings.

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

* build: cancel in-progress Flatpak builds on new push

Add concurrency group keyed on git ref so a new push cancels
any running build for the same branch or release.

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

* fix: address PR review findings for Flatpak packaging

- Remove unnecessary --filesystem=xdg-config/dash-evo-tool:create
  (Flatpak already redirects XDG_CONFIG_HOME to sandbox)
- Add categories and keywords to AppStream metainfo for discoverability
- Update README with both x86_64/aarch64 install commands, uninstall
  instructions, and Flatpak data path note
- Clarify aarch64 comment in manifest to reference CI sed patching

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

* chore: workflow timeout and perms

* fix: move permissions to job level in Flatpak workflow

Step-level permissions are not valid in GitHub Actions. Move
contents: write to the job level where it is needed for release
attachment.

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

* build: cache Cargo registry and target in Flatpak CI

Bind-mount host-side cargo-cache and cargo-target directories into the
Flatpak build sandbox so CARGO_HOME and target/ persist across builds.
Uses split restore/save with cleanup of incremental and registry/src
(similar to Swatinem/rust-cache).

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

* fix: scope cargo cache bind-mount sed to build-args only

The previous sed matched --share=network in both finish-args and
build-args, corrupting finish-args. Use a sed range to only target
the build-args section.

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

* Apply suggestions from code review

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* chore: fix build

* Update src/app.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore: peer review

* feat: add collapsible details and suggestion support to MessageBanner

Enhance BannerState with optional details (collapsible technical info)
and suggestion (inline recovery hint) fields. BannerHandle gains
with_details() and with_suggestion() builder methods and is now Clone.
The details section renders collapsed by default with a "Show details"
toggle and scrollable monospace content area.

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

* fix: correct MessageBanner dedup, replace_global reset, and doc drift

- set_global now updates message_type on deduplicated banners
- replace_global resets details/suggestion/details_expanded on replacement
- Fix doc comment referencing set_text instead of set_message
- Update architecture.md BannerState struct with details/suggestion fields
- Update architecture.md render_banner signature and BannerHandle method table

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

* feat: log everything that is displayed by the MessageBanner

* fix(ui): address PR #601 review items 12-16 for MessageBanner

Add BannerState::new() and reset_to() helpers to eliminate duplicated
field initialization across set_message, set_global, and replace_global.
Fix dedup paths that forgot to update created_at/auto_dismiss_after/
show_elapsed (items 13-14). Fix concurrent refresh showing premature
success by tracking pending_refresh_count (item 15). Remove unreachable
match arm and tighten wildcard to guard on identity refresh tasks only
(item 16). Update architecture docs to reflect current code (item 12).

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

* fix(ui): clarify display_message contract for Success/Info in MintTokensScreen

Add explicit comment documenting that Success/Info types require no
local state change since the global banner handles display. Addresses
PR #601 review comment about asymmetric handling.

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

* fix(ui): use distinct icon for Error vs Warning banners

Error banners now show ❌ (cross mark) instead of ⚠ (warning sign),
so colorblind users can distinguish severity by shape, not just color.

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

* fix(test): update banner test to expect new Error icon

The Error icon changed from ⚠ to ❌ in the previous commit.
Update test_banner_renders_all_types to match.

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

* Update docs/ai-design/2026-02-17-unified-messages/architecture.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Pasta Lil Claw <pasta+claw@dashboost.org>
Co-authored-by: PastaClaw <thepastaclaw@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
lklimek added a commit that referenced this pull request Mar 3, 2026
* docs: add unified message display design documents

Add UX specification, technical architecture, and HTML mockup for the
MessageBanner component that will replace the ~50 ad-hoc error/message
display implementations across screens with a single reusable component.

Key design decisions:
- Per-screen MessageBanner with show()/set_message() API
- All colors via DashColors (zero hardcoded Color32 values)
- 4 severity levels: Error, Warning, Success, Info
- Auto-dismiss for Success/Info (5s), persistent for Error/Warning
- Follows Component Design Pattern conventions (private fields, builder, show)
- No changes to BackendTask/TaskResult/AppState architecture

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

* feat: add MessageType::Warning

* chore: initial implementation

* chore: docs

* chore: self review

* refactor(context): replace RwLock<Sdk> with ArcSwap<Sdk> (#600)

* refactor(context): replace RwLock<Sdk> with ArcSwap<Sdk>

Sdk is internally thread-safe (Arc, ArcSwapOption, atomics) and all
methods take &self. The RwLock was adding unnecessary contention across
backend tasks.

Using ArcSwap instead of plain Sdk because reinit_core_client_and_sdk()
needs to atomically swap the entire Sdk instance when config changes.
ArcSwap provides lock-free reads with atomic swap for the rare write.

Suggested-by: lklimek

* fix: address CodeRabbit review findings for ArcSwap migration

- Fix import ordering: move arc_swap::ArcSwap before crossbeam_channel
- Remove redundant SDK loads in load_identity_from_wallet, register_dpns_name,
  and load_identity — use the sdk parameter already passed to these functions
- Fix stale TODO referencing removed sdk.read().unwrap() API
- Rename sdk_guard → sdk in transfer, withdraw_from_identity, and
  refresh_loaded_identities_dpns_names (no longer lock guards)
- Pass &sdk to run_platform_info_task from dispatch site instead of
  reloading internally
- Fix leftover sdk.write() call in context_provider.rs (RwLock remnant)
- Add missing Color32 import in wallets dialogs

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

* refactor: address remaining CodeRabbit review feedback on ArcSwap migration

- Move SDK load outside for loop in refresh_loaded_identities_dpns_names.rs
  so it's loaded once for the batch instead of on each iteration
- Update stale TODO comment in default_platform_version() to reflect that
  this is a free function with no sdk access

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

* refactor: consolidate double read-lock on spv_context_provider

Clone the SPV provider in a single lock acquisition, then bind app
context on the clone instead of locking twice.

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

---------

Co-authored-by: PastaClaw <thepastaclaw@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: remove unused Insight API and show_in_ui config fields (#597)

* refactor: remove unused Insight API references

The `insight_api_url` field in `NetworkConfig` and its associated
`insight_api_uri()` method were never used in production code (both
marked `#[allow(dead_code)]`). Remove the field, method, config
entries, env example lines, and related tests.

https://claude.ai/code/session_01HWPmCJHT8KTZGP9bFiksjn

* refactor: remove unused `show_in_ui` field from NetworkConfig

The `show_in_ui` field was defined on `NetworkConfig` and serialized in
`save()`, but never read by any production code to control network
visibility. Remove the field, its serialization, env example lines,
and test references.

https://claude.ai/code/session_01HWPmCJHT8KTZGP9bFiksjn

* fix: add missing `Color32` import in wallet dialogs

https://claude.ai/code/session_01HWPmCJHT8KTZGP9bFiksjn

---------

Co-authored-by: Claude <noreply@anthropic.com>

* build: add Flatpak packaging and CI workflow (#589)

* build: remove snap version

* build: add Flatpak packaging and CI workflow

Add Flatpak build manifest, desktop entry, AppStream metadata, and
GitHub Actions workflow for building and distributing Flatpak bundles.
Uses freedesktop 25.08 runtime with rust-stable and llvm21 extensions.
No application source code changes required - works in SPV mode by default.

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

* build: address review findings for Flatpak packaging

- Pin GitHub Actions to commit SHAs for supply chain security
- Upgrade softprops/action-gh-release from v1 to v2.2.2
- Remove redundant --socket=x11 (fallback-x11 suffices)
- Remove duplicate tag trigger preventing double builds on release
- Remove duplicate env vars inherited from top-level build-options
- Add Flatpak build artifacts to .gitignore
- Add bugtracker URL to AppStream metainfo
- Remove deprecated <categories> from metainfo (use .desktop instead)
- Add Terminal=false and Keywords to desktop entry
- Add disk space check after SDK install in CI
- Rename artifact to include architecture suffix

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

* build: simplify CI workflows for Linux-only releases

- Remove "Free disk space" step from flatpak and release workflows
- Remove Windows and macOS builds from release workflow
- Use "ubuntu" runner image instead of pinned versions
- Clean up unused matrix.ext references

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

* build: attach to existing releases instead of creating new ones

- Replace release-creating job with attach-to-release (only on release event)
- Add 14-day retention for build artifacts
- On tag push or workflow_dispatch, only upload artifacts (no release)

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

* revert: restore release.yml to original v1.0-dev version

The release workflow changes were out of scope for the Flatpak PR.

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

* fix: address CodeRabbit review comments

- Fix CRLF line endings in Flatpak manifest (convert to LF)
- Set app_id on ViewportBuilder to match desktop StartupWMClass
- Use --locked flag for reproducible cargo builds in Flatpak
- Rename --repo=repo to --repo=flatpak-repo to match .gitignore
- Add architecture note for protoc x86_64 binary

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

* docs: add Flatpak install instructions to README

Add a dedicated section for installing via Flatpak on Linux,
clarify that prerequisites are only needed for building from source,
and rename "Installation" to "Build from Source" for clarity.

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

* fix: match StartupWMClass to Flatpak app_id

Use reverse-DNS format org.dash.DashEvoTool to match the
Wayland app_id set via ViewportBuilder::with_app_id().

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

* fix: use ** glob for branch trigger to match feat/flatpak

Single * doesn't match path separators in GitHub Actions branch filters.

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

* feat: add aarch64 Flatpak build and caching to CI

- Add matrix strategy for parallel x86_64 and aarch64 builds
- Patch protoc URL/sha256 per architecture at build time
- Cache .flatpak-builder directory keyed on arch + manifest + lockfile
- Pin actions/cache to SHA

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

* fix: convert desktop and metainfo files to LF line endings

Flatpak builder validates desktop files and rejects CRLF line endings.

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

* build: cancel in-progress Flatpak builds on new push

Add concurrency group keyed on git ref so a new push cancels
any running build for the same branch or release.

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

* fix: address PR review findings for Flatpak packaging

- Remove unnecessary --filesystem=xdg-config/dash-evo-tool:create
  (Flatpak already redirects XDG_CONFIG_HOME to sandbox)
- Add categories and keywords to AppStream metainfo for discoverability
- Update README with both x86_64/aarch64 install commands, uninstall
  instructions, and Flatpak data path note
- Clarify aarch64 comment in manifest to reference CI sed patching

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

* chore: workflow timeout and perms

* fix: move permissions to job level in Flatpak workflow

Step-level permissions are not valid in GitHub Actions. Move
contents: write to the job level where it is needed for release
attachment.

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

* build: cache Cargo registry and target in Flatpak CI

Bind-mount host-side cargo-cache and cargo-target directories into the
Flatpak build sandbox so CARGO_HOME and target/ persist across builds.
Uses split restore/save with cleanup of incremental and registry/src
(similar to Swatinem/rust-cache).

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

* fix: scope cargo cache bind-mount sed to build-args only

The previous sed matched --share=network in both finish-args and
build-args, corrupting finish-args. Use a sed range to only target
the build-args section.

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

* Apply suggestions from code review

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* chore: fix build

* chore: use new error handling everywhere - not self reviewed

* chore: use message banner to show progress

* fix: start elapsed counter at 1s instead of 0s

Aligns elapsed display with the countdown timer which already adds 1
to avoid showing "0s" immediately.

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

* chore: rabbit review

* Update src/app.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore: peer review

* chore: fix build errors

* fix(ui): make MessageBanner::set_global truly idempotent

set_global() no longer resets timestamps, auto-dismiss timer, or
logged flag when a banner with identical text already exists. This
makes it safe to call every frame without log spam or timer restarts.

Cherry-picked from origin/fix/spv-peer-timeout (08e3b3b).

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

* fix(ui): address code review findings R01, R03, R06, R09, R10

- R01: Replace expect("No key selected") with graceful match + error
  banner in 11 token screens to prevent panics on missing signing key
- R03: Remove dead backend_message field from AddExistingIdentityScreen
- R06: Replace is_some() + unwrap() with idiomatic if-let-Some pattern
  in 10 token screens; use is_some_and() in structs.rs
- R09: Add use imports for MessageBanner in 5 dashpay screens, replacing
  22 fully-qualified crate::ui::components::MessageBanner:: calls
- R10: Replace custom_dash_qt_error_message inline rendering with
  MessageBanner::set_global in network_chooser_screen

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

* fix(ui): address review findings SEC-08, SEC-09, RUST-015, SEC-05, SEC-07

- SEC-08: Restore safe if-let-Some pattern in WithdrawalScreen::refresh()
  to prevent double unwrap() panic on DB error or deleted identity
- SEC-09: Restore original DB lookup in SendPaymentScreen::load_contact_info()
  replacing hardcoded "alice.dash" mock data
- RUST-015: Revert unimplemented!() back to ui.label() in
  update_token_config MarketplaceTradeMode arm
- SEC-05: Add success banners for contact request accept/reject in
  ContactRequests::display_task_result
- SEC-07: Add MessageBanner::clear_all_global() and call it from
  AppState::change_network() to prevent stale banners leaking across
  network switches

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

* docs: update coding conventions and message display guidance

Add fallible constructor rule (Result<Self, ...> when they can fail),
rename section to "General rules", and document MessageBanner
idempotency (no guard needed for set_global).

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

* fix(ui): replace expect/panic with graceful error handling (SEC-10)

Replace all expect() calls in token screen constructors and confirmation
handlers with MessageBanner error display. Constructors handle errors
internally and return Self with degraded state, keeping create_screen()
clean. refresh() methods now show errors via MessageBanner instead of
tracing-only logging.

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

* refactor(ui): accept impl Display/Debug in MessageBanner API

Change MessageBanner public methods to accept `impl Display` for
message text and `impl Debug` for details, instead of `&str`. Remove
needless `&format!(...)` borrows across 27 call sites.

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

* fix(ui): remove error Failed to get best chain lock for mainnet, testnet, devnet, and local

Fixes #633

* feat(ui): add automatic connection status banners

Display persistent MessageBanner notifications based on network
connection state transitions. Mode-aware messages guide users toward
the right recovery action (RPC vs SPV).

- Disconnected (RPC): "Disconnected — check that Dash Core is running"
- Disconnected (SPV): "Disconnected — check your internet connection"
- Syncing (RPC): "Syncing with Dash Core…"
- Syncing (SPV): "SPV sync in progress…"
- Synced: banner cleared

Uses Option<OverallConnectionState> for change detection, with None
as initial/post-network-switch sentinel to force first evaluation.

Closes #667 (partial — action links deferred to follow-up)

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

* fix(ui): pass TaskError directly to with_details() to avoid double-formatting

The previous code used `format!("{err:?}")` which produced a String, then
`with_details()` applied `{:#?}` again — wrapping the output in quotes and
escaping inner characters. Passing `&err` directly lets Debug format once.

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

* fix(ui): correct copy-paste error messages in token screens

Replace "Burning" error messages that were copy-pasted from burn screen
into freeze, destroy, and resume token screens with contextually correct
messages.

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

* fix(ui): restore lost success/error messages in 5 screens

Replace display_message() calls with MessageBanner::set_global() in
screens where display_message() is now a side-effect-only handler and
no longer displays messages directly.

Affected screens: create_asset_lock_screen, wallets_screen (MineBlocks),
address_table (export error), profile_screen (validation), contact_details.

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

* fix(ui): replace unwrap/expect with graceful error handling

Replace double unwrap in transfer_screen refresh() with unwrap_or_else
+ MessageBanner error display, matching the pattern from withdraw_screen.

SEC-002 tokens_screen skipped: the .expect() calls are only on
compile-time embedded image data (include_bytes!) which is safe.

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

* refactor(ui): migrate masternode_list_diff_screen to global MessageBanner

Replace ~15 local ui_state.message assignments and custom
render_message_banner() with MessageBanner::set_global() via the
display_message() trait method. Remove the message field from UiState
and the unused Color32 import.

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

* fix(ui): improve banner eviction logging and atomics

- Upgrade BANNER_KEY_COUNTER from Relaxed to SeqCst ordering for
  future-proofing against multi-threaded usage
- Log evicted banners at warn level in set_global() and replace_global()
- Add comment explaining why show_global() always writes back

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

* chore: remove resolved TODO.md

All items tracked in the unified message display TODO have been
addressed or moved to the review findings.

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

* docs(ui): add INTENTIONAL markers and API documentation

- Document why with_details() accepts Debug (not Display): structured
  error context is more useful in diagnostic details panes
- Document replace_global() fallback-to-add behavior as intentional
- Add INTENTIONAL(SEC-003) marker for developer mode error details
- Add INTENTIONAL(SEC-004) marker for BannerHandle Send+Sync safety

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

* refactor(ui): extract shared token validation and fix ordering

- Add validate_signing_key() helper in tokens/mod.rs to eliminate
  duplicated signing key validation across 12 token screens
- Move signing key validation BEFORE WaitingForResult state transition
  so users see immediate errors instead of loading spinner then error
- Replace is_err()/unwrap() anti-pattern with idiomatic let-else blocks
  in freeze, mint, transfer, destroy_frozen_funds, unfreeze screens

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

* refactor(ui): return Result from get_selected_wallet

Replace &mut Option<String> error out-parameter with idiomatic
Result<Option<Arc<RwLock<Wallet>>>, String>. Update 26+ callsites
across identity, token, DashPay, and contract screens.

Callsite patterns: unwrap_or_else with MessageBanner for user-visible
errors, unwrap_or(None) where errors were previously silently ignored.

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

* fix(ui): resolve duplicate imports and clippy warnings

Remove duplicate MessageBanner imports in create_asset_lock_screen and
wallets_screen/mod. Fix needless_borrows_for_generic_args clippy lints
in profile_screen, transfer_screen, and wallets_screen.

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

* style: reorder imports in masternode_list_diff_screen

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

* fix(ui): address review findings from MessageBanner migration audit

Apply 13 triaged review fixes plus 1 bug fix across 22 files:

- Remove dead error state fields (backend_message, error_message, Error variant)
- Replace .expect() panics with graceful fallback + MessageBanner in token screens
- Fix missing MessageBanner::show_global() on contracts documents screen
- Migrate DocumentActionScreen inline errors to MessageBanner
- Replace unwrap_or(None) with error-reporting fallback in DashPay screens
- Fix replace_global idempotency and use relaxed atomic ordering in banner
- Extract shared set_error_banner helper for 8 token screens
- Restore correct Some(0) wallet index semantics
- Document BannerHandle lifecycle in CLAUDE.md

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

* fix: validate token description length before sending to Platform (#530)

* fix: validate token description length before sending to Platform

Descriptions must be either empty or 3-100 characters long.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ui): validate token description by char count, not byte length

String::len() counts UTF-8 bytes, causing multi-byte characters
(CJK, emoji) to be miscounted against the 3–100 limit. Switch to
chars().count() and update all UI labels to surface the minimum.

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Lukasz Klimek <842586+lklimek@users.noreply.github.com>

* refactor(ui): consolidate banner extension traits into message_banner

Move BannerHandleExt and ResultBannerExt from banner_ext.rs into
message_banner.rs where they belong. Merge take_and_clear() into
OptionBannerExt trait (impl for Option<BannerHandle>) alongside
or_show_error() for Option. Remove the separate banner_ext module
and Clearable helper trait for simplicity.

Apply review findings: DRY patterns (take_and_clear, or_show_error,
load_identities_with_banner), fix .expect() panics in constructors,
restore known_identities in refresh(), narrow pub field visibility,
add ScreenLike doc comments, and update CLAUDE.md conventions.

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

* doc(tmp): review guide for pr 604

* fix(ui): address review findings from grumpy-review iteration 1

- Replace .expect() panics in TransferTokensScreen and ClaimTokensScreen
  constructors with graceful degradation via Option<QualifiedIdentity>
  and MessageBanner error display (PROJ-001 HIGH)
- Fix CLAUDE.md referencing non-existent BannerHandleExt trait name,
  corrected to OptionBannerExt (PROJ-002 MEDIUM)
- Update set_global to preserve message_type when same text appears
  with different severity (RUST-001 MEDIUM)
- Standardize display_message to handle both Error and Warning across
  all 11 token screens (RUST-002 MEDIUM)
- Replace 21 manual take().clear() patterns with take_and_clear()
  across 6 files (RUST-003 MEDIUM)
- Remove unused OptionBannerExt::or_show_error method (RUST-004 MEDIUM)
- Migrate update_token_config from old error_message pattern to
  set_error_banner closure (RUST-005 MEDIUM)

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

* perf(ui): replace per-frame QualifiedIdentity clone with borrow

Use .as_ref() instead of .clone() in the ui() identity guard of
TransferTokensScreen and ClaimTokensScreen. QualifiedIdentity
(Identity + KeyStorage + BTreeMap + Vec) was being cloned 60x/sec;
now only borrowed for display, with clones deferred to button-click
paths that actually need ownership.

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

* feat(ui): add OptionResultExt::or_show_error for Option<T>

Mirrors ResultBannerExt::or_show_error but for Option<T>: if None,
displays a global error banner with the given message. Enables
concise patterns like:
  identities.first().cloned().or_show_error(ctx, "No identities loaded")

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

* fix(ui): address review findings from grumpy-review iteration 2

- Standardize display_message to handle both Error and Warning across
  13 non-token screens that were missed in iteration 1 (PROJ-001 MEDIUM)
- Replace .expect() panic in AddKeyScreen::refresh() with graceful
  or_show_error() + unwrap_or_default() (PROJ-002 MEDIUM)
- Rename OptionResultExt to OptionBannerShowExt to avoid confusion
  with ResultBannerExt (RUST-001 MEDIUM)

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

* fix(ui): handle Warning in add_new_identity_screen display_message

Missed in the previous sweep — standardize display_message to handle
both Error and Warning, matching all other screens.

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

* fix(ui): standardize display_message side-effect patterns across screens

Guard side effects with Error|Warning match, use take_and_clear(),
and remove redundant MessageBanner::set_global() call in 4 screens.

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

* chore(deps): update dashpay/platform to rev 570e3af0

Adapt to breaking changes in rust-dashcore (a05d256f → 2824e52a):

- Replace removed FeeLevel enum with FeeRate::normal() direct calls
- Replace removed WalletManager::create_unsigned_payment_transaction()
  with TransactionBuilder + WalletManager::get_change_address()
- Replace removed DashSpvClientInterface/DashSpvClientCommand with
  direct Arc<SpvClient> for quorum lookups via get_quorum_at_height()
- Replace removed start()+monitor_network() with client.run(token)
- Add .await to now-async subscribe_sync/network/progress methods
- Replace removed SyncState::Initializing with SyncState::WaitForEvents

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

* chore: log backtrace on panic

* fix: panic in asset locks

* fix(ui): address PR #604 review comments (CMT-001, CMT-002, CMT-003)

- Fix QR scanner form reset matching wrong result type (CMT-001)
- Remove dangerous identity fallback in token transfer screen (CMT-002)
- Add fee-aware validation before credit transfers (CMT-003)

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

* refactor(spv): replace AsyncRwLock with ArcSwapOption for SPV client reference

The SPV client reference only needs atomic set/clear (on start/stop) and
wait-free reads (quorum lookups). ArcSwapOption is a better fit than
AsyncRwLock<Option<Arc<...>>> — no lock contention, no async in blocking
context, and consistent with how AppContext already uses ArcSwap for the SDK.

Also fixes stale doc comment referencing removed DashSpvClientInterface.

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

* fix(ui): address PR #604 review comments iteration 2 (transfer_tokens_screen)

- Remove duplicate conflicting banner on missing identity (CMT-003)
- Use generic banner messages with with_details() for errors (CMT-002)
- Fix refresh to match specific token by contract+position (CMT-001)
- Document error banner pattern in CLAUDE.md

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

* doc: review guide updated

* fix(ui): apply grumpy-review triage fixes — core infrastructure

Address findings from code review triage (SEC-002, RUST-003, RUST-012,
PROJ-005): preserve error context in payment tx builder, add INTENTIONAL
comment for Debug-formatting accepted risk, remove dead import in SPV
manager, fix CLAUDE.md error banner documentation, and add OptionBannerExt
replace/replace_with_elapsed convenience methods.

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

* fix(ui): apply grumpy-review triage fixes — screen-level changes

RUST-010: Add wallet_open_attempted guard to ~30 screens preventing
per-frame try_open_wallet_no_password calls. Guard resets on wallet
or identity selection change.

PROJ-001: Migrate register/update contract and document action screens
from BroadcastStatus::Broadcasting(u64) to refresh_banner with elapsed
time display.

RUST-001: Surface database errors via .or_show_error() in contacts_list
instead of silently swallowing with let _ =.

RUST-005: tokens_screen display_message only clears operation_banner on
Error/Warning, preserving it on Success/Info.

RUST-007: Remove dead Error(String, Instant) variant from
TransitionBroadcastStatus in transition_visualizer_screen.

RUST-009: Make identity Optional in claim_tokens_screen with degraded
state handling when identity not found locally.

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

* fix(ui): handle OverallConnectionState::Error in connection banner

Cover the new Error variant added by #650 (SPV sync error state) in the
connection banner match arm. Shows an error banner directing users to the
connection status tooltip for details.

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

* build: update Cargo.lock

* build: reduce dependency debuginfo to fix <unknown> panic backtraces

std's backtrace symbolizer (gimli) silently fails to resolve symbols
when parsing ~790MB of DWARF debug sections in our 1.1GB debug binary,
producing backtraces full of <unknown> frames.

Set `debug = "line-tables-only"` for dependency crates while keeping
full debuginfo for our own code. This cuts DWARF from 790MB to ~354MB
and binary size from 1.1GB to 600MB, letting gimli actually resolve
panic backtraces.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Pasta Lil Claw <pasta+claw@dashboost.org>
Co-authored-by: PastaClaw <thepastaclaw@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Paul DeLucia <69597248+pauldelucia@users.noreply.github.com>
lklimek added a commit that referenced this pull request Mar 18, 2026
* docs: add unified message display design documents

Add UX specification, technical architecture, and HTML mockup for the
MessageBanner component that will replace the ~50 ad-hoc error/message
display implementations across screens with a single reusable component.

Key design decisions:
- Per-screen MessageBanner with show()/set_message() API
- All colors via DashColors (zero hardcoded Color32 values)
- 4 severity levels: Error, Warning, Success, Info
- Auto-dismiss for Success/Info (5s), persistent for Error/Warning
- Follows Component Design Pattern conventions (private fields, builder, show)
- No changes to BackendTask/TaskResult/AppState architecture

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

* feat: add MessageType::Warning

* chore: initial implementation

* chore: docs

* chore: self review

* refactor(context): replace RwLock<Sdk> with ArcSwap<Sdk> (#600)

* refactor(context): replace RwLock<Sdk> with ArcSwap<Sdk>

Sdk is internally thread-safe (Arc, ArcSwapOption, atomics) and all
methods take &self. The RwLock was adding unnecessary contention across
backend tasks.

Using ArcSwap instead of plain Sdk because reinit_core_client_and_sdk()
needs to atomically swap the entire Sdk instance when config changes.
ArcSwap provides lock-free reads with atomic swap for the rare write.

Suggested-by: lklimek

* fix: address CodeRabbit review findings for ArcSwap migration

- Fix import ordering: move arc_swap::ArcSwap before crossbeam_channel
- Remove redundant SDK loads in load_identity_from_wallet, register_dpns_name,
  and load_identity — use the sdk parameter already passed to these functions
- Fix stale TODO referencing removed sdk.read().unwrap() API
- Rename sdk_guard → sdk in transfer, withdraw_from_identity, and
  refresh_loaded_identities_dpns_names (no longer lock guards)
- Pass &sdk to run_platform_info_task from dispatch site instead of
  reloading internally
- Fix leftover sdk.write() call in context_provider.rs (RwLock remnant)
- Add missing Color32 import in wallets dialogs

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

* refactor: address remaining CodeRabbit review feedback on ArcSwap migration

- Move SDK load outside for loop in refresh_loaded_identities_dpns_names.rs
  so it's loaded once for the batch instead of on each iteration
- Update stale TODO comment in default_platform_version() to reflect that
  this is a free function with no sdk access

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

* refactor: consolidate double read-lock on spv_context_provider

Clone the SPV provider in a single lock acquisition, then bind app
context on the clone instead of locking twice.

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

---------

Co-authored-by: PastaClaw <thepastaclaw@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: remove unused Insight API and show_in_ui config fields (#597)

* refactor: remove unused Insight API references

The `insight_api_url` field in `NetworkConfig` and its associated
`insight_api_uri()` method were never used in production code (both
marked `#[allow(dead_code)]`). Remove the field, method, config
entries, env example lines, and related tests.

https://claude.ai/code/session_01HWPmCJHT8KTZGP9bFiksjn

* refactor: remove unused `show_in_ui` field from NetworkConfig

The `show_in_ui` field was defined on `NetworkConfig` and serialized in
`save()`, but never read by any production code to control network
visibility. Remove the field, its serialization, env example lines,
and test references.

https://claude.ai/code/session_01HWPmCJHT8KTZGP9bFiksjn

* fix: add missing `Color32` import in wallet dialogs

https://claude.ai/code/session_01HWPmCJHT8KTZGP9bFiksjn

---------

Co-authored-by: Claude <noreply@anthropic.com>

* build: add Flatpak packaging and CI workflow (#589)

* build: remove snap version

* build: add Flatpak packaging and CI workflow

Add Flatpak build manifest, desktop entry, AppStream metadata, and
GitHub Actions workflow for building and distributing Flatpak bundles.
Uses freedesktop 25.08 runtime with rust-stable and llvm21 extensions.
No application source code changes required - works in SPV mode by default.

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

* build: address review findings for Flatpak packaging

- Pin GitHub Actions to commit SHAs for supply chain security
- Upgrade softprops/action-gh-release from v1 to v2.2.2
- Remove redundant --socket=x11 (fallback-x11 suffices)
- Remove duplicate tag trigger preventing double builds on release
- Remove duplicate env vars inherited from top-level build-options
- Add Flatpak build artifacts to .gitignore
- Add bugtracker URL to AppStream metainfo
- Remove deprecated <categories> from metainfo (use .desktop instead)
- Add Terminal=false and Keywords to desktop entry
- Add disk space check after SDK install in CI
- Rename artifact to include architecture suffix

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

* build: simplify CI workflows for Linux-only releases

- Remove "Free disk space" step from flatpak and release workflows
- Remove Windows and macOS builds from release workflow
- Use "ubuntu" runner image instead of pinned versions
- Clean up unused matrix.ext references

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

* build: attach to existing releases instead of creating new ones

- Replace release-creating job with attach-to-release (only on release event)
- Add 14-day retention for build artifacts
- On tag push or workflow_dispatch, only upload artifacts (no release)

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

* revert: restore release.yml to original v1.0-dev version

The release workflow changes were out of scope for the Flatpak PR.

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

* fix: address CodeRabbit review comments

- Fix CRLF line endings in Flatpak manifest (convert to LF)
- Set app_id on ViewportBuilder to match desktop StartupWMClass
- Use --locked flag for reproducible cargo builds in Flatpak
- Rename --repo=repo to --repo=flatpak-repo to match .gitignore
- Add architecture note for protoc x86_64 binary

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

* docs: add Flatpak install instructions to README

Add a dedicated section for installing via Flatpak on Linux,
clarify that prerequisites are only needed for building from source,
and rename "Installation" to "Build from Source" for clarity.

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

* fix: match StartupWMClass to Flatpak app_id

Use reverse-DNS format org.dash.DashEvoTool to match the
Wayland app_id set via ViewportBuilder::with_app_id().

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

* fix: use ** glob for branch trigger to match feat/flatpak

Single * doesn't match path separators in GitHub Actions branch filters.

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

* feat: add aarch64 Flatpak build and caching to CI

- Add matrix strategy for parallel x86_64 and aarch64 builds
- Patch protoc URL/sha256 per architecture at build time
- Cache .flatpak-builder directory keyed on arch + manifest + lockfile
- Pin actions/cache to SHA

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

* fix: convert desktop and metainfo files to LF line endings

Flatpak builder validates desktop files and rejects CRLF line endings.

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

* build: cancel in-progress Flatpak builds on new push

Add concurrency group keyed on git ref so a new push cancels
any running build for the same branch or release.

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

* fix: address PR review findings for Flatpak packaging

- Remove unnecessary --filesystem=xdg-config/dash-evo-tool:create
  (Flatpak already redirects XDG_CONFIG_HOME to sandbox)
- Add categories and keywords to AppStream metainfo for discoverability
- Update README with both x86_64/aarch64 install commands, uninstall
  instructions, and Flatpak data path note
- Clarify aarch64 comment in manifest to reference CI sed patching

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

* chore: workflow timeout and perms

* fix: move permissions to job level in Flatpak workflow

Step-level permissions are not valid in GitHub Actions. Move
contents: write to the job level where it is needed for release
attachment.

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

* build: cache Cargo registry and target in Flatpak CI

Bind-mount host-side cargo-cache and cargo-target directories into the
Flatpak build sandbox so CARGO_HOME and target/ persist across builds.
Uses split restore/save with cleanup of incremental and registry/src
(similar to Swatinem/rust-cache).

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

* fix: scope cargo cache bind-mount sed to build-args only

The previous sed matched --share=network in both finish-args and
build-args, corrupting finish-args. Use a sed range to only target
the build-args section.

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

* Apply suggestions from code review

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* chore: fix build

* chore: use new error handling everywhere - not self reviewed

* chore: use message banner to show progress

* fix: start elapsed counter at 1s instead of 0s

Aligns elapsed display with the countdown timer which already adds 1
to avoid showing "0s" immediately.

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

* chore: rabbit review

* Update src/app.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore: peer review

* chore: fix build errors

* fix(ui): make MessageBanner::set_global truly idempotent

set_global() no longer resets timestamps, auto-dismiss timer, or
logged flag when a banner with identical text already exists. This
makes it safe to call every frame without log spam or timer restarts.

Cherry-picked from origin/fix/spv-peer-timeout (08e3b3b).

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

* fix(ui): address code review findings R01, R03, R06, R09, R10

- R01: Replace expect("No key selected") with graceful match + error
  banner in 11 token screens to prevent panics on missing signing key
- R03: Remove dead backend_message field from AddExistingIdentityScreen
- R06: Replace is_some() + unwrap() with idiomatic if-let-Some pattern
  in 10 token screens; use is_some_and() in structs.rs
- R09: Add use imports for MessageBanner in 5 dashpay screens, replacing
  22 fully-qualified crate::ui::components::MessageBanner:: calls
- R10: Replace custom_dash_qt_error_message inline rendering with
  MessageBanner::set_global in network_chooser_screen

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

* fix(ui): address review findings SEC-08, SEC-09, RUST-015, SEC-05, SEC-07

- SEC-08: Restore safe if-let-Some pattern in WithdrawalScreen::refresh()
  to prevent double unwrap() panic on DB error or deleted identity
- SEC-09: Restore original DB lookup in SendPaymentScreen::load_contact_info()
  replacing hardcoded "alice.dash" mock data
- RUST-015: Revert unimplemented!() back to ui.label() in
  update_token_config MarketplaceTradeMode arm
- SEC-05: Add success banners for contact request accept/reject in
  ContactRequests::display_task_result
- SEC-07: Add MessageBanner::clear_all_global() and call it from
  AppState::change_network() to prevent stale banners leaking across
  network switches

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

* docs: update coding conventions and message display guidance

Add fallible constructor rule (Result<Self, ...> when they can fail),
rename section to "General rules", and document MessageBanner
idempotency (no guard needed for set_global).

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

* fix(ui): replace expect/panic with graceful error handling (SEC-10)

Replace all expect() calls in token screen constructors and confirmation
handlers with MessageBanner error display. Constructors handle errors
internally and return Self with degraded state, keeping create_screen()
clean. refresh() methods now show errors via MessageBanner instead of
tracing-only logging.

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

* refactor(ui): accept impl Display/Debug in MessageBanner API

Change MessageBanner public methods to accept `impl Display` for
message text and `impl Debug` for details, instead of `&str`. Remove
needless `&format!(...)` borrows across 27 call sites.

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

* fix(ui): remove error Failed to get best chain lock for mainnet, testnet, devnet, and local

Fixes #633

* feat(ui): add automatic connection status banners

Display persistent MessageBanner notifications based on network
connection state transitions. Mode-aware messages guide users toward
the right recovery action (RPC vs SPV).

- Disconnected (RPC): "Disconnected — check that Dash Core is running"
- Disconnected (SPV): "Disconnected — check your internet connection"
- Syncing (RPC): "Syncing with Dash Core…"
- Syncing (SPV): "SPV sync in progress…"
- Synced: banner cleared

Uses Option<OverallConnectionState> for change detection, with None
as initial/post-network-switch sentinel to force first evaluation.

Closes #667 (partial — action links deferred to follow-up)

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

* fix(ui): pass TaskError directly to with_details() to avoid double-formatting

The previous code used `format!("{err:?}")` which produced a String, then
`with_details()` applied `{:#?}` again — wrapping the output in quotes and
escaping inner characters. Passing `&err` directly lets Debug format once.

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

* fix(ui): correct copy-paste error messages in token screens

Replace "Burning" error messages that were copy-pasted from burn screen
into freeze, destroy, and resume token screens with contextually correct
messages.

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

* fix(ui): restore lost success/error messages in 5 screens

Replace display_message() calls with MessageBanner::set_global() in
screens where display_message() is now a side-effect-only handler and
no longer displays messages directly.

Affected screens: create_asset_lock_screen, wallets_screen (MineBlocks),
address_table (export error), profile_screen (validation), contact_details.

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

* fix(ui): replace unwrap/expect with graceful error handling

Replace double unwrap in transfer_screen refresh() with unwrap_or_else
+ MessageBanner error display, matching the pattern from withdraw_screen.

SEC-002 tokens_screen skipped: the .expect() calls are only on
compile-time embedded image data (include_bytes!) which is safe.

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

* refactor(ui): migrate masternode_list_diff_screen to global MessageBanner

Replace ~15 local ui_state.message assignments and custom
render_message_banner() with MessageBanner::set_global() via the
display_message() trait method. Remove the message field from UiState
and the unused Color32 import.

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

* fix(ui): improve banner eviction logging and atomics

- Upgrade BANNER_KEY_COUNTER from Relaxed to SeqCst ordering for
  future-proofing against multi-threaded usage
- Log evicted banners at warn level in set_global() and replace_global()
- Add comment explaining why show_global() always writes back

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

* chore: remove resolved TODO.md

All items tracked in the unified message display TODO have been
addressed or moved to the review findings.

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

* docs(ui): add INTENTIONAL markers and API documentation

- Document why with_details() accepts Debug (not Display): structured
  error context is more useful in diagnostic details panes
- Document replace_global() fallback-to-add behavior as intentional
- Add INTENTIONAL(SEC-003) marker for developer mode error details
- Add INTENTIONAL(SEC-004) marker for BannerHandle Send+Sync safety

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

* refactor(ui): extract shared token validation and fix ordering

- Add validate_signing_key() helper in tokens/mod.rs to eliminate
  duplicated signing key validation across 12 token screens
- Move signing key validation BEFORE WaitingForResult state transition
  so users see immediate errors instead of loading spinner then error
- Replace is_err()/unwrap() anti-pattern with idiomatic let-else blocks
  in freeze, mint, transfer, destroy_frozen_funds, unfreeze screens

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

* refactor(ui): return Result from get_selected_wallet

Replace &mut Option<String> error out-parameter with idiomatic
Result<Option<Arc<RwLock<Wallet>>>, String>. Update 26+ callsites
across identity, token, DashPay, and contract screens.

Callsite patterns: unwrap_or_else with MessageBanner for user-visible
errors, unwrap_or(None) where errors were previously silently ignored.

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

* fix(ui): resolve duplicate imports and clippy warnings

Remove duplicate MessageBanner imports in create_asset_lock_screen and
wallets_screen/mod. Fix needless_borrows_for_generic_args clippy lints
in profile_screen, transfer_screen, and wallets_screen.

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

* style: reorder imports in masternode_list_diff_screen

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

* fix(ui): address review findings from MessageBanner migration audit

Apply 13 triaged review fixes plus 1 bug fix across 22 files:

- Remove dead error state fields (backend_message, error_message, Error variant)
- Replace .expect() panics with graceful fallback + MessageBanner in token screens
- Fix missing MessageBanner::show_global() on contracts documents screen
- Migrate DocumentActionScreen inline errors to MessageBanner
- Replace unwrap_or(None) with error-reporting fallback in DashPay screens
- Fix replace_global idempotency and use relaxed atomic ordering in banner
- Extract shared set_error_banner helper for 8 token screens
- Restore correct Some(0) wallet index semantics
- Document BannerHandle lifecycle in CLAUDE.md

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

* fix: validate token description length before sending to Platform (#530)

* fix: validate token description length before sending to Platform

Descriptions must be either empty or 3-100 characters long.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ui): validate token description by char count, not byte length

String::len() counts UTF-8 bytes, causing multi-byte characters
(CJK, emoji) to be miscounted against the 3–100 limit. Switch to
chars().count() and update all UI labels to surface the minimum.

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Lukasz Klimek <842586+lklimek@users.noreply.github.com>

* refactor(ui): consolidate banner extension traits into message_banner

Move BannerHandleExt and ResultBannerExt from banner_ext.rs into
message_banner.rs where they belong. Merge take_and_clear() into
OptionBannerExt trait (impl for Option<BannerHandle>) alongside
or_show_error() for Option. Remove the separate banner_ext module
and Clearable helper trait for simplicity.

Apply review findings: DRY patterns (take_and_clear, or_show_error,
load_identities_with_banner), fix .expect() panics in constructors,
restore known_identities in refresh(), narrow pub field visibility,
add ScreenLike doc comments, and update CLAUDE.md conventions.

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

* doc(tmp): review guide for pr 604

* fix(ui): address review findings from grumpy-review iteration 1

- Replace .expect() panics in TransferTokensScreen and ClaimTokensScreen
  constructors with graceful degradation via Option<QualifiedIdentity>
  and MessageBanner error display (PROJ-001 HIGH)
- Fix CLAUDE.md referencing non-existent BannerHandleExt trait name,
  corrected to OptionBannerExt (PROJ-002 MEDIUM)
- Update set_global to preserve message_type when same text appears
  with different severity (RUST-001 MEDIUM)
- Standardize display_message to handle both Error and Warning across
  all 11 token screens (RUST-002 MEDIUM)
- Replace 21 manual take().clear() patterns with take_and_clear()
  across 6 files (RUST-003 MEDIUM)
- Remove unused OptionBannerExt::or_show_error method (RUST-004 MEDIUM)
- Migrate update_token_config from old error_message pattern to
  set_error_banner closure (RUST-005 MEDIUM)

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

* perf(ui): replace per-frame QualifiedIdentity clone with borrow

Use .as_ref() instead of .clone() in the ui() identity guard of
TransferTokensScreen and ClaimTokensScreen. QualifiedIdentity
(Identity + KeyStorage + BTreeMap + Vec) was being cloned 60x/sec;
now only borrowed for display, with clones deferred to button-click
paths that actually need ownership.

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

* feat(ui): add OptionResultExt::or_show_error for Option<T>

Mirrors ResultBannerExt::or_show_error but for Option<T>: if None,
displays a global error banner with the given message. Enables
concise patterns like:
  identities.first().cloned().or_show_error(ctx, "No identities loaded")

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

* fix(ui): address review findings from grumpy-review iteration 2

- Standardize display_message to handle both Error and Warning across
  13 non-token screens that were missed in iteration 1 (PROJ-001 MEDIUM)
- Replace .expect() panic in AddKeyScreen::refresh() with graceful
  or_show_error() + unwrap_or_default() (PROJ-002 MEDIUM)
- Rename OptionResultExt to OptionBannerShowExt to avoid confusion
  with ResultBannerExt (RUST-001 MEDIUM)

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

* fix(ui): handle Warning in add_new_identity_screen display_message

Missed in the previous sweep — standardize display_message to handle
both Error and Warning, matching all other screens.

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

* fix(ui): standardize display_message side-effect patterns across screens

Guard side effects with Error|Warning match, use take_and_clear(),
and remove redundant MessageBanner::set_global() call in 4 screens.

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

* chore(deps): update dashpay/platform to rev 570e3af0

Adapt to breaking changes in rust-dashcore (a05d256f → 2824e52a):

- Replace removed FeeLevel enum with FeeRate::normal() direct calls
- Replace removed WalletManager::create_unsigned_payment_transaction()
  with TransactionBuilder + WalletManager::get_change_address()
- Replace removed DashSpvClientInterface/DashSpvClientCommand with
  direct Arc<SpvClient> for quorum lookups via get_quorum_at_height()
- Replace removed start()+monitor_network() with client.run(token)
- Add .await to now-async subscribe_sync/network/progress methods
- Replace removed SyncState::Initializing with SyncState::WaitForEvents

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

* chore: log backtrace on panic

* fix: panic in asset locks

* fix(ui): address PR #604 review comments (CMT-001, CMT-002, CMT-003)

- Fix QR scanner form reset matching wrong result type (CMT-001)
- Remove dangerous identity fallback in token transfer screen (CMT-002)
- Add fee-aware validation before credit transfers (CMT-003)

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

* refactor(spv): replace AsyncRwLock with ArcSwapOption for SPV client reference

The SPV client reference only needs atomic set/clear (on start/stop) and
wait-free reads (quorum lookups). ArcSwapOption is a better fit than
AsyncRwLock<Option<Arc<...>>> — no lock contention, no async in blocking
context, and consistent with how AppContext already uses ArcSwap for the SDK.

Also fixes stale doc comment referencing removed DashSpvClientInterface.

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

* fix(ui): address PR #604 review comments iteration 2 (transfer_tokens_screen)

- Remove duplicate conflicting banner on missing identity (CMT-003)
- Use generic banner messages with with_details() for errors (CMT-002)
- Fix refresh to match specific token by contract+position (CMT-001)
- Document error banner pattern in CLAUDE.md

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

* [claudesquad] update from 'testing research' on 02 Mar 26 13:25 CET (paused)

* test: add backend E2E test harness and SPV wallet test

Add test-only accessors (db(), wallets()) on AppContext gated behind
cfg(test/testing), fix compilation errors in the backend-e2e test
(private field access, unused import), and apply nightly rustfmt.

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

* feat: add DASH_EVO_DATA_DIR env var to override app data directory

Allows tests and CI to redirect all app data (database, SPV chain
state, .env config) to a temp directory. The backend-e2e test harness
now uses this to achieve full data isolation.

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

* test: add backend E2E test framework with shared state and funded wallets

Evolve the prototype backend E2E test harness into a reusable framework:

- LazyLock shared BackendTestContext with persistent workdir, SPV, and
  framework wallet (funded via E2E_WALLET_MNEMONIC or testnet faucet)
- Task runner wrapper, polling wait helpers, faucet HTTP client
- Identity key derivation helpers for wallet-funded registration
- Six test scenarios: SPV wallet, identity create, identity withdraw,
  send/receive funds, fetch contracts, register DPNS name
- Move default_identity_key_specs() from UI to backend_task::identity
  (domain logic, not UI concern) and make IdentityKeys fields pub
- Add dashpay_contract_id() test accessor to AppContext

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

* fix(test): use tokio::sync::OnceCell instead of LazyLock for async init

LazyLock triggers synchronously inside the #[tokio::test] runtime,
causing "Cannot start a runtime from within a runtime" when the init
function calls block_on(). Switch to tokio::sync::OnceCell with an
async init() method so shared state initialization runs cooperatively
within the existing tokio runtime.

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

* fix(test): handle persistent DB and SPV balance sync in E2E harness

- Wait for SPV to sync existing wallet balance before checking if
  faucet funding is needed (pre-funded wallets need time to discover
  on-chain UTXOs)
- Handle "already imported" error gracefully when framework wallet
  exists in persistent DB from a previous run

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

* fix(test): wait for spendable balance and retry sends in E2E harness

The SPV wallet reports total balance (including unconfirmed) but only
confirmed/IS-locked UTXOs are available for transaction building. This
caused "Insufficient funds" errors when tests tried to spend immediately
after receiving funds.

- Add wait_for_spendable_balance() that checks confirmed_balance_duffs()
  and triggers reconcile_spv_wallets() on each poll iteration
- Add retry logic (5 attempts, 10s backoff) to create_funded_test_wallet()
  for sends that fail with InsufficientFunds
- Wait for framework wallet change output to become spendable after each
  send so subsequent calls don't fail
- Add wait_for_spendable_balance() before identity registration in all
  identity/DPNS tests
- Add send_with_retry() helper in send_funds test
- Add developer-facing README.md for the test framework

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

* fix(test): use tokio-shared-rt for shared runtime and sweep orphaned wallets

Replace per-test tokio runtimes with tokio-shared-rt's global shared runtime
to prevent SPV background tasks from dying between test functions. Add
automatic orphaned wallet fund recovery during setup — wallets persist in DB,
so on next run the harness sweeps funds back to the framework wallet.

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

* fix: handle OverallConnectionState::Error in connection banner

Semantic merge conflict from v1.0-dev: PR #650 added an Error variant to
OverallConnectionState, which our connection banner match didn't cover.
Show an error banner when SPV sync enters the error state.

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

* docs(test): improve backend-e2e documentation and funding UX

- Add backend E2E section to CLAUDE.md pointing to the full README
- Document .env file handling (project root vs workdir) and precedence
- Fix test attribute in README: tokio::test → tokio_shared_rt::test(shared)
- Update init sequence to reflect current code (spendable wait, orphan sweep)
- Document automatic cleanup-on-init of orphaned test wallets
- Raise minimum balance threshold from 1 to 10 tDASH
- Always panic with receive address when faucet fails and balance is below
  minimum (previously only panicked on zero balance)
- Show receive address in spendable-balance timeout warning

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

* fix: patch SPV UTXO spendability flags before coin selection

Upstream key-wallet-manager (rust-dashcore) never sets is_confirmed or
is_instantlocked on UTXOs, but CoinSelector requires one of them.
This caused "No UTXOs available for selection" errors despite having
balance. Workaround infers status from block inclusion (height > 0 →
confirmed, height == 0 → IS-locked).

Ref: dashpay/rust-dashcore#514

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

* test: harden backend E2E tests with retry logic and calibrated amounts

- Increase funding amounts to avoid insufficient-funds flakes
- Add 3-attempt retry for identity registration (chain height sync)
- Retry on "No UTXOs" in send_with_retry alongside "Insufficient"
- Wait for spendable balance in create_funded_test_wallet before return
- Add CI workflow for backend E2E tests

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

* Update test command in backend E2E workflow

* ci: merge backend-e2e workflow into tests workflow (#727)

* Initial plan

* ci: merge backend-e2e workflow into tests workflow as an additional step

Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>

* test: add cleanup_only noop test to sweep orphaned wallets

Add a standalone test that triggers BackendTestContext initialization,
which runs cleanup_test_wallets() as its final step. This can be run
as a dedicated CI step after the E2E suite to sweep orphaned wallet
funds back to the framework wallet.

Run with:
  cargo test --test backend-e2e --all-features -- --ignored --nocapture cleanup_only

Co-authored-by: lklimek <lklimek@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add cleanup step for E2E test wallets

Added a cleanup step for E2E test wallets in the workflow.

* Simplify E2E test workflow conditions

Removed conditional checks for E2E_WALLET_MNEMONIC in test steps.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: lklimek <lklimek@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address PR #673 review comments from triage

Production code:
- Extract patch_utxo_spendability_flags() helper to deduplicate
  workaround in estimate_fallback_amount and build_unsigned_payment_tx
- Add IdentityKeys::new() constructor
- Make wallet+address persistence atomic via store_wallet_with_addresses()
- Add pending_wallet_selection after wallet creation

Test code:
- Add DPNS registration retry for identity propagation delay
- Use u64 hex for DPNS name uniqueness (CMT-023)
- Calibrate test funding amounts per reviewer feedback
- Add fragility note on string-match wallet detection (CMT-006)
- Add TODO for identity fund withdrawal in cleanup (CMT-032)
- Add INTENTIONAL comment for bounded channel design (CMT-017)
- Add balance assertion for return leg in send_funds test
- Log reconcile_spv_wallets errors in wait helpers
- Use is_ok_and for clarity in spv_wallet test

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

* refactor: remove UTXO spendability workaround, update platform dep

Remove `patch_utxo_spendability_flags()` that faked IS-locked status on
mempool UTXOs. Wait for upstream fix (dashpay/rust-dashcore#514) to
properly set is_confirmed/is_instantlocked flags on UTXOs.

Also:
- Update dashpay/platform rev to aa86b74f7e2
- Adapt to upstream API: FeeLevel→FeeRate, remove NetworkExt import
- Fix retry to catch "No UTXOs" errors in test harness

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

* refactor: deduplicate default_identity_key_specs

Move the single canonical copy to backend_task::identity::mod and have
the UI screen import it, eliminating ~240 lines of duplicated function
and tests.

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

* ci: temporarily disable backend E2E tests in CI

The backend E2E tests need updates after the TaskError migration
(#739) changed AppContext field visibility. Commenting out the
CI steps until the tests are adapted.

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

* refactor: type-safe wallet creation and identity key visibility

- Restrict IdentityKeys fields to pub(crate) to prevent private key
  exposure outside the crate
- Change register_wallet() to return TaskError instead of String, using
  proper rusqlite error matching via is_unique_constraint_violation()
  and a new WalletAlreadyImported variant
- Change Wallet::new_from_seed() to accept Option<&Secret> for password
  instead of Option<&str>, keeping sensitive data in the Secret wrapper
- Change Wallet::new_from_seed() to return TaskError instead of String,
  with a new WalletKeyDerivationFailed variant for derivation errors
- Move build_identity_registration() and get_receive_address() from
  test helpers to production code in src/backend_task/identity/mod.rs
- Extract is_unique_constraint_violation() to src/database/mod.rs as a
  shared pub(crate) utility, removing the duplicate in import_mnemonic_screen
- Update all callers in add_new_wallet_screen and import_mnemonic_screen

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

* test: address PR #673 review comments for E2E test framework

- Move framework modules (harness, task_runner, wait, funding, cleanup,
  identity_helpers) into tests/backend-e2e/framework/ subdirectory
- Make E2E_WALLET_MNEMONIC required (panic with instructions if unset)
- Remove auto-faucet from initialization flow (keep as helper)
- Remove retry loops in identity_create and identity_withdraw tests
- Remove unnecessary wait_for_spendable_balance calls (already done
  by create_funded_test_wallet)
- Replace all println!/eprintln! with tracing macros
- Initialize tracing subscriber in harness init
- Add "No spendable funds" and "spendable" to send retry conditions
- Remove stale "other agent" NOTE comments from identity_helpers
- Consolidate funding logic (harness delegates to funding module)
- Update README for required mnemonic and new directory structure

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

* fix: reconcile production and test code after type-safe refactor

Adapt test framework to production API changes:
- Use IdentityKeys::new() constructor (fields now pub(crate))
- Match TaskError::WalletAlreadyImported variant instead of string
- Allow dead_code on faucet helpers (kept but not auto-called)

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

* refactor: thread data_dir as explicit parameter to eliminate env var dependency

Add `data_dir: PathBuf` field to `AppContext` and thread it through
`Config::load_from()`, `Config::save()`, `SpvManager::new()`,
`start_dash_qt()`, and `create_dash_core_config_if_not_exists()`.

This enables E2E tests to specify their data directory without mutating
process-wide environment variables, making parallel test execution safe.

The `DASH_EVO_DATA_DIR` env var is still checked in production via
`app_user_data_dir_path()`, but the resolved path is threaded through
as a value rather than re-read from env on every call.

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

* fix(test): simplify funded wallet creation and make spendable balance check reliable

- Remove retry loop from create_funded_test_wallet; wait for full
  amount_duffs instead of 1 duff in spendable balance check
- Add Wallet::spv_confirmed_balance() that returns None when SPV
  hasn't synced yet (no max_balance fallback)
- Use spv_confirmed_balance() in wait_for_spendable_balance so
  the wait never gets false positives from the fallback
- Remove --test-threads=1 requirement from README (unsafe set_var
  was the only reason; data_dir is now threaded explicitly)

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

* fix: remove send retry loop, handle PRIMARY KEY constraints, isolate SPV test dirs

- Remove send_with_retry() from send_funds.rs; use
  wait_for_spendable_balance before each send instead
- Add SQLITE_CONSTRAINT_PRIMARYKEY (1555) to uniqueness check
  alongside SQLITE_CONSTRAINT_UNIQUE (2067)
- Use tempfile::TempDir in SPV tests instead of fixed /tmp/spv-test
  path to prevent state leaks and support concurrent test runs

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Pasta Lil Claw <pasta+claw@dashboost.org>
Co-authored-by: PastaClaw <thepastaclaw@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Paul DeLucia <69597248+pauldelucia@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: lklimek <lklimek@users.noreply.github.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