MGS1028: a changed file seeds a project it does not key
A changed file matches no project's declared globs, and still put a project into the affected set - because directory containment seeds, and the root project catches whatever no directory claims.
hint: [MGS1028] projects seeded by changed files nothing declares: . Directory
containment selected them, so the targets they rerun were already correct. Declare the
files in the owning project's sources, or leave them undeclared deliberately (see ...)
It names the projects rather than the files, because magus affected --impact and
magus affected --explain - the two commands that emit it - already mark each file
inline, and magus describe file <path> explains any one of them in full.
Why this matters
Seeding and keying are separate mechanisms, and this is the case where they disagree.
- Seeding decides which projects
magus affected <target>selects. A changed file seeds the project whose directory contains it, plus every project that declares it from outside that tree; failing both, the root project catches it. - Keying decides whether a selected target re-runs or replays. Only declared sources enter a cache key.
An undeclared file gets the first without the second. Touching it selects the project, magus runs the target, the key has not moved, and the answer is the one that was already recorded. The cost is real: a config edit at the root of a monorepo can rebuild and retest everything, every time, and produce nothing new.
The expensive half is the half you can see. The silent half is worse and it is the same declaration missing: when that file genuinely does change what a target produces - a lint rule set, a toolchain pin, a formatter config - the cache does not know, so a target that was going to be selected anyway can still replay a verdict computed under the old rules.
Example
.golangci.yml sits at the workspace root. No project declares it; the root project
contains it.
magus\project({
"spells": [go], // contributes **/*.go - and nothing else
});
Editing it seeds ., reruns build, test, and lint, and every one of them replays
or recomputes an unchanged answer. Meanwhile the lint verdict recorded under the previous
rule set stays valid in the cache, because the file that changed the rules was never an
input.
Resolve it
If the file is an input, declare it. Declaring is what backs the seeding with a key: the file now matches the owning project's globs, so its rerun can produce a different answer, and this diagnostic clears for it.
magus\project({
"spells": [go],
"sources": [".golangci.yml"],
});
Project-wide sources, not a per-target ctx.readsFiles: a target's ctx.readsFiles
replaces its footprint rather than adding to it, so declaring a config there would drop
the spell's source globs from that target's key.
If the file is not an input, leave it undeclared. A LICENSE, an editor config, a note to yourself - nothing reads them, and declaring one only makes an unrelated edit invalidate a cache. Seeding by containment is the fail-safe working as intended: magus would rather rerun a project than let a gate pass having checked nothing.
Which files, across the whole tree
The diagnostic sees one changeset. magus doctor answers the standing question - every
committed file no project declares - as advice, never a failure, because which files
are build inputs is your workspace's call and not magus's:
$ magus doctor
[advice] undeclared seeding files: 4 committed file(s) seed a project by directory
containment while no project declares them
magus describe file <path> explains any single one, and magus affected --impact marks
them inline in a changeset.
See also
- Cache model - what enters a key and what does not
- Dependencies - how the seed set expands into the affected set
- MGS1004 - a footprint declaration that never reaches a cache key
- MGS1010 - the affected set becoming uncomputable, and every project selected instead
- MGS1018 - a declared output glob that matches nothing