Bench Virtual Rule Mirror Skill
bench/config.ts does not extends: ['markuplint:html-standard'].
It curates rules explicitly so the bench surface stays scoped to
nu-validator capability. Consequence: any new entry in a preset's
nodeRules[] is invisible to the benchmark until the same selectors
are mirrored into bench/config.ts. Symptom: fixtures the new
virtual rule should detect remain at nu-only and look like a
markuplint coverage gap when the rule already exists.
Procedure
- Add the selector(s) to the relevant preset
(
preset.html-standard.jsoncor similar). - Mirror the same selectors into
bench/config.tsnodeRules[]with a comment naming the source preset rule (e.g.// Mirrors html-standard/no-duplicate-charset). - Run
yarn bench:update:ml. - Verify the target fixtures flipped from
nu-only→match-error. If they didn't, the selectors don't actually match those fixtures — check selector syntax (caveats below). - If the rule does not map onto any nu-validator capability, skip
step 2 and add a
// not mirrored: <reason>comment to the preset rule's JSDoc so the next maintainer knows it was a conscious decision.
Selector caveats
- HTML attribute names are matched ASCII case-insensitively
(
[charset]matches<meta CHARSET>). Use lowercase to match HTML's normative form. - The
iflag (e.g.[name="description" i]) only applies to attribute values — it is unnecessary for the name, which is already case-folded for HTML. - Sibling selectors (
~) only match elements after the anchor. Coexistence-style constraints typically need both directions (a ~ bandb ~ a) so the rule fires regardless of source order.