When handling async actions, transport startup, or event-driven UI, treat failures and edge-case delivery as first-class: recover explicitly, preserve user input on failure, and always clean up global/UI state.
Apply these standards: 1) Clear/commit state only after confirmed success
2) Replace—not just cover—UI on late failures
3) Recover from timeouts by retrying on reconnect/transport changes
4) Harden event flows for missing lifecycle events
Mini-pattern (success-gated state cleanup):
const commit = useCallback(async () => {
const trimmed = message.trim();
if (!trimmed || busy) return;
const ok = await onAction({ type: "commit", message: trimmed, push: true });
if (!ok) return; // keep message for user correction
setMessage("");
}, [message, busy, onAction]);
Mini-pattern (retry lookup on reconnect):
useEffect(() => {
if (transport !== "connected") return;
desktopClient.invoke<string>("get_cline_app_base_url")
.then(setClineAppBaseUrl)
.catch(() => undefined);
}, [transport]);
Mini-pattern (event cleanup on inferred release):
const handleMove = (move: PointerEvent) => {
// If buttons state indicates release without pointerup delivery
if (move.buttons === 0) { cleanupAndEndDrag(); return; }
onHeightChange(clamp(...));
};