# ADR-0002: Use float sort_order for drag-and-drop ordering

## Status

accepted

## Context

The planning screens (PBI list, Story list, Task list, Solo board) all support drag-and-drop reordering. With integer positions, inserting an item between positions 3 and 4 requires renumbering every subsequent row — an O(N) write for every drag operation. At the scale of a sprint board this is tolerable, but it causes unnecessary lock contention and makes optimistic UI rollback harder. See `docs/patterns/sort-order.md` for the full implementation pattern.

## Decision

Every ordered collection uses a `Float` column named `sort_order`. Inserting between two items sets `sort_order = (prev + next) / 2`. New items appended to the end get `last + 1.0`.

## Consequences

### Positive

- Reorder writes are O(1) — only the moved item's row is updated.
- Optimistic UI updates map directly to the same midpoint calculation.
- No lock contention on adjacent rows during concurrent drags.

### Negative

- Repeated insertions between the same two items cause float precision drift. Mitigation: a periodic compaction job normalizes `sort_order` values to integers × 1000 when the gap drops below `0.001`. This is a known trade-off; compaction has not been needed in practice yet.
- Queries that return items in `sort_order` order must always include `ORDER BY sort_order` — there is no implicit ordering.
