refactor: fix all unresolved review comments — proof errors, asset lock, format! migrations#740
Conversation
…d_task files Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
…ing, add typed TaskError variants Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. |
…o Result<T,TaskError> Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
…elper, migrate token tasks to TaskError Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. |
… identity tasks to TaskError Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
There was a problem hiding this comment.
🔍 Claudius Review — PR #740: Migrate Result<T, String> to Result<T, TaskError>
Verdict: REQUEST CHANGES — 1 CRITICAL regression must be fixed before merge.
The Good
This is a well-executed refactoring. The TaskError enum design is sound, the From<SdkError> classification is thorough with 8 unit tests, and log_drive_proof_error elegantly consolidates a repeated pattern across 14+ callsites. Net -208 lines while adding real type safety — that's the kind of ratio I respect.
The Bad
🚨 CRITICAL — Behavior regression in contract screens (register_contract_screen.rs:329, update_contract_screen.rs:340): Both UI screens match on "proof error logged, contract inserted into the database" to detect contracts registered despite proof errors. This PR replaced that format string with TaskError::ProofError whose Display is completely different. The substring will never match. A successfully registered contract will incorrectly show as failed.
The Ugly
The identity registration/top-up files (register_identity.rs, top_up_identity.rs) were only partially migrated:
- 6+ inline
DriveProofErrorhandlers not replaced bylog_drive_proof_error - Asset lock expiration errors use
format!()instead of existingTaskError::AssetLockExpired - State transition
Debugrepr leaked to user-facing messages viaGeneric
Summary Statistics
| Severity | Count |
|---|---|
| CRITICAL | 1 |
| MEDIUM | 8 |
| LOW | 6 |
All 13 previous review threads verified as fixed and resolved.
Full report: review-report/report.json and review-report/report.html.
🤖 Co-authored by Claudius the Magnificent AI Agent
| "Error broadcasting Register Contract transition: {}, proof error logged, contract inserted into the database", | ||
| proof_error | ||
| ))); | ||
| return Err(TaskError::ProofError { source_error }); |
There was a problem hiding this comment.
🚨 CRITICAL — Behavior regression: contract screen string-match broken
This change replaced the format string "...proof error logged, contract inserted into the database" with TaskError::ProofError { source_error }, whose Display is now "The operation could not be fully verified by the platform...".
Both register_contract_screen.rs:329 and update_contract_screen.rs:340 use message.contains("proof error logged, contract inserted into the database") to detect a contract registered despite proof error, setting BroadcastStatus::Done. That substring will never match the new error message.
Impact: A contract registered on-chain despite a proof error will incorrectly show as failed. Users may re-submit.
Fix: Update the UI screens to structurally match on the ProofError variant via display_task_result() instead of string-matching in display_message(). The string-matching pattern should be replaced entirely.
🤖 Claudius the Magnificent — I found the needle your haystack was hiding.
| tracing::warn!("Failed to persist proof log: {}", e); | ||
| } | ||
| return Err(format!( | ||
| return Err(TaskError::from(format!( |
There was a problem hiding this comment.
MEDIUM — Inline proof-error handling should use log_drive_proof_error
This file (and top_up_identity.rs) has 6+ inline blocks that manually match Error::DriveProofError, insert a ProofLogItem, and return TaskError::from(format!(...)) — the exact pattern log_drive_proof_error was built to replace. These produce TaskError::Generic with raw error text instead of TaskError::ProofError with the source chain preserved.
Additionally, at lines 541-548, the format string "error: {}, transaction is {:?}" embeds the state transition Debug repr into a user-facing Generic error, which leaks public key hashes and internal identity structure to the UI banner.
Fix: Replace inline DriveProofError handling with .map_err(|e| self.log_drive_proof_error(e)) — same as the token/document tasks.
| // Platform hasn't verified this Core block yet | ||
| return Err(format!( | ||
| return Err(TaskError::from(format!( | ||
| "Cannot use this asset lock yet. The instant lock proof has expired (quorum rotated), \ |
There was a problem hiding this comment.
MEDIUM — Use TaskError::AssetLockExpired instead of format!()
Six callsites (3 in this file, 3 in top_up_identity.rs) construct asset lock expiration errors via TaskError::from(format!(...)) with jargon terms ("quorum rotated", "instant lock proof has expired", "Platform hasn't verified Core block N"). The dedicated TaskError::AssetLockExpired variant already exists with a proper user-friendly Display message.
Fix: Replace with:
return Err(TaskError::AssetLockExpired {
tx_block_height,
platform_height: metadata.core_chain_locked_height,
});For the chainlock-pending case (line 414), consider adding TaskError::AssetLockChainLockPending with jargon-free text.
| ) | ||
| })? | ||
| .get_contract_by_id(&identity_token_info.data_contract.contract.id())? | ||
| .ok_or(TaskError::DocumentNotFound)? |
There was a problem hiding this comment.
MEDIUM — DocumentNotFound misused for missing DataContract
TaskError::DocumentNotFound says "The document could not be found" — wrong concept for a missing data contract. Same issue at line 92.
Fix: Add TaskError::ContractNotFound with an appropriate Display message, or use TaskError::Generic("The token contract could not be found...".into()) as a quick fix.
There was a problem hiding this comment.
MEDIUM — .expect() at line 228 can panic after asset lock broadcast
asset_lock_proof.create_identifier().expect(...) panics if the proof is malformed. This runs after the asset lock has been broadcast and UTXOs removed — a panic here leaves funds locked on-chain with no identity registration.
Fix: Replace .expect() with .ok_or_else(|| TaskError::Generic("Could not derive identity from asset lock. Please check the transaction and retry.".into()))?
There was a problem hiding this comment.
MEDIUM — sdk_error_user_message fallback (line 311) embeds raw SDK error in user-facing message
The _ catch-all arm at line 311: format!("An unexpected error occurred: {error}. Please try again later.") sends the raw SDK Display text to the UI banner. This may include gRPC endpoint addresses, IP addresses, or protocol details — violating CLAUDE.md Rule 4.
The #[source] chain already preserves the full error for Debug/logs.
Fix: "An unexpected error occurred. Please try again later.".to_string()
There was a problem hiding this comment.
MEDIUM — Five format!() string error conversions not migrated
This method still has five .map_err(|e| format!(...)) calls (lines 75, 83, 88-93, 105-110, 116) that route through From<String> to TaskError::Generic. The identity and token tasks were migrated — this contract task was left behind.
Fix: Map to typed variants: nonce fetch → TaskError::from(sdk_error), sender → TaskError::InternalSendError, protocol error → TaskError::from(SdkError::Protocol(e)), signing → similar, database → ? via From<rusqlite::Error>.
There was a problem hiding this comment.
MEDIUM — .unwrap() on wallet.read() at line 172 — missed migration
wallet.read().unwrap().seed_hash() will panic if the RwLock is poisoned. Every other wallet lock acquisition in this PR uses map_err(TaskError::from). This is the only missed site.
Fix: wallet.read().map_err(TaskError::from)?.seed_hash() or use filter_map with error logging.
|
@copilot please check all comments and fix them |
Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
All previous comment threads are resolved. Fixed the remaining CI failure (Clippy workflow was failing on Summary of all changes across this PR:
|
| // Platform hasn't verified this Core block yet | ||
| return Err(format!( | ||
| return Err(TaskError::from(format!( | ||
| "Cannot use this asset lock yet. The instant lock proof has expired (quorum rotated), \ |
| tracing::warn!("Failed to persist proof log: {}", e); | ||
| } | ||
| return Err(format!( | ||
| return Err(TaskError::from(format!( |
| "Error broadcasting Register Contract transition: {}, proof error logged, contract inserted into the database", | ||
| proof_error | ||
| ))); | ||
| return Err(TaskError::ProofError { source_error }); |
| ) | ||
| })? | ||
| .get_contract_by_id(&identity_token_info.data_contract.contract.id())? | ||
| .ok_or(TaskError::DocumentNotFound)? |
Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
a5c577d
into
task/660-i18n-ready-strings-general-rule
) * docs: promote i18n-ready strings to general coding rule (#660) Move the i18n guideline out of the error-messages section into general rules, broadening its scope to all user-facing strings (labels, tooltips, messages). Remove direct Fluent reference, fix placeholder syntax to Rust-style `{ name }`, and renumber remaining error rules. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: add typed error variants for migration (#660) Add new TaskError variants (LockPoisoned, Database, CoreRpc, P2P), new domain error types (P2PError, WalletError::KeyDerivation, WalletError::Sighash, DashPayError::QueryCreation, DashPayError::CryptoKeyParsing, DashPayError::PrivateKeyResolution, ConfigError::SaveError), and replace the transparent Sqlite variant with a user-friendly Database variant. Drop Clone/PartialEq from DashPayError to support #[source] fields and fix the two downstream callsites that depended on them. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: replace string errors with typed errors in spv/config/infra (#660) - core_p2p_handler: eliminate ReadMessageError(String), use P2PError variants throughout internal methods; keep public API returning String for callers outside scope - config: replace ConfigError::LoadError with SaveError in save() for all I/O operations (writeln, sync_all, persist) - backend_task/mod: add map_err(TaskError::from) bridges for wallet task functions that still return String - model/wallet: fix KeyDerivation source type mismatch (key_wallet::Error != bip32::Error) by reverting to e.to_string() at derivation_path() callsites Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor: replace string errors with typed TaskError in model/database/context (#660) - Use WalletError::AddressError in utxos.rs for dashcore address errors - Use TaskError::from(e) for RPC errors in broadcast_raw_transaction Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor: replace string errors with typed TaskError in backend_task/ (#660) Migrate callsites in src/backend_task/ from Result<T, String> to Result<T, TaskError>: - broadcast_state_transition: map SDK error via TaskError::from - contract: direct ? for rusqlite, TaskError::from for SDK errors - document: all 7 document operations migrated - mod.rs: run_wallet_task return type updated to TaskError - register_contract: sender error → InternalSendError, SDK → TaskError::from - update_data_contract: sender error → InternalSendError, format strings → Generic - wallet/*: lock poison → Generic, SDK errors → TaskError::from, ? for rusqlite Build, clippy, and fmt all pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor: replace string errors with typed TaskError in ui/ (#660) Migrate rusqlite error callsites in src/ui/ to typed TaskError variants: - `IdentityTokenInfo::try_from_*` functions in tokens_screen/structs.rs now return `Result<Self, TaskError>` — DB errors become `TaskError::Database` via `?` instead of `.map_err(|e| e.to_string())`. Callers use `MessageBanner::set_global` with the error which accepts `impl Display`, so no caller changes were needed. - `save_private_info` in contact_profile_viewer.rs now returns `Result<(), TaskError>` — the rusqlite error is wrapped explicitly as `TaskError::Database { source: e }` for clear error semantics. All other `map_err(|e| e.to_string())` callsites in src/ui/ were reviewed and left unchanged — they are in UI-local validation functions (clipboard, form validation, address generation) that do not feed into the backend task error system. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: remove useless TaskError::from conversions in wallet task dispatch (#660) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: fix all unresolved review comments — proof errors, asset lock, format! migrations (#740) * Initial plan * refactor: add typed TaskError variants, eliminate Generic from backend_task files Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * refactor: eliminate Result<T,String> from context/transaction_processing, add typed TaskError variants Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * refactor: migrate context/wallet_lifecycle.rs from Result<T,String> to Result<T,TaskError> Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * refactor: add source_error to ProofError, add log_drive_proof_error helper, migrate token tasks to TaskError Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * refactor: replace TaskError::Internal with granular variants, migrate identity tasks to TaskError Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * style: apply cargo +nightly fmt to fix CI formatting failures Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * refactor: fix all unresolved review comments (Claude + lklimek) Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * refactor: remove TaskError::Generic and TaskError::Other, replace with specialized variants (#744) * Initial plan * refactor: remove TaskError::Generic and TaskError::Other, add specialized variants - Remove Generic(String) and Other(Box<dyn Error>) variants from TaskError - Add SerializationError, IdentifierParsingError, IdentityCreationError, InvalidPrivateKey, DpnsFetchError, AssetLockNotValidForWallet, AssetLockInstantLockExpiredNotChainlocked, PlatformFetchError variants - Update From<String> bridge to map to UserInput instead of Generic - Replace TaskError::Generic("Identity not found") with IdentityNotFoundLocally - Replace TaskError::Generic("Contract not found") with DataContractNotFound - Replace TaskError::Generic(e.to_string()) for bincode with SerializationError - Fix instant-lock fallback to use Debug repr instead of Display for string matching - Fix poisoned lock spinning in transaction_processing.rs - Fix silently dropped wallet locks in load_identity.rs and load_identity_by_dpns_name.rs - Change contract_token_db::remove_wallet to return TaskError instead of String - Use typed variants in register_identity.rs and top_up_identity.rs - Use ? operator for lock errors in core/mod.rs Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * refactor: address remaining PR 739 review comments - Fix wallet removal atomicity: acquire write lock before DB removal - Fix proof-log write failures: warn instead of silently dropping - Fix domain jargon in AssetLock* error messages (no "asset lock", "instant lock") - Fix token metadata update atomicity: use upsert instead of remove+insert Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * refactor: address code review comments - improve error messages and add TODO notes Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * refactor: replace UserInput catch-all with granular DashCoreStartError, OperationNotAvailableOnNetwork, and LegacyError variants Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * refactor: improve DashCoreStartError message and simplify OperationNotAvailableOnNetwork display Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * refactor: address PR #739 review comments — structural error matching, lock poisoning cleanup, parameterized RequestType - Parameterize `log_drive_proof_error` with `RequestType` instead of hardcoding `BroadcastStateTransition` (26 callsites across 15 files) - Replace all `map_err` to `LockPoisoned` with `?` operator using blanket `From<PoisonError<T>>` impl; add doc comment explaining the intentional design - Change `CreditCalculationOverflow` variant to carry raw data fields (`amount`, `credits_per_duff`) instead of pre-formatted text - Add `TaskError::AssetLockInstantLockProofInvalid` variant with structural SDK error matching, replacing fragile `format!("{:?}").contains(...)` in register_identity and top_up_identity - Replace `StaleNode` string matching with structural `Error::StaleNode(_)` match in contested names queries - Add `is_unique_constraint_violation()` helper for SQLite error matching in import_mnemonic_screen - Fix wrong error variant: `DocumentNotFound` → `DataContractNotFound` in update_token_config - Add TODO for `BroadcastError(String)` pending `ScreenLike::display_message` trait redesign Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: address remaining PR #739 review comments — lock poisoning, error interpolation, StaleNode matching - Remove all remaining explicit `map_err` to `LockPoisoned` across 10 files, using `?` with blanket `From<PoisonError<T>>` impl - Fix `context/mod.rs` sites returning `Result<_, String>` to use `TaskError::from(e).to_string()` instead of discarding resource info - Add `StaleNode` structural matching to `query_dpns_vote_contenders.rs` for consistency with `query_dpns_contested_resources.rs` - Interpolate `operation` and `allowed_networks` fields in `OperationNotAvailableOnNetwork` error message - Narrow `is_unique_constraint_violation` to check `extended_code: 2067` (SQLITE_CONSTRAINT_UNIQUE) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: address final PR #739 review comments — jargon removal, dual signal fix - Replace protocol jargon ("asset lock", "instant lock proof", "chain lock proof") with user-friendly language in three TaskError Display messages per CLAUDE.md error guidelines - Fix dual success+error signal in register_contract.rs: return Ok(ContractSavedAfterProofError) instead of sending success via channel then returning Err(ProofError) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: add 6 new TaskError variants for LegacyError removal Add PlatformInfoFetchError, EncryptionError, WalletDatabasePersistError, AvatarProcessingError, MasterKeyNotFound, and TokenQueryError variants to prepare for removing From<String> and LegacyError. Also fix test assertion for updated jargon-free error message. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: migrate system/grovestark/mnlist/platform_info to TaskError Replace Result<_, String> with Result<_, TaskError> in four domain dispatcher modules, eliminating reliance on From<String> for TaskError in these paths. - system_task: use ? on rusqlite errors (via #[from]) - grovestark: use ? on GroveSTARKError (via #[from]) - mnlist: replace .unwrap() on RwLock with proper error handling - platform_info: wrap SDK errors in TaskError::SdkError, use TaskError::Generic for document property extraction errors Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: remove From<String> for TaskError and LegacyError variant Remove the `impl From<String> for TaskError` bridge and `TaskError::LegacyError(String)` variant. All 45 files that relied on string-to-TaskError conversion now use typed variants. Migration patterns applied: - RwLock/Mutex `.map_err(|e| e.to_string())?` → bare `?` (From<PoisonError>) - rusqlite `.map_err(|e| e.to_string())?` → bare `?` (Database #[from]) - dashcore_rpc errors → bare `?` (From<dashcore_rpc::Error>) - SDK errors → bare `?` (From<SdkError>) - String literals → typed variants (UserInput, WalletNotFound, etc.) - Model/SPV boundary → .map_err(TaskError::UserInput) at callsite New variants used: PlatformInfoFetchError, EncryptionError, WalletDatabasePersistError, AvatarProcessingError, MasterKeyNotFound, TokenQueryError. 45 files changed, 859 insertions(+), 1000 deletions(-) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: address 16 review findings across error handling and conventions Error design (error.rs): - Remove dead AvatarProcessingError variant (CODE-004) - Add ContractSchemaMismatch variant for contested index (CODE-006) - Add WithdrawalDocumentParsingError variant for withdrawal parsing (CODE-007) - Route 9 platform_info.rs callsites through From<SdkError> classification (CODE-001) Correctness fixes: - Fix dual signal in update_data_contract: return Ok instead of send+Err (CODE-002) - Return Ok(None) instead of Err(QueryReturnedNoRows) in contract_token_db (CODE-003) P2P module: - Public API returns P2PError instead of String, enabling #[from] conversion (CODE-008) - Add ProtocolError variant for protocol violations instead of synthetic io::Error (CODE-009) Error message quality: - Rewrite ~20 DashPayError Display messages for Everyday User audience (PROJ-001) - Rewrite ConfigError::NoValidConfigs and WalletError::AddressError Display (PROJ-004) - Update CLAUDE.md rule 7: remove stale Generic references (PROJ-002) - Clarify i18n placeholder style in CLAUDE.md (PROJ-005) Mechanical improvements: - Replace explicit TaskError::Database{source:e} with ? via #[from] (CODE-010) - Replace ok_or_else with ok_or for unit-like TaskError variants (CODE-011) - Replace .unwrap() with .unwrap_or_else(|e| e.into_inner()) in identity_db (CODE-017) - Simplify lock poisoning double-conversion in context/mod.rs (CODE-018) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: replace `UserInput(String)` with typed `TaskError` variants (#751) * Initial plan * refactor: replace all UserInput usages with typed TaskError variants Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * refactor: improve error message clarity (reviewer feedback) Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * refactor: merge RPC/context variants, split NotTokenDistributionRecipient, use #[source] for typed errors Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * refactor: address review feedback on TaskError migration — jargon, transparent errors, variant cleanup (#753) * Initial plan * refactor: address all review feedback — transparent errors, IdentitySaveError, DpnsFetchError, CLAUDE.md Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * fix: resolve CI formatting failures (#754) * Initial plan * fix: run cargo +nightly fmt --all to fix CI formatting failures Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> * fix: address 3 PR review findings — error chain, transitional note, vote errors - DashPayError::SdkError: preserve error chain with #[source] Box<dash_sdk::Error> instead of stringifying to reason: String - CLAUDE.md rule 7: add transitional note acknowledging detail: String pattern - vote_on_dpns_name: route SDK errors through TaskError for user-friendly messages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address review round 4 — typed errors, dead code, lock safety - vote_on_dpns_name: use ContractSchemaMismatch instead of fake SdkError::Generic - core/mod.rs: migrate 7 payment functions from Result<_, String> to Result<_, TaskError> - load_identity_from_wallet: replace .unwrap() with ? on wallet RwLock operations - Remove dead UiError type (src/ui/error.rs) — zero usages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: strengthen error variant policy — never use String fields for user messages CLAUDE.md rule 7: replace transitional note with strict rule — error variants must not contain String fields that hold user-facing messages. Use #[source] with typed errors, or fieldless variants. Replace existing String-field variants when encountered. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Addresses all unresolved review comments from the previous
refactor: migrate ResultPR. Eliminates remainingformat!()error conversions, brittle string matching in UI, and panicking.expect()/.unwrap()calls.ContractSavedAfterProofError— remove UI string matchingAdded
BackendTaskSuccessResult::ContractSavedAfterProofError. Backend sends it via channel when a contract is fetched and saved after aDriveProofError. UI screens (register_contract_screen,update_contract_screen) now handle it indisplay_task_result→BroadcastStatus::Done, replacing the previous fragilemessage.contains("proof error logged, contract inserted into the database")check.put_new_identity_to_platform/top_up_identity— uselog_drive_proof_errorReplaced all inline
DriveProofErrormatch blocks (with manualinsert_proof_log_item+format!()) withself.log_drive_proof_error(e). Transition debug info now goes throughtracing::debug!rather than being wrapped in a fakeError::Genericpayload.AssetLockExpired— replace format! conversionsAll
TaskError::from(format!("Cannot use this asset lock yet..."))calls inregister_identity.rsandtop_up_identity.rsreplaced with the structuredTaskError::AssetLockExpired { tx_block_height, platform_height }variant.create_identifier()— replace.expect()DataContractNotFound— new variant, replaces misusedDocumentNotFoundupdate_token_configwas usingTaskError::DocumentNotFoundfor a missingDataContract. AddedTaskError::DataContractNotFoundand updated the call site.update_data_contract.rs— migrate 5 remainingformat!()conversionsmap_err(|_| "Failed to get nonce".to_string())?viaFrom<SdkError>map_err(|e| format!("Failed to send message: {}", e))InternalSendErrormap_err(|e: ProtocolError| format!(...))TaskError::from(SdkError::Protocol(e))map_err(|e| format!("Failed to sign..."))TaskError::from(SdkError::Protocol(e))map_err(|e| format!("Error inserting..."))?viaFrom<rusqlite::Error>load_identity_by_dpns_name.rs— remove.unwrap()andformat!()conversionswallet.read().unwrap()replaced withfilter_map+.read().ok(). Remaining SDK and DPNSformat!()errors migrated toTaskError::from(e)/TaskError::IdentityNotFound.sdk_error_user_messagefallback — strip raw SDK error from user-facing textThe wildcard arm no longer embeds
{error}(raw SDKDisplay) in the message shown to users. Returns a static string; full error chain available to developers via#[source]/ details panel.📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.