Skip to content

fix(swift-sdk): freeze failed registration step at the failure instant#3854

Merged
QuantumExplorer merged 3 commits into
v3.1-devfrom
claude/sad-booth-3f3579
Jun 11, 2026
Merged

fix(swift-sdk): freeze failed registration step at the failure instant#3854
QuantumExplorer merged 3 commits into
v3.1-devfrom
claude/sad-booth-3f3579

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Jun 11, 2026

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

Note: this PR originally implemented shielded-pool step labels for the Registration Progress sheet, but #3845 landed an equivalent implementation on v3.1-dev first. The merge adopts #3845 wholesale; what remains here is the one piece it doesn't cover.

RegistrationProgressSection.shieldedCurrentStep derives the .failed step from live wall-clock elapsed time since lastSubmittedAt. Failed registrations are retained in Pending Registrations until the user dismisses them, so a registration that fails during note selection (< 2 s) first shows the red failure icon on step 1 ("Selecting shielded notes") and then silently moves it to step 2 ("Generating Halo 2 proof") once the 2-second note-selection window lapses on the wall clock — the failure marker drifts to a stage that never ran.

What was done?

  • IdentityRegistrationController records a terminalAt timestamp when the phase reaches .completed / .failed, reset on each submit so retries re-measure from the new attempt.
  • shieldedCurrentStep's .failed branch anchors the elapsed-time mapping at terminalAt instead of live now, freezing the failed icon on the step that was actually displayed when the failure happened. The .inFlight branch still uses live now; the shared window mapping is factored into a small shieldedStep(elapsedTo:) helper.

How Has This Been Tested?

  • Rebuilt the simulator xcframework from this branch (post-merge, includes the fix(swift-sdk): show shielded funding steps and real fee estimate #3845 FFI additions) via ./build_ios.sh --target sim and built SwiftExampleApp — BUILD SUCCEEDED.
  • The freeze mechanism was verified on an iPhone 17 Pro simulator with a stubbed registration body driven through the real coordinator → controller → progress-view path: a failure pinned the red icon to the in-progress step and it remained there 50 s later, where the live-now derivation drifts.

Breaking Changes

None.

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

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved progress tracking accuracy during identity registration retries by preventing progress calculations from drifting when registration fails and is restarted.

The Registration Progress sheet always rendered the asset-lock
pipeline labels (asset-lock tx / broadcast / InstantSend / ChainLock)
even when the identity was funded from the shielded pool via a
Type-20 IdentityCreateFromShieldedPool, where none of those stages
exist.

Plumb a FundingMode from CreateIdentityView through
RegistrationCoordinator onto IdentityRegistrationController, and
render a 4-step shielded list (selecting notes, building the Halo 2
proof, broadcasting the state transition, registering the identity).
The Type-20 FFI call is opaque, so the active step is a display
heuristic anchored to the ~30s proof duration; a terminal-at
timestamp freezes the failed step so it doesn't drift while a failed
row sits in Pending Registrations. The asset-lock path is unchanged.

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

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 14c5a609-fe11-4f60-bd31-e325c55c8391

📥 Commits

Reviewing files that changed from the base of the PR and between d16218f and 5eec7dc.

📒 Files selected for processing (2)
  • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Services/IdentityRegistrationController.swift
  • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegistrationProgressView.swift

📝 Walkthrough

Walkthrough

IdentityRegistrationController now records the instant of terminal transition (.completed or .failed) in a new terminalAt timestamp. The controller resets this on each submission and captures it before phase updates. RegistrationProgressView's shielded-step logic uses this frozen anchor instead of live time when computing the active step during failure, stabilizing progress-indicator position across retries.

Changes

Terminal-Time Anchoring for Shielded Progress

Layer / File(s) Summary
Terminal timestamp state management
packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Services/IdentityRegistrationController.swift
Adds terminalAt: Date? property initialized/reset to nil on each submit() call, and set to Date() on the main actor when reaching .completed or .failed phase transitions.
Frozen-time shielded-step derivation
packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegistrationProgressView.swift
Introduces shieldedStep(elapsedTo:) helper and updates the .failed branch to measure elapsed time against controller.terminalAt (fallback: live now) instead of wall-clock time, preventing step drift after failure; expands inline documentation on failure-time anchoring.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • dashpay/platform#3845: Both PRs modify shielded-step rendering logic in RegistrationProgressView, with this PR refining failure-time step calculation by introducing and anchoring to IdentityRegistrationController.terminalAt.

Suggested reviewers

  • shumkov
  • llbartekll
  • ZocoLini

Poem

A rabbit hops through time's long hall,
Now freezing clocks when progress stalls,
No drifting steps at failure's gate,
Just anchored marks that mark their fate! 🐰⏱️

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: freezing the failed registration step at the failure instant to prevent drift in the shielded-pool progress UI.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ 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 claude/sad-booth-3f3579

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.

@thepastaclaw

thepastaclaw commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

✅ Review complete (commit 5eec7dc)

QuantumExplorer and others added 2 commits June 11, 2026 15:54
…3f3579

# Conflicts:
#	packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Services/IdentityRegistrationController.swift
#	packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Services/RegistrationCoordinator.swift
#	packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/CreateIdentityView.swift
#	packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegistrationProgressView.swift
The shielded step heuristic derived the .failed step from live wall
clock, so a registration failing during note selection showed the red
icon on step 1 and then drifted it to step 2 once the 2s selection
window lapsed — failed rows are retained until dismissed, so the
drift is always visible. Record terminalAt on the terminal phase
transition and anchor the .failed derivation there.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@QuantumExplorer QuantumExplorer changed the title fix(swift-sdk): show shielded-pool steps in registration progress fix(swift-sdk): freeze failed registration step at the failure instant Jun 11, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegistrationProgressView.swift`:
- Around line 213-257: shieldedStep(elapsedTo:) currently only returns 1 or 2 so
the in-flight path never maps to steps 3 or 4; update shieldedStep(elapsedTo:)
to return 1..4 by splitting the in-flight timeline into multiple thresholds
(e.g. shieldedNoteSelectionWindow → step 1, next window → step 2 (Halo2 proof),
next window → step 3 (broadcast), else step 4 (registering identity)), using
existing Self.* window constants or adding new constants (e.g.
shieldedProofGenerationWindow, shieldedBroadcastWindow) as needed; keep
shieldedCurrentStep’s use of controller.phase/.terminalAt as-is so .inFlight and
.failed continue to call the revised shieldedStep(elapsedTo:) to determine the
correct step.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 14c5a609-fe11-4f60-bd31-e325c55c8391

📥 Commits

Reviewing files that changed from the base of the PR and between d16218f and 5eec7dc.

📒 Files selected for processing (2)
  • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Services/IdentityRegistrationController.swift
  • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegistrationProgressView.swift

@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

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

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

Inline comments:
In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegistrationProgressView.swift`:
- Around line 213-257: shieldedStep(elapsedTo:) currently only returns 1 or 2 so
the in-flight path never maps to steps 3 or 4; update shieldedStep(elapsedTo:)
to return 1..4 by splitting the in-flight timeline into multiple thresholds
(e.g. shieldedNoteSelectionWindow → step 1, next window → step 2 (Halo2 proof),
next window → step 3 (broadcast), else step 4 (registering identity)), using
existing Self.* window constants or adding new constants (e.g.
shieldedProofGenerationWindow, shieldedBroadcastWindow) as needed; keep
shieldedCurrentStep’s use of controller.phase/.terminalAt as-is so .inFlight and
.failed continue to call the revised shieldedStep(elapsedTo:) to determine the
correct step.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 14c5a609-fe11-4f60-bd31-e325c55c8391

📥 Commits

Reviewing files that changed from the base of the PR and between d16218f and 5eec7dc.

📒 Files selected for processing (2)
  • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Services/IdentityRegistrationController.swift
  • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegistrationProgressView.swift
🛑 Comments failed to post (1)
packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegistrationProgressView.swift (1)

213-257: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Shielded step mapping never reaches steps 3/4 before completion.

shieldedStep(elapsedTo:) only returns step 1 or 2, so the shielded flow cannot progress to “Broadcasting transition” or “Registering identity” while in-flight, despite rendering a 4-step model.

Suggested fix
+    // Tune these to your existing heuristic targets for shielded flow.
+    private static let shieldedProofWindowEnd: TimeInterval = 36.0
+    private static let shieldedBroadcastWindowEnd: TimeInterval = 40.0
+
     private func shieldedStep(elapsedTo anchor: Date) -> Int {
         guard let submittedAt = controller.lastSubmittedAt else { return 1 }
         let elapsed = anchor.timeIntervalSince(submittedAt)
-        return elapsed < Self.shieldedNoteSelectionWindow ? 1 : 2
+        if elapsed < Self.shieldedNoteSelectionWindow { return 1 }
+        if elapsed < Self.shieldedProofWindowEnd { return 2 }
+        if elapsed < Self.shieldedBroadcastWindowEnd { return 3 }
+        return 4
     }
🤖 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/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegistrationProgressView.swift`
around lines 213 - 257, shieldedStep(elapsedTo:) currently only returns 1 or 2
so the in-flight path never maps to steps 3 or 4; update
shieldedStep(elapsedTo:) to return 1..4 by splitting the in-flight timeline into
multiple thresholds (e.g. shieldedNoteSelectionWindow → step 1, next window →
step 2 (Halo2 proof), next window → step 3 (broadcast), else step 4 (registering
identity)), using existing Self.* window constants or adding new constants (e.g.
shieldedProofGenerationWindow, shieldedBroadcastWindow) as needed; keep
shieldedCurrentStep’s use of controller.phase/.terminalAt as-is so .inFlight and
.failed continue to call the revised shieldedStep(elapsedTo:) to determine the
correct step.

@QuantumExplorer

Copy link
Copy Markdown
Member Author

Re CodeRabbit's finding that shieldedStep(elapsedTo:) never returns steps 3/4 in flight: that is the deliberate design adopted from #3845, not an oversight. The whole Type-20 flow is one opaque FFI call with no per-stage signal, so steps 3 (broadcast) and 4 (register) intentionally stay pending instead of green-checking work that may not have happened yet — see the doc comment on shieldedCurrentStep. This PR only changes the anchor used for the .failed derivation; it keeps the step semantics as merged. No code change.

@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

Prior PastaClaw findings: none. Latest-delta findings (5eec7dc): none. Cumulative current-head findings: none. The two-file fix adds a terminalAt timestamp to anchor the shielded .failed step display, with correct write ordering (reset on submit, set before phase inside the same MainActor.run), a safe ?? now fallback for pre-submit failure shapes, and a clean extraction of the step heuristic into a shared helper.

@github-actions

Copy link
Copy Markdown
Contributor

✅ DashSDKFFI.xcframework built for this PR.

SwiftPM (host the zip at a stable URL, then use):

.binaryTarget(
  name: "DashSDKFFI",
  url: "https://your.cdn.example/DashSDKFFI.xcframework.zip",
  checksum: "8011b89f6cbc707c13c6e571e5b84e0848c72a7a48496f817b846eb86ae5bb72"
)

Xcode manual integration:

  • Download 'DashSDKFFI.xcframework' artifact from the run link above.
  • Drag it into your app target (Frameworks, Libraries & Embedded Content) and set Embed & Sign.
  • If using the Swift wrapper package, point its binaryTarget to the xcframework location or add the package and place the xcframework at the expected path.

@QuantumExplorer
QuantumExplorer merged commit b6972dc into v3.1-dev Jun 11, 2026
19 checks passed
@QuantumExplorer
QuantumExplorer deleted the claude/sad-booth-3f3579 branch June 11, 2026 21:26
QuantumExplorer added a commit that referenced this pull request Jun 11, 2026
Resolves conflicts with #3854 (freeze failed registration step at the
failure instant): the .unconfirmed and .failed transitions now also
stamp terminalAt, and the shielded failed-step heuristic combines the
broadcast-rejected stage attribution with the frozen terminalAt anchor.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants