Your tests passed. Did they test anything?
An agent wrote the change and the tests for it, and both landed green. Mergestro Gate mutates the code you changed and checks whether your suite notices. A mutant nothing catches is a test that asserts nothing — and it is found before a human is asked to review the pull request.
- Apache-2.0, free
- Runs in your CI
- No account, no key
# .github/workflows/mergestro-gate.yml
on: pull_request
permissions: { contents: read, pull-requests: write }
jobs:
gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: lucheeseng827/mergestro-gate@v1
with:
advisory: true # report, never block — start here
Two failures this catches that a diff cannot
Mergestro is two tools for one problem: an agent can now write the change and the tests for it, and both land green. The first tool checks whether the tests prove anything. The second works out what the change actually reaches, and tests that too. They are separate products, and the first one is free.
- Mergestro Gate Apache-2.0 · free Mutates the lines your pull request touched and re-runs your suite. A mutation nothing catches is a test that asserts nothing. Runs on your own runner, no account.
- Mergestro Queue paid · source-available Derives your dependency graph from the repository, works out what a change reaches, and runs the dependents' suites before the merge. Catches the conflicts that never touch the same line.
- Control plane paid · self-hosted The trends one CI runner cannot compute: whether a team kept the gate on, and which components keep turning up in everyone else's blast radius. Not offered as a hosted service.
The rest of this page is the evidence for each, in that order.
A test that proves nothing
A green suite is evidence only if it would have failed when the behaviour
changed. Mergestro Gate checks by changing the behaviour on purpose: it flips
>= to > on the lines your PR touched and re-runs the
tests. A mutation the suite never notices is
a hole in it.
mutants: 13 candidate(s), 13 tested
outcomes: 12 caught · 1 SURVIVED
verdict: BLOCK
Survivors — the suite passed over these
mutations (most severe first):
• [high] src/lib.rs:42:12 replace >= with >
Severity is real work: a flipped comparison in a permission check ranks critical; the same flip in a log formatter ranks low. This is Mergestro Gate — free and Apache-2.0.
A conflict with no overlapping lines
#102 renames auth::login. #103 adds a billing endpoint that calls
login(). Different files, no textual conflict, so GitHub's queue,
Mergify, Bors, Aviator and Graphite all put them in the same batch, and
main stops compiling. Mergestro Queue reads the symbols:
Semantic findings [heuristic] (advisory):
- #102 ↔ #103 (60%): #102 changes a symbol
#103 relies on: login
(used in src/billing.rs)
Output from mergeq plan against the example queue in the repo. It runs
with no git repo, no network and no keys.
This is Mergestro Queue — a paid tier.
What none of it does
- The graph is derived, not perfect. Roughly one declared edge in seven needs the overlay, and the audit tells you which ones.
- Mutation is not a correctness proof. It samples one class of fault on the lines you changed. A clean run means no cheap mutant survived there.
- It needs a green, deterministic suite. No tests, red, or flaky, and mutation is suppressed. The gate will not certify what it cannot trust.
- Rust is stable; the other mutation engines are PoCs. Python, JS/TS, Go and Java/Kotlin are advisory and coarser. Dependent verification covers Cargo, npm and Go today.
- It costs CI minutes. That is the whole reason for the budget, the scoring, and the cost model below.
Every queue serialises merges.
One reads the changes.
Merge queues are a solved category: take the pull requests, test them in an order, merge what passes. They differ on batching and bisection, and any of them will stop two edits to the same line from landing on top of each other.
They agree on one thing. A conflict is two changes touching the same text. The rename-plus-new-caller above touches no shared line, so a textual queue sees two independent pull requests and batches them together.
Serialises merges textually
GitHub Merge Queue · Mergify · Aviator MergeQueue · Trunk.io · Graphite · Bors-ng · Kodiak
Mature, well-supported and, between them, the reason most teams stopped breaking
main on overlapping edits. Several add speculative batching, batch
bisection and merge prioritisation on top.
Also reads what the changes mean
Mergestro Queue
Indexes the symbols each component exports and which components use them, so a
pull request that renames auth::login and one that adds a caller of
it are recognised as related, with no line in common. That is the whole
difference, and it is the reason the graph and the audit exist.
Compared on one capability, not a scorecard: detecting two changes that break each other without overlapping a line. On textual serialisation, batching and bisection the established queues are ahead, and Mergestro Gate does not compete with any of them: it is a mutation gate that runs before a queue, not instead of one. Field reviewed 2026-06-19 against vendor documentation; capabilities move, so check theirs before you decide.
Start advisory. Make it required when you believe it.
The gate is free and Apache-2.0. It comments on the pull request and never fails the build until you say so, so it is safe to leave on while you decide whether to trust it. There is no account, no API key and no service to call — the Action builds a static binary and runs it on your own runner.
# .github/workflows/mergestro-gate.yml
on: pull_request
permissions: { contents: read, pull-requests: write }
jobs:
gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 } # it diffs against the base ref
- uses: lucheeseng827/mergestro-gate@v1
with:
advisory: true # report, never block
max-survivors: 0 # later: any survivor blocks
block-on-zero-assertion: true
The gate, run on its own source
A fourteen-line change to mergestro-gate adds one function that decides
whether a survivor lives in test scaffolding. The suite stayed green. Here is what the
gate said about it.
$ slop-gate --repo . --base main --head HEAD --advisory
── Mergestro Gate · behavioral merge gate ──
diff: main...HEAD
changed: 1 Rust + 0 Python + 0 JS/TS + 0 Go + 0 Java/Kotlin file(s)
mutants: 5 candidate(s), 4 tested, 0 capped out
outcomes: 1 caught · 0 timed out · 1 unviable · 3 SURVIVED
no-assert: 0 test(s) with no assertions
runtime: 49.4s
verdict: PASS
Survivors — the suite passed over these mutations (most severe first):
• [high] src/severity.rs:137:5 replace is_test_scaffold -> bool with false
• [high] src/severity.rs:137:34 replace || with && in is_test_scaffold
• [high] src/severity.rs:137:68 replace || with && in is_test_scaffold
The first survivor is the one that matters: the whole function could return
false — classifying nothing as scaffolding, ever — and not one test would
notice. The other two say the same thing about its || branches. The new
code was never tested at all, and a green suite said otherwise. Forty-nine seconds,
on a free runner, advisory.
Run it yourself against the public mirror.
You don't write the graph. It reads your repo.
Every tool that asks you to hand-maintain a dependency file is asking for
the one artifact nobody keeps current.
mergeq graph derive walks the repository instead: it discovers components
from Cargo, npm, Go and Compose manifests, indexes the symbols each one exports, and
derives the edges between them, each edge recording how it was found.
Run it on your repo
$ mergeq graph derive
derived .mergestro/graph.json:
7 component(s)
14 edge(s)
3 declared
11 derived
Three of those edges were declared: two Cargo path dependencies and one
depends_on in a compose file. The other eleven it worked out on its
own, by reading which component uses which symbol. Four of them cross a language
boundary that no manifest in the repository spans.
Every edge says where it came from
Manifest means a build file declares the dependency.
SymbolUse means one component imports a symbol another exports, and the
edge records which symbol. Confidence is evidence-based, and the closure score
decays with depth, so a direct dependent outranks something three hops away.
Wiring that is invisible to a static read (a queue topic, a shared database, a
service two teams talk about but nothing imports) goes in a
mergestro.components.yaml overlay. For precision past heuristics, feed
it a SCIP or LSIF index with --symbols and the named components'
tables are replaced wholesale.
We measured how much it misses, and shipped the tool that measures it
A derived graph that quietly misses an edge is a false green: the dependent nobody
tested. So mergeq graph audit replays the graph against the topology the
repo actually declares and reports recall, naming every edge it failed to
recover:
$ mergeq graph audit
Mergestro Queue — graph derivation audit
recall: 66.6% (2 of 3 declared code-owning
pair(s) independently derived)
missing from derivation: web → api
One declared edge in three was not recovered by the static read. It is
web → api, and the reason is instructive: that dependency exists only as
a depends_on line in a compose file. Nothing in the front end calls a
symbol the API exports, so there is no code for the deriver to read. The audit names
it rather than hiding it, so you can put it in the overlay and hold the line with
--min-recall. A graph you cannot audit is a graph you should not gate on.
What a change actually reaches
With the graph in hand, a pull request stops being a list of files and becomes a region. Pick the component a PR changes and watch what has to be rebuilt.
- changed by the PR
- downstream — must rebuild and re-check
- unaffected — don't spend CI on it
Then it runs their suites, most dangerous first
Knowing the blast radius is half of it. mergeq verify links the diff onto
the graph and then actually tests the dependents against the merged tree — ordered by
score, inside a budget you set, and honest about everything it did not reach.
$ mergeq verify --base main --head rename-login
Mergestro Queue — dependent verification
impact: 78/100 (critical)
coverage: tested 4 of 4 affected dependent(s)
✓ session (depth 1, score 0.40)
✓ api (depth 2, score 0.28)
✓ billing (depth 2, score 0.28)
✓ web (depth 2, score 0.28)
verdict: PASS (advisory unless --block-on-* is set)
Four suites in four components across three languages, in seven seconds, none of which the rename touched a line of. They passed — which is the answer you wanted, and you have it without merging to find out.
The coverage line is the point
Four dependents fit inside the default budget, so this run has nothing to report as
skipped. On a real repository it usually will: testing every dependent on every pull
request is not a product, it is a denial of service. So verify spends a budget
(--max-components,
--max-minutes, --max-depth) on the highest-scoring
dependents, then tells you exactly what it skipped and
why. Nothing is silently dropped, including the files it could not attribute
to any component at all.
Cargo dependents run cargo test -p from the workspace root; npm and Go
components run npm test and go test ./... in their own
root. Across repos, the changed provider is patched in through
[patch.crates-io], a package.json overrides entry, or a
go.mod replace.
Three stages, and what each is allowed to do
- P1, the static lane. Contract-symbol and
oasdiffspec-diff findings on touched API-contract edges. Probe-and-skip, advisory unless--block-on-contract-break. - P2, the dependent suites. Budgeted and score-ordered, run against the merged tree. Advisory unless
--block-on-dependent-failureor--block-on-impact. - P3, the subgraph runtime. Only at or above
--env-band, and only when--env-check-cmdis set: render the affected subgraph's compose plan, bring it up, run your command, tear it down. - A stale graph refuses to run. An artifact more than
--max-graph-lagcommits behind the base exits 1 rather than driving a verdict from a picture of a repo that no longer exists.
Where the time actually goes
Running other people's test suites costs real CI minutes, so the cost model is measured and published rather than glossed. On the mutation side, the orchestrator is not the cost. The compile-and-test cycle is.
~11 ms The Rust orchestrator's flat overhead, under 5% of a realistic diff.
>90% Of wall-clock is the engine rebuilding and re-running your suite per mutant.
You set the ceiling. --max-components, --max-minutes and --max-depth bound dependent verification, and every skip is reported.
Measured median of 7 iterations, warm target/, offline, 32-core Linux,
cargo-mutants 27.1.0, on a zero-dependency micro-fixture, reproducible
from bench/. Treat these as a floor and a ratio, not an SLA: a
real workspace pays a larger baseline build.
Across every repo, over calendar time
One thing a CI runner structurally cannot compute: whether a team kept the gate on. A
disabled gate emits nothing. Retention, fix-vs-override, red-mains
prevented, and which components keep turning up in everyone else's blast radius only
exist as trends across repos, so they live in a control plane that ingests what the
gates already emit.
What exists today, stated plainly
- It runs. Durable by default, refuses to boot without a database, serves HTTPS, rotates its secrets without a restart, and has a restore drill that runs in CI.
- There is no login. No SSO, no roles, no audit log and no dashboard sign-up. Machine keys only.
- There is no price yet. The paid tiers are being priced with design partners rather than published ahead of them.
Free, paid, and on the way
One row per capability. The first column is the whole free product. It is not a crippled tier, and it is the only one you can install right now.
| Capability | Gate | Queue | Control plane |
|---|---|---|---|
| Mutation gate on the lines a PR touched | included | no | no |
| CLI and GitHub Action | included | included | no |
| Runs on your own runner, no account | included | included | self-hosted |
| Derived dependency graph, blast radius, audit | no | included | no |
| Dependent verification against the merged tree | no | included | no |
| Semantic conflict detection, heuristic | no | included | no |
| AI semantic checker, your own API key | included | included | no |
| Cross-repo queue state and dashboards | no | no | included |
| Org policy and retention trends across repos | no | no | included |
| Managed AI checker, we run the key | no | no | on the way |
| SSO, roles, audit log | no | no | on the way |
| Hosted, we run it for you | no | no | on the way |
on the way means built but not offered yet, or not built. Either way it is not something you can buy today, and nothing on this page is sold on the promise of it. The Gate column is the only one you can act on right now, and it is free.
Not on sale yet. The paid tiers are in design-partner phase: the Queue and the control plane are source-available and you run them in your own perimeter, by arrangement. There is no hosted deployment to sign up for and no published price, because we would rather set one with the first few teams than guess at it now. It is on this page because the gates already emit the telemetry it reads.
Or write to contact@mergestro.com. A person reads it; there is no form and
no sequence behind it.
Find out what your suite is not catching.
One file, advisory, on your next pull request. If it finds nothing, it costs you a few minutes of CI and you have learned something worth knowing.
uses: lucheeseng827/mergestro-gate@v1
Apache-2.0 · v0.5.0 · static binary, checksummed