W-MATCH-RULE-INERT
rule=
declared on a state-child inside a
<match>
block. Legal but inert.
What it means
Unlike
effect=
and
<onTransition>
(which are FORBIDDEN inside match), the
rule=
attribute is LEGAL on a match arm but does nothing at runtime.
Match is rules-inert — the compiler reads
rule=
for documentation purposes only, NOT for active enforcement.
W-MATCH-RULE-INERT surfaces the mismatch between authored
intent (you declared a contract) and runtime behavior
(nothing enforces it).
The warning is the lint that nudges adoption of the engine tier — per the Tier 0/1/2 commitment ladder (PRIMER §1), rule= belongs in Tier 2.
Minimal reproducer
type Phase:enum = { Idle, Loading, Done }
<match for=Phase>
<Idle rule=.Loading />
// ^^^^^^^^^^^^^^^
// W-MATCH-RULE-INERT: rule= legal but does nothing in match.
// Promote to <engine> to activate.
<Loading rule=.Done />
<Done rule=.Idle />
</match>
How to fix
-
Promote to
<engine>if the intent IS a state machine. State-children carry forward verbatim; the wrapper swap activates rule= enforcement. Thebun scrml promote --matchCLI automates this (per SPEC §56). Also see I-MATCH-PROMOTABLE — the info-level lint that detects promotion shape. -
Remove the
rule=attribute if it's purely documentary. Match arms describe WHAT a variant is, not how it transitions. If the rule= is just authoring intent that won't be enforced, removing the noise keeps the match arm focused on its case-analysis purpose. -
Suppress the warning per SPEC §28 (lint
suppression configs) if the rule= is intentionally retained
as documentation in a context where promotion isn't
yet appropriate. Lint config:
lint.match-rule-inert.
Why warning, not error
rule=
on a match arm is legal-but-inert because the promotion path
preserves it verbatim. An adopter sketching out a state
machine with match (because the engine wrapper feels heavy
during prototyping) can declare rule= intent on each arm; the
compiler accepts it; later promotion activates it without
changes to the state-child bodies. The warning surfaces the
"you declared this but it doesn't work yet" mismatch.
Compare: E-MATCH-EFFECT-FORBIDDEN and E-MATCH-ONTRANSITION-FORBIDDEN are ERRORS, not warnings, because effect handlers and transition handlers ASSUME the transition actually runs. Carrying them through match arms silently would be a code shape that pretends to run effects but doesn't — actively misleading. rule= is just a contract declaration; inert declaration is less harmful than inert effect.
Related
- <match> — element reference. Rules-inert Tier 1.
- <engine> — Tier 2 promotion target. rule= becomes active.
- I-MATCH-PROMOTABLE — info-level lint that detects when match shape is ready for engine promotion.
- E-MATCH-EFFECT-FORBIDDEN — sibling error for effect= attribute.
- E-MATCH-ONTRANSITION-FORBIDDEN — sibling error for <onTransition>.
Specification
Normative text: SPEC §18.0.2 (rule= legal-but-inert in match), §51.0.F (rule= contract in engine context), §56 (promotion ergonomics + bun scrml promote CLI), §28 (lint suppression configs), §34 catalog row. Spec lives at compiler/SPEC.md .