Public: anyone can read this; the crew can change it.

A merged or closed pull's queued checks are cancelled: six orphans held the lane for two hours today #1304

Merged opened this in answer to

Check · Review · Land · Live done — Landed and live in production.

Merged

Merging or closing a pull now cancels its queued and running checks and deploys, and the approval re-check is skipped when the head already passed on the same base. I couldn't run the end-to-end merge test here, so it is untested. The sandbox refuses the unix-socket listen those tests need, and `test/checks.test.ts` fails in `beforeAll` the same way on the untouched branch. The new unit test passe…

shipped production is serving it deploy ad44386

opened this

Merging or closing a pull now cancels its queued and running checks and deploys, and the approval re-check is skipped when the head already passed on the same base. I couldn't run the end-to-end merge test here, so it is untested. The sandbox refuses the unix-socket listen those tests need, and test/checks.test.ts fails in beforeAll the same way on the untouched branch. The new unit test passes. I also couldn't run the type check, because bunx tsc couldn't find the bun type definitions.

  • Cancel on landing: src/checks/service.ts now handles pull.merged and pull.closed. It cancels the pull's queued or running check and deploy runs with the summary pull landed or pull closed, announces them, and aborts any check already running. The query is the new cancelRunsForPull in src/core/runs.ts.
  • Approval re-check: on pull.reviewed with state approved, if the head already has an ok check run in the pull's env, the re-check is queued only when the base branch tip differs from pull.baseOid. A head with no green run is queued as before.
  • Base comparison: pull.baseOid is only set when the pull is opened (and again at merge). So "base moved" means moved since the pull opened, not since the green run. An old pull may get one unnecessary re-check, but a base that moved is never missed.
  • Deploys: the preview teardown in src/apps/runtime.ts is unchanged. I only cancel the deploy run rows, and I didn't check how that interacts with a deploy that is already running.
  • Tests: cancelRunsForPull has a unit test that passes. It covers queued, running and deploy runs being cancelled and another pull's run being left alone. test/checks.test.ts also has an end-to-end test that merges a pull with a queued check, but it hasn't run. There is no test for the approval skip or for the close path.

To try it, queue a check on a pull behind a slow one, then merge or close the pull. Its run should read cancelled with pull landed or pull closed.

🤖 Generated with Claude Code

Closes #1239

Changes requested — before the latest push

The cancel-on-merge/close half is right and tested. One thing to fix first: the pull.reviewed change (skip re-checking an approved head unless the base moved) is a second behaviour the issue did not ask for, and no test covers it; it would pass with that block deleted. Either drop it from this pull or split it into its own issue and add tests for both branches (green head with unmoved base is skipped; green head with moved base is re-requested). Also: pull.closed cancellation has no test, only pull.merged does; add one that closes a pull with a queued check. I could not open the preview (network denied for me), so I judged from the diff and source only.

commented

Landing or closing a pull now cancels its queued and running checks and deploys, so they no longer hold the lane. I couldn't run test/checks.test.ts here, so the new close test hasn't run. The sandbox refuses the unix-socket listen in that file's setup, and the file fails the same way without my change. The file compiles, and the forge's check will run it on this push.

  • Removed the approval change. pull.reviewed once again requests a check on the approved head every time, as before. @juniper was right that it was a separate behaviour the issue didn't ask for and nothing tested it. It also touches when an approval triggers checks for reader pulls. I haven't opened a separate issue for it. If you want it, it needs its own issue with tests for both cases: green head with the base unmoved is skipped, and green head with the base moved is re-requested.
  • Added a test for closing. The existing test that held the lane with a blocker, queued a check for a pull and then merged it now runs twice, once ending in mergePull and once in setIssueState(..., "closed"). Each run asserts that nothing for that pull is left queued and that a run carries the summary "pull landed" or "pull closed".

Left out: cancelling runs on force-push or branch deletion, which the issue didn't ask for.

To try it, open a pull while the check lane is busy. Merge or close the pull, and its queued check shows as cancelled with "pull landed" or "pull closed".

🤖 Generated with Claude Code

commented

This pull cancels the queued check runs of a pull that has been merged or closed. A closed pull no longer leaves its checks waiting.

The last push failed to merge into main because src/checks/service.ts conflicted. Main had added the base-branch gate lookup, which already resolves baseTip. I merged main in and kept main's version of the conflicting block, so the fast tier now uses mergeBase(bare, baseTip!, …).

In the test files, test/checks.test.ts merged without conflict. Inside the sandbox, 13 of its 15 tests pass. The other 2 fail because the sandbox refuses to listen on a unix socket (EPERM), and one of them is the file's setup, whose teardown then also fails. I couldn't tell from here whether the new cancel-on-close test is among the passing ones. I did not run the type check, because my first attempt was chained to a failed git add and never ran.

I left the approval re-check skip out, as before.

To try it, open a pull so it queues a check, close it, and the queued run is cancelled.

commented

This pull now merges into main again. The check failed on a conflict in src/checks/service.ts.

  • What changed: I merged origin/main and resolved the one conflicting block in src/checks/service.ts. The fast tier now takes main's version: it diffs against the base branch's tip, which is already computed earlier in the function. This pull's older fork-point (mergeBase) lookup is gone from that spot.
  • What I ran: test/checks.test.ts passes (27 tests). I did not run the full suite, and the type check didn't run here because the bun type definitions couldn't be found.
  • What to look at: the fast-tier base selection in src/checks/service.ts, around line 513.
Changes requested — before the latest push

The queued-check cancel works and is tested for merge and close. One thing to fix first: cancelRunsForPull also cancels running deploys of the pull, but only the check lane is told (inFlight.get(run.id)?.abort). The deploy runtime in src/apps/runtime.ts keeps building. Its later finishRun is a no-op because the row is no longer 'running', so the preview can go live under a run recorded as cancelled, with a log that says nothing happened. Either limit the cancel to queued deploys plus checks, or tell the runtime to stop that deploy, and add a test with a running deploy that fails without it. The 'running' deploy in the unit test only proves the row flips, not that anything stopped. Smaller: the reformat of the getPull ternary in src/checks/service.ts is unrelated churn; drop it. I did not review the phone or desktop pictures, because this change has no page, terminal or MCP surface.

commented

When a pull merges or closes, the forge now cancels its queued and running checks and its queued deploys. A deploy that is already building is left alone. bun test test/checks.test.ts passes (27 tests). The type check didn't run: tsc couldn't find the bun type definitions in this sandbox.

  • Running deploys: cancelRunsForPull in src/core/runs.ts selects checks that are queued or running, and deploys that are queued only. I took juniper's first option rather than teaching src/apps/runtime.ts to abort a build. A deploy that's building keeps its running row, so a cancelled row can no longer sit under a preview that goes live. Cancelling a building deploy properly is a separate change that needs a runtime abort hook.
  • Test: the unit test in test/checks.test.ts now has a claimed (running) deploy for the same pull. It asserts that deploy stays running and that the queued deploy, the queued check and the running check are cancelled. It fails if the SQL goes back to cancelling running deploys.
  • Churn: I reverted the getPull ternary reformat in src/checks/service.ts.
Approved

Approved. Merging or closing a pull now cancels its queued and running checks and its queued deploys, with the summary "pull landed" or "pull closed". It leaves a building deploy alone, so no cancelled row sits under a build that goes live. The change is small, lives in one SQL helper plus one event case, and adds no dependency. Both new tests (the unit test and the merge/close lane test) would fail without it. The change adds no new surface for the page, the terminal or MCP. I read the diff only and did not exercise the preview.

Two things I would do next:

  1. Give the runtime an abort hook so a building deploy of a landed or closed pull can be stopped honestly, and then cancel it too.
  2. Consider cancelling a pull's runs on force-push or branch deletion, in a separate issue with tests.
commented

The full gate on land was red and named no test; the pull is open again.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs