Classifies a render pipeline run as a line-patch fast path or a full path (#2287).
The classification is a telemetry and observability tag: both paths run the
same seven stages and emit the same begin_frame/commit_frame transaction
with the same gui_window_content/delta encodings. There are no new opcodes.
What differs is the work the Content stage actually does: on the :patch
path, the upstream row-retention cache lets unchanged rows skip composition,
so a patch frame rasterizes only the rows that changed.
Path meaning
:patch— cursor motion or a single-line edit confined to the active window's current viewport. The frame is expected to rasterize zero rows (pure cursor motion) or only the affected rows (a single-line edit).:full— anything structural: a window split/open/close, a resize, a theme change, chrome state changes, a forced keyframe, the first frame, a content-epoch reset, or a viewport scroll. Multi-window frames are always:full.
Conservative by construction
Classification only ever labels the frame; it never suppresses work that a
frame legitimately needs, because the row-level content hashing decides reuse
independently. A frame mislabelled :patch still renders correctly, and a
frame mislabelled :full is merely pessimistic. Per the ticket's risk note,
anything ambiguous classifies as :full.
Summary
Functions
Classifies a render frame as :patch or :full.
Types
@type path() :: :patch | :full
@type scrolls() :: %{ required(MingaEditor.Window.id()) => MingaEditor.RenderPipeline.Scroll.WindowScroll.t() }
Functions
@spec classify(MingaEditor.RenderPipeline.Input.t(), scrolls()) :: path()
Classifies a render frame as :patch or :full.
Consumes the prefetched per-window scroll snapshots, which already carry the
resolved per-window invalidation (dirty lines, viewport, line count, epoch
reset). Returns :full whenever a structural trigger is present or the state
is ambiguous; otherwise :patch.