Transition kernel
Flyology_TUI.Programs defines the backend-free program contract. The runner calls initialization once. It then calls update for each event and presentation for each resulting frame.
The model can be mutable. The important invariant is exclusive ownership, not immutability.
Commands return messages.
A transition can request one typed command or quit. The executor receives the command value. It returns an optional application message.
Prepare all detached input before requesting the command. Do not pass a model reference, component reference, surface view, or retained callback to a worker.
External tasks are message sources.
An external task can perform work and post a detached typed snapshot to the bounded event queue. It must not mutate or render live component state. The application model owner applies the snapshot during update.
This rule permits task-based services without creating a second UI ownership model.
Capacity is part of behavior.
The runner uses bounded event and command queues. Select capacities for the expected burst. Mouse motion is coalesced without crossing click, release, wheel, modifier, or application-message boundaries.
Handle capacity rejection explicitly in component models. A rejected mutation must leave visible state unchanged.