Merging PRs back to back can break main, and every check passed on the way in
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 9
- Forks
- 0
- Avg merge
- 3h 3m
- Merged PRs (30d)
- 509
Description
What happened
On 2026-08-12, #481, #485, #486 and #487 were merged within about ninety seconds of each other. All four were green: 7 of 7 checks each, on their current heads, against a main that at the time contained none of the others.
main did not build afterwards:
pkg/flowstate/v1/eval.go:1440:56: not enough arguments in call to runNodes
have (context.Context, []*Node, *Scope, *UndoLog, UndoScope, int)
want (context.Context, []*Node, *Scope, *UndoLog, UndoScope, int, map[string]struct{})
#485 added runSwitch, which calls runNodes with six arguments. #481 gave runNodes a seventh parameter, the set of body step ids whose failure was tolerated. Neither change conflicts textually, so git merged both without complaint, and neither PR's CI ever compiled the other's tree. The first thing to notice the breakage was an unrelated docs-only PR (#488), whose five red jobs had nothing to do with its diff.
The code fix rides in #483, which threads tolerated through runNodeWithVars, runNode and runSwitch.
Why the existing gates cannot catch this
Every check we have answers a question about one tree: this branch, merged with the main that existed when CI started. A semantic merge conflict is a property of a tree that has never been built anywhere, and it appears at the moment of the second merge. make check, the diff-scoped gate, and the required CI jobs are all blind to it by construction, and adding more checks to any of them does not help.
The failure is also silent in the worst way: it does not show up on the PR that causes it. It shows up later, on whoever pushes next, which is how a docs change to three markdown files came to have a red test job.
Options
- Require branches to be up to date before merging (branch protection setting). GitHub then forces each PR to absorb
mainand re-run CI before it can land, so the second merge in a batch cannot happen until the combined tree has actually been built. Costs one CI round trip per PR in a batch, which is exactly the cost of knowing. This is an owner decision, not something an agent can set. - A merge queue, which does the same thing without the manual rebase, at the price of more moving parts.
- A rule for whoever is merging: after each merge, rebase the next PR onto the new
mainand wait for green before merging it. Free, and only as reliable as the person or agent following it.
Option 1 is the one that cannot be forgotten.
Related
- The four PRs: #481, #485, #486, #487
- The repair: #483
- The false alarm it produced: #488
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the failure in pkg/flowstate/v1/eval.go and the repair described in #483, then review the branch-protection option in this issue. The intended outcome is that a pull request must update from main and pass CI before merging, preventing back-to-back merges from producing an unbuilt tree; repository-owner access is required to apply this setting.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github, go
- Domain
- ci-cd, devops
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100