The two BlockCore length setters swapped their anchors relative to the
C++ semantics they document, so the ported edit commands produced wrong
geometry on the live UI paths: roll edits kept the seam still, slides
left negative in-points, and trims wrote the timeline in-point into
media_in (playing the wrong media content).
Adopt three stored-range primitives in block.rs:
- set_length_and_media_out: in fixed, out moves, media untouched
(resize, trim-out, gaps growing rightward).
- set_length_and_media_in: in fixed, out moves, media_in += old-new
(resize-with-media-in, splice right half, ripple trim-in).
- set_length_keeping_out (new): out fixed, in moves, media_in +=
old-new (trim-in body and out-neighbour, slide out-neighbour,
ripple trim-in of the trailing block).
Point every command at the primitive matching its intent (undopointer,
undogeneral, undoripple, undosplit, graphops, cli, nodeops) and fix the
two real defects the swap hid:
- TrackReplaceBlockWithGapCommand grew a following gap rightward,
swallowing whatever followed it: the "dragging one clip moves
unrelated clips" regression. The gap now grows leftward over the
removed block's span; regression test in domain_test.
- The ripple/splice trims now advance media_in instead of rewriting it,
and BlockSplitCommand writes both halves' ranges and media
explicitly (the second half continues from the split point).
Rewrite the KNOWN-SWAP expectations to the correct geometry (roll moves
the seam, slide has no negative in-point, insert-gaps grows rightward,
resize-with-media-in yields media_in = 20) and add the missing media
assertions. TrackSlideCommand documents that the caller positions the
sliding blocks (the stored model has no track layout).