The gap
bin/fm-pr-merge.sh enforces "guarded merging is limited to the current default branch" on GitHub only. github_assert_default_target refuses a pull request whose target is not the default branch, naming both branches. The GitLab path contains no target-or-default comparison of any kind, so a merge request targeting a release or long-lived branch is merged with no refusal.
The point that matters: this is a fleet policy, not a GitHub property. It exists because merging into a branch nobody nominated is the same class of harm whichever forge hosts it. So enforcing it on one forge is not a partial implementation - it is a rule that silently does not apply to half the places it was written for.
Implementation and cost
It needs no new API call. gitlab_require_attested_merge already reads the project response, which carries default_branch, and gitlab_verify_mergeable already reads the merge request, which carries target_branch. The work is a comparison and a refusal message, not a new read.
Why it was filed rather than fixed
It would be a third deliberate divergence from upstream in a subsystem upstream actively develops, while two others on the same branch are still unanswered with the captain (docs/fork-divergence.md). Firstmate's estimate of what such a divergence costs has already been wrong twice on that branch, in the same direction.
Reopen trigger
The first GitLab project this fleet registers.
Until then nothing can reach this. But the reason it is unreachable is that we have no GitLab project - not that the rule is GitHub-shaped. A later reader should not mistake the first for the second.
Provenance
Found by a diff-driven neighbour sweep: the behavioural claims were enumerated from the branch diff rather than from the review findings. That scoping is what exposed it - three finding-scoped review rounds, a reviewer, an automated fixer and firstmate all walked past it, because a finding list is someone's attention while the diff is evidence.
The gap
bin/fm-pr-merge.shenforces "guarded merging is limited to the current default branch" on GitHub only.github_assert_default_targetrefuses a pull request whose target is not the default branch, naming both branches. The GitLab path contains no target-or-default comparison of any kind, so a merge request targeting a release or long-lived branch is merged with no refusal.The point that matters: this is a fleet policy, not a GitHub property. It exists because merging into a branch nobody nominated is the same class of harm whichever forge hosts it. So enforcing it on one forge is not a partial implementation - it is a rule that silently does not apply to half the places it was written for.
Implementation and cost
It needs no new API call.
gitlab_require_attested_mergealready reads the project response, which carriesdefault_branch, andgitlab_verify_mergeablealready reads the merge request, which carriestarget_branch. The work is a comparison and a refusal message, not a new read.Why it was filed rather than fixed
It would be a third deliberate divergence from upstream in a subsystem upstream actively develops, while two others on the same branch are still unanswered with the captain (
docs/fork-divergence.md). Firstmate's estimate of what such a divergence costs has already been wrong twice on that branch, in the same direction.Reopen trigger
The first GitLab project this fleet registers.
Until then nothing can reach this. But the reason it is unreachable is that we have no GitLab project - not that the rule is GitHub-shaped. A later reader should not mistake the first for the second.
Provenance
Found by a diff-driven neighbour sweep: the behavioural claims were enumerated from the branch diff rather than from the review findings. That scoping is what exposed it - three finding-scoped review rounds, a reviewer, an automated fixer and firstmate all walked past it, because a finding list is someone's attention while the diff is evidence.