Build image / build-and-push (push) Successful in 8s
- useClearObject: Promise.allSettled + invalidate in onSettled (not onSuccess), so a partial failure still reconciles the cache with the server instead of losing the already-removed rows; reports how many failed. - Keyboard nudge: the keydown effect is now mounted once and reads live values from a ref, so a data refetch can't re-subscribe and cancel a pending debounced commit. The pending move is flushed on unmount instead of dropped, a fire only commits if its live value is still present (a drag that cleared it already committed its own PATCH), and nudges are ignored while a pointer drag is active — closing the nudge/drag race. - usePageTitle: dropped the restore-on-unmount, which raced and could clobber the incoming route's title on a fast navigation. - ClearBedModal disables confirm on an empty plop list. - Extracted EditorHint (empty-state overlays) and objectDisplayName (harmonized the name fallback across the toolbar and clear dialog). Skipped (false positive): "nudge clamp ignores rotation" — the clamp is to the object's LOCAL bounds (±w/2, ±h/2), exactly what the server enforces, so a plop can't escape a rotated bed. tsc --noEmit clean; 24/24 vitest; production build green. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01JdQpdYYsTgtkJBxbcpAszi