Repository navigation
feat(errors): pick the pull request to attach, and hydrate it on link - #642
Merged
Merged
Conversation
Attaching a PR is the hinge of the fix→verify loop: the link is what opens a post-merge verification window and lets an issue close on evidence. That hinge was a bare text box asking for a PR URL, so the flow was leave Maple, find the PR on GitHub, copy, come back, paste — while the org's repositories were already synced and could simply have been offered. Fixes a real bug along the way. linkPullRequest only string-parsed the URL and stored title: null, state: "open", waiting for a webhook to enrich the row. For a PR that merged BEFORE it was attached — the normal human order of operations — no `closed` event is ever redelivered, so the verification window never opened and the issue sat in `in_review` indefinitely. The merge handling is now factored out of onPullRequestEvent into a shared openMergedVerifications and called from the link path too. - VcsProviderClient gains fetchPullRequests / fetchPullRequest, implemented over /pulls. One page, sort=updated, no pagination walk: the PR that fixes a live issue is recent by construction. Deliberately not /search/issues, whose 30-req/min secondary limit suits a keystroke-driven picker poorly — filtering happens client-side over the fetched page. - GET /api/integrations/vcs/pull-requests exposes them, scoped to one connected repository so the picker's options can never cross a tenant boundary. - Hydration crosses the VCS↔errors boundary through a new PullRequestLookup port, mirroring PullRequestEventSink but pointing the other way, so errors never imports the VCS layer. Strictly best-effort: an unconnected repo or an unreachable provider stores the link unenriched, exactly as before. A re-attach also repairs a stale row whose webhook was missed. - listIssuePullRequests now carries suggestedRepository, so the picker opens on the right repo with no extra round trip. Four Postgres-only signals, first hit wins: a repo already linked to this issue, the only connected repo, an unambiguous service-name match, then wherever the org's fixes most recently landed. It abstains rather than guess when two repos match — a silent wrong preselection is only noticed after somebody attaches the wrong PR. - The dialog moves into its own component so the panel, the verification slot, and the in_review transition can all open it. Pasting still works (full URL, #123, or a bare number), which stays the only way to attach a PR in a repo the org has not connected — something the link table deliberately supports. Verified locally against a seeded installation: the suggester resolves by name match and falls back to the most recent link when nothing matches; the paste path attaches and stores an unenriched row when the provider is unreachable; the not-connected fallback renders. Also fixed the new nudge button overflowing the 255px rail. The new runtime/vcs-source-layer.ts is added to the vendor-import allowlist in .oxlintrc.json — it is a composition root, which is what lets the alerting worker get a source service without naming a provider module itself.
Contributor
🍁 Maple PR previewWarning Preview cleanup could not be confirmed. The Alchemy teardown outcome was Final commit |
This branch had an error being deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Attaching a PR is the hinge of the whole fix→verify loop in
docs/error-issue-lifecycle.md— the link is what opens a post-merge verification window and lets Maple close an issue on evidence rather than on someone's word. That hinge was one text box asking forhttps://github.com/owner/repo/pull/123: leave Maple, find the PR, copy, come back, paste. Meanwhile the org's installation, repos and branches are already synced intovcs_*, and the issue knows itsserviceName. Everything needed to just offer the right PR was already there and unused.The bug this also fixes
linkPullRequestnever called the provider. It string-parsed the URL and storedtitle: null, authorLogin: null, state: "open", and the row was only ever enriched when apull_requestwebhook arrived.So a PR that merged before it was attached — the normal human order of operations — never verified. GitHub does not redeliver a past
closedevent,onPullRequestEventnever fired, the verification window never opened, and the issue sat inin_reviewforever.Merge handling is now factored out of
onPullRequestEventinto a sharedopenMergedVerifications, called from the link path too.What changed
Provider port —
VcsProviderClientgainsfetchPullRequests/fetchPullRequest, implemented over/pulls. One page,sort=updated&direction=desc, no pagination walk: the PR that fixes a live issue is recent by construction, and a walk would spend an installation's rate budget on history nobody scrolls to. Deliberately not/search/issues— its 30-req/min secondary limit is a poor fit for a keystroke-driven picker, so filtering happens client-side over the fetched page.stateis normalized at the provider (merged_at != null ⇒ "merged"), the same rule the webhook mapper already applies.Endpoint —
GET /api/integrations/vcs/pull-requests?repository=&limit=, scoped to one connected repository so the picker's options can never cross a tenant boundary. An unconnected repo comes back as a 400, not a generic 404.Hydration — crosses the VCS↔errors boundary through a new
PullRequestLookupport, mirroringPullRequestEventSinkbut pointing the other way, so the errors side never imports the VCS layer. Strictly best-effort: an unconnected repo or an unreachable provider stores the link unenriched, exactly as today. A re-attach now also repairs a stale row whose webhook was missed, instead of the conflict path silently ignoring it.Repo suggestion — rides on the existing
listIssuePullRequestsresponse, so no extra round trip. Four Postgres-only signals, first hit wins:serviceName↔ repo-name matchIt abstains rather than guessing when two repos match. A silent wrong preselection is worse than none — it is only noticed after somebody attaches the wrong PR. Resolving
deployment.commit_sha→vcs_commitswould be exact but puts a warehouse read on the issue page to compute a default; skipped on purpose.UI — the dialog moves into
attach-pull-request-dialog.tsxso three call sites can open it: the panel, the verification slot (when anin_progress/in_reviewissue has nothing attached), and after a transition toin_review. Pasting still works — full URL,#123, or a bare number — and stays the only way to attach a PR in a repo the org has not connected, whicherror_issue_pull_requestsdeliberately supports by not being FK'd tovcs_repositories.Verification
bun typecheckandbun run lintclean. 140 tests pass across the touched suites, 11 of them new — including one asserting that attaching an already-merged PR opens a verification window, and one that the suggester abstains on an ambiguous match.Browser pass against a locally seeded installation with three repos:
subscriptions-apiissue, and for anintegration-routerissue correctly abstained and fell back to the org's most recent link (both confirmed from the API response, not the client fallback)Not covered by the browser pass: a populated PR list against live data. There were no real App credentials locally, so
vcs/pull-requestsreturned a correctly-mapped 502 throughout; that path rests on the unit tests.For the reviewer
.oxlintrc.jsongains one entry.apps/api/src/runtime/vcs-source-layer.tsis added to the vendor-import allowlist — it is a genuine composition root, and it exists so the alerting worker can get a source service without naming a provider module itself. Worth a look since it is a lint-config change.vcs-sync-runtime.ts) bindsPullRequestLookup.noneon purpose: it only handles deliveries that already carry the PR's title, state and merge, so nothing there asks a provider anything.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.