Before submitting
Area
apps/server
Steps to reproduce
- Clone a fork that you develop on as its own project. Set
origin to <you>/<repo> and upstream to <org>/<repo>.
- Point
gh at the fork: gh repo set-default <you>/<repo>. This writes remote.origin.gh-resolved=base.
- Add the checkout as a T3 project.
- From a branch pushed to
origin, create a PR with T3's source-control action, or open an existing fork PR in T3.
Expected behavior
The project's repository is <you>/<repo>, the repository gh resolves for the checkout. T3 links the fork PR to the thread, and the PR page and its actions (merge, close, update branch) work on it.
Actual behavior
The project's repositoryIdentity is github.com/<org>/<repo> with locator.remoteName: "upstream". I see this in the project list on my install.
The gh calls and the project identity pick different repositories:
pickPrimaryRemote in apps/server/src/project/RepositoryIdentityResolver.ts takes upstream before origin and does not read remote.*.gh-resolved.
gh pr create runs without --repo, and listPullRequestsByHead uses selectGitHubBaseRepository in apps/server/src/sourceControl/GitHubCli.ts, which honors gh repo set-default. So the PR is created on the fork, and branch lookup finds it there.
- The found PR's
repositoryKey comes from its URL (github.com/<you>/<repo>). pullRequestMatchesProject in apps/server/src/orchestration-v2/ThreadPullRequestService.ts compares it with the project identity (github.com/<org>/<repo>), the comparison fails, and the PR is not linked to the thread.
requireProject in apps/server/src/pullRequest/PullRequestService.ts uses the identity's repository. A hostless reference to the fork PR fails with "The change request does not belong to the selected project." The PR list for the project reads <org>/<repo>.
I found this by reading main at 3a7058da50. I have not traced it at runtime the way #7382 did.
#7382 is the mirror case: gh resolves to upstream, and PR creation assumes origin. #14843 is a related cleanup report about the primary-remote rule. Neither covers a checkout whose gh default is the fork.
A possible fix is to have RepositoryIdentityResolver apply the same gh-resolved rule as selectGitHubBaseRepository when a mark exists, and keep upstream before origin only when there is none. That would change the project identity for such checkouts, and project grouping (#4880) keys on it. A fork checkout with gh pointed at the fork would stop grouping with upstream, which seems to match what gh repo set-default asks for.
Impact
Major degradation or frequent failure
Version or commit
main at 3a7058da50 (2026-10-02). The project identity above is from T3 Code Nightly on WSL.
Environment
Desktop app connected to a WSL (Ubuntu) environment, gh 2.102.0
Logs or stack traces
The change request does not belong to the selected project.
This string comes from requireProject and is the expected error for a hostless reference. I did not capture it from a running session.
Workaround
Renaming the upstream remote makes origin the identity, but it breaks tooling that expects a remote named upstream. Otherwise, merge fork PRs with gh outside T3.
Before submitting
Area
apps/server
Steps to reproduce
originto<you>/<repo>andupstreamto<org>/<repo>.ghat the fork:gh repo set-default <you>/<repo>. This writesremote.origin.gh-resolved=base.origin, create a PR with T3's source-control action, or open an existing fork PR in T3.Expected behavior
The project's repository is
<you>/<repo>, the repositoryghresolves for the checkout. T3 links the fork PR to the thread, and the PR page and its actions (merge, close, update branch) work on it.Actual behavior
The project's
repositoryIdentityisgithub.com/<org>/<repo>withlocator.remoteName: "upstream". I see this in the project list on my install.The
ghcalls and the project identity pick different repositories:pickPrimaryRemoteinapps/server/src/project/RepositoryIdentityResolver.tstakesupstreambeforeoriginand does not readremote.*.gh-resolved.gh pr createruns without--repo, andlistPullRequestsByHeadusesselectGitHubBaseRepositoryinapps/server/src/sourceControl/GitHubCli.ts, which honorsgh repo set-default. So the PR is created on the fork, and branch lookup finds it there.repositoryKeycomes from its URL (github.com/<you>/<repo>).pullRequestMatchesProjectinapps/server/src/orchestration-v2/ThreadPullRequestService.tscompares it with the project identity (github.com/<org>/<repo>), the comparison fails, and the PR is not linked to the thread.requireProjectinapps/server/src/pullRequest/PullRequestService.tsuses the identity's repository. A hostless reference to the fork PR fails with "The change request does not belong to the selected project." The PR list for the project reads<org>/<repo>.I found this by reading
mainat3a7058da50. I have not traced it at runtime the way #7382 did.#7382 is the mirror case:
ghresolves toupstream, and PR creation assumesorigin. #14843 is a related cleanup report about the primary-remote rule. Neither covers a checkout whoseghdefault is the fork.A possible fix is to have
RepositoryIdentityResolverapply the samegh-resolvedrule asselectGitHubBaseRepositorywhen a mark exists, and keepupstreambeforeoriginonly when there is none. That would change the project identity for such checkouts, and project grouping (#4880) keys on it. A fork checkout withghpointed at the fork would stop grouping with upstream, which seems to match whatgh repo set-defaultasks for.Impact
Major degradation or frequent failure
Version or commit
mainat3a7058da50(2026-10-02). The project identity above is from T3 Code Nightly on WSL.Environment
Desktop app connected to a WSL (Ubuntu) environment,
gh2.102.0Logs or stack traces
This string comes from
requireProjectand is the expected error for a hostless reference. I did not capture it from a running session.Workaround
Renaming the
upstreamremote makesoriginthe identity, but it breaks tooling that expects a remote namedupstream. Otherwise, merge fork PRs withghoutside T3.