DR-242. Intent, not device operations.
`open` carries the start position, so no caller sequences load-then-seek and
none can race an engine's asynchronous load — the engine is the only layer
that knows when its pipeline can accept a position, and it absorbs that
internally by deferring or re-opening.
`seek` states a destination and nothing else. Whether that is an in-place seek
or a re-opened stream is the engine's business: hls.js seeks within a VOD
playlist, mpv's HLS demuxer cannot make a server transcode from a new offset.
Callers stop guessing on behalf of engines they do not own.
`snapshot` is one coherent read rather than a dozen getters, because reading
position and duration separately is how a player reported <position> / 0.0
when a file unloaded between the two calls.
`Phase::Opening` names the state the previous design could not express, and is
the direct cause of DR-241: a seek arriving with nothing loaded had no phase
to be queued against, so it was discarded.
`Capabilities` exists so callers adapt without naming engines. If a caller
ever branches on which engine it holds, this struct is missing something —
engine identity leaking into callers is the coupling DR-238 came from.
Nothing consumes it yet; PlayerController is ported in DR-245. Carries an
explicit allow(dead_code) tied to that step rather than being hidden behind
cfg(test), because it is production code being built in shippable pieces.