| Bins mirrored vertically / drag ghost offset from cursor | Y inversion missed or applied twice | Route all conversion through useGridCoords getGridCoords/clampCoords |
| Group drop lands near (0,0) | Treated drag currentCoord as absolute | It is the delta; commit as bin.x + currentCoord.x (see useDragInteraction.handleUp) |
| "Collision"/"blocked zone" on an empty-looking layer | Lower-layer bin protrudes upward, or new code forgot the STAGING_ID skip | Inspect getBlockedZones output; skip bin.layerId === STAGING_ID in every bin loop |
| Drag preview lags / validation storms | Heavy work in the unthrottled draw/paint path | Keep expensive validation in the RAF-throttled branch of useInteraction (processHeavyMove); draw/paint stays cheap |
| Handlers act on stale state | Mode handlers captured directly in document listeners | Use the existing ref-sync pattern; read live state via useInteractionStore.getState() inside handlers |
| Commit logic never ran after a drag | pointercancel (OS gesture steal) discards without calling handleUp | Never assume handleUp runs; keep all commit logic in handleUp, nothing partial before it |
| Interaction stuck or cleared twice | Mode handleUp called setInteraction(null) on normal completion | Parent useInteraction clears it; only early-return branches (swap, staging drop) clear themselves |
| Staged bins drift above stash Y=0 | CSS repeat(N, …) drops non-integer N | Keep Staging.tsx gridHeight = Math.ceil(...) and StagingBin.tsx alignSelf: 'end' for fractional depth — git show 5517327ae |
| Half-grid toggle-off silently fails | toggleHalfGridMode returns Err while fractional bins exist | Check the Result; resize/delete fractional bins first. localStorage key gridfinity-half-bin-mode is legacy — never rename without a migration |
| Selection empties on layer switch | setActiveLayer clears selectedBinIds by design (src/core/store/selection.ts) | Not a bug; cross-layer selection is a product decision |
| Blocked zones stale mid-drag | getBlockedZones caches by reference equality of bins/layers arrays (src/shared/utils/collision.ts) | Never mutate layout arrays in place; Zustand+Immer must produce new references |
| Half-grid ON changes bin-designer defaults | Intentional: seeds base.halfSockets = true on new designs | See halfGridMode.ts docstring; bin-designer skill covers the designer side |