<!-- Grounding: user decision (2026-09-25 coordinator message): "The user has explicitly approved the optimistic theme apply." Justification: board evidence (docs/evidence/omarchy-themes/instant-theme-swap/ board-chooser-2026-09-25.md) showed tap-to-commit at 397 ms even after removing the redundant re-prepare, still short of the user's original ~100 ms target ("theme swaps should be instant"), with the remaining cost inside the durable two-phase commit's own pointer-swap, preference, and app-sync work -- none of which the receivers' already-prepared, already-validated resources need to wait on merely to be drawn. Proof: nix/rust-shell-client/src/main.rs (should_apply_optimistically, optimistic_apply_due, show_theme_optimistically), nix/card-shell/appearance.c (the show phase), and their own tests. "Apply tap" below now means a tap on the theme or background carousel's own already-centred slice (see "Tapping a theme or background applies it immediately", above) rather than a since-removed separate Apply button; the mechanism this requirement describes -- what the receiver does once that tap's own activate request is dispatched -- is unchanged by that later decision. -->
groundinguser decision of 2026-09-25 (comment above); board apply trials in docs/evidence/theme-picker/board-session-2026-10-12b/README.md: tap-up to shown frame 27.5-42.2 ms with prerendered=true, ahead of a durable activation of 149-179 ms, including one trial on installed system 298a2bf6. Operator acceptance 2026-10-12: "it's great now i tried it all it's good". Taps were injected.
When an Apply tap's target generation is already the Rust receiver's own prepared snapshot, the chooser SHALL render that appearance -- the wallpaper, and every other Rust-shell surface driven by it -- on the very next frame, without waiting for the durable two-phase commit (still dispatched, unchanged, and left to settle to completion asynchronously). This SHALL NOT alter the two-phase protocol's own acknowledgement contract in any way: a receiver's prepared/active bookkeeping, and the "ack only after a real, flushed frame" rule each receiver's commit/rollback handling already applies, remain exactly as before this requirement: the optimistic render is a side effect additional to that protocol, never a substitute for its own eventual, authoritative commit or rollback. A generation that is not already prepared SHALL continue to show the pre-existing busy/pending state on Apply and SHALL NOT be prepared early merely to make it eligible for this requirement. When the compositor can be reached directly, the same already-prepared candidate MAY also be shown there immediately, on the same advisory, side-effect-only basis (never altering its own two-phase bookkeeping either); this is a best-effort optimization, not a correctness requirement in its own right, since the durable commit's own real commit/rollback message to the compositor settles its display correctly regardless of whether this arrives.
scenarios An already-prepared Apply shows on the next frame
- WHEN a person taps Apply for a theme the chooser has already prepared (by browsing to it, by prepare-ahead of a carousel neighbour, or by a previous identical Apply) and the wallpaper surface is ready for a new frame - THEN the new appearance is rendered and flushed before the durable commit's own reply arrives, and the tap-to-shown latency is logged
The durable commit later succeeds
- WHEN an Apply was shown optimistically and the durable two-phase commit subsequently acknowledges successfully - THEN the receiver's own active snapshot and every other durable record (the active pointer, preferences, app appearance) settle to match exactly what is already on screen, with no further visible change
The durable commit later fails
- WHEN an Apply was shown optimistically and the durable two-phase commit subsequently fails for any reason - THEN the visible appearance is rolled back to the previous generation and the chooser shows a clear, specific error; at no point after the transaction settles does the screen show a theme that is not the durably active one
A cold, unprepared theme is never shown optimistically
- WHEN an Apply targets a generation the chooser's receiver has not already prepared - THEN the chooser shows its pre-existing busy/pending state and waits for the durable commit, exactly as before this requirement, with no early or speculative preparation triggered merely to qualify
A rapid second Apply is not confused by the first
- WHEN a person applies one already-prepared theme, and before or shortly after that transaction settles applies a second, different already-prepared theme - THEN each Apply's own optimistic check and shown appearance are scoped to that Apply's own request, and the second Apply is never suppressed or corrupted by bookkeeping left over from the first
Rendering ahead of Apply never shows anything before it is confirmed
- WHEN a candidate theme's appearance is rendered ahead of time, while it is only being previewed - THEN that rendering never becomes visible on any surface, and never alters what any ordinary (non-Apply) redraw shows, until an Apply tap actually requests it
A render made ahead of Apply is discarded, not reused, if anything it depended on changed
- WHEN a theme's appearance was rendered ahead of an Apply tap, and before that tap the surface's geometry changed, the chooser navigated to a different page, or other on-screen content it captured changed - THEN Apply falls back to rendering fresh rather than showing that stale render, with no incorrect or outdated content ever reaching the screen