Skip to content

feat(swift-ios): link thread rows to pull requests - #5804

Open
saphid wants to merge 1 commit into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:t3code/show-thread-pull-request-links
Open

feat(swift-ios): link thread rows to pull requests#5804
saphid wants to merge 1 commit into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:t3code/show-thread-pull-request-links

Conversation

@saphid

@saphid saphid commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

What changed

  • Resolve each visible SwiftUI thread row's related pull request from the existing cached VCS status stream.
  • Show the matching PR as a native SwiftUI Link with the short #<number> label.
  • Accept only credential-free HTTP(S) destinations, preserve row selection for the row itself, and expose a separate accessibility action for the PR.

Why

The server already publishes pull-request metadata, but the SwiftUI thread list did not surface it. A manual VCS refresh invalidates the backend PR cache, so list rows use the existing status subscription instead; the source-control screen keeps its explicit refresh behavior.

Scope

This is one native SwiftUI change. Every changed file is under apps/swift-ios or its native tests. There are no apps/mobile, Expo, React Native, or bridge changes.

UI evidence

Owner baseline 0d0c77431c851ff31181fb5f1708f351e0c5e80c:

Thread row before the PR link

UI capture at fba2518d76761185499935255b74d1e725936dfd:

Thread row with the short PR link

Integrated simulator safe-destination smoke video — starts on the row and verifies the sanitized destination opens PR #5804 in Safari. The destination launch in this recording was invoked at the simulator OS level because the hosted cell hides nested SwiftUI controls from the semantic automation tree; it is not presented as coordinate-tap evidence.

Final head d56c1dcf937285609ca31b1c2462d14e9fdb47b9 changes only the cache-expiry behavior and its test after this capture; it does not alter the rendered row or link destination.

Evidence is Tailnet-only. The downloaded MP4 matched the source byte-for-byte (f9d14dbf581f6934b4833c39fcaa2ece0e32f11d7c5ccbca63b83afe32f2fa0f, 3,514,304 bytes, video/mp4).

Verification

  • Focused native tests: 25 passed, 0 failed, 0 skipped on iPhone 17 Pro simulator 4401D856-DE6C-4769-A649-468778C929F6.
  • apps/swift-ios/Scripts/ci-test.sh: 222 passed across 27 suites; TEST SUCCEEDED.
  • Integrated SwiftUI simulator pass against a disposable copied backend: #5804 rendered on the matching thread and the sanitized URL opened the actual PR.
  • Before/after screenshots and an interaction smoke video are linked above.
  • The diff is limited to apps/swift-ios and native Swift tests.

Macroscope's valid stale-cache finding was addressed by expiring successful lookup results after five minutes; the focused cache test now covers both success expiry and failure retry.

Independent cross-provider review was attempted with Claude Code 2.1.224 / Claude Opus 5 high, but Claude returned HTTP 429 before inference because the weekly quota was exhausted. No independent-model review is claimed.

Built with GPT-5.6 Sol high in T3 Code's Codex harness.

Note

Add pull request links to thread rows in the iOS workspace view

  • Thread rows in the home collection view now display a tappable pull request link (e.g. #1234 with an external-link icon) when a matching pull request is found for the thread's branch.
  • Pull request data is fetched asynchronously via projectFaviconClient.sourceControlStatus and cached per HomeThreadPullRequestLookupKey (keyed on environmentID, projectID, branch, and worktreePath); stale lookups are cancelled when rows leave the view.
  • HomeThreadPullRequestPresentation validates that the thread and PR branches match, the PR number is positive, and the URL passes a new safeExternalURL check (http/https only, no embedded credentials).
  • VoiceOver gains a custom action to open the pull request URL and the accessibility value includes the PR state.
  • Tests covering presentation validation, key equality, and unsafe URL rejection are added in HomeThreadMetadataTests.swift.

Macroscope summarized 5f5a76b.


Note

Low Risk
Scoped to Swift iOS list UI with explicit external URL sanitization; main caveat is extra per-visible-row VCS status fetches, mitigated by keyed caching and task cancellation.

Overview
Swift iOS home thread rows now surface linked pull requests from existing VCS status, without changing server or non-iOS clients.

FeaturePullRequest gains safeExternalURL, which only allows credential-free http/https URLs before anything is opened externally. HomeThreadPullRequestPresentation builds display data when the thread branch matches status and the PR URL passes that check.

The home UICollectionView coordinator loads PR metadata asynchronously via sourceControlStatus, caches results by checkout identity (environment, project, branch, worktree—not thread ID), cancels stale work when rows scroll away, and reconfigures cells when data arrives. FeatureThreadRow shows a compact #<number> Link in rich and slim layouts; hosted cells add a VoiceOver custom action so opening the PR does not steal the row’s “open task” behavior.

Focused tests cover URL rejection, branch matching, lookup-key stability across recycled row IDs, and accessibility copy.

Reviewed by Cursor Bugbot for commit 5f5a76b. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Aug 9, 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: 0c456ff2-f5ca-446c-8c5a-eb9662692da8

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

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.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 9, 2026
@saphid
saphid force-pushed the t3code/show-thread-pull-request-links branch 2 times, most recently from 230a113 to fba2518 Compare August 9, 2026 12:34
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:35
Comment thread apps/swift-ios/Features/Workspace/HomeThreadCollectionView.swift
@saphid
saphid force-pushed the t3code/show-thread-pull-request-links branch from fba2518 to d56c1dc Compare August 9, 2026 12:41
@macroscopeapp

macroscopeapp Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

New feature adding pull request links to thread rows, introducing new UI components, async loading logic, and user-facing behavior. Additionally, unresolved Cursor Bugbot findings identify potential issues with unbounded retry loops and stale cache behavior that warrant attention.

You can customize Macroscope's approvability policy. Learn more.

@saphid

saphid commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

@t3dotgg This SwiftUI PR is ready for your review. Its exact head is mergeable; repository/native CI, MacroScope, Cursor, and review-thread audits are clean with zero unresolved threads. The only red status is the unrelated Vercel marketing authorization check.

@t3dotgg
t3dotgg force-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54f Compare August 10, 2026 03:58
@saphid

saphid commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

Rebuilt as one focused commit on exact current Theo 5b7ee58f6. All cached-status protocol/accumulator/subscription/forced-refresh code that duplicated #5975 has been removed. This PR now contains only its unique user outcome: branch-matched, safe credential-free PR number/state presentation, compact #<number> ↗ link, recycled-row cleanup, preserved row selection, and VoiceOver value/custom action.

Verification on this exact Theo-based head:

Conflict classification: stale branch topology + duplicated foundation code, now removed. Unique feature remains wanted. Landing order: merge #5975 first so this UI consumes the cached subscription path; landing this first would remain correct but use the existing expensive refresh path. That is a dependency/performance concern, not a feature conflict.

Fresh direct Opus review is unavailable because the confirmed session quota returns HTTP 429 before inference; no independent verdict is claimed.

@saphid
saphid force-pushed the t3code/show-thread-pull-request-links branch from d56c1dc to 5f5a76b Compare August 10, 2026 12:44

@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 2 potential issues.

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 5f5a76b. Configure here.

reconfigureThreadRows(matching: key)
}
pullRequestTasks[key] = (token, task)
}

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.

Stale PR lookup cache

Medium Severity

loadPullRequestIfNeeded treats any stored HomeThreadPullRequestResolution as final, including .resolved(nil). While a checkout key stays visible, the row never refetches, so a missing PR can stay hidden and an existing #number or state can stay outdated after remote changes.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 5f5a76b. Configure here.

} catch {
guard let self, pullRequestTasks[key]?.token == token else { return }
pullRequestTasks[key] = nil
return

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.

Unbounded PR lookup retries

High Severity

On sourceControlStatus failure, the task entry is cleared and no cooldown is recorded. Visible working rows reconfigure about once per second, so loadPullRequestIfNeeded can immediately retry and call refreshVCSStatus, which also invalidates the server PR-lookup cache.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 5f5a76b. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 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