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

Closed
saphid wants to merge 5 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:t3code/show-thread-pull-request-links
Closed

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

Conversation

@saphid

@saphidsaphid 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 home view

  • Thread rows in the home collection view now display a tappable pull request badge that opens the PR in the system browser, with full accessibility labeling and a custom accessibility action.
  • The coordinator in HomeThreadCollectionView.swift asynchronously resolves source control status per thread, caches results for 5 minutes, and throttles failed lookups for 10 seconds.
  • HomeThreadPullRequestPresentation in WorkspaceView.swift validates PR data before surfacing it: branch must match, PR number must be positive, and the URL must be a credential-free http/https link with a host.
  • Provider resolution in homeProviderLabel and HomeThreadRowContext.index now falls back to the global providers list when providersByEnvironment is absent, fixing cases where the provider ID was shown instead of its name.

Macroscope summarized b499d83.


Note

Low Risk
SwiftUI-only home list UX with URL sanitization and tests; provider fallback change is a targeted correctness fix with no auth or data-path changes.

Overview
Home thread rows now asynchronously resolve and show a tappable PR badge (#<number>) when source-control status matches the thread’s branch.

The home collection coordinator loads status via sourceControlStatus, keys lookups by checkout (not thread id), caches successes for five minutes with failure backoff, and cancels/prunes work when rows scroll off or the view dismantles. HomeThreadPullRequestPresentation only surfaces PRs with matching branches and safeExternalURL (credential-free http/https). Rich and slim rows get a SwiftUI Link; VoiceOver gets PR text plus a custom action to open the PR in Safari.

Provider resolution no longer falls back to legacy snapshot.providers when providersByEnvironment exists but omits the thread’s environment—avoiding wrong harness labels across devices.

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

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable with runnable checks green; requested review changes remain. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot 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: 91e26d0e-e692-4c1b-ba90-32b8829c33de

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-actionsgithub-actionsBot 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
saphidforce-pushed the t3code/show-thread-pull-request-links branch 2 times, most recently from 230a113 to fba2518CompareAugust 9, 2026 12:34
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:35
@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fba2518 to d56c1dcCompareAugust 9, 2026 12:41
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. New feature adding pull request links to thread rows with async data loading and caching. Multiple unresolved comments identify potential bugs in cache expiration and retry logic. A Medium-severity finding about provider fallback logic also requires attention.

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

@saphid

Copy link
Copy Markdown
ContributorAuthor

@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
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@saphid

Copy link
Copy Markdown
ContributorAuthor

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
saphidforce-pushed the t3code/show-thread-pull-request-links branch from d56c1dc to 5f5a76bCompareAugust 10, 2026 12:44

@t3-codet3-codeBot 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.

the current head still has two blocking cache behaviors in the new per-row PR lookup.

@@ -325,6 +360,51 @@ struct HomeThreadCollectionView: UIViewRepresentable {
}
}

private func loadPullRequestIfNeeded(for thread: FeatureThread) {
guard let key = HomeThreadPullRequestLookupKey(thread: thread),
pullRequestResolutions[key] == nil,

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.

successful lookups, including nil, are cached forever for the coordinator lifetime. a newly created PR or later state/title change therefore never appears while the row remains active. store a timestamp and expire resolved entries so visible rows can refresh.

let status = try await client.sourceControlStatus(threadID: thread.id)
presentation = HomeThreadPullRequestPresentation(thread: thread, status: status)
} catch {
guard let self, pullRequestTasks[key]?.token == token else { 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.

on failure the task entry is cleared with no failure resolution or retry deadline. working rows reconfigure frequently, so this can immediately launch another sourceControlStatus call and keep retrying. record a cooldown/backoff entry before allowing another lookup.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Updated frozen head: fc5786d11. The cache now uses a 5-minute success/nil TTL and a 10-second failure cooldown. Focused native verification passed 10 tests with 0 failures and 0 skips. Durable result bundle: ~/Library/Developer/XcodeBuildMCP/workspaces/t3code-8f2a7900-7e7011b508e2/result-bundles/test_sim_2026-08-13T15-16-08-673Z_pid9862_c66bcad9.xcresult. Two earlier static reviews reported no actionable findings. A fresh direct Claude Opus 5 high review attempt exited 1 because the session quota was exhausted and produced no report; no fresh cross-provider review is claimed.

@cursorcursorBot 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 fc5786d119b00eac24269bdbcfa9772ad63c370d. Configure here.

@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fc5786d to 0abd88cCompareAugust 13, 2026 15:39
@saphid

Copy link
Copy Markdown
ContributorAuthor

Refreshed this branch onto current t3code/rebuild-mobile-app-swift (f98cab553) and repaired the provider-catalog compatibility failure from the merge build.

The environment-specific provider catalog remains authoritative when present. Legacy snapshots now fall back to snapshot.providers when no per-environment catalog exists.

Verification on exact head 0abd88c5989f35c6fa4fbabf54700aedbe945da1:

  • Swift parse: passed
  • diff check: passed
  • focused native HomeThreadMetadataTests: 10 passed, 0 failed
  • result bundle: test_sim_2026-08-13T15-37-27-449Z_pid9862_0f5833dd.xcresult

A fresh direct Claude Opus 5 high review was attempted after the test pass. The process exited 1 because the session quota is exhausted until 04:50 AEST. No independent review is claimed for this refreshed head.

Comment threadapps/swift-ios/Features/Workspace/DailyUXModels.swift Outdated
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 13, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

@saphidsaphid closed this Aug 15, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:trustedPR 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

@saphid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

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

Closed
saphid wants to merge 5 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:t3code/show-thread-pull-request-links
Closed

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

Conversation

@saphid

@saphidsaphid 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 home view

  • Thread rows in the home collection view now display a tappable pull request badge that opens the PR in the system browser, with full accessibility labeling and a custom accessibility action.
  • The coordinator in HomeThreadCollectionView.swift asynchronously resolves source control status per thread, caches results for 5 minutes, and throttles failed lookups for 10 seconds.
  • HomeThreadPullRequestPresentation in WorkspaceView.swift validates PR data before surfacing it: branch must match, PR number must be positive, and the URL must be a credential-free http/https link with a host.
  • Provider resolution in homeProviderLabel and HomeThreadRowContext.index now falls back to the global providers list when providersByEnvironment is absent, fixing cases where the provider ID was shown instead of its name.

Macroscope summarized b499d83.


Note

Low Risk
SwiftUI-only home list UX with URL sanitization and tests; provider fallback change is a targeted correctness fix with no auth or data-path changes.

Overview
Home thread rows now asynchronously resolve and show a tappable PR badge (#<number>) when source-control status matches the thread’s branch.

The home collection coordinator loads status via sourceControlStatus, keys lookups by checkout (not thread id), caches successes for five minutes with failure backoff, and cancels/prunes work when rows scroll off or the view dismantles. HomeThreadPullRequestPresentation only surfaces PRs with matching branches and safeExternalURL (credential-free http/https). Rich and slim rows get a SwiftUI Link; VoiceOver gets PR text plus a custom action to open the PR in Safari.

Provider resolution no longer falls back to legacy snapshot.providers when providersByEnvironment exists but omits the thread’s environment—avoiding wrong harness labels across devices.

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

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable with runnable checks green; requested review changes remain. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot 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: 91e26d0e-e692-4c1b-ba90-32b8829c33de

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-actionsgithub-actionsBot 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
saphidforce-pushed the t3code/show-thread-pull-request-links branch 2 times, most recently from 230a113 to fba2518CompareAugust 9, 2026 12:34
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:35
@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fba2518 to d56c1dcCompareAugust 9, 2026 12:41
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. New feature adding pull request links to thread rows with async data loading and caching. Multiple unresolved comments identify potential bugs in cache expiration and retry logic. A Medium-severity finding about provider fallback logic also requires attention.

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

@saphid

Copy link
Copy Markdown
ContributorAuthor

@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
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@saphid

Copy link
Copy Markdown
ContributorAuthor

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
saphidforce-pushed the t3code/show-thread-pull-request-links branch from d56c1dc to 5f5a76bCompareAugust 10, 2026 12:44

@t3-codet3-codeBot 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.

the current head still has two blocking cache behaviors in the new per-row PR lookup.

@@ -325,6 +360,51 @@ struct HomeThreadCollectionView: UIViewRepresentable {
}
}

private func loadPullRequestIfNeeded(for thread: FeatureThread) {
guard let key = HomeThreadPullRequestLookupKey(thread: thread),
pullRequestResolutions[key] == nil,

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.

successful lookups, including nil, are cached forever for the coordinator lifetime. a newly created PR or later state/title change therefore never appears while the row remains active. store a timestamp and expire resolved entries so visible rows can refresh.

let status = try await client.sourceControlStatus(threadID: thread.id)
presentation = HomeThreadPullRequestPresentation(thread: thread, status: status)
} catch {
guard let self, pullRequestTasks[key]?.token == token else { 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.

on failure the task entry is cleared with no failure resolution or retry deadline. working rows reconfigure frequently, so this can immediately launch another sourceControlStatus call and keep retrying. record a cooldown/backoff entry before allowing another lookup.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Updated frozen head: fc5786d11. The cache now uses a 5-minute success/nil TTL and a 10-second failure cooldown. Focused native verification passed 10 tests with 0 failures and 0 skips. Durable result bundle: ~/Library/Developer/XcodeBuildMCP/workspaces/t3code-8f2a7900-7e7011b508e2/result-bundles/test_sim_2026-08-13T15-16-08-673Z_pid9862_c66bcad9.xcresult. Two earlier static reviews reported no actionable findings. A fresh direct Claude Opus 5 high review attempt exited 1 because the session quota was exhausted and produced no report; no fresh cross-provider review is claimed.

@cursorcursorBot 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 fc5786d119b00eac24269bdbcfa9772ad63c370d. Configure here.

@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fc5786d to 0abd88cCompareAugust 13, 2026 15:39
@saphid

Copy link
Copy Markdown
ContributorAuthor

Refreshed this branch onto current t3code/rebuild-mobile-app-swift (f98cab553) and repaired the provider-catalog compatibility failure from the merge build.

The environment-specific provider catalog remains authoritative when present. Legacy snapshots now fall back to snapshot.providers when no per-environment catalog exists.

Verification on exact head 0abd88c5989f35c6fa4fbabf54700aedbe945da1:

  • Swift parse: passed
  • diff check: passed
  • focused native HomeThreadMetadataTests: 10 passed, 0 failed
  • result bundle: test_sim_2026-08-13T15-37-27-449Z_pid9862_0f5833dd.xcresult

A fresh direct Claude Opus 5 high review was attempted after the test pass. The process exited 1 because the session quota is exhausted until 04:50 AEST. No independent review is claimed for this refreshed head.

Comment threadapps/swift-ios/Features/Workspace/DailyUXModels.swift Outdated
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 13, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

@saphidsaphid closed this Aug 15, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:trustedPR 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

@saphid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

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

Closed
saphid wants to merge 5 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:t3code/show-thread-pull-request-links
Closed

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

Conversation

@saphid

@saphidsaphid 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 home view

  • Thread rows in the home collection view now display a tappable pull request badge that opens the PR in the system browser, with full accessibility labeling and a custom accessibility action.
  • The coordinator in HomeThreadCollectionView.swift asynchronously resolves source control status per thread, caches results for 5 minutes, and throttles failed lookups for 10 seconds.
  • HomeThreadPullRequestPresentation in WorkspaceView.swift validates PR data before surfacing it: branch must match, PR number must be positive, and the URL must be a credential-free http/https link with a host.
  • Provider resolution in homeProviderLabel and HomeThreadRowContext.index now falls back to the global providers list when providersByEnvironment is absent, fixing cases where the provider ID was shown instead of its name.

Macroscope summarized b499d83.


Note

Low Risk
SwiftUI-only home list UX with URL sanitization and tests; provider fallback change is a targeted correctness fix with no auth or data-path changes.

Overview
Home thread rows now asynchronously resolve and show a tappable PR badge (#<number>) when source-control status matches the thread’s branch.

The home collection coordinator loads status via sourceControlStatus, keys lookups by checkout (not thread id), caches successes for five minutes with failure backoff, and cancels/prunes work when rows scroll off or the view dismantles. HomeThreadPullRequestPresentation only surfaces PRs with matching branches and safeExternalURL (credential-free http/https). Rich and slim rows get a SwiftUI Link; VoiceOver gets PR text plus a custom action to open the PR in Safari.

Provider resolution no longer falls back to legacy snapshot.providers when providersByEnvironment exists but omits the thread’s environment—avoiding wrong harness labels across devices.

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

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable with runnable checks green; requested review changes remain. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot 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: 91e26d0e-e692-4c1b-ba90-32b8829c33de

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-actionsgithub-actionsBot 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
saphidforce-pushed the t3code/show-thread-pull-request-links branch 2 times, most recently from 230a113 to fba2518CompareAugust 9, 2026 12:34
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:35
@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fba2518 to d56c1dcCompareAugust 9, 2026 12:41
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. New feature adding pull request links to thread rows with async data loading and caching. Multiple unresolved comments identify potential bugs in cache expiration and retry logic. A Medium-severity finding about provider fallback logic also requires attention.

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

@saphid

Copy link
Copy Markdown
ContributorAuthor

@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
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@saphid

Copy link
Copy Markdown
ContributorAuthor

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
saphidforce-pushed the t3code/show-thread-pull-request-links branch from d56c1dc to 5f5a76bCompareAugust 10, 2026 12:44

@t3-codet3-codeBot 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.

the current head still has two blocking cache behaviors in the new per-row PR lookup.

@@ -325,6 +360,51 @@ struct HomeThreadCollectionView: UIViewRepresentable {
}
}

private func loadPullRequestIfNeeded(for thread: FeatureThread) {
guard let key = HomeThreadPullRequestLookupKey(thread: thread),
pullRequestResolutions[key] == nil,

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.

successful lookups, including nil, are cached forever for the coordinator lifetime. a newly created PR or later state/title change therefore never appears while the row remains active. store a timestamp and expire resolved entries so visible rows can refresh.

let status = try await client.sourceControlStatus(threadID: thread.id)
presentation = HomeThreadPullRequestPresentation(thread: thread, status: status)
} catch {
guard let self, pullRequestTasks[key]?.token == token else { 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.

on failure the task entry is cleared with no failure resolution or retry deadline. working rows reconfigure frequently, so this can immediately launch another sourceControlStatus call and keep retrying. record a cooldown/backoff entry before allowing another lookup.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Updated frozen head: fc5786d11. The cache now uses a 5-minute success/nil TTL and a 10-second failure cooldown. Focused native verification passed 10 tests with 0 failures and 0 skips. Durable result bundle: ~/Library/Developer/XcodeBuildMCP/workspaces/t3code-8f2a7900-7e7011b508e2/result-bundles/test_sim_2026-08-13T15-16-08-673Z_pid9862_c66bcad9.xcresult. Two earlier static reviews reported no actionable findings. A fresh direct Claude Opus 5 high review attempt exited 1 because the session quota was exhausted and produced no report; no fresh cross-provider review is claimed.

@cursorcursorBot 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 fc5786d119b00eac24269bdbcfa9772ad63c370d. Configure here.

@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fc5786d to 0abd88cCompareAugust 13, 2026 15:39
@saphid

Copy link
Copy Markdown
ContributorAuthor

Refreshed this branch onto current t3code/rebuild-mobile-app-swift (f98cab553) and repaired the provider-catalog compatibility failure from the merge build.

The environment-specific provider catalog remains authoritative when present. Legacy snapshots now fall back to snapshot.providers when no per-environment catalog exists.

Verification on exact head 0abd88c5989f35c6fa4fbabf54700aedbe945da1:

  • Swift parse: passed
  • diff check: passed
  • focused native HomeThreadMetadataTests: 10 passed, 0 failed
  • result bundle: test_sim_2026-08-13T15-37-27-449Z_pid9862_0f5833dd.xcresult

A fresh direct Claude Opus 5 high review was attempted after the test pass. The process exited 1 because the session quota is exhausted until 04:50 AEST. No independent review is claimed for this refreshed head.

Comment threadapps/swift-ios/Features/Workspace/DailyUXModels.swift Outdated
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 13, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

@saphidsaphid closed this Aug 15, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:trustedPR 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

@saphid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

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

Closed
saphid wants to merge 5 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:t3code/show-thread-pull-request-links
Closed

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

Conversation

@saphid

@saphidsaphid 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 home view

  • Thread rows in the home collection view now display a tappable pull request badge that opens the PR in the system browser, with full accessibility labeling and a custom accessibility action.
  • The coordinator in HomeThreadCollectionView.swift asynchronously resolves source control status per thread, caches results for 5 minutes, and throttles failed lookups for 10 seconds.
  • HomeThreadPullRequestPresentation in WorkspaceView.swift validates PR data before surfacing it: branch must match, PR number must be positive, and the URL must be a credential-free http/https link with a host.
  • Provider resolution in homeProviderLabel and HomeThreadRowContext.index now falls back to the global providers list when providersByEnvironment is absent, fixing cases where the provider ID was shown instead of its name.

Macroscope summarized b499d83.


Note

Low Risk
SwiftUI-only home list UX with URL sanitization and tests; provider fallback change is a targeted correctness fix with no auth or data-path changes.

Overview
Home thread rows now asynchronously resolve and show a tappable PR badge (#<number>) when source-control status matches the thread’s branch.

The home collection coordinator loads status via sourceControlStatus, keys lookups by checkout (not thread id), caches successes for five minutes with failure backoff, and cancels/prunes work when rows scroll off or the view dismantles. HomeThreadPullRequestPresentation only surfaces PRs with matching branches and safeExternalURL (credential-free http/https). Rich and slim rows get a SwiftUI Link; VoiceOver gets PR text plus a custom action to open the PR in Safari.

Provider resolution no longer falls back to legacy snapshot.providers when providersByEnvironment exists but omits the thread’s environment—avoiding wrong harness labels across devices.

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

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable with runnable checks green; requested review changes remain. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot 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: 91e26d0e-e692-4c1b-ba90-32b8829c33de

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-actionsgithub-actionsBot 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
saphidforce-pushed the t3code/show-thread-pull-request-links branch 2 times, most recently from 230a113 to fba2518CompareAugust 9, 2026 12:34
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:35
@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fba2518 to d56c1dcCompareAugust 9, 2026 12:41
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. New feature adding pull request links to thread rows with async data loading and caching. Multiple unresolved comments identify potential bugs in cache expiration and retry logic. A Medium-severity finding about provider fallback logic also requires attention.

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

@saphid

Copy link
Copy Markdown
ContributorAuthor

@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
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@saphid

Copy link
Copy Markdown
ContributorAuthor

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
saphidforce-pushed the t3code/show-thread-pull-request-links branch from d56c1dc to 5f5a76bCompareAugust 10, 2026 12:44

@t3-codet3-codeBot 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.

the current head still has two blocking cache behaviors in the new per-row PR lookup.

@@ -325,6 +360,51 @@ struct HomeThreadCollectionView: UIViewRepresentable {
}
}

private func loadPullRequestIfNeeded(for thread: FeatureThread) {
guard let key = HomeThreadPullRequestLookupKey(thread: thread),
pullRequestResolutions[key] == nil,

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.

successful lookups, including nil, are cached forever for the coordinator lifetime. a newly created PR or later state/title change therefore never appears while the row remains active. store a timestamp and expire resolved entries so visible rows can refresh.

let status = try await client.sourceControlStatus(threadID: thread.id)
presentation = HomeThreadPullRequestPresentation(thread: thread, status: status)
} catch {
guard let self, pullRequestTasks[key]?.token == token else { 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.

on failure the task entry is cleared with no failure resolution or retry deadline. working rows reconfigure frequently, so this can immediately launch another sourceControlStatus call and keep retrying. record a cooldown/backoff entry before allowing another lookup.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Updated frozen head: fc5786d11. The cache now uses a 5-minute success/nil TTL and a 10-second failure cooldown. Focused native verification passed 10 tests with 0 failures and 0 skips. Durable result bundle: ~/Library/Developer/XcodeBuildMCP/workspaces/t3code-8f2a7900-7e7011b508e2/result-bundles/test_sim_2026-08-13T15-16-08-673Z_pid9862_c66bcad9.xcresult. Two earlier static reviews reported no actionable findings. A fresh direct Claude Opus 5 high review attempt exited 1 because the session quota was exhausted and produced no report; no fresh cross-provider review is claimed.

@cursorcursorBot 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 fc5786d119b00eac24269bdbcfa9772ad63c370d. Configure here.

@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fc5786d to 0abd88cCompareAugust 13, 2026 15:39
@saphid

Copy link
Copy Markdown
ContributorAuthor

Refreshed this branch onto current t3code/rebuild-mobile-app-swift (f98cab553) and repaired the provider-catalog compatibility failure from the merge build.

The environment-specific provider catalog remains authoritative when present. Legacy snapshots now fall back to snapshot.providers when no per-environment catalog exists.

Verification on exact head 0abd88c5989f35c6fa4fbabf54700aedbe945da1:

  • Swift parse: passed
  • diff check: passed
  • focused native HomeThreadMetadataTests: 10 passed, 0 failed
  • result bundle: test_sim_2026-08-13T15-37-27-449Z_pid9862_0f5833dd.xcresult

A fresh direct Claude Opus 5 high review was attempted after the test pass. The process exited 1 because the session quota is exhausted until 04:50 AEST. No independent review is claimed for this refreshed head.

Comment threadapps/swift-ios/Features/Workspace/DailyUXModels.swift Outdated
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 13, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

@saphidsaphid closed this Aug 15, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:trustedPR 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

@saphid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

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

Closed
saphid wants to merge 5 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:t3code/show-thread-pull-request-links
Closed

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

Conversation

@saphid

@saphidsaphid 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 home view

  • Thread rows in the home collection view now display a tappable pull request badge that opens the PR in the system browser, with full accessibility labeling and a custom accessibility action.
  • The coordinator in HomeThreadCollectionView.swift asynchronously resolves source control status per thread, caches results for 5 minutes, and throttles failed lookups for 10 seconds.
  • HomeThreadPullRequestPresentation in WorkspaceView.swift validates PR data before surfacing it: branch must match, PR number must be positive, and the URL must be a credential-free http/https link with a host.
  • Provider resolution in homeProviderLabel and HomeThreadRowContext.index now falls back to the global providers list when providersByEnvironment is absent, fixing cases where the provider ID was shown instead of its name.

Macroscope summarized b499d83.


Note

Low Risk
SwiftUI-only home list UX with URL sanitization and tests; provider fallback change is a targeted correctness fix with no auth or data-path changes.

Overview
Home thread rows now asynchronously resolve and show a tappable PR badge (#<number>) when source-control status matches the thread’s branch.

The home collection coordinator loads status via sourceControlStatus, keys lookups by checkout (not thread id), caches successes for five minutes with failure backoff, and cancels/prunes work when rows scroll off or the view dismantles. HomeThreadPullRequestPresentation only surfaces PRs with matching branches and safeExternalURL (credential-free http/https). Rich and slim rows get a SwiftUI Link; VoiceOver gets PR text plus a custom action to open the PR in Safari.

Provider resolution no longer falls back to legacy snapshot.providers when providersByEnvironment exists but omits the thread’s environment—avoiding wrong harness labels across devices.

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

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable with runnable checks green; requested review changes remain. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot 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: 91e26d0e-e692-4c1b-ba90-32b8829c33de

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-actionsgithub-actionsBot 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
saphidforce-pushed the t3code/show-thread-pull-request-links branch 2 times, most recently from 230a113 to fba2518CompareAugust 9, 2026 12:34
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:35
@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fba2518 to d56c1dcCompareAugust 9, 2026 12:41
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. New feature adding pull request links to thread rows with async data loading and caching. Multiple unresolved comments identify potential bugs in cache expiration and retry logic. A Medium-severity finding about provider fallback logic also requires attention.

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

@saphid

Copy link
Copy Markdown
ContributorAuthor

@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
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@saphid

Copy link
Copy Markdown
ContributorAuthor

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
saphidforce-pushed the t3code/show-thread-pull-request-links branch from d56c1dc to 5f5a76bCompareAugust 10, 2026 12:44

@t3-codet3-codeBot 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.

the current head still has two blocking cache behaviors in the new per-row PR lookup.

@@ -325,6 +360,51 @@ struct HomeThreadCollectionView: UIViewRepresentable {
}
}

private func loadPullRequestIfNeeded(for thread: FeatureThread) {
guard let key = HomeThreadPullRequestLookupKey(thread: thread),
pullRequestResolutions[key] == nil,

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.

successful lookups, including nil, are cached forever for the coordinator lifetime. a newly created PR or later state/title change therefore never appears while the row remains active. store a timestamp and expire resolved entries so visible rows can refresh.

let status = try await client.sourceControlStatus(threadID: thread.id)
presentation = HomeThreadPullRequestPresentation(thread: thread, status: status)
} catch {
guard let self, pullRequestTasks[key]?.token == token else { 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.

on failure the task entry is cleared with no failure resolution or retry deadline. working rows reconfigure frequently, so this can immediately launch another sourceControlStatus call and keep retrying. record a cooldown/backoff entry before allowing another lookup.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Updated frozen head: fc5786d11. The cache now uses a 5-minute success/nil TTL and a 10-second failure cooldown. Focused native verification passed 10 tests with 0 failures and 0 skips. Durable result bundle: ~/Library/Developer/XcodeBuildMCP/workspaces/t3code-8f2a7900-7e7011b508e2/result-bundles/test_sim_2026-08-13T15-16-08-673Z_pid9862_c66bcad9.xcresult. Two earlier static reviews reported no actionable findings. A fresh direct Claude Opus 5 high review attempt exited 1 because the session quota was exhausted and produced no report; no fresh cross-provider review is claimed.

@cursorcursorBot 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 fc5786d119b00eac24269bdbcfa9772ad63c370d. Configure here.

@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fc5786d to 0abd88cCompareAugust 13, 2026 15:39
@saphid

Copy link
Copy Markdown
ContributorAuthor

Refreshed this branch onto current t3code/rebuild-mobile-app-swift (f98cab553) and repaired the provider-catalog compatibility failure from the merge build.

The environment-specific provider catalog remains authoritative when present. Legacy snapshots now fall back to snapshot.providers when no per-environment catalog exists.

Verification on exact head 0abd88c5989f35c6fa4fbabf54700aedbe945da1:

  • Swift parse: passed
  • diff check: passed
  • focused native HomeThreadMetadataTests: 10 passed, 0 failed
  • result bundle: test_sim_2026-08-13T15-37-27-449Z_pid9862_0f5833dd.xcresult

A fresh direct Claude Opus 5 high review was attempted after the test pass. The process exited 1 because the session quota is exhausted until 04:50 AEST. No independent review is claimed for this refreshed head.

Comment threadapps/swift-ios/Features/Workspace/DailyUXModels.swift Outdated
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 13, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

@saphidsaphid closed this Aug 15, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:trustedPR 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

@saphid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

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

Closed
saphid wants to merge 5 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:t3code/show-thread-pull-request-links
Closed

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

Conversation

@saphid

@saphidsaphid 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 home view

  • Thread rows in the home collection view now display a tappable pull request badge that opens the PR in the system browser, with full accessibility labeling and a custom accessibility action.
  • The coordinator in HomeThreadCollectionView.swift asynchronously resolves source control status per thread, caches results for 5 minutes, and throttles failed lookups for 10 seconds.
  • HomeThreadPullRequestPresentation in WorkspaceView.swift validates PR data before surfacing it: branch must match, PR number must be positive, and the URL must be a credential-free http/https link with a host.
  • Provider resolution in homeProviderLabel and HomeThreadRowContext.index now falls back to the global providers list when providersByEnvironment is absent, fixing cases where the provider ID was shown instead of its name.

Macroscope summarized b499d83.


Note

Low Risk
SwiftUI-only home list UX with URL sanitization and tests; provider fallback change is a targeted correctness fix with no auth or data-path changes.

Overview
Home thread rows now asynchronously resolve and show a tappable PR badge (#<number>) when source-control status matches the thread’s branch.

The home collection coordinator loads status via sourceControlStatus, keys lookups by checkout (not thread id), caches successes for five minutes with failure backoff, and cancels/prunes work when rows scroll off or the view dismantles. HomeThreadPullRequestPresentation only surfaces PRs with matching branches and safeExternalURL (credential-free http/https). Rich and slim rows get a SwiftUI Link; VoiceOver gets PR text plus a custom action to open the PR in Safari.

Provider resolution no longer falls back to legacy snapshot.providers when providersByEnvironment exists but omits the thread’s environment—avoiding wrong harness labels across devices.

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

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable with runnable checks green; requested review changes remain. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot 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: 91e26d0e-e692-4c1b-ba90-32b8829c33de

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-actionsgithub-actionsBot 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
saphidforce-pushed the t3code/show-thread-pull-request-links branch 2 times, most recently from 230a113 to fba2518CompareAugust 9, 2026 12:34
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:35
@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fba2518 to d56c1dcCompareAugust 9, 2026 12:41
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. New feature adding pull request links to thread rows with async data loading and caching. Multiple unresolved comments identify potential bugs in cache expiration and retry logic. A Medium-severity finding about provider fallback logic also requires attention.

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

@saphid

Copy link
Copy Markdown
ContributorAuthor

@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
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@saphid

Copy link
Copy Markdown
ContributorAuthor

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
saphidforce-pushed the t3code/show-thread-pull-request-links branch from d56c1dc to 5f5a76bCompareAugust 10, 2026 12:44

@t3-codet3-codeBot 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.

the current head still has two blocking cache behaviors in the new per-row PR lookup.

@@ -325,6 +360,51 @@ struct HomeThreadCollectionView: UIViewRepresentable {
}
}

private func loadPullRequestIfNeeded(for thread: FeatureThread) {
guard let key = HomeThreadPullRequestLookupKey(thread: thread),
pullRequestResolutions[key] == nil,

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.

successful lookups, including nil, are cached forever for the coordinator lifetime. a newly created PR or later state/title change therefore never appears while the row remains active. store a timestamp and expire resolved entries so visible rows can refresh.

let status = try await client.sourceControlStatus(threadID: thread.id)
presentation = HomeThreadPullRequestPresentation(thread: thread, status: status)
} catch {
guard let self, pullRequestTasks[key]?.token == token else { 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.

on failure the task entry is cleared with no failure resolution or retry deadline. working rows reconfigure frequently, so this can immediately launch another sourceControlStatus call and keep retrying. record a cooldown/backoff entry before allowing another lookup.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Updated frozen head: fc5786d11. The cache now uses a 5-minute success/nil TTL and a 10-second failure cooldown. Focused native verification passed 10 tests with 0 failures and 0 skips. Durable result bundle: ~/Library/Developer/XcodeBuildMCP/workspaces/t3code-8f2a7900-7e7011b508e2/result-bundles/test_sim_2026-08-13T15-16-08-673Z_pid9862_c66bcad9.xcresult. Two earlier static reviews reported no actionable findings. A fresh direct Claude Opus 5 high review attempt exited 1 because the session quota was exhausted and produced no report; no fresh cross-provider review is claimed.

@cursorcursorBot 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 fc5786d119b00eac24269bdbcfa9772ad63c370d. Configure here.

@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fc5786d to 0abd88cCompareAugust 13, 2026 15:39
@saphid

Copy link
Copy Markdown
ContributorAuthor

Refreshed this branch onto current t3code/rebuild-mobile-app-swift (f98cab553) and repaired the provider-catalog compatibility failure from the merge build.

The environment-specific provider catalog remains authoritative when present. Legacy snapshots now fall back to snapshot.providers when no per-environment catalog exists.

Verification on exact head 0abd88c5989f35c6fa4fbabf54700aedbe945da1:

  • Swift parse: passed
  • diff check: passed
  • focused native HomeThreadMetadataTests: 10 passed, 0 failed
  • result bundle: test_sim_2026-08-13T15-37-27-449Z_pid9862_0f5833dd.xcresult

A fresh direct Claude Opus 5 high review was attempted after the test pass. The process exited 1 because the session quota is exhausted until 04:50 AEST. No independent review is claimed for this refreshed head.

Comment threadapps/swift-ios/Features/Workspace/DailyUXModels.swift Outdated
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 13, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

@saphidsaphid closed this Aug 15, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:trustedPR 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

@saphid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

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

Closed
saphid wants to merge 5 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:t3code/show-thread-pull-request-links
Closed

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

Conversation

@saphid

@saphidsaphid 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 home view

  • Thread rows in the home collection view now display a tappable pull request badge that opens the PR in the system browser, with full accessibility labeling and a custom accessibility action.
  • The coordinator in HomeThreadCollectionView.swift asynchronously resolves source control status per thread, caches results for 5 minutes, and throttles failed lookups for 10 seconds.
  • HomeThreadPullRequestPresentation in WorkspaceView.swift validates PR data before surfacing it: branch must match, PR number must be positive, and the URL must be a credential-free http/https link with a host.
  • Provider resolution in homeProviderLabel and HomeThreadRowContext.index now falls back to the global providers list when providersByEnvironment is absent, fixing cases where the provider ID was shown instead of its name.

Macroscope summarized b499d83.


Note

Low Risk
SwiftUI-only home list UX with URL sanitization and tests; provider fallback change is a targeted correctness fix with no auth or data-path changes.

Overview
Home thread rows now asynchronously resolve and show a tappable PR badge (#<number>) when source-control status matches the thread’s branch.

The home collection coordinator loads status via sourceControlStatus, keys lookups by checkout (not thread id), caches successes for five minutes with failure backoff, and cancels/prunes work when rows scroll off or the view dismantles. HomeThreadPullRequestPresentation only surfaces PRs with matching branches and safeExternalURL (credential-free http/https). Rich and slim rows get a SwiftUI Link; VoiceOver gets PR text plus a custom action to open the PR in Safari.

Provider resolution no longer falls back to legacy snapshot.providers when providersByEnvironment exists but omits the thread’s environment—avoiding wrong harness labels across devices.

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

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable with runnable checks green; requested review changes remain. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot 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: 91e26d0e-e692-4c1b-ba90-32b8829c33de

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-actionsgithub-actionsBot 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
saphidforce-pushed the t3code/show-thread-pull-request-links branch 2 times, most recently from 230a113 to fba2518CompareAugust 9, 2026 12:34
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:35
@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fba2518 to d56c1dcCompareAugust 9, 2026 12:41
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. New feature adding pull request links to thread rows with async data loading and caching. Multiple unresolved comments identify potential bugs in cache expiration and retry logic. A Medium-severity finding about provider fallback logic also requires attention.

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

@saphid

Copy link
Copy Markdown
ContributorAuthor

@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
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@saphid

Copy link
Copy Markdown
ContributorAuthor

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
saphidforce-pushed the t3code/show-thread-pull-request-links branch from d56c1dc to 5f5a76bCompareAugust 10, 2026 12:44

@t3-codet3-codeBot 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.

the current head still has two blocking cache behaviors in the new per-row PR lookup.

@@ -325,6 +360,51 @@ struct HomeThreadCollectionView: UIViewRepresentable {
}
}

private func loadPullRequestIfNeeded(for thread: FeatureThread) {
guard let key = HomeThreadPullRequestLookupKey(thread: thread),
pullRequestResolutions[key] == nil,

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.

successful lookups, including nil, are cached forever for the coordinator lifetime. a newly created PR or later state/title change therefore never appears while the row remains active. store a timestamp and expire resolved entries so visible rows can refresh.

let status = try await client.sourceControlStatus(threadID: thread.id)
presentation = HomeThreadPullRequestPresentation(thread: thread, status: status)
} catch {
guard let self, pullRequestTasks[key]?.token == token else { 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.

on failure the task entry is cleared with no failure resolution or retry deadline. working rows reconfigure frequently, so this can immediately launch another sourceControlStatus call and keep retrying. record a cooldown/backoff entry before allowing another lookup.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Updated frozen head: fc5786d11. The cache now uses a 5-minute success/nil TTL and a 10-second failure cooldown. Focused native verification passed 10 tests with 0 failures and 0 skips. Durable result bundle: ~/Library/Developer/XcodeBuildMCP/workspaces/t3code-8f2a7900-7e7011b508e2/result-bundles/test_sim_2026-08-13T15-16-08-673Z_pid9862_c66bcad9.xcresult. Two earlier static reviews reported no actionable findings. A fresh direct Claude Opus 5 high review attempt exited 1 because the session quota was exhausted and produced no report; no fresh cross-provider review is claimed.

@cursorcursorBot 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 fc5786d119b00eac24269bdbcfa9772ad63c370d. Configure here.

@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fc5786d to 0abd88cCompareAugust 13, 2026 15:39
@saphid

Copy link
Copy Markdown
ContributorAuthor

Refreshed this branch onto current t3code/rebuild-mobile-app-swift (f98cab553) and repaired the provider-catalog compatibility failure from the merge build.

The environment-specific provider catalog remains authoritative when present. Legacy snapshots now fall back to snapshot.providers when no per-environment catalog exists.

Verification on exact head 0abd88c5989f35c6fa4fbabf54700aedbe945da1:

  • Swift parse: passed
  • diff check: passed
  • focused native HomeThreadMetadataTests: 10 passed, 0 failed
  • result bundle: test_sim_2026-08-13T15-37-27-449Z_pid9862_0f5833dd.xcresult

A fresh direct Claude Opus 5 high review was attempted after the test pass. The process exited 1 because the session quota is exhausted until 04:50 AEST. No independent review is claimed for this refreshed head.

Comment threadapps/swift-ios/Features/Workspace/DailyUXModels.swift Outdated
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 13, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

@saphidsaphid closed this Aug 15, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:trustedPR 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

@saphid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

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

Closed
saphid wants to merge 5 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:t3code/show-thread-pull-request-links
Closed

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

Conversation

@saphid

@saphidsaphid 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 home view

  • Thread rows in the home collection view now display a tappable pull request badge that opens the PR in the system browser, with full accessibility labeling and a custom accessibility action.
  • The coordinator in HomeThreadCollectionView.swift asynchronously resolves source control status per thread, caches results for 5 minutes, and throttles failed lookups for 10 seconds.
  • HomeThreadPullRequestPresentation in WorkspaceView.swift validates PR data before surfacing it: branch must match, PR number must be positive, and the URL must be a credential-free http/https link with a host.
  • Provider resolution in homeProviderLabel and HomeThreadRowContext.index now falls back to the global providers list when providersByEnvironment is absent, fixing cases where the provider ID was shown instead of its name.

Macroscope summarized b499d83.


Note

Low Risk
SwiftUI-only home list UX with URL sanitization and tests; provider fallback change is a targeted correctness fix with no auth or data-path changes.

Overview
Home thread rows now asynchronously resolve and show a tappable PR badge (#<number>) when source-control status matches the thread’s branch.

The home collection coordinator loads status via sourceControlStatus, keys lookups by checkout (not thread id), caches successes for five minutes with failure backoff, and cancels/prunes work when rows scroll off or the view dismantles. HomeThreadPullRequestPresentation only surfaces PRs with matching branches and safeExternalURL (credential-free http/https). Rich and slim rows get a SwiftUI Link; VoiceOver gets PR text plus a custom action to open the PR in Safari.

Provider resolution no longer falls back to legacy snapshot.providers when providersByEnvironment exists but omits the thread’s environment—avoiding wrong harness labels across devices.

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

Delivery: direct
Validated against Theo commit: f98cab5
Depends on: none
Merge order: this PR only
Validation status: Mergeable with runnable checks green; requested review changes remain. The unrelated Vercel authorization failure is a maintainer-side gate.

@coderabbitai

coderabbitaiBot 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: 91e26d0e-e692-4c1b-ba90-32b8829c33de

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-actionsgithub-actionsBot 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
saphidforce-pushed the t3code/show-thread-pull-request-links branch 2 times, most recently from 230a113 to fba2518CompareAugust 9, 2026 12:34
@saphid
saphid marked this pull request as ready for review August 9, 2026 12:35
@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fba2518 to d56c1dcCompareAugust 9, 2026 12:41
@macroscopeapp

macroscopeappBot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. New feature adding pull request links to thread rows with async data loading and caching. Multiple unresolved comments identify potential bugs in cache expiration and retry logic. A Medium-severity finding about provider fallback logic also requires attention.

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

@saphid

Copy link
Copy Markdown
ContributorAuthor

@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
t3dotggforce-pushed the t3code/rebuild-mobile-app-swift branch from 4cb3307 to 497f54fCompareAugust 10, 2026 03:58
@saphid

Copy link
Copy Markdown
ContributorAuthor

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
saphidforce-pushed the t3code/show-thread-pull-request-links branch from d56c1dc to 5f5a76bCompareAugust 10, 2026 12:44

@t3-codet3-codeBot 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.

the current head still has two blocking cache behaviors in the new per-row PR lookup.

@@ -325,6 +360,51 @@ struct HomeThreadCollectionView: UIViewRepresentable {
}
}

private func loadPullRequestIfNeeded(for thread: FeatureThread) {
guard let key = HomeThreadPullRequestLookupKey(thread: thread),
pullRequestResolutions[key] == nil,

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.

successful lookups, including nil, are cached forever for the coordinator lifetime. a newly created PR or later state/title change therefore never appears while the row remains active. store a timestamp and expire resolved entries so visible rows can refresh.

let status = try await client.sourceControlStatus(threadID: thread.id)
presentation = HomeThreadPullRequestPresentation(thread: thread, status: status)
} catch {
guard let self, pullRequestTasks[key]?.token == token else { 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.

on failure the task entry is cleared with no failure resolution or retry deadline. working rows reconfigure frequently, so this can immediately launch another sourceControlStatus call and keep retrying. record a cooldown/backoff entry before allowing another lookup.

@saphid

Copy link
Copy Markdown
ContributorAuthor

Updated frozen head: fc5786d11. The cache now uses a 5-minute success/nil TTL and a 10-second failure cooldown. Focused native verification passed 10 tests with 0 failures and 0 skips. Durable result bundle: ~/Library/Developer/XcodeBuildMCP/workspaces/t3code-8f2a7900-7e7011b508e2/result-bundles/test_sim_2026-08-13T15-16-08-673Z_pid9862_c66bcad9.xcresult. Two earlier static reviews reported no actionable findings. A fresh direct Claude Opus 5 high review attempt exited 1 because the session quota was exhausted and produced no report; no fresh cross-provider review is claimed.

@cursorcursorBot 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 fc5786d119b00eac24269bdbcfa9772ad63c370d. Configure here.

@saphid
saphidforce-pushed the t3code/show-thread-pull-request-links branch from fc5786d to 0abd88cCompareAugust 13, 2026 15:39
@saphid

Copy link
Copy Markdown
ContributorAuthor

Refreshed this branch onto current t3code/rebuild-mobile-app-swift (f98cab553) and repaired the provider-catalog compatibility failure from the merge build.

The environment-specific provider catalog remains authoritative when present. Legacy snapshots now fall back to snapshot.providers when no per-environment catalog exists.

Verification on exact head 0abd88c5989f35c6fa4fbabf54700aedbe945da1:

  • Swift parse: passed
  • diff check: passed
  • focused native HomeThreadMetadataTests: 10 passed, 0 failed
  • result bundle: test_sim_2026-08-13T15-37-27-449Z_pid9862_0f5833dd.xcresult

A fresh direct Claude Opus 5 high review was attempted after the test pass. The process exited 1 because the session quota is exhausted until 04:50 AEST. No independent review is claimed for this refreshed head.

Comment threadapps/swift-ios/Features/Workspace/DailyUXModels.swift Outdated
@github-actionsgithub-actionsBot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 13, 2026
@saphid

Copy link
Copy Markdown
ContributorAuthor

Closing this version while I rebuild the upstream contribution set from the latest base. Clean versions are coming soon.

@saphidsaphid closed this Aug 15, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:trustedPR 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

@saphid