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

MGS1003: bespoke phase-fragment target name

magus doctor found a target whose normalized name is one of typecheck, type-check, vet, audit, style, or prettify. Each of these names a subset of an existing canonical phase - static analysis or formatting - rather than a phase of its own.

[advice] bespoke phase-fragment target names: 1 target(s) name static analysis or
formatting rather than a phase of their own; composing the op into lint (or
format) lets `magus affected ci` cover it (docs/targets.md#the-target-name, see
.../MGS1003.md)
    typecheck: "typecheck" in web/magusfile.buzz

This does not fail anything. It is magus doctor advice: reported, exit 0. magus reserves exactly one target name, ci, and how the rest of your workspace is laid out is your call.

Why

lint is defined as "static analysis, type-check" (see targets): a Go project's go vet and a TypeScript project's tsc --noEmit both compose into lint, the same way eslint and golangci-lint do. format plays the analogous role for style/prettify tools. A standalone typecheck (or vet, audit, style, prettify) target carves one tool's check out of that composition into its own name.

The practical cost is that ci is composed from the canonical phases via magus\needs. A bespoke typecheck target sitting beside lint is invisible to any ci that only needs lint - the type-check silently never runs in CI unless someone remembers to add it separately. Folding the op into lint means it rides along automatically wherever lint already does.

This is advice, not a magusfile load error and not a failed check. Unlike MGS1002 (a spell shadow, which is dead code and unresolvable without a rename or an acknowledgment), a bespoke name is a valid, working target - just one that is easy to forget in a pipeline. Whether that trade is worth it depends on your workspace, and that is not magus's call to make.

Resolution

Move the tool invocation into lint (or format for prettify/style) instead of a standalone target:

// Before: a standalone typecheck target ci must remember to add separately.
export fun typecheck(ctx: magus\Context, args: [str]) > void {
    ts["tsc"](ctx);
}

// After: tsc composes into lint, alongside eslint - one target ci already needs.
export fun lint(ctx: magus\Context, args: [str]) > void {
    ts["tsc"](ctx);
    ts["eslint"](ctx);
}

Keeping the name

Keep it. There is nothing to configure and nothing to acknowledge: the finding is advice, magus doctor still exits 0, and the line stays in the report as a note for the next reader.

Sometimes the target genuinely is not the fragment its name suggests. An advisory audit is the clearest case: lint is cached on the tree, but an advisory scan's answer changes when the registry's database does, so folding it into lint would either replay a stale clean bill of health or force lint to stop caching. That is a good reason, and magus does not need to be told it.

An earlier version of this check failed the build and grew a targets[...].allow_bespoke_name key to opt out of it. Both are gone. A check that costs a paragraph of justification to disagree with is still a requirement, and the config surface was on course to accumulate one escape-hatch key per opinion magus holds.

What this is NOT

  • Not a failure. The target runs, magus doctor exits 0, and nothing blocks the build. There is also no flag that turns this into a failure: that would be the same imposition wearing an opt-in label.
  • Not the canonical-name litmus test itself. See targets for the full reasoning; this check only notes the specific set of known static-analysis and formatting fragments, not any custom target name.

See also

  • targets: the seven canonical target names and what composes into lint/format.
  • magus describe targets: lists every target and which spell ops compose into it.
MGS1003magusfiletargetslintformatdoctornaming
Last updated (a103255f)
Earlier changes on this page (4)

Full history ↗ · Blame source ↗

Glossary

Workspace

The magus root directory that owns a set of projects and shared config; the unit magus operates over. See workspace.

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.

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.

Affected

The set of projects touched by a change; magus affected <target> runs a target only over them. See affected.

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.

Health

The at-a-glance daemon state derived from the pool: healthy when the pool is reporting, degraded when it reports an error, down when there is no pool. The dashboard color-codes each state. See daemon.

Conventions

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