The reducer combines the protection reasons (the mutator tag → "sheet protected", plus the
rotation commands' extra isContinuousSpan gate) with the selection-shape rules (sort needs
a single range; insert/delete by whole-row/column + overlap; merge/header). Both must be computed
together per command — within-scope updateCommand overrides, so reasons are combined in one
call, not stacked. Returns a disposer that detaches the model + selection listeners.
The per-sheet command behavior (paired with registerSheetDefinitions). A plain contributor over the Command.CommandContribution authoring facet:
use(), so the command callbacks stay pure;updateCommands can run per-tick).