Skip to content

feat(swift-ios): keep failed source control output visible with accessible Retry - #7371

Open
saphid wants to merge 5 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:feat/issue87-tool-error-recovery
Open

feat(swift-ios): keep failed source control output visible with accessible Retry#7371
saphid wants to merge 5 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:feat/issue87-tool-error-recovery

Conversation

@saphid

@saphid saphid commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Observed problem and reproduction

Open SwiftUI Source Control, let repository status load, then trigger an operation that fails. Before this change, the surface could keep showing stale repository content while silently discarding the recoverable error. There was no operation-specific Retry and no predictable VoiceOver focus.

Cause

Load and mutation failures shared transient view state. The client also hid a follow-up status refresh inside the mutation call, so a refresh failure could be mistaken for mutation failure and retry a completed non-idempotent action.

Change and boundary

A retained failure banner stays above existing repository content and keeps its message while Retry runs. Retry replays the exact failed operation, including commit text. Cancellation does not create a failure. Successful recovery clears the matching failure with one accessibility announcement.

Source-control mutations and their follow-up status refresh now have separate failure boundaries. If the mutation completes and refresh fails, Retry reloads status only. A single-flight state prevents overlapping load, action, and retry races. Long error text scrolls within a capped region so Dynamic Type cannot push Retry off screen.

Conflict resolution used a merge of the live t3code/rebuild-mobile-app-swift target at 22b22f146 into the contributor branch. The resolution preserves the target's new source-control status event stream and re-expresses only this PR's separate mutation/refresh boundary.

Non-goals

This PR does not change git command semantics, server contracts, provider adapters, web, desktop, or React Native mobile. It does not retry automatically or hide the original failure cause.

Affected areas

  • Affected client: SwiftUI mobile Source Control view, recovery value types, FeatureClient mutation boundary, and native client implementation.
  • Platform: iOS simulator.
  • Providers: none.
  • Contracts/connections: no wire change; local runtime proof only.
  • States: load failure, action failure, cancellation, repeat failure, successful matching recovery, unrelated success, post-action refresh failure, and overlapping-operation rejection.

Validation

Current head: 87ce6873a.

  • Focused FeatureToolRecoveryTests: 20 passed, 0 failed, 0 skipped; real xcodebuild exit 0 on iPhone 17 Pro / iOS 26.5 with isolated private DerivedData. The result bundle confirms 20 matched test cases.
  • xcrun swiftc -parse on all six touched Swift files: passed, exit 0.
  • git diff --check: passed, exit 0.
  • Final diff against live target 22b22f146: exactly the intended six Swift files; 641 additions and 61 deletions.
  • The conflict-resolved build exposed and removed the target's now-obsolete transient errorMessage alert, which had been superseded by this PR's retained recovery banner.
  • The earlier full native bundle recorded 374 passed and one pre-existing environment-gated skip. It was not rerun after the conflict resolution.

Risks, untested paths, and known gaps

  • The change affects non-idempotent source-control action boundaries. Current-head focused coverage includes the completed-mutation plus failed-refresh case so Retry cannot repeat commit, push, pull, or PR creation.
  • The full native bundle was not rerun on the final head.
  • Remote, relay, and tunnel runtime behavior was not exercised.
  • Known gaps (Virtualize branch picker list and forward ComboboxList ref #150): refreshed current-head light/dark proof, interaction video, and any claimed full native-suite result are pending; the evidence below is retained pre-merge evidence from 47389c712 and must not be treated as exact-head proof. Human review has not been re-requested.

Evidence

The following media was captured on pre-merge head 47389c712. It remains useful for historical comparison but is not current-head proof.

Before, healthy repository in light appearance

Healthy source-control state in light appearance

Before, healthy repository in dark appearance

Healthy source-control state in dark appearance

After, retained failure and Retry in light appearance

Retained source-control failure with Retry in light appearance

After, retained failure and Retry in dark appearance

Retained source-control failure with Retry in dark appearance

Interaction video

Source-control failure, Retry, and recovery

Play or download the MP4.

Owning issue and stack

Owning issue: saphid/t3code-personal#87. Exact-head proof is tracked by saphid/t3code-personal#150. This PR targets the open SwiftUI parent branch and depends on #5178 landing. It is not stacked on #7345. Maintainer edits are enabled.

Note

Add persistent failure banner with accessible Retry to source control UI

  • Replaces transient alert-based error messaging in FeatureSourceControlView with a retained failure banner that shows a scroll-limited message and an accessible Retry button that replays the exact failed operation (including commit messages)
  • Adds a reusable recovery infrastructure in FeatureToolRecovery.swift: FeatureToolFailureState manages cancellation-aware failure state with one-time recovery announcements, FeatureToolRunState prevents overlapping operations via single-flight, and FeatureRecoverableOperation protocol models retryable operations
  • Shifts accessibility focus to failure content on error and back to content on recovery, announcing success exactly once
  • Changes performSourceControlAction on FeatureClient protocol and NativeFeatureClient to return Void instead of FeatureSourceControlStatus; callers now refresh status themselves after mutations
  • Behavioral Change: conformers of FeatureClient.performSourceControlAction must drop the return value; the source control view now performs an explicit post-action status refresh rather than relying on the method's return value

Macroscope summarized 87ce687.

@github-actions github-actions Bot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Aug 18, 2026
@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f68ddd95-d8eb-4430-b3d9-f721e3989029

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@github-actions github-actions Bot added the size:L 100-499 changed lines (additions + deletions). label Aug 18, 2026
Comment thread apps/swift-ios/Features/Shared/FeatureToolRecovery.swift Outdated
@macroscopeapp

macroscopeapp Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This introduces a new production recovery workflow for source-control operations, including persistent failure UI, accessibility focus management, single-flight state, and Retry for side-effectful actions. It also changes the mutation and status-refresh boundary, so the scope and runtime behavior warrant human review.

You can add or adjust custom eligibility rules. Learn more.

@t3dotgg
t3dotgg force-pushed the t3code/rebuild-mobile-app-swift branch from 1f39d72 to fce7740 Compare August 18, 2026 21:35
…sible Retry

Recoverable source-control failures were invisible whenever a repository
status had already loaded: the error string only ever reached the
ContentUnavailableView fallback, so a failed commit, push, pull, or pull
request silently did nothing. There was also no way to retry the exact
failed operation and no accessibility focus handling.

Retain the failure content in a banner that survives its own retry, keep a
stable "Retry <operation>" accessibility label, replay the failed operation
with its commit message, move VoiceOver focus to the retained failure and
back to the refreshed repository status on recovery, and stop treating
cancellation as a failure.
@saphid
saphid force-pushed the feat/issue87-tool-error-recovery branch from 73a4932 to 27a897e Compare August 18, 2026 22:23
@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 21, 2026

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 42696d5. Configure here.

Comment thread apps/swift-ios/Features/Shared/FeatureToolRecovery.swift
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant