Problem
mutation-diff resolves its base as the merge commit's first parent, which is the base branch tip. For a stacked unit that base is main, so every unmerged ancestor is charged to the unit. The gate measures the chain, not the unit.
Measured on the file-safety chain against main (9af6f87e tip, extension package entry, cap 500):
| unit |
own delta |
measured against main |
result |
| U1 #1910 |
203 |
210 |
green |
| U2 #1911 |
27 |
237 |
red |
| U3 #1912 |
12 |
250 |
red |
| U4 #1913 |
37 |
287 |
red |
| U5 #1914 |
225 |
512 |
red |
| U8 #1916 |
215 |
727 |
red |
| U6 #1915 |
52 |
783 |
red |
| U7 #1918 |
33 |
815 |
red |
| U9 #1917 |
12 |
827 |
red |
Every unit is individually compliant. The red is a measurement artifact, and it makes the check ineffective for stacked PRs: it reports nothing about the unit under review, and it forces work (further splitting) that would not be needed if the gate measured the unit.
Failure evidence, run for f8d2a8d06:
HEAD_SHA: 12aee9c3ca02263ea3ac6357e0f3495d3ee4852d # GitHub merge commit, not the PR head
Mutation gate failed: extension has 512 changed executable lines (limit 500).
Design
The merge commit's second parent is the pull request head. When that head's own parent is the head of another open pull request, the pull request is a stacked unit, and that parent is its real base. The diff then contains only the unit's delta.
- Detection is by graph, not by a label or a mapping file: the parent commit is only accepted when it is another open pull request's head.
- A pull request whose parent is not another pull request head keeps the event base, so a multi-commit pull request is never charged only its last commit.
- An unparsable stacked map degrades to the event base instead of throwing.
- The job summary records which base was used, so a reviewer can tell whether the number is the unit or the chain.
- The merge-queue enforcement is unchanged: when a unit enters the queue its base is
main, so the cumulative cap is still checked at the moment it matters.
With this, all nine units measure their own delta and pass.
Second requirement: reviewer filtering
A reviewer cannot tell a stacked unit apart from a standalone PR in the PR list, so the reconcile
workflow also applies a stacked label to a unit. That half is specified and tracked in #1945 and
delivered by #1925, so this issue is judged against the measurement work only. The label is not a
detection signal here: the gate detects a unit from the commit graph, as specified above.
This issue is closed only after both PRs land.
Implementation
PR: #1924
scripts/stryker-diff.mjs — resolveStackedUnitBase + parseStackedMap, wired into the ci command through an optional --stacked-map.
.github/workflows/mutation-testing.yml — pull-requests: read, builds the open pull request map with gh api, passes --stacked-map.
scripts/stryker-diff.test.mjs — three new cases (stacked parent, non-stacked parent keeps the event base, unparsable map) plus workflow-shape assertions.
Local run: node --test scripts/stryker-diff.test.mjs — 47 tests, 0 fail.
Problem
mutation-diffresolves its base as the merge commit's first parent, which is the base branch tip. For a stacked unit that base ismain, so every unmerged ancestor is charged to the unit. The gate measures the chain, not the unit.Measured on the file-safety chain against
main(9af6f87etip,extensionpackage entry, cap 500):Every unit is individually compliant. The red is a measurement artifact, and it makes the check ineffective for stacked PRs: it reports nothing about the unit under review, and it forces work (further splitting) that would not be needed if the gate measured the unit.
Failure evidence, run for
f8d2a8d06:Design
The merge commit's second parent is the pull request head. When that head's own parent is the head of another open pull request, the pull request is a stacked unit, and that parent is its real base. The diff then contains only the unit's delta.
main, so the cumulative cap is still checked at the moment it matters.With this, all nine units measure their own delta and pass.
Second requirement: reviewer filtering
A reviewer cannot tell a stacked unit apart from a standalone PR in the PR list, so the reconcile
workflow also applies a
stackedlabel to a unit. That half is specified and tracked in #1945 anddelivered by #1925, so this issue is judged against the measurement work only. The label is not a
detection signal here: the gate detects a unit from the commit graph, as specified above.
This issue is closed only after both PRs land.
Implementation
PR: #1924
scripts/stryker-diff.mjs—resolveStackedUnitBase+parseStackedMap, wired into thecicommand through an optional--stacked-map..github/workflows/mutation-testing.yml—pull-requests: read, builds the open pull request map withgh api, passes--stacked-map.scripts/stryker-diff.test.mjs— three new cases (stacked parent, non-stacked parent keeps the event base, unparsable map) plus workflow-shape assertions.Local run:
node --test scripts/stryker-diff.test.mjs— 47 tests, 0 fail.