magus v0.3.0 is out. See what's new
¶ View markdown source · ✎ Suggest an edit
2 min read

MGS1018: dead output glob

A project declares an output glob that matches no files, while other globs the same project declares do match. The glob is almost always inherited from a bound spell that this project never satisfies.

Why this matters, and why it hides

Declared outputs are per project, and a bound spell contributes its provides globs to every target on that project. A target that declares nothing of its own (ctx.writesFiles) inherits the whole set. So a check-only target - a test, a lint - inherits an output glob it was never going to write.

That is harmless until the target has to snapshot, which only happens on a cache miss. As long as the target keeps replaying, the code path never runs. The first thing to see the failure is a cold cache: a fresh clone, a new CI runner, or magus clean --cache. By then the declaration that caused it may be months old, and the error arrives somewhere that looks unrelated to it.

This diagnostic moves that discovery forward, to the moment the glob stops matching.

Example

A project binds the typescript spell, which provides dist/**, but emits its bundles to gen/:

magus\project({
    "spells": [typescript],   // contributes dist/** to every target
    "outputs": ["gen/**"],    // what this project actually writes
});

// No ctx.writesFiles, so this inherits dist/** - a glob it never produces.
export fun test(ctx: magus\Context, args: [str]) > void {
    magus\cmd("buzz", args: ["-t", "render.buzz"]);
}

Resolve it

Pick whichever is true of your project:

  • The target does produce files. Declare them, so its snapshot records the real artifact instead of an inherited glob:

    ctx.writesFiles("gen/assets/mermaid.js");
    
  • The target produces nothing (a test, a check). Nothing to declare - the inherited glob simply should not have applied. magus only treats an empty result as an error when the target declared the outputs itself, so this case is already safe; the diagnostic is pointing at the project-level glob, not at your target.

  • The project never writes that glob at all. The spell binding is contributing an output shape this project does not use. Either the binding is wrong, or the spell's mgs_listProvidedGlobs does not describe how this project builds.

Why the check stays quiet on an unbuilt tree

If nothing a project declares has been produced yet, the project simply has not been built, and every glob matching zero is expected. Reporting then would fire on every fresh clone and teach people to ignore the check. It only speaks when some outputs exist and one glob still matches nothing - which is the case that indicates a real mistake rather than an empty tree.

See also

  • Cache model - what provides means and how a snapshot works
  • Spells - what a bound spell contributes to a project
  • MGS1005 - a per-target output glob that duplicates a project-wide one
MGS1018magusfileoutputscachesnapshotdoctorspells
Last updated (843581cb)
Earlier changes on this page (1)

Full history ↗ · Blame source ↗

Glossary

Project

A directory magus recognizes as a unit of work (it has a magusfile); the unit of caching, scheduling, and dependency tracking. See workspace.

Magusfile

The magusfile.buzz that declares a project's targets (as export funs) and binds its spells. See targets.

Target

A named operation (build, test, ...) you invoke with magus run <target>; it may compose a spell's tool-native operations and depend on other targets. See targets.

Spell

A language/runtime adapter (e.g. go, md) that maps generic targets onto a toolchain's real commands. See spells.

Ward

A coded diagnostic that inspects a resolved op and nudges or blocks an anti-pattern before it runs. See wards.

Buzz

The language magusfiles are written in (the .buzz engine). See engines.

Cache

The content-addressed store magus consults before running a target, so unchanged work is skipped. See cache.

CI

An ordinary magusfile-defined target you compose yourself with magus\needs - magus does not hardcode its stages. Magus.RunCI treats it specially only in that it strips the rw charm, it is the anchor magus affected ci keys off, and a selected scope with no project declaring it is a load error rather than a silent no-op. See targets.

Snapshot

A point-in-time view of live state - the pool's occupancy or a tick of exported metrics - as opposed to accumulated history. See daemon.

Conventions

This page uses none of the site's convention markers. The full set is on the conventions page.