From ce21f535a995bacffb8762bd5c8408ddf589448b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Tue, 29 Sep 2026 16:20:11 +0000 Subject: [PATCH 1/5] fix(sessions): link a pull request only on the session's verified own evidence --- .../cloud-agent-next/PrHoverCardContent.tsx | 15 +- .../cloud-agent-next/SessionPrIndicator.tsx | 7 +- .../src/components/cloud-agent-next/types.ts | 12 +- apps/web/src/lib/active-sessions-list.test.ts | 60 +- apps/web/src/lib/active-sessions-list.ts | 9 + .../platforms/github/adapter.test.ts | 187 +- .../integrations/platforms/github/adapter.ts | 87 +- .../github/batch-review-decisions.test.ts | 26 +- .../github/batch-review-decisions.ts | 27 +- .../platforms/github/pr-link-identity.test.ts | 332 + .../platforms/github/pr-link-identity.ts | 332 + ...bhook-handler-dispatch.integration.test.ts | 41 +- .../webhook-handlers/supported-platforms.ts | 13 - ...rt-cli-session-pull-request-review.test.ts | 161 +- .../upsert-cli-session-pull-request-review.ts | 37 +- .../upsert-cli-session-pull-requests.test.ts | 651 +- .../upsert-cli-session-pull-requests.ts | 181 +- .../routers/active-sessions-router.test.ts | 26 + .../routers/cli-sessions-v2-router.test.ts | 554 +- .../web/src/routers/cli-sessions-v2-router.ts | 477 +- .../routers/cli-sessions-v2-worktree.test.ts | 58 +- .../integrations/platforms/github/adapter.ts | 38 + dev/seed/app/session-pr-link.ts | 260 +- ...sessions-pr-number-index-migration.test.ts | 71 + .../src/migrations/0264_pr_link_identity.sql | 11 + ...5_cli_sessions_git_url_pr_number_index.sql | 3 + .../db/src/migrations/meta/0264_snapshot.json | 42487 +++++++++++++++ .../db/src/migrations/meta/0265_snapshot.json | 42508 ++++++++++++++++ packages/db/src/migrations/meta/_journal.json | 14 + packages/db/src/schema.ts | 44 +- .../src/dos/SessionIngestDO.test.ts | 55 + .../session-ingest/src/dos/SessionIngestDO.ts | 12 +- .../src/dos/UserConnectionDO.test.ts | 55 +- .../src/dos/UserConnectionDO.ts | 19 + .../src/dos/session-ingest-extractors.test.ts | 56 +- .../src/dos/session-ingest-extractors.ts | 45 +- .../src/ingest/metadata.test.ts | 183 +- .../session-ingest/src/ingest/metadata.ts | 98 +- .../src/types/session-sync.test.ts | 32 + .../session-ingest/src/types/session-sync.ts | 7 + .../types/user-connection-protocol.test.ts | 29 + .../src/types/user-connection-protocol.ts | 5 + 42 files changed, 88532 insertions(+), 793 deletions(-) create mode 100644 apps/web/src/lib/integrations/platforms/github/pr-link-identity.test.ts create mode 100644 apps/web/src/lib/integrations/platforms/github/pr-link-identity.ts delete mode 100644 apps/web/src/lib/integrations/platforms/github/webhook-handlers/supported-platforms.ts create mode 100644 packages/db/src/cli-sessions-pr-number-index-migration.test.ts create mode 100644 packages/db/src/migrations/0264_pr_link_identity.sql create mode 100644 packages/db/src/migrations/0265_cli_sessions_git_url_pr_number_index.sql create mode 100644 packages/db/src/migrations/meta/0264_snapshot.json create mode 100644 packages/db/src/migrations/meta/0265_snapshot.json diff --git a/apps/web/src/components/cloud-agent-next/PrHoverCardContent.tsx b/apps/web/src/components/cloud-agent-next/PrHoverCardContent.tsx index 2afdbe9c37f..2e35f9ad5e3 100644 --- a/apps/web/src/components/cloud-agent-next/PrHoverCardContent.tsx +++ b/apps/web/src/components/cloud-agent-next/PrHoverCardContent.tsx @@ -58,6 +58,12 @@ export function PrHoverCardContent({ pr, sessionId, gitBranch }: PrHoverCardCont const trpc = useTRPC(); const queryClient = useQueryClient(); const state = normalizePrBadgeState(pr.state); + // A verified link whose per-PR cache row has not synced yet renders with + // state `unknown` and no title. The Refresh action must stay reachable for + // it, or a missed webhook leaves the session's own PR stuck without live + // state. (An unverified link never reaches this component: the server shows + // no PR for it.) + const awaitingVerification = pr.state === 'unknown'; const headShaShort = pr.headSha?.slice(0, 7) ?? null; const truncatedTitle = truncatePrTitle(pr.title, 80); @@ -85,6 +91,13 @@ export function PrHoverCardContent({ pr, sessionId, gitBranch }: PrHoverCardCont PR #{pr.number} + {awaitingVerification && ( +

+ Not verified against GitHub yet. Refresh to confirm this is the session's own pull + request. +

+ )} + {truncatedTitle && (

{truncatedTitle}

)} @@ -115,7 +128,7 @@ export function PrHoverCardContent({ pr, sessionId, gitBranch }: PrHoverCardCont
- {!isWithinRefreshThrottle(pr.lastSyncedAt) && ( + {(awaitingVerification || !isWithinRefreshThrottle(pr.lastSyncedAt)) && (