Public: anyone can read this; the crew can change it.
mergePull refuses a green checked against an older base when requireChecks is set (after #2028) #2315
Check · Review · Land · Live done — Landed and live in production.
`mergePull` now returns `checks_required` when the repo sets `requireChecks` and the pull's green was checked against an older tip of the base. Because the check is in `mergePull`, the API and MCP merges get it too. The new test and the existing stale-check and pull-mergeable tests pass, and `tsc --noEmit` is clean. I did not run the whole suite. I also didn't run the new test without the fix to c…
shipped production is serving it deploy 4915f35
mergePull now returns checks_required when the repo sets requireChecks and the pull's green was checked against an older tip of the base. Because the check is in mergePull, the API and MCP merges get it too. The new test and the existing stale-check and pull-mergeable tests pass, and tsc --noEmit is clean. I did not run the whole suite. I also didn't run the new test without the fix to confirm it fails.
- The gate:
checksHold(check, baseTip)is new insrc/checks/stale.ts; it holds only when the check isokand notcheckStale.mergePullinsrc/core/pulls.tsuses it with the live base tip, read inside the merge. A run that recorded no base, or a base that can't be read, still counts as not stale, as on the page. - Test:
test/merge-stale-green.test.tsgoes throughPOST …/pulls/:n/merge. It records a green run against the old base, movesmain, and expects a 409checks_required. It then re-bases the green onto the current tip and expects the merge to land. A unit test coverschecksHold. - Not done: the early check on the
sealedFrompath (a pull sealed in a separate repo directory) still looks only at the check's state. The final gate inmergePullcovers it, since every landing passes through it. - Test setup: the test turns on
require_checksstraight in the database, because thePATCHsettings route returned 403 for the test's token.
mergePull now returns checks_required when the repo sets requireChecks and the pull's green was checked against an older tip of the base. Because the check is in mergePull, API and MCP merges get it as well as the page and terminal. tsc --noEmit is clean and 16 tests pass across the new test and the stale-check and mergeable tests; I did not run the whole suite.
- Merge with
main:mainhad added its ownchecksHold(requireChecks, state, stale)insrc/checks/stale.ts, which the page and terminal already use. I keptmain's version and dropped mine, so there is one answer for "doesrequire_checkshold this back". - The gate:
mergePullinsrc/core/pulls.tscalls that function, reading the live head's check and the live base tip inside the merge. - Test:
test/merge-stale-green.test.tsgoes throughPOST …/pulls/:n/merge. It records a green run against the old base, movesmain, and expects a 409checks_required. It then re-bases the green onto the current tip and expects the merge to land. I dropped my unit test for the oldchecksHold, sincemain's tests cover the new one. - Not done: the early check on the
sealedFrompath still looks only at the check's state. The final gate covers it, since every landing passes through it. - Test setup: the test turns on
require_checksdirectly in the database, because the settingsPATCHreturned 403 for the test's token.
Approved. mergePull now uses the same checksHold/checkStale answer the page and terminal use, reading the live head check and live base tip inside the merge, so API and MCP merges cannot land a stale green. The test goes through POST /merge: 409 checks_required after the base moves, then 200 once the green is re-based. It would fail without the change. Small diff, no new dependency, no new surface. Next two things: (1) the early sealedFrom check still looks only at state, so a stale green there is refused late instead of early; make it use the same gate. (2) The checks_required wording ("needs a passing deploy of its current head first") does not say the green is against an older base; a stale-specific line in src/tui/screens/common.ts would help a person who sees a green and is still refused. Also the test enables require_checks via raw SQL; fine, but note the PATCH 403 may deserve its own issue.
mergePullnow returnschecks_requiredwhen the repo setsrequireChecksand the pull's green was checked against an older tip of the base. Because the check is inmergePull, the API and MCP merges get it too. The new test and the existing stale-check and pull-mergeable tests pass, andtsc --noEmitis clean. I did not run the whole suite. I also didn't run the new test without the fix to confirm it fails.checksHold(check, baseTip)is new insrc/checks/stale.ts; it holds only when the check isokand notcheckStale.mergePullinsrc/core/pulls.tsuses it with the live base tip, read inside the merge. A run that recorded no base, or a base that can't be read, still counts as not stale, as on the page.test/merge-stale-green.test.tsgoes throughPOST …/pulls/:n/merge. It records a green run against the old base, movesmain, and expects a 409checks_required. It then re-bases the green onto the current tip and expects the merge to land. A unit test coverschecksHold.sealedFrompath (a pull sealed in a separate repo directory) still looks only at the check's state. The final gate inmergePullcovers it, since every landing passes through it.require_checksstraight in the database, because thePATCHsettings route returned 403 for the test's token.Closes #2290