sparkles:wsi — Feature requirements
Normative requirement ledger for SPEC.md. planned means the contract is accepted but has no implementation evidence; partial names the missing platform or semantic edge; verified requires the evidence described in SPEC §11.
Last reviewed: August 21, 2026
Architecture (WSI)
| ID | Requirement | Status | Traces to |
|---|---|---|---|
| WSI1 | The native desktop package is named sparkles:wsi and has no third-party cross-platform windowing, widget, or renderer dependency. Native platform client libraries are permitted. | partial — package/core and all four native lifecycle modules delivered; the full desktop baseline remains | libs/wsi; SPEC §1 |
| WSI2 | Wayland, X11, Win32, and AppKit are peer native backends behind one value-level contract. No supported desktop silently falls through to SDL. | partial — all four native lifecycle adapters are peers; the common facade and full feature parity remain | platform.*; SPEC §9 |
| WSI3 | Event Horizon is the only application event loop, scheduler, timer source, blocking wait, and cross-thread wake path. | partial — Wayland/XCB over uring plus User32/IOCP and CFRunLoop/kqueue combined waits delivered; HITL and race coverage remain | loop; SPEC §4 |
| WSI4 | The UI/main thread owns all windows and native callbacks; cross-thread work is value commands plus a coalescing waker. | partial — all four backends enforce their owner/main thread and non-reentrant drains; the portable command surface remains | loop; SPEC §3 |
| WSI5 | WSI events, ids, configurations, and commands are Regular values with explicit lifetime and generation rules. | partial — owned event algebra and generation-safe lifecycles delivered on all four backends, including keyboard, pointer button/motion/enter/leave, and scroll values; native command algebra remains | types, events, loop, platform.* |
| WSI6 | Platform and renderer failures use typed WsiError/Expected, not assertions, sentinel handles, or IoError. | partial — allocation-free error/result path and all four native lifecycle mappings delivered; renderer mappings remain | types, loop, platform.* |
| WSI7 | SDL 3 compatibility, Vulkan surface/swapchain integration, and Skia Graphite live in separate packages above native WSI. | partial — native surface/context and shared presentation resources live in sparkles:vulkan-wsi; the SDL host package and Graphite remain | SPEC §10 |
| WSI8 | Shared Sparkles primitives are reused or moved to the lowest owning package; WSI does not introduce parallel geometry, pointer-shape, cell-metric, UTF conversion, or event-loop implementations. | partial — shared foundations and all four native Event Horizon consumers are delivered; future integration must preserve that reuse | PLAN M1 |
Desktop feature baseline (F01–F17)
Every row applies independently to Wayland, X11, Win32, and AppKit unless the row says otherwise. The first implementation may stage platforms, but the native baseline does not complete until all four columns are verified.
| ID | Requirement | Status | Principal evidence |
|---|---|---|---|
| F01 | First pixel and initialization: create one window, deliver authoritative logical/physical metrics and stable renderer handles, and reach a presentable first frame without an avoidable round trip or created-at-wrong-scale frame. | partial — all four native backends deliver metrics, typed handles and expose/frame-ready opportunities; Wayland bootstraps asynchronously; renderer present and HITL remain | native lifecycle smokes; first-frame traces per platform |
| F02 | Resize: preserve continuous live resize, report every authoritative surface-size transition in order, acknowledge protocol requests promptly, and never resize a swapchain from logical size. | partial — programmatic transitions pass on all four backends and Wayland configure is acked in the listener; interactive/modal and renderer paths remain | native lifecycle smokes; latency/HITL traces |
| F03 | Modal-loop survival: continue native replies, input queuing, repaint opportunities, and Event Horizon wake progress during move/size/menu/modal tracking loops. | planned | modal-loop scenarios per platform |
| F04 | Frame pacing: expose native frame opportunities/presentation timing where available and an Event Horizon deadline fallback without sleeping inside WSI. | planned | cadence/jitter trace |
| F05 | Loop wakeup and external sources: integrate native readiness with Event Horizon, provide a contention-safe coalesced cross-thread wake, and never run a second blocking application loop. | partial — all four native waits share Event Horizon with a timer and foreign-thread waker; HITL, wake-race and zero-idle coverage remain | native loop smokes; wake-race and zero-idle tests |
| F06 | Keyboard and keymap: report physical and logical key identity, location, modifiers, press/repeat/release, keymap/layout changes, and unknown native codes without inventing text. | partial — physical identity, location, modifiers, press/repeat/release and layout-derived unshifted logical keys are queued on all four backends (xkbcommon compiles the Wayland keymap fd and the X11 core device's map; Win32 maps MAPVK_VK_TO_CHAR; AppKit reads charactersIgnoringModifiers, with function keys as named private-range scalars); Wayland synthesizes client-side repeat from repeat_info on an Event Horizon timer; keymap-change events and native-Windows evidence remain | Win32 Wine smoke; layout/repeat/keymap matrix |
| F07 | IME and text input: separate UTF-8 commit from keys; report pre-edit, selection and cursor/segments; position candidate UI; use text-input-v3, XIM, IMM32 first, and NSTextInputClient. | partial — Win32 UTF-16 commits and IMM32 pre-edit/attributes/cursor/result are queued as owned UTF-8, and Wayland binds per-seat text-input-v3 (auto-enabled on the compositor's enter, double-buffered batches applied on done: commit before pre-edit, byte-offset cursor/selection, one composition-end event); X11 speaks XIM through xcb-imdkit's client on the backend's single XCB connection (keys forward through a live input context and bounce back unconsumed; commits arrive as owned UTF-8), verified end-to-end against an in-tree test XIM server; AppKit adopts NSTextInputClient (runtime protocol registration; keyDown routes through the view's input context, insertText commits, setMarkedText maps UTF-16-unit selection to byte offsets); candidate placement, callback-style XIM pre-edit, and Wayland live-IME evidence remain (Weston implements only text-input-v1, so that column's runtime proof is owed to a v3 compositor) | Wine IMM32 self-injection; native IME scenarios |
| F08 | DPI and runtime rescale: use logical public geometry plus authoritative physical surface size and scale; handle mixed-DPI movement atomically where the platform permits. | partial — Wayland derives the window scale from its entered outputs (maximum policy), requests the matching buffer scale, and reports one atomic logical/physical/scale transition, verified at scale 2 under Weston; Win32 reports GetDpiForWindow with WM_DPICHANGED transitions (per-monitor evidence owed to native Windows — Wine monitors are fixed at 96 DPI); AppKit reports the backing scale; X11 scale detection and mixed-DPI movement remain | mixed-output scale test |
| F09 | Outputs: enumerate, add/change/remove displays with identity, geometry/work area, scale, modes and refresh; report the active output set of each window. | partial — Wayland binds outputs, tracks each window's entered-output set (OutputEnteredEvent) and per-output scale; output identity/geometry/modes, hotplug reporting and the other platforms remain | hotplug/topology test |
| F10 | Pointer capture: support capture/confinement and raw relative motion as distinct capabilities; preserve releases outside content and unwind capture on focus loss/destruction. | partial — drag release-outside-content is preserved and verified on X11 (automatic core grab, outside coordinates asserted under Xvfb), Win32 (implicit SetCapture spanning first press to last release, engagement proven via GetCapture under Wine, unwound on WM_CAPTURECHANGED), and AppKit (window-tracked drag routing); explicit capture/confinement, raw relative motion, and focus-loss unwind coverage remain | drag-outside/raw-motion test |
| F11 | Scroll fidelity: preserve pixel/logical delta, discrete steps, source, phase/momentum and natural-direction metadata where supplied; normalization happens above WSI. | partial — delta, discrete steps, source, unit and the natural-direction flag are queued on all four backends (Wayland axis frames with axis_source/axis_discrete, X11 legacy wheel buttons, Win32 wheel deltas, AppKit precise pixel deltas); phase/momentum and trackpad fidelity evidence remain | mouse/trackpad trace fixtures |
| F12 | Cursors: support standard shapes through the shared PointerShape, custom images/hotspots, visibility and scale changes; report unsupported shapes. | partial — the seven shared PointerShape shapes and per-window visibility on all four backends: server-side cursor-shape-v1 on Wayland (typed unsupported without the global), core cursor-font glyphs on X11 (grab/grabbing approximate as fleur), stock IDC_* applied on WM_SETCURSOR for Win32 (grab/grabbing approximate as IDC_SIZEALL), stock NSCursor on AppKit (all seven exact); custom images/hotspots, cursor scale and the manual catalog pass remain | cursor catalog/manual pass |
| F13 | Decorations: on Wayland request xdg-decoration SSD and provide renderer-drawn CSD fallback without libdecor; report frame actions and correct input regions. Other platforms use their native equivalent. | planned | GNOME and SSD compositor passes |
| F14 | Window state and vetoable close: report minimize/maximize/fullscreen/focus/occlusion and allow close requests to be accepted or vetoed without duplicate destruction. | planned | state-transition model tests |
| F15 | Grabbed popup: create anchored/gravity-constrained native popups with a compositor/server grab, reposition feedback and outside-dismiss semantics. | planned | nested/reposition/dismiss scenarios |
| F16 | Clipboard and drag-and-drop: offer and receive typed data incrementally, negotiate MIME/format choices, handle large transfers without blocking, and implement both drag source and target. | planned | round-trip/large-transfer matrix |
| F17 | Threading and reentrancy: enforce the UI/main-thread rule, never call application code re-entrantly from native callbacks, and make shutdown/cancellation race-safe. | partial — all four backends queue callbacks and reject wrong-thread calls; both Linux poll paths have cancellation-safe teardown; modal/native races remain | recording lifecycle plus native loop smokes |
Handoff and integration (INT)
| ID | Requirement | Status | Traces to |
|---|---|---|---|
| INT1 | NativeHandles is a closed typed sum with only backend-valid fields and a documented ready-to-destroy lifetime. | partial — live Wayland display/surface, XCB connection/window/visual, HWND/HINSTANCE and NSApplication/NSWindow/NSView queries plus recording unsupported are exercised | handles; native loop smokes; SPEC §8 |
| INT2 | sparkles:vulkan-wsi creates native Vulkan surfaces and reuses the loader, command tables, error vocabulary, and proven frame/swapchain retirement policy. | partial — typed Wayland/XCB/Win32 surfaces, present-device selection, command pools, frame sync, swapchain decisions and deferred retirement are shared; the native Wayland frame loop presents under sync validation with compositor resize, and the X11/Win32 runtime probes reach a present-capable device on the live ICD; X11/Win32/macOS native presents remain | libs/vulkan-wsi; examples/native-wayland-triangle.d; unchanged SDL triangle build |
| INT3 | Skia Graphite uses Vulkan on Linux/Windows and Metal on macOS without WSI importing Skia or either graphics API. | planned | libs/ui-skia |
| INT4 | sparkles:ui-app exposes tui, gui-skia (default GUI), gui-skia-sdl, gui-raylib, and full configurations while application source remains backend-neutral. | planned | libs/ui-app/dub.sdl |
| INT5 | The UI adapter converts the lossless WSI vocabulary into sparkles:input once, using shared cell-metric and capability policies. | planned | ui-app/input adapter |
| INT6 | Every capability-bearing commit updates the supported-feature matrix and points at its automated and HITL evidence. | partial — every native slice so far has updated the ledger with automated evidence; the named HITL lanes remain incomplete | comparison.md |
Deferred (POST)
| ID | Requirement | Status | Entry condition |
|---|---|---|---|
| POST1 | Replace or augment Win32 IMM32 with TSF without changing the public composition/commit contract. | deferred | native F01–F17, Graphite, and ui-app integration verified |
| POST2 | Add Android/iOS backends without weakening the callback/lifecycle and typed-handle contracts. | deferred | desktop baseline verified |