Skip to content

fix: verify scraped PR URLs against the git platform before pr_opened - #561

Merged
jonwiggins merged 2 commits into
mainfrom
fix/pr-detection-verify
Aug 8, 2026
Merged

fix: verify scraped PR URLs against the git platform before pr_opened#561
jonwiggins merged 2 commits into
mainfrom
fix/pr-detection-verify

Conversation

@jonwiggins

Copy link
Copy Markdown
Owner

Summary

Fixes #531 — PR detection accepted any same-repo /pull/N URL in agent output as the task's opened PR, even when no PR was opened. As @genisd noted, even a PR URL pasted into the prompt (and echoed back by the agent) would immediately flip the task to pr_opened, pointing at a PR that may not exist or belongs to someone else.

Root cause

task-worker scans streamed agent output for PR/MR URLs and, at exec end, trusted any candidate that merely matched the task's repo (capturedPrUrl / persisted tasks.prUrl / raw-log fallback) — no check that the PR exists, is open, or was created from the task's branch.

Fix — verify against the platform before trusting the URL

Task branches are deterministic (optio/task-<taskId>), so the platform's answer for that branch is a strong, authoritative signal. Before the pr_opened transition, the worker now calls the existing GitPlatform.listOpenPullRequests(ri, { branch }) (already implemented with head/source-branch filtering for GitHub, GitLab, and CodeCommit) via a new verifyTaskPr():

  • Verified (open PR with head = task branch): transition to pr_opened using the canonical URL from the platform (wins over the scraped URL, which may be truncated or wrong).
  • No PR on the branch: the scraped URL is ignored with a logged skip, and any prUrl persisted mid-stream is cleared (clearTaskPr). The task then flows to needs_attention with reason completed_without_pr — the behavior the issue expected. The verification result is reused so the existing API-fallback path doesn't repeat the same platform call.
  • Platform unavailable (no git token, unparseable repo URL, or API error): falls back to the previous trust-the-logs behavior rather than breaking detection for that configuration. This is the graceful-degradation path — verification never turns a working setup into a broken one.

checkExistingPr (pre-agent short-circuit, API fallbacks, reconciliation) is now a thin wrapper over verifyTaskPr, so all platform lookups share one implementation.

Changes

  • apps/api/src/services/pr-detection-service.ts — new verifyTaskPr() (discriminated verified / no_pr / unavailable result) and pure resolveDetectedPrUrl() decision helper; checkExistingPr() refactored on top
  • apps/api/src/workers/task-worker.ts — verify scraped URL before the pr_opened transition; skip redundant API-fallback calls when the platform already reported no PR
  • apps/api/src/services/task-service.tsclearTaskPr() to remove a bogus prUrl/prNumber persisted during streaming
  • apps/api/src/services/pr-detection-service.test.ts — tests: prompt-echoed URL rejected when no PR exists on the branch; genuine PR with matching head branch accepted; canonical-URL preference; unavailable-platform fallback

Testing

  • pnpm turbo typecheck — 12/12 packages pass
  • apps/api vitest suite — 122 files, 2156 tests pass (includes new verification tests)
  • pnpm format:check — clean

jonwiggins and others added 2 commits July 20, 2026 17:13
A /pull/N URL matching the task's repo in agent output was trusted as
proof that the task opened a PR — including example URLs echoed straight
from the prompt. Before transitioning to pr_opened, ask the platform
(GitHub/GitLab/CodeCommit via the GitPlatform abstraction) whether an
open PR exists for the task's deterministic branch (optio/task-<id>):

- verified: use the canonical PR URL from the platform
- no PR on the branch: ignore the scraped URL (logged) and clear any
  prUrl persisted mid-stream, so the task escalates to
  needs_attention (completed_without_pr) instead of pr_opened
- platform unavailable (no token / API error): fall back to the
  previous trust-the-logs behavior

Fixes #531
@jonwiggins
jonwiggins merged commit dec2d92 into main Aug 8, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PR detection accepts any same-repo /pull/N URL in agent output, even when no PR was opened

1 participant