feat(mutation): share the full cold run as a reusable workflow - #29
Merged
Conversation
Every library over the five-minute per-push budget is moving to an incremental Stryker run, which needs a cold measurement behind it — an incremental run reuses stored verdicts, and Stryker's guidance is that reused verdicts for STATIC mutants can be stale. That cold run was written once, in nest-auth, and copying it into eight more repositories would put a 130-line decision in nine places to drift. It also fixes two things the copy could not. The caller's workflow file is now DERIVED from `github.workflow_ref` rather than hardcoded — the copy compared against `gh run list --workflow mutation-full.yml`, so a caller naming its file anything else would find no previous run, forever, and green, because "no previous run" fails open into running. And the pathspec list is an input with a superset default; a pathspec absent from a caller matches nothing rather than erroring, so one default fits repositories with different Jest and TypeScript config layouts. The caller keeps what is genuinely per-repository: the schedule, the ceiling, and its Stryker configuration.
There was a problem hiding this comment.
Pull request overview
Introduces a new reusable GitHub Actions workflow that runs a weekly “cold” (full) Stryker mutation suite for Node libraries/apps, with logic to skip runs when score-affecting files haven’t changed and to refresh the incremental baseline cache used by per-push mutation jobs.
Changes:
- Adds
.github/workflows/mutation-full.ymlreusable workflow (workflow_call) with inputs for timeout, command, and score-relevant pathspecs. - Implements “should we run?” logic by comparing against the last successful run of the caller’s workflow file.
- Saves the Stryker incremental baseline cache and uploads mutation reports when the suite runs.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+64
to
+67
| permissions: | ||
| contents: read | ||
| # `gh run list`, in the step that decides whether anything can have moved the score. | ||
| actions: read |
msalvatti
added a commit
to bymaxone/nest-ai-tokens
that referenced
this pull request
Aug 8, 2026
…each week (#64) ## The change The per-push mutation run becomes **incremental**, and a **weekly cold run** is added behind it. Mutation is the deepest gate in this repository and it was cold on every push that touched `src/` — the honest measurement, but it puts the whole cold duration in the path of every merge. `incremental: true` makes the routine run re-test only what changed. That is a trade rather than a free win: an incremental run reuses stored verdicts, and Stryker's own guidance is that reused verdicts for **static** mutants can be stale. So the truth is measured cold once a week, and that run also refreshes the baseline the following week's pushes reuse. ## Where the logic lives The weekly job is a **thin caller**. The 130 lines that decide what counts as "the score can have moved", why the job is pinned to the default branch, and why a partial baseline must never be saved live once in [`bymaxone/.github`](bymaxone/.github#29) and are shared by every library. What stays here is what is genuinely local: - **the schedule**, staggered against the other libraries so a Monday morning does not start ten cold suites at once; - **the ceilings**, calibrated to this repository's own measured cold duration. ## What the weekly run skips It compares against the commit the last successful run measured and skips when nothing that can move the score has changed. That surface is deliberately wider than the per-push job's `^(src/)`: the score also moves when a **test** changes (a new test kills a mutant that survived), when the Stryker or Jest configuration changes, or when a dependency changes underneath the suite. Gating on `src/` alone would skip exactly the week someone spent writing tests — the week most likely to change the number. ## Why the ceiling is not the old default The per-push run is fast now, but the ceiling exists for the **cold** one: the first run after this merges has no baseline, and neither does any run whose cache expired. The job is *cancelled* rather than failed when it lands, which reads as an infrastructure blip rather than a budget — that is exactly how nest-auth's mutation gate produced nothing for weeks.
msalvatti
added a commit
to bymaxone/nest-auth
that referenced
this pull request
Aug 8, 2026
…each week (#86) ## The change The per-push mutation run becomes **incremental**, and a **weekly cold run** is added behind it. Mutation is the deepest gate in this repository and it was cold on every push that touched `src/` — the honest measurement, but it puts the whole cold duration in the path of every merge. `incremental: true` makes the routine run re-test only what changed. That is a trade rather than a free win: an incremental run reuses stored verdicts, and Stryker's own guidance is that reused verdicts for **static** mutants can be stale. So the truth is measured cold once a week, and that run also refreshes the baseline the following week's pushes reuse. ## Where the logic lives The weekly job is a **thin caller**. The 130 lines that decide what counts as "the score can have moved", why the job is pinned to the default branch, and why a partial baseline must never be saved live once in [`bymaxone/.github`](bymaxone/.github#29) and are shared by every library. What stays here is what is genuinely local: - **the schedule**, staggered against the other libraries so a Monday morning does not start ten cold suites at once; - **the ceilings**, calibrated to this repository's own measured cold duration. ## What the weekly run skips It compares against the commit the last successful run measured and skips when nothing that can move the score has changed. That surface is deliberately wider than the per-push job's `^(src/)`: the score also moves when a **test** changes (a new test kills a mutant that survived), when the Stryker or Jest configuration changes, or when a dependency changes underneath the suite. Gating on `src/` alone would skip exactly the week someone spent writing tests — the week most likely to change the number. ## Why the ceiling is not the old default The per-push run is fast now, but the ceiling exists for the **cold** one: the first run after this merges has no baseline, and neither does any run whose cache expired. The job is *cancelled* rather than failed when it lands, which reads as an infrastructure blip rather than a budget — that is exactly how nest-auth's mutation gate produced nothing for weeks.
msalvatti
added a commit
to bymaxone/nest-cache
that referenced
this pull request
Aug 8, 2026
…each week (#70) ## The change The per-push mutation run becomes **incremental**, and a **weekly cold run** is added behind it. Mutation is the deepest gate in this repository and it was cold on every push that touched `src/` — the honest measurement, but it puts the whole cold duration in the path of every merge. `incremental: true` makes the routine run re-test only what changed. That is a trade rather than a free win: an incremental run reuses stored verdicts, and Stryker's own guidance is that reused verdicts for **static** mutants can be stale. So the truth is measured cold once a week, and that run also refreshes the baseline the following week's pushes reuse. ## Where the logic lives The weekly job is a **thin caller**. The 130 lines that decide what counts as "the score can have moved", why the job is pinned to the default branch, and why a partial baseline must never be saved live once in [`bymaxone/.github`](bymaxone/.github#29) and are shared by every library. What stays here is what is genuinely local: - **the schedule**, staggered against the other libraries so a Monday morning does not start ten cold suites at once; - **the ceilings**, calibrated to this repository's own measured cold duration. ## What the weekly run skips It compares against the commit the last successful run measured and skips when nothing that can move the score has changed. That surface is deliberately wider than the per-push job's `^(src/)`: the score also moves when a **test** changes (a new test kills a mutant that survived), when the Stryker or Jest configuration changes, or when a dependency changes underneath the suite. Gating on `src/` alone would skip exactly the week someone spent writing tests — the week most likely to change the number. ## Why the ceiling is not the old default The per-push run is fast now, but the ceiling exists for the **cold** one: the first run after this merges has no baseline, and neither does any run whose cache expired. The job is *cancelled* rather than failed when it lands, which reads as an infrastructure blip rather than a budget — that is exactly how nest-auth's mutation gate produced nothing for weeks.
msalvatti
added a commit
to bymaxone/nest-config
that referenced
this pull request
Aug 8, 2026
…each week (#47) ## The change The per-push mutation run becomes **incremental**, and a **weekly cold run** is added behind it. Mutation is the deepest gate in this repository and it was cold on every push that touched `src/` — the honest measurement, but it puts the whole cold duration in the path of every merge. `incremental: true` makes the routine run re-test only what changed. That is a trade rather than a free win: an incremental run reuses stored verdicts, and Stryker's own guidance is that reused verdicts for **static** mutants can be stale. So the truth is measured cold once a week, and that run also refreshes the baseline the following week's pushes reuse. ## Where the logic lives The weekly job is a **thin caller**. The 130 lines that decide what counts as "the score can have moved", why the job is pinned to the default branch, and why a partial baseline must never be saved live once in [`bymaxone/.github`](bymaxone/.github#29) and are shared by every library. What stays here is what is genuinely local: - **the schedule**, staggered against the other libraries so a Monday morning does not start ten cold suites at once; - **the ceilings**, calibrated to this repository's own measured cold duration. ## What the weekly run skips It compares against the commit the last successful run measured and skips when nothing that can move the score has changed. That surface is deliberately wider than the per-push job's `^(src/)`: the score also moves when a **test** changes (a new test kills a mutant that survived), when the Stryker or Jest configuration changes, or when a dependency changes underneath the suite. Gating on `src/` alone would skip exactly the week someone spent writing tests — the week most likely to change the number. ## Why the ceiling is not the old default The per-push run is fast now, but the ceiling exists for the **cold** one: the first run after this merges has no baseline, and neither does any run whose cache expired. The job is *cancelled* rather than failed when it lands, which reads as an infrastructure blip rather than a budget — that is exactly how nest-auth's mutation gate produced nothing for weeks.
msalvatti
added a commit
to bymaxone/nest-core
that referenced
this pull request
Aug 8, 2026
…each week (#55) ## The change The per-push mutation run becomes **incremental**, and a **weekly cold run** is added behind it. Mutation is the deepest gate in this repository and it was cold on every push that touched `src/` — the honest measurement, but it puts the whole cold duration in the path of every merge. `incremental: true` makes the routine run re-test only what changed. That is a trade rather than a free win: an incremental run reuses stored verdicts, and Stryker's own guidance is that reused verdicts for **static** mutants can be stale. So the truth is measured cold once a week, and that run also refreshes the baseline the following week's pushes reuse. ## Where the logic lives The weekly job is a **thin caller**. The 130 lines that decide what counts as "the score can have moved", why the job is pinned to the default branch, and why a partial baseline must never be saved live once in [`bymaxone/.github`](bymaxone/.github#29) and are shared by every library. What stays here is what is genuinely local: - **the schedule**, staggered against the other libraries so a Monday morning does not start ten cold suites at once; - **the ceilings**, calibrated to this repository's own measured cold duration. ## What the weekly run skips It compares against the commit the last successful run measured and skips when nothing that can move the score has changed. That surface is deliberately wider than the per-push job's `^(src/)`: the score also moves when a **test** changes (a new test kills a mutant that survived), when the Stryker or Jest configuration changes, or when a dependency changes underneath the suite. Gating on `src/` alone would skip exactly the week someone spent writing tests — the week most likely to change the number. ## Why the ceiling is not the old default The per-push run is fast now, but the ceiling exists for the **cold** one: the first run after this merges has no baseline, and neither does any run whose cache expired. The job is *cancelled* rather than failed when it lands, which reads as an infrastructure blip rather than a budget — that is exactly how nest-auth's mutation gate produced nothing for weeks.
msalvatti
added a commit
to bymaxone/nest-logger
that referenced
this pull request
Aug 8, 2026
…each week (#74) ## The change The per-push mutation run becomes **incremental**, and a **weekly cold run** is added behind it. Mutation is the deepest gate in this repository and it was cold on every push that touched `src/` — the honest measurement, but it puts the whole cold duration in the path of every merge. `incremental: true` makes the routine run re-test only what changed. That is a trade rather than a free win: an incremental run reuses stored verdicts, and Stryker's own guidance is that reused verdicts for **static** mutants can be stale. So the truth is measured cold once a week, and that run also refreshes the baseline the following week's pushes reuse. ## Where the logic lives The weekly job is a **thin caller**. The 130 lines that decide what counts as "the score can have moved", why the job is pinned to the default branch, and why a partial baseline must never be saved live once in [`bymaxone/.github`](bymaxone/.github#29) and are shared by every library. What stays here is what is genuinely local: - **the schedule**, staggered against the other libraries so a Monday morning does not start ten cold suites at once; - **the ceilings**, calibrated to this repository's own measured cold duration. ## What the weekly run skips It compares against the commit the last successful run measured and skips when nothing that can move the score has changed. That surface is deliberately wider than the per-push job's `^(src/)`: the score also moves when a **test** changes (a new test kills a mutant that survived), when the Stryker or Jest configuration changes, or when a dependency changes underneath the suite. Gating on `src/` alone would skip exactly the week someone spent writing tests — the week most likely to change the number. ## Why the ceiling is not the old default The per-push run is fast now, but the ceiling exists for the **cold** one: the first run after this merges has no baseline, and neither does any run whose cache expired. The job is *cancelled* rather than failed when it lands, which reads as an infrastructure blip rather than a budget — that is exactly how nest-auth's mutation gate produced nothing for weeks.
msalvatti
added a commit
to bymaxone/nest-notification
that referenced
this pull request
Aug 8, 2026
…each week (#52) ## The change The per-push mutation run becomes **incremental**, and a **weekly cold run** is added behind it. Mutation is the deepest gate in this repository and it was cold on every push that touched `src/` — the honest measurement, but it puts the whole cold duration in the path of every merge. `incremental: true` makes the routine run re-test only what changed. That is a trade rather than a free win: an incremental run reuses stored verdicts, and Stryker's own guidance is that reused verdicts for **static** mutants can be stale. So the truth is measured cold once a week, and that run also refreshes the baseline the following week's pushes reuse. ## Where the logic lives The weekly job is a **thin caller**. The 130 lines that decide what counts as "the score can have moved", why the job is pinned to the default branch, and why a partial baseline must never be saved live once in [`bymaxone/.github`](bymaxone/.github#29) and are shared by every library. What stays here is what is genuinely local: - **the schedule**, staggered against the other libraries so a Monday morning does not start ten cold suites at once; - **the ceilings**, calibrated to this repository's own measured cold duration. ## What the weekly run skips It compares against the commit the last successful run measured and skips when nothing that can move the score has changed. That surface is deliberately wider than the per-push job's `^(src/)`: the score also moves when a **test** changes (a new test kills a mutant that survived), when the Stryker or Jest configuration changes, or when a dependency changes underneath the suite. Gating on `src/` alone would skip exactly the week someone spent writing tests — the week most likely to change the number. ## Why the ceiling is not the old default The per-push run is fast now, but the ceiling exists for the **cold** one: the first run after this merges has no baseline, and neither does any run whose cache expired. The job is *cancelled* rather than failed when it lands, which reads as an infrastructure blip rather than a budget — that is exactly how nest-auth's mutation gate produced nothing for weeks.
msalvatti
added a commit
to bymaxone/nest-queue
that referenced
this pull request
Aug 8, 2026
…each week (#87) ## The change The per-push mutation run becomes **incremental**, and a **weekly cold run** is added behind it. Mutation is the deepest gate in this repository and it was cold on every push that touched `src/` — the honest measurement, but it puts the whole cold duration in the path of every merge. `incremental: true` makes the routine run re-test only what changed. That is a trade rather than a free win: an incremental run reuses stored verdicts, and Stryker's own guidance is that reused verdicts for **static** mutants can be stale. So the truth is measured cold once a week, and that run also refreshes the baseline the following week's pushes reuse. ## Where the logic lives The weekly job is a **thin caller**. The 130 lines that decide what counts as "the score can have moved", why the job is pinned to the default branch, and why a partial baseline must never be saved live once in [`bymaxone/.github`](bymaxone/.github#29) and are shared by every library. What stays here is what is genuinely local: - **the schedule**, staggered against the other libraries so a Monday morning does not start ten cold suites at once; - **the ceilings**, calibrated to this repository's own measured cold duration. ## What the weekly run skips It compares against the commit the last successful run measured and skips when nothing that can move the score has changed. That surface is deliberately wider than the per-push job's `^(src/)`: the score also moves when a **test** changes (a new test kills a mutant that survived), when the Stryker or Jest configuration changes, or when a dependency changes underneath the suite. Gating on `src/` alone would skip exactly the week someone spent writing tests — the week most likely to change the number. ## Why the ceiling is not the old default The per-push run is fast now, but the ceiling exists for the **cold** one: the first run after this merges has no baseline, and neither does any run whose cache expired. The job is *cancelled* rather than failed when it lands, which reads as an infrastructure blip rather than a budget — that is exactly how nest-auth's mutation gate produced nothing for weeks.
msalvatti
added a commit
to bymaxone/nest-realtime
that referenced
this pull request
Aug 8, 2026
…each week (#94) ## The change The per-push mutation run becomes **incremental**, and a **weekly cold run** is added behind it. Mutation is the deepest gate in this repository and it was cold on every push that touched `src/` — the honest measurement, but it puts the whole cold duration in the path of every merge. `incremental: true` makes the routine run re-test only what changed. That is a trade rather than a free win: an incremental run reuses stored verdicts, and Stryker's own guidance is that reused verdicts for **static** mutants can be stale. So the truth is measured cold once a week, and that run also refreshes the baseline the following week's pushes reuse. ## Where the logic lives The weekly job is a **thin caller**. The 130 lines that decide what counts as "the score can have moved", why the job is pinned to the default branch, and why a partial baseline must never be saved live once in [`bymaxone/.github`](bymaxone/.github#29) and are shared by every library. What stays here is what is genuinely local: - **the schedule**, staggered against the other libraries so a Monday morning does not start ten cold suites at once; - **the ceilings**, calibrated to this repository's own measured cold duration. ## What the weekly run skips It compares against the commit the last successful run measured and skips when nothing that can move the score has changed. That surface is deliberately wider than the per-push job's `^(src/)`: the score also moves when a **test** changes (a new test kills a mutant that survived), when the Stryker or Jest configuration changes, or when a dependency changes underneath the suite. Gating on `src/` alone would skip exactly the week someone spent writing tests — the week most likely to change the number. ## Why the ceiling is not the old default The per-push run is fast now, but the ceiling exists for the **cold** one: the first run after this merges has no baseline, and neither does any run whose cache expired. The job is *cancelled* rather than failed when it lands, which reads as an infrastructure blip rather than a budget — that is exactly how nest-auth's mutation gate produced nothing for weeks.
msalvatti
added a commit
to bymaxone/nest-storage
that referenced
this pull request
Aug 8, 2026
…each week (#58) ## The change The per-push mutation run becomes **incremental**, and a **weekly cold run** is added behind it. Mutation is the deepest gate in this repository and it was cold on every push that touched `src/` — the honest measurement, but it puts the whole cold duration in the path of every merge. `incremental: true` makes the routine run re-test only what changed. That is a trade rather than a free win: an incremental run reuses stored verdicts, and Stryker's own guidance is that reused verdicts for **static** mutants can be stale. So the truth is measured cold once a week, and that run also refreshes the baseline the following week's pushes reuse. ## Where the logic lives The weekly job is a **thin caller**. The 130 lines that decide what counts as "the score can have moved", why the job is pinned to the default branch, and why a partial baseline must never be saved live once in [`bymaxone/.github`](bymaxone/.github#29) and are shared by every library. What stays here is what is genuinely local: - **the schedule**, staggered against the other libraries so a Monday morning does not start ten cold suites at once; - **the ceilings**, calibrated to this repository's own measured cold duration. ## What the weekly run skips It compares against the commit the last successful run measured and skips when nothing that can move the score has changed. That surface is deliberately wider than the per-push job's `^(src/)`: the score also moves when a **test** changes (a new test kills a mutant that survived), when the Stryker or Jest configuration changes, or when a dependency changes underneath the suite. Gating on `src/` alone would skip exactly the week someone spent writing tests — the week most likely to change the number. ## Why the ceiling is not the old default The per-push run is fast now, but the ceiling exists for the **cold** one: the first run after this merges has no baseline, and neither does any run whose cache expired. The job is *cancelled* rather than failed when it lands, which reads as an infrastructure blip rather than a budget — that is exactly how nest-auth's mutation gate produced nothing for weeks.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Every library whose per-push mutation run exceeds five minutes is moving to an incremental Stryker run. That is the right trade for a gate on every push, but it is a trade: an incremental run reuses stored verdicts, and Stryker's own guidance is that reused verdicts for static mutants can be stale. A score built on reuse is a fast signal, not the truth — so the truth needs a cold run behind it.
That cold run already exists, written once in
nest-auth. Nine repositories are about to need it. Copying it would put a 130-line decision — what counts as "the score can have moved", why the job is pinned to the default branch, why a partial baseline must not be saved — in nine places to drift apart.What it fixes that the copy could not
The caller's workflow file is derived, not hardcoded. The copy compares against
gh run list --workflow mutation-full.yml. A caller that names its file anything else finds no previous run — forever, and green, because "no previous run" fails open into running. The failure mode is a weekly cold run that never skips and never says why. This readsgithub.workflow_refinstead, so the name is whatever the caller actually called it.The pathspec list is an input with a superset default. Repositories differ in which Jest and TypeScript config files they have. A pathspec that does not exist in the caller matches nothing rather than erroring — verified — so one default covers every layout, and a repository with an unusual one can still override.
What stays with the caller
The schedule (
on: schedulecannot live in a reusable), the ceiling, and the Stryker configuration. Those are genuinely per-repository: the ceiling is calibrated to a measured cold duration, and the schedules are staggered so a Monday morning does not start ten cold suites at once.A caller becomes:
Verification
The file parses, declares
workflow_call, exposes three inputs, and pins all three third-party actions by SHA. The filename derivation was checked against bothmutation-full.ymland a deliberately different name.Sequencing
This does not reach any library on merge.
v1moves only when avN.Y.Ztag is pushed — the release gate added in #28 — and novN.Y.Ztag exists yet, sov1currently sits one commit behindmain. The callers cannot be opened until a release is cut, and cutting the first one also exercisesrelease-major-alias.ymlfor the first time.