fix(server): avoid transient GitHub mergeability sync churn#22022
GitHub temporarily reports unknown while recomputing mergeability. A linked open PR whose other fields have not changed can therefore generate two persisted updates and repeated stack reads as its answer changes from known → unknown → the same known value.
Keep the last known mergeability only for an open GitHub PR with an unchanged updatedAt. Both persistence and stack-refresh comparisons use that rule. Changed timestamps, other providers, terminal states, and actual computed changes retain their existing behavior.
This addresses residual polling churn. #19248 already reduced full-thread PR payload amplification; this does not reclaim existing SQLite free pages or change event retention.
Verification:
- The suppression regression fails on the base because an unnecessary
unknownupdate is dispatched. - All 25 focused
PullRequestSyncReactortests pass, including real computed changes, timestamp changes, and Forgejounknownresults. - Server typecheck passes. Targeted lint reports no errors and two pre-existing unused-parameter warnings.
- Live GitHub timestamp behavior during a base push has not been separately reproduced; the regression exercises the unchanged-timestamp response directly.
Implemented with Claude Opus 5.5 and GPT-6.1 Sol through T3 Code / Codex; independent review by Claude Opus 5.5 through T3 Code.
Checks
Added 1 commit
- fix(server): stop pull request sync rewriting threads on every base pushd5041fe
Approvability
Verdict: Approved at 6c1dca7
Macroscope's review found this PR approvable — The reactor retains known GitHub mergeability during transient unknown responses, avoiding redundant snapshot updates and stack reads. The behavior is limited to open PRs with unchanged timestamps and does not alter merge operations or permissions.
You can add or adjust custom eligibility rules. Learn more.
No actionable comments were generated in the recent review.
External image Recent review info
-
External image Run configuration
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: main
- File: .coderabbit.config.ts
- Commit: 50c1c5d
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Advanced
- Run ID:
b2772451-89a4-431e-9f9b-12fc10ee08c4
External image Commits
Reviewing files that changed from the base of the PR and between 5abdd2d2fe6fbb1a1434139615d0a74d264243cd and 6c1dca77f28717761193416227202f08d81e2ece.
External image Files selected for processing: 2
apps/server/src/orchestration-v2/PullRequestSyncReactor.test.tsapps/server/src/orchestration-v2/PullRequestSyncReactor.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 3 remain after this review.
Walkthrough
The sync reactor preserves known mergeability for unchanged open GitHub pull requests when the host reports
unknown. It applies this normalization during snapshot comparison and persistence. Tests cover GitHub and Forgejo behavior.Changes: Mergeability synchronization
Layer / File(s) Summary Provider-aware mergeability synchronization
apps/server/src/orchestration-v2/PullRequestSyncReactor.ts,apps/server/src/orchestration-v2/PullRequestSyncReactor.test.tsThe reactor applies GitHub-specific mergeability normalization during snapshot comparison and persistence. Tests cover retaining a known value until GitHub reports mergeable, and syncingunknownfor GitHub and Forgejo.Estimated code review effort: 2 (Simple) | ~10 minutes
Change: Bug fix
Possibly related issues
- pingdotgg/t3code#23860: The issue describes transient GitHub
unknownmergeability and repeated snapshot writes. This change retains the stored known value when the relevant GitHub pull request is unchanged.
Possibly related PRs
- pingdotgg/t3code#24408: This PR addresses the same GitHub mergeability behavior and applies the retained value during snapshot persistence and stack-refresh comparison.
Suggested reviewers:
t3dotgg,juliusmarminge- pingdotgg/t3code#23860: The issue describes transient GitHub
Merge Risk: External image Minimal · up to 6c1dc
No merge-blocking risk was identified in the supplied evidence.
Security architecture risk: External image Low · up to c44d0
The change is narrowly scoped and does not weaken merge permissions or provider enforcement. Remaining uncertainty concerns how long a retained status can remain stale, rather than a demonstrated authorization bypass.
Retained concerns No architecture-level concerns identified.
Security review details
Security Blast Radius
- observed — Synchronization reads remain grouped by project and pull-request identity, retaining project-specific credential scope. Normalization uses each linked snapshot rather than borrowing a prior value across projects.
Trust Boundaries and Controls
- observed — Retained mergeability affects synchronization and downstream watch scheduling, but the inspected action path independently checks provider capabilities and viewer permissions before invoking the provider. Cached mergeability is not supplied as authorization for that operation.
Pre-merge checks: Passed 4
Check name Status Explanation Title check Passed The title clearly identifies the server fix for transient GitHub mergeability synchronization churn. Description check Passed The description clearly explains the problem, the change, affected providers and states, focused verification, test results, and known limitations. It does not use the template headings or provide exp… Linked Issues check Passed Check skipped because no linked issues were found for this pull request. Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request. Full details: Description check
Explanation
The description clearly explains the problem, the change, affected providers and states, focused verification, test results, and known limitations. It does not use the template headings or provide explicit maintainer approval, but the required context is mostly complete.
Finishing Touches
Generate unit tests (beta)
- Create a new PR
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Added 1 commit
- merge: preserve PR 22022 behavior on current mainc44d067
Integrated main d36b7da2485bc889b320a285deea181f637d760a in c44d0674bda947e5fd62733175cb82c0423ac1f6 with a normal descendant push. Known GitHub mergeability is retained through an unchanged PR’s transient unknown window while current avatar-token identity handling and stack sync remain intact. Updated the regression to main’s five-minute quiet-PR cadence and asserted both actual summary reads. All 37 focused tests and targeted lint pass; imported ACP type diagnostics remain.
Focused tests: 37 passed (37); exit 0. Targeted lint exit 0. Focused typecheck exit 1. Diagnostics: packages/provider-acp/src/server/AcpSessionRuntime.ts(1334,29): error TS2339: Property 'signal' does not exist on type 'AcpProcessExitedError'.; packages/provider-acp/src/server/AcpSessionRuntime.ts(1334,68): error TS2339: Property 'signal' does not exist on type 'AcpProcessExitedError'.; packages/provider-acp/src/server/adapter.ts(3302,49): error TS2339: Property 'error' does not exist on type '{ readonly sessionUpdate: "state_update"; readonly state: "idle"; readonly stopReason?: string | null; readonly usage?: Usage | null; readonly _meta?: Meta; }'.; packages/provider-acp/src/server/adapter.ts(4449,32): error TS2339: Property 'error' does not exist on type '{ readonly sessionUpdate: "state_update"; readonly state: "idle"; readonly stopReason?: string | null; readonly usage?: Usage | null; readonly _meta?: Meta; }'.; packages/provider-acp/src/server/adapter.ts(4450,40): error TS2339: Property 'error' does not exist on type '{ readonly sessionUpdate: "state_update"; readonly state: "idle"; readonly stopReason?: string | null; readonly usage?: Usage | null; readonly _meta?: Meta; }'.; packages/provider-acp/src/server/adapter.ts(4451,30): error TS2339: Property 'error' does not exist on type '{ readonly sessionUpdate: "state_update"; readonly state: "idle"; readonly stopReason?: string | null; readonly usage?: Usage | null; readonly _meta?: Meta; }'. No browser/device verification was run.
Fresh current-head CI/review and all existing product, maintainer, and native-evidence gates remain. Upstream permission is READ; the parent owns watches and merges.
Added 3 commits
Note
Written by gpt-6.1-sol on behalf of Maria
Verified in a real dev environment
partial verification at 6c1dca77f28717761193416227202f08d81e2ece, on a linux boat vm. ran github/main (575579d68a) in a separate worktree first, stopped its background server, then ran the exact pr head with isolated state. used repository playwright and /usr/bin/google-chrome, app-created projects and threads, and real codex gpt-6.1-sol turns. the turns completed on main and the pr head.
linked this github pr through the app, opened its live detail, and ran ten actions → refresh iterations. github summaries stayed mergeable with updatedAt=2026-10-31T07:23:50Z; the persisted snapshot-update count stayed at three across the two links. a new link initially persisted unknown and then mergeable, as expected when there is no prior known snapshot.
vp run check:changed 50c1c5dc536493826fc66e220598f38b831d5bde passed through blacksmith: format, lint, knip, graphql, affected typechecks, and 53 tests. the 52 focused reactor tests also passed. no source changes or pushes.
live pr detail after a completed codex turn and refresh
recording playback and seeking were checked in chrome; github may expose this external recording as a link rather than an inline player.
Not verified
the core known → unknown → same-known regression remains unverified in the real app. main never exhibited that sequence, and github never returned unknown for an already-known snapshot during the pr-head refresh observations. the initial unknown → known transition does not prove suppression. github controls recomputation; no mocks, forced responses, base pushes, or external pr mutations were used to manufacture it. passing tests and stable refreshes are not evidence that the live flap was suppressed.
native ios/android clients, electron shells, and forgejo were not exercised on this linux vm.