Skip to content

fix(server): link thread PRs without an open client - #10101

Merged
t3dotgg merged 6 commits into
mainfrom
t3code/move-pr-thread-linking-server
Sep 6, 2026
Merged

fix(server): link thread PRs without an open client#10101
t3dotgg merged 6 commits into
mainfrom
t3code/move-pr-thread-linking-server

Conversation

@t3dotgg

@t3dotgg t3dotgg commented Sep 5, 2026

Copy link
Copy Markdown
Member

Thread PR links depended on client-side logic. Automatic relinking required an open web chat, and web and mobile could show different associations.

The server now discovers and saves PR links for each thread's branch. All clients read those links. Manual links stay separate, and stale lookups cannot overwrite newer changes. Settlement checks for a newer open PR before acting on a merged link.

Automatic branch links require the updated server. The client fallback is removed.

Focused tests and affected package typechecks pass. Targeted lint reports warnings but no errors.

Created with GPT-6 Astra in Codex.

Note

Add server-side thread PR discovery and remove client-side VCS PR resolution

  • The server now discovers and syncs thread PRs through the new ThreadPullRequestReactor and thread.pull-request.sync command, allowing PR links without an open client.
  • Web and mobile clients remove local VCS branch PR resolution, relying solely on server-provided linkedPullRequest or branchPullRequest metadata.
  • Migration 048_ProjectionThreadBranchPullRequest adds branch_pull_request_json to projection_threads; projection and contract schemas now support branchPullRequest.
  • GitManager.branchPullRequest supports an optional refresh flag and derives repository keys for GitHub, GitLab, Bitbucket, and Azure DevOps URLs.
  • Risk: thread.pull-request.sync fails with OrchestrationCommandInvariantError if the thread is recreated after the command snapshot. Clients cannot open PRs when no server link exists.

Macroscope summarized 6760605.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Sep 5, 2026
Comment thread apps/mobile/src/features/home/HomeScreen.tsx
Comment thread apps/server/src/git/GitManager.ts
Comment thread apps/server/src/orchestration/Layers/OrchestrationEngine.ts
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.6 KiB 13.6 KiB +18 B (+0.1%) 15.1 KiB
Codex Thread snapshot wire 7.0 KiB 7.0 KiB +12 B (+0.2%) 7.3 KiB
Codex Live turn WebSocket wire 6.6 KiB 6.6 KiB +6 B (+0.1%) 7.8 KiB
Codex Live turn WebSocket decoded 57.1 KiB 57.1 KiB 0 B (0.0%) 66.4 KiB
Codex Live turn messages 10 10 0 (0.0%) 21
Claude Total thread wire 13.6 KiB 13.6 KiB −47 B (−0.3%) 15.1 KiB
Claude Thread snapshot wire 7.0 KiB 7.0 KiB 0 B (0.0%) 7.3 KiB
Claude Live turn WebSocket wire 6.6 KiB 6.5 KiB −47 B (−0.7%) 7.8 KiB
Claude Live turn WebSocket decoded 57.9 KiB 57.8 KiB −88 B (−0.1%) 66.4 KiB
Claude Live turn messages 10 8 −2 (−20.0%) 21

Baseline: 5fa35d2 · PR result: 03c0d05 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.9 KiB
  • Claude decoded thread snapshot: 114.5 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp

macroscopeapp Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces an always-on server reactor that discovers and persists branch pull requests, changes automatic settlement behavior, and propagates new state through migrations, orchestration, web, and mobile clients. Its cross-layer runtime impact and default-on background activity require human review.

Not approved because:

  • Monthly spending limit reached (workspace setting). Approvability relies on correctness review in order to determine eligibility

Review your spending limits in Billing settings. You can add or adjust custom eligibility rules. Learn more.

Comment thread apps/server/src/orchestration/ThreadPullRequestReactor.ts Outdated
Comment thread apps/server/src/orchestration/ThreadPullRequestReactor.ts
@t3dotgg
t3dotgg force-pushed the t3code/move-pr-thread-linking-server branch from fad79ef to d8dd9be Compare September 6, 2026 04:28
@t3dotgg
t3dotgg force-pushed the t3code/move-pr-thread-linking-server branch from d8dd9be to 0d90c12 Compare September 6, 2026 10:21
Comment thread apps/server/src/git/GitManager.ts Outdated
Comment thread docs/user/thread-sidebar.md Outdated
@cursor

cursor Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

The startup backfill kept every settled thread without a saved PR link in a
retry set until a lookup succeeded. A machine without gh, a logged-out CLI,
or a removed remote would run a git spawn per settled branch every minute
forever. Real userdata has about 700 such threads.

Each settled thread now gets a bounded number of backfill attempts. Skips
for a missing project or repository identity count as finished. Unsettled
threads and threads with new events are unaffected.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@t3dotgg
t3dotgg merged commit 223ff44 into main Sep 6, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the t3code/move-pr-thread-linking-server branch September 6, 2026 11:06
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 6, 2026
## What's Changed
* feat(usage): pool subscription limits per provider across accounts and environments by @juliusmarminge in pingdotgg/t3code#10300
* chore(web): remove usage limits demo fixtures by @juliusmarminge in pingdotgg/t3code#10330
* fix(web): expose error disclosure state by @saphid in pingdotgg/t3code#10125
* fix(web): name the editor picker accurately by @saphid in pingdotgg/t3code#10124
* fix(web): make task row states readable by @saphid in pingdotgg/t3code#10128
* fix(web): explain hosted connection prerequisites by @saphid in pingdotgg/t3code#10129
* fix(web): name combobox chip removal targets by @saphid in pingdotgg/t3code#10127
* fix(marketing): present the Git workflow as an illustration by @saphid in pingdotgg/t3code#10130
* feat(mobile): pool usage limits across selected environments by @juliusmarminge in pingdotgg/t3code#10334
* fix(release): space automatic nightlies at least six hours apart by @t3dotgg in pingdotgg/t3code#10272
* refactor(web): share bulk thread deletion between sidebars by @t3dotgg in pingdotgg/t3code#10106
* refactor(client): share tool outcome rules by @t3dotgg in pingdotgg/t3code#10122
* refactor(server): share Claude result status and error mapping by @t3dotgg in pingdotgg/t3code#10296
* fix(server): settle inactive threads without a PR lookup by @t3dotgg in pingdotgg/t3code#10103
* fix(ssh): report remote stop failures without losing ownership by @t3dotgg in pingdotgg/t3code#10105
* perf(server): stop scanning old OpenCode parts by @t3dotgg in pingdotgg/t3code#10116
* perf(server): avoid full thread reads on turn start by @t3dotgg in pingdotgg/t3code#10108
* perf(web): skip checkpoint map rebuilds while streaming by @t3dotgg in pingdotgg/t3code#10118
* perf(server): skip plan bodies in thread summaries by @t3dotgg in pingdotgg/t3code#10341
* fix(server): skip disabled provider instances for text generation fallback by @t3dotgg in pingdotgg/t3code#10346
* fix(server): capture checkpoints before refreshing PR status by @t3dotgg in pingdotgg/t3code#10347
* fix(web): keep manual panel choices during a turn by @t3dotgg in pingdotgg/t3code#10113
* fix(threads): keep completed requests closed across clients by @t3dotgg in pingdotgg/t3code#10123
* perf(server): finish runtime messages without full thread reads by @t3dotgg in pingdotgg/t3code#10120
* refactor(server): let adapters declare context compaction by @t3dotgg in pingdotgg/t3code#10112
* fix(server): link thread PRs without an open client by @t3dotgg in pingdotgg/t3code#10101


**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260906.1293...v0.0.39-nightly.20260906.1303

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260906.1303
sheehanmunim added a commit to munimtechnologies/mtcode that referenced this pull request Sep 7, 2026
Adopts upstream's manual active-thread ordering (pingdotgg#9729) in place of the
fork's own implementation, per Sheehan's call. The decider now emits
upstream's `thread.meta-updated` with `activeOrderKey` and its guards
(reject deleted/pinned/settled, retain the snooze slot, leave updatedAt
alone). The fork's `thread.active-reordered` event is no longer emitted,
but its schema, projector, ProjectionPipeline and client reducer cases are
deliberately RETAINED: shipped fork databases contain those events and
replay must keep decoding them.

Conflict resolutions worth remembering:

- ProjectionSnapshotQuery: upstream's new `getTurnStartMessage` SELECT
  omitted the fork's message-correction columns that the shared row schema
  requires, so every turn start failed to decode (`MissingKey`) and took 14
  orchestration tests with it. Added original_text, correction_target_message_id,
  correction_replacement_text and delivery_state to the SELECT.
- ProviderCommandReactor: upstream moved turn-start lookups to the projection
  and switched the handler to a thread SHELL, which carries only a truncated
  objectivePreview. The fork's Goal Continuation needs the full Objective, so
  it re-reads the detail on that path only. `buildSendTurnRequestForThread`
  also loaded the whole transcript eagerly; it now uses the shell and defers
  the detail read to the hand-off prelude that actually needs it (this is what
  upstream's "without loading old message bodies" test asserts).
- ProviderRuntimeIngestion: the fork's nullable Continuation messageId flowed
  into upstream's non-null `getThreadMessageById`; guarded.
- OpenCodeAdapter: took upstream's `textPartsByMessageId` and dropped
  partById/emittedTextByPartId/completedAssistantPartIds (no remaining uses),
  keeping the fork's turns/context-window/compaction fields.
- Migrations: upstream's ProjectionThreadBranchPullRequest appended as fork id
  52; upstream's ProjectionThreadsActiveOrderKey NOT registered again — it is
  byte-identical to the fork's already-shipped id 43.
- MessagesTimeline.logic: restored the fork's checkpoint-readiness guard that
  upstream's relocated copy lacked, so Revert stays hidden until a checkpoint
  is ready; the two fork tests that drove this through the removed
  revertTurnCountByUserMessageId prop now build a real ready-checkpoint fixture.
- threadCommands: removed duplicate ReorderActiveThreadInput/reorderActiveThread
  declarations left by a keep-both resolution.
- Re-exported helpers upstream's Knip sweep privatized but the fork imports:
  activeThreadAnchorTimestampMs.
- Sidebar.tsx keeps the FORK's drag-and-drop subsystem (drag-to-snooze, overlay
  ghost, force-settle of a running thread, sidebarActiveThreadSortOrder) over
  upstream's pingdotgg#9731/pingdotgg#9750 rework; upstream's Sidebar.drag.ts/motion.ts are now
  referenced only by their own tests.
- Guard script: upstream pingdotgg#10101 deleted the client-side ThreadChangeRequestSnapshot
  atom the linked-PR check pointed at, so the check now follows the badge to its
  new server-provided source.

Verification: all packages typecheck; server orchestration+persistence 603/603,
client-runtime 1349/1349, contracts 393/393, web unit 4427 pass. The only web
failures are the two fork Goal e2e specs, confirmed failing identically on
backup/mtcode-pre-upstream-sync-20260906b.

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

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant