---
title: "MGS1028: a changed file seeds a project it does not key"
description: A changed file no project declares still pulls its containing project into the affected set. The targets it reruns could not have produced a different answer, and the file that would change the answer is the same one nothing is watching.
tags: [MGS1028, magusfile, sources, affected, cache, seeding, doctor]
---

# 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.

```text
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.

```buzz
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.

```buzz
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:

```console
$ 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](../../../concepts/cache.md) - what enters a key and what does not
- [Dependencies](../../../concepts/dependencies.md) - how the seed set expands into the affected set
- [MGS1004](MGS1004.md) - a footprint declaration that never reaches a cache key
- [MGS1010](MGS1010.md) - the affected set becoming uncomputable, and every project selected instead
- [MGS1018](MGS1018.md) - a declared output glob that matches nothing
