Epic 7 — Pull Request Delivery

Covers the PR delivery card (URL, branch, commit SHA, files changed), idempotent re-PR detection, the StaleBaseBranch terminal failure card, and live PR-lock contention status. This epic renders the StaleBaseBranch and pr_lock failure classes.

Personas: BU (primary viewer) OP

Shared modules: CorrelationChip LastSyncedBadge EnvProvenance

Story 7.1 — View PR Delivery Card

As a
BU
I want
to see the pull request created by the pipeline for a completed run
So that
I can review and merge the generated test changes
Scenario: PR delivery card renders for a passed run
Giventhe run's status is passed and a pull request has been created by the test_engineer_output stage WhenGET /runs/{run_id}/pull_request resolves Thena PR card is rendered showing the PR URL (external link, new tab), branch_name, commit_sha, and the count of files changed
Scenario: PR not yet created — stage still running
Giventhe PR delivery stage is still running Thena Creating pull request… loading state is shown with a spinner; no PR card is rendered until the stage completes
Scenario: Run failed — no PR card
Giventhe run's status is failed (not from PR delivery failure) Thenthe PR delivery section shows a Run did not complete — no PR created empty state
Endpoint / DBPurpose
GET /runs/{run_id}/pull_requestPR metadata (URL, branch, commit SHA, files changed)
DB runs.commit_sha, runs.branch_nameRun branch details

Story 7.2 — Idempotent Re-PR Detection

As a
BU
I want
to see when a re-run has detected an existing open PR for the same branch
So that
I am not confused by the pipeline skipping PR creation
Scenario: Existing open PR detected — idempotent result card
Givena re-run targets the same branch as an existing open PR and the pipeline detects it via the GitHub App Whenthe PR delivery stage completes Thenthe PR card renders with a Re-PR detected badge; copy reads: An open PR already exists for this branch. The pipeline has linked to the existing PR rather than creating a duplicate.; the existing PR URL is shown
Endpoint / DBPurpose
GET /runs/{run_id}/pull_requestis_existing_pr: true flag triggers the idempotent card variant

Story 7.3 — StaleBaseBranch Terminal Failure Card

As a
BU
I want
to see a clear StaleBaseBranch failure explanation when the pipeline cannot deliver a PR because the base branch has diverged
So that
I know to rebase and retrigger rather than investigating the agent logic
Scenario: StaleBaseBranch failure card renders on PR delivery section
Giventhe PR delivery stage has failed with error class StaleBaseBranch Whenthe run timeline renders the PR delivery section Thena StaleBaseBranch terminal failure card is shown with copy: The target base branch has moved ahead since this run started. Rebase your branch and trigger a new run. Andthe CorrelationChip shows run_id and request_id; a Trigger new run button is provided (cross-link to Epic 3); no PR URL is shown
Endpoint / DBPurpose
GET /runs/{run_id}/pull_requesterror: "StaleBaseBranch" triggers this card
DB runs.status = failedTerminal state guard

Story 7.4 — PR-Lock Contention Live Status

As a
BU
I want
to see a live status when the pipeline is waiting for the repository advisory lock to be released
So that
I understand the run is healthy and simply queued behind another PR delivery for the same repository
Scenario: pr_lock wait state rendered on PR delivery stage card
Giventhe PR delivery stage is running and the SSE stream emits a pr_lock_waiting event Whenthe stage card processes the event Thenthe card renders a Waiting for repository lock status with a spinner and an elapsed wait timer; CorrelationChip shows run_id
Scenario: Lock released — PR delivery resumes
Whenthe SSE stream emits a pr_lock_acquired event Thenthe lock-wait status is dismissed and the stage card resumes normal running state
Scenario: pr_lock 409 on run trigger (Epic 3 cross-link)
Givena concurrent run trigger is attempted while the lock is held and POST /runs returns 409 with error pr_lock Whenthe optimistic run row rollback fires (Story 3.2) Thenthe failure cause displayed is pr_lock contention with the CorrelationChip
Endpoint / DBPurpose
SSE /runs/{run_id}/eventsEvents: pr_lock_waiting, pr_lock_acquired
POST /runs409 pr_lock triggers rollback (Story 3.2)