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

MGS1004: unreached footprint declaration

magus doctor found a ctx.readsFiles(...) or ctx.writesFiles(...) call that the static extractor cannot reach from any target body. magus reads these declarations from the source without running it (a cache hit skips the body entirely), following a target's body and the helpers it calls by name. A call it can't reach never enters a cache key.

[MGS1004] 1 ctx.readsFiles/writesFiles call(s) are not statically reachable from a
target body, so they never enter a cache key; call them directly in the target
body (see .../MGS1004.md)
  ctx.readsFiles in srcGlobs (web/magusfile.buzz:14)

Why

A per-target footprint has to be known before the target runs, because on a cache hit the body never executes. So magus recovers ctx.readsFiles/ctx.writesFiles statically: it walks each export fun target and the helper functions it calls by a plain name (srcGlobs()), and collects the string-literal globs it finds.

A declaration outside that reach is invisible to the cache:

  • a call in a helper that no target (transitively) calls by name - often dead code;
  • a call reached only through indirection - the identifier used as a value (final f = ctx.readsFiles; f("src/**")) or dynamic dispatch, which the static read cannot follow.

The danger is silent under-declaration: the input you thought you declared is not in the key, so editing it produces no miss and you replay a stale build. This check makes that loud. It is the counterpart to the hard load error you get for a non-literal argument in a reached call (ctx.readsFiles(someVar)) - that one magus can see and rejects immediately; an unreached call it can only warn about.

This is a warning, not a load error: an unreached call may simply be dead code, which is harmless.

Resolution

Call ctx.readsFiles/ctx.writesFiles directly in the target body, or from a helper the target invokes by name:

// Before: the glob lives in a helper nothing calls, so it never keys anything.
fun srcGlobs() > void { ctx.readsFiles("src/**"); }
export fun build(ctx: magus\Context, args: [str]) > void { go["go-build"](ctx); }

// After: declared in the body (or a bare-called helper), so it enters the key.
export fun build(ctx: magus\Context, args: [str]) > void {
    ctx.readsFiles("src/**");
    go["go-build"](ctx);
}

If the flagged call is genuinely dead code, delete it.

What this is NOT

  • Not a hard error. Nothing blocks the build; it is a magus doctor finding.
  • Not the non-literal-argument error. A computed argument in a reachable call (ctx.readsFiles(x)) is a magusfile load error, because magus sees the call but cannot resolve the glob. MGS1004 is the opposite: magus resolves nothing because it never reaches the call.

See also

  • cache: how ctx.readsFiles and ctx.writesFiles declare a target's per-target footprint.
  • dependencies: the static-extraction discipline ctx.readsFiles shares with magus\needs.
MGS1004magusfilecachereads-fileswrites-filesdoctor
Last updated (3da15dc9)
Earlier changes on this page (3)

Full history ↗ · Blame source ↗

Glossary

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.

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.

Conventions

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