scrml.dev v0.7.1
Reference › Errors

W-MATCH-RULE-INERT

rule= declared on a state-child inside a <match> block. Legal but inert.

Warning Compile-time SPEC §18.0.2 (normative)

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

  1. Promote to <engine> if the intent IS a state machine. State-children carry forward verbatim; the wrapper swap activates rule= enforcement. The bun scrml promote --match CLI automates this (per SPEC §56). Also see I-MATCH-PROMOTABLE — the info-level lint that detects promotion shape.
  2. 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.
  3. 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

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 .