block="substitution" (or a block set containing it, including #all) on a
substitution-group head forbids every member from substituting, regardless of
the head's or members' types. filterSubstitutions gated the whole filter --
including this type-independent substitution ban -- on the head having a type,
so an abstract untyped head (the particlesDc cluster) skipped filtering and its
members still substituted. The substitution ban now applies first and
type-independently; the type-derivation block (extension/restriction) still
needs the head's type, unchanged.
An adversarial review confirmed no false positive: the head's own appearance is
computed independently of the member list (a concrete blocked head still
validates), and the typed-and-substitution-blocked case is provably equivalent
to the prior per-member rejection. Disclosed pre-existing under-rejection (not
introduced here): blockDefault="substitution" is not honored, only an explicit
block on the head.
XSTS: invalid-instances-accepted 107 to 101 (particlesDc004/005/006/008/009 and
a sibling), valid-instances-rejected and valid-schemas-rejected held at 0.