Skip to content

fix(platform-wallet): make post-acceptance identity bookkeeping best-effort#4011

Merged
QuantumExplorer merged 1 commit into
v4.1-devfrom
fix/register-identity-post-acceptance-warn
Jul 5, 2026
Merged

fix(platform-wallet): make post-acceptance identity bookkeeping best-effort#4011
QuantumExplorer merged 1 commit into
v4.1-devfrom
fix/register-identity-post-acceptance-warn

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Jul 5, 2026

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

PR #4008 made post-acceptance add_identity best-effort (warn, not ?) in the address-funded register_from_addresses flow. The sibling asset-lock flows in identity/network/registration.rs still propagated post-acceptance failures with ?:

  • register_identity_with_funding — Step 4's get_wallet_info_mut(...).ok_or_else(...)? and info.identity_manager.add_identity(...)? both ran after Platform accepted the IdentityCreate.
  • top_up_identity_with_funding — Step 4's get_wallet_info_mut(...).ok_or_else(...)? ran after Platform accepted the top-up.

In both, an early Err there had two bad consequences:

  1. The app reported failure for an identity/credits that already exist on chain.
  2. The early return skipped Step 5's consume_asset_lock, leaving the spent lock in the Resumable Funding list. A user Resume then hits Platform's deterministic "lock already consumed" rejection — a dead-end for a lock that did its job.

What was done?

Converted both post-acceptance steps to the same warn-and-continue posture as register_from_addresses Step 3 (#4008):

  • get_wallet_info_mut returning Nonetracing::warn! and skip local persistence instead of returning WalletNotFound.
  • add_identity returning Err (register flow) → tracing::warn! and skip the key-breadcrumb stamping (an IdentityAlreadyExists may point at an out-of-wallet entry; stamping wallet_id without moving buckets would contradict the location index).
  • The flow now always falls through to consume_asset_lock, so the spent lock is cleaned up. Stale local state self-heals on the next identity re-sync.

Method doc-comment step lists updated to note the best-effort posture. Comment style mirrors register_from_addresses.rs Step 3.

How Has This Been Tested?

  • cargo fmt --all
  • cargo test -p platform-wallet — green (8 passed, 0 failed).

The unit-test module in registration.rs covers only the IS→CL timeout discriminator; exercising the post-acceptance path would require a live SDK submission mock the module doesn't set up, so — as with #4008's treatment of register_from_addresses — no unit test was added for this branch.

Breaking Changes

None. Local-only behavior change (error → warn); no consensus, serialization, or API surface change.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Identity registration and balance top-ups now complete successfully even if local bookkeeping or wallet-state saving fails after platform acceptance.
    • These non-critical failures are now handled as warnings, helping avoid unnecessary error returns.
    • Improved handling when wallet information is unavailable during post-acceptance updates.

…effort

`register_identity_with_funding` and `top_up_identity_with_funding` ran
their local IdentityManager bookkeeping (`get_wallet_info_mut(...)?` and
`add_identity(...)?`) with `?` AFTER Platform had already accepted the
registration/top-up. A failure there propagated as `Err`, so the app
reported failure for an identity/credits that exist on chain, and the
early return skipped the subsequent `consume_asset_lock` — stranding the
spent lock in the Resumable Funding list, where a Resume gets Platform's
deterministic "lock already consumed" rejection.

Convert both post-acceptance steps to warn-and-continue so the flow
reaches `consume_asset_lock`, matching the posture PR #4008 gave the
sibling `register_from_addresses` Step 3.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot added this to the v4.1.0 milestone Jul 5, 2026
@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Registration and top-up entry points in registration.rs now treat local IdentityManager updates and wallet-state persistence as best-effort after Platform acceptance. Failures to update or persist local bookkeeping log warnings instead of returning errors; documentation comments were updated accordingly.

Changes

Best-effort bookkeeping changes

Layer / File(s) Summary
Registration Step 4 best-effort update
packages/rs-platform-wallet/src/wallet/identity/network/registration.rs
register_identity_with_funding now conditionally updates the local IdentityManager only when wallet info exists, logs warnings instead of propagating errors on missing wallet info or add_identity failure, and continues to cleanup returning Ok(identity); docs updated to reflect this.
Top-up Step 4 best-effort update
packages/rs-platform-wallet/src/wallet/identity/network/registration.rs
top_up_identity_with_funding now conditionally updates the managed identity balance and persists wallet state only when local wallet info exists, logs warnings on missing wallet info or persistence failure instead of returning errors, and returns Ok(new_balance); docs updated to reflect this.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • dashpay/platform#4006: Both PRs modify register_identity_with_funding/top_up_identity_with_funding in registration.rs, adjusting the identity funding flow behavior.

Suggested labels: ready for final review

Suggested reviewers: lklimek, shumkov, llbartekll

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: making post-acceptance identity bookkeeping best-effort.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/register-identity-post-acceptance-warn

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.

@thepastaclaw

thepastaclaw commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

✅ Review complete (commit b3e4395)

@QuantumExplorer QuantumExplorer merged commit b2b30d5 into v4.1-dev Jul 5, 2026
17 of 18 checks passed
@QuantumExplorer QuantumExplorer deleted the fix/register-identity-post-acceptance-warn branch July 5, 2026 12:30

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
packages/rs-platform-wallet/src/wallet/identity/network/registration.rs (1)

503-527: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Silent skip when the managed identity is missing.

If get_wallet_info_mut returns Some(info) but managed_identity_mut(identity_id) returns None, the balance is neither updated nor persisted and nothing is logged. This can happen if the identity is removed between the Step 1 read-lock lookup and this Step 4 write-lock. The None wallet-info branch logs a warning, but this inner miss does not, leaving a stale local balance with no trace — inconsistent with the stated best-effort "log, don't propagate" posture.

🔎 Add an observability warning for the missing-managed-identity case
             Some(info) => {
                 if let Some(managed) = info.identity_manager.managed_identity_mut(identity_id) {
                     managed.identity.set_balance(new_balance);
                     if let Err(e) = self.persister.store(managed.snapshot_changeset().into()) {
                         tracing::error!(
                             identity = %identity_id,
                             error = %e,
                             "Failed to persist identity balance update after top_up"
                         );
                     }
+                } else {
+                    tracing::warn!(
+                        identity = %identity_id,
+                        "top_up_identity_with_funding: top-up accepted on Platform \
+                         but managed identity was not found locally; skipping balance \
+                         persistence"
+                    );
                 }
             }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/rs-platform-wallet/src/wallet/identity/network/registration.rs`
around lines 503 - 527, The top-up flow in
registration::top_up_identity_with_funding silently ignores the case where
get_wallet_info_mut returns Some(info) but
info.identity_manager.managed_identity_mut(identity_id) returns None. Add a
tracing::warn! in that inner None branch with the identity_id and enough context
to show the balance update was skipped after a successful Platform top-up,
matching the existing best-effort logging style used in the wallet-info-missing
branch. Keep the persistence path unchanged for the Some(managed) case, but make
sure the missing-managed-identity path is observable instead of silently leaving
the local balance stale.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/rs-platform-wallet/src/wallet/identity/network/registration.rs`:
- Around line 503-527: The top-up flow in
registration::top_up_identity_with_funding silently ignores the case where
get_wallet_info_mut returns Some(info) but
info.identity_manager.managed_identity_mut(identity_id) returns None. Add a
tracing::warn! in that inner None branch with the identity_id and enough context
to show the balance update was skipped after a successful Platform top-up,
matching the existing best-effort logging style used in the wallet-info-missing
branch. Keep the persistence path unchanged for the Some(managed) case, but make
sure the missing-managed-identity path is observable instead of silently leaving
the local balance stale.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7d15df93-4d87-44e3-aaa8-4945518d9b4e

📥 Commits

Reviewing files that changed from the base of the PR and between 56f37ac and b3e4395.

📒 Files selected for processing (1)
  • packages/rs-platform-wallet/src/wallet/identity/network/registration.rs

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Code Review

Well-scoped follow-up to #4008 that converts two post-acceptance ? sites in the asset-lock-funded register/top-up flows into warn-and-continue, so consume_asset_lock runs and the spent lock is not stranded. No consensus, serialization, proof, or FFI surface is touched. Verified against b3e4395: IdentityManager::add_identity does raise IdentityAlreadyExists for both buckets, but the OOW-collision path is speculative for freshly-registered identities and the PR is a strict improvement over the prior stranded-lock behavior. Two observability suggestions worth surfacing; no in-scope blockers.

Source: reviewers claude/opus (general), codex/gpt-5.5 (general), claude/opus (rust-quality), codex/gpt-5.5 (rust-quality); verifier claude/opus; specialists: rust-quality.

🟡 1 suggestion(s) | 💬 1 nitpick(s)

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

In `packages/rs-platform-wallet/src/wallet/identity/network/registration.rs`:
- [SUGGESTION] packages/rs-platform-wallet/src/wallet/identity/network/registration.rs:312-324: Step 4 Err arm swallows every add_identity failure, not just IdentityAlreadyExists
  The catch-all `Err(e)` arm at line 312 warns and continues for every error from `add_identity`, but the inline justification comment only reasons about `IdentityAlreadyExists`. Two consequences worth acknowledging in the comment or the match shape:

  1. `add_identity` returns `IdentityAlreadyExists` whether the pre-existing entry is in the wallet-owned bucket *or* the out-of-wallet bucket (verified: `lifecycle.rs:45` guards on `self.identity(...).is_some()`, and `accessors.rs:21-32` scans both buckets). For the out-of-wallet duplicate case, this PR now returns `Ok(identity)` while `location_index` still reports `OutOfWallet`, so a follow-up `top_up_identity_with_funding` on the same id will fail with `IdentityIndexNotSet` (`identity_index` returns `None` for the OOW discriminant at `lifecycle.rs:144-149`). The comment claims this self-heals on re-sync, but the current refresh/discovery paths mutate the existing managed identity rather than moving buckets, so it does not.
  2. For non-`IdentityAlreadyExists` variants (e.g. an internal persister propagation error surfaced by a future signature change), silently swallowing is not obviously the desired posture — the location-index reasoning does not apply.

  Either discriminate on the error variant (promote/replace on `IdentityAlreadyExists` with an OutOfWallet location; propagate — or at least error-level log — the rest) or expand the comment so future maintainers know the catch-all is deliberate for reasons beyond the location-index invariant. Not blocking because the register-funded fresh-identity path where a same-id OOW entry already exists is a narrow scenario, and this PR is a strict improvement over the previous behavior that stranded the asset lock.

- [NITPICK] packages/rs-platform-wallet/src/wallet/identity/network/registration.rs:505-527: Top-up Step 4 silently no-ops when managed identity is missing under the write lock
  When `wm.get_wallet_info_mut(&self.wallet_id)` returns `Some(info)` but `info.identity_manager.managed_identity_mut(identity_id)` returns `None` (line 507), the `if let Some(managed)` block exits without logging. That's the case where the identity was present at Step 1 under the read lock but disappeared before Step 4 acquired the write lock — Platform accepted the top-up and the new balance is dropped with no operator signal. The outer `None` arm at line 518 warns; the inner `None` case should too, matching the register-flow style ("top-up accepted on Platform but managed identity vanished locally; skipping balance persistence"). Small, but the PR's stated posture is that every post-acceptance skip is logged.

Comment on lines +312 to +324
Err(e) => {
// Breadcrumbs are skipped too: `IdentityAlreadyExists`
// can mean an out-of-wallet entry, and stamping
// `wallet_id` on one without moving buckets would
// contradict the manager's location index.
tracing::warn!(
error = %e,
identity_id = %identity.id(),
"register_identity_with_funding: identity registered on \
Platform but local add_identity failed; continuing so \
the spent asset lock is still consumed"
);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟡 Suggestion: Step 4 Err arm swallows every add_identity failure, not just IdentityAlreadyExists

The catch-all Err(e) arm at line 312 warns and continues for every error from add_identity, but the inline justification comment only reasons about IdentityAlreadyExists. Two consequences worth acknowledging in the comment or the match shape:

  1. add_identity returns IdentityAlreadyExists whether the pre-existing entry is in the wallet-owned bucket or the out-of-wallet bucket (verified: lifecycle.rs:45 guards on self.identity(...).is_some(), and accessors.rs:21-32 scans both buckets). For the out-of-wallet duplicate case, this PR now returns Ok(identity) while location_index still reports OutOfWallet, so a follow-up top_up_identity_with_funding on the same id will fail with IdentityIndexNotSet (identity_index returns None for the OOW discriminant at lifecycle.rs:144-149). The comment claims this self-heals on re-sync, but the current refresh/discovery paths mutate the existing managed identity rather than moving buckets, so it does not.
  2. For non-IdentityAlreadyExists variants (e.g. an internal persister propagation error surfaced by a future signature change), silently swallowing is not obviously the desired posture — the location-index reasoning does not apply.

Either discriminate on the error variant (promote/replace on IdentityAlreadyExists with an OutOfWallet location; propagate — or at least error-level log — the rest) or expand the comment so future maintainers know the catch-all is deliberate for reasons beyond the location-index invariant. Not blocking because the register-funded fresh-identity path where a same-id OOW entry already exists is a narrow scenario, and this PR is a strict improvement over the previous behavior that stranded the asset lock.

source: ['claude', 'codex']

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.

2 participants