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