The duration-palette gesture: resize the selected note/rest. Shrinking frees the
space after it; lengthening makes room over the events it grows into (trim,
delete, or split), atomically with the resize — the same overwrite policy as
insert. Built on phase 3's metric placement materialization.
Extracts the make-room logic shared with insert_note_at: make_room classifies a
voice's events overlapping a span (excluding the event being inserted/resized)
into deletes/trims/split-tails; make_room_ops turns that into ops (cloning a
split tail's shape with fresh ids, carrying authored spellings); a Minter struct
replaces the inline id closures. insert_note_at now calls these (its 7 tests
confirm behaviour is preserved).
Refuses cleanly: InvalidDuration (non-positive), WrongSelection (nothing apt /
non-metric / not a note or rest — replace_span only resizes Pitched/Rest),
OverlapsTuplet (a tuplet member, whose duration is ratio-governed), and
DecomposedEvent — a resize/trim/split would change the duration of an event with
a persistent decomposition attachment, leaving its notated components no longer
summing to it (invariant 15); a full-cover delete is allowed, since the
tombstoned target's decomposition is no longer checked. make_room also skips
non-positive existing spans, matching the reducer's overlap rule.
Tests: shrink, lengthen-into-empty, lengthen-deletes-a-covered-note,
lengthen-trims-a-partial-overlap, refuse non-positive/tuplet, refuse a decomposed
event, refuse a non-note/rest event, requires a selection.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NAtEiJtt9yKVV1zjKYmZhS