MGS3010: redundant gate deferred
A ci gate was not started. An identical-or-equivalent gate already passed for this branch on this machine, so running another would re-verify what the session store already proves - and magus refuses fast instead. A deferral is never a success: the command exits 75, and the refusal prints every input to its decision, so a reader can reconstruct and dispute it from the message alone:
[MGS3010] not running the ci gate for branch polish: it re-verifies a gate that
already passed.
green gate: run inv0193ab, branch polish, commit 2d15f62c, recorded
2026-09-03T18:04:11Z (14m ago), fingerprint 4c1f22ab9e01
delta since that gate, every file:
notes/setup.md: trivial (prose: matches "**/*.md" (built-in default); nothing
in ci's chain reads it)
gen/knowledge-graph.json: trivial (generated: generated by .:graph-generate,
and nothing it reads changed)
machine pool: saturated: 8 of 8 slots held, 2 runs queued
override: pass --no-redundancy-check to run it here anyway
alternative: push; the pull request runs the identical check
This fires when both facts hold at once:
- A green gate is on record for this branch. Every completed
magus run ciandmagus affected cirecords its branch, commit, input fingerprint and verdict in the per-repository session store, which every worktree shares. The first gate on a branch always runs; so does any gate after a recorded failure - in both cases this feature says nothing at all. - The gate would re-verify what that one verified. Either the input fingerprint
is identical (derived from the same per-step cache keys a real run mints - sources,
tool versions, charms), or everything changed since the green gate's commit
tiers
trivial(gate sizing): generated output whose generator the change left untouched, and prose (globs: markdown by default, configurable - see below) that no target inci's chain reads and no package compiles in. A comment-only edit ismechanical, nottrivial, because lint and some generators read comments, so it re-gates at that size. A merge commit in the range is never equivalent, however clean - a merge combines two verified histories into a tree neither gate saw, so it always re-gates.
Machine load is not a third condition. It was until 2026-09-07, and that made this refusal unreachable in the case it was written for: the load reading came from the server, ordinary commands ran without a persistent one, so an idle machine always took the advisory path and ran the duplicate. Measured across one session, the advisory printed seven times and about 17 minutes of wall clock went to gates whose answer was already on record. The pool state is still probed and printed - a refusal should say what the machine was doing - but it decides nothing.
The one caller that still only advises is a nested magus, one running under another. It counts its own ancestors' claims as load, so its view of the machine is the reading that cannot be trusted to refuse on.
Exit 75 is EX_TEMPFAIL, the same convention as MGS3009: the
refusal is about what this machine has already done, not about the build. The refusal
is also recorded in the session store as a deferred gate record pointing at the green
gate it deferred to, so the decision stays interrogable after the fact.
Configuring the prose class
magus.project's gate_low_risk key declares the prose globs, following the same
project-relative shape as review_required. magus ships **/*.md and
**/*.markdown; any declaration replaces the defaults workspace-wide, and []
turns the prose class off. The per-path lines name the matching glob and whether it
came from the defaults or a declaration, so each verdict reads straight back to the
key that produced it. See workspace. The other
classes are deliberately not glob-configurable: generated stays structural and
comment-only stays a mechanism, because a glob cannot assert either honestly.
Why
Gates get repeated out of discipline. One person or agent runs magus affected ci
after a changelog edit, a regeneration, a clean merge - and again before pushing, and
again after a review comment - each run re-proving what the session store already
proves. Parallel worktrees multiply it: the record is per-repository and machine-wide
precisely so one worktree's green gate is visible to its siblings.
The named alternative is not "skip verification" but "verify where it is not
redundant": the push triggers the pull request pipeline, which runs the identical
check, on the identical tree, on a machine nobody is waiting at. That is also the
answer to the obvious objection - that refusing sends a first red to CI instead of
the laptop. It does, deliberately. Redundancy is only declared when the change
since the green gate tiers trivial, which is exactly the delta no step of the
gate can observe.
Resolution
-
Push. The pull request runs the same gate; that is the alternative the refusal exists to point at.
-
Force the run. Pass
--no-redundancy-checktomagus run ciormagus affected cito run the full gate: no deferral and no tier reduction. -
Dispute a classification. Every path line names the glob or mechanism that decided it. A glob doing the wrong work is yours to change:
gate_low_riskin the declaring magusfile. -
Change something real. Any change above
trivialin the delta makes the next gate run; the check never argues with a tree that differs meaningfully from the one it verified.
See also
- MGS3009: the machine budget this check reports, and the exit-75 convention.
- workspace: the
gate_low_riskdeclaration. - Concurrency: the scopes magus coordinates on one machine.
- The broker and the server: the process that owns the budget, and why losing it fails open.