From c3d89554e87354faf6a61efdcddcfca4795e2c68 Mon Sep 17 00:00:00 2001 From: david raistrick <1108844+keen99@users.noreply.github.com> Date: Fri, 3 Jul 2026 17:18:00 -0400 Subject: [PATCH] docs: initiative ordering design (slot, never sort) Single list = display = turn order. Slot by initiative, tie-break = add order. Drag = same-init only (DM tie override). No re-sort on mutation. Round wrap no rebuild. No cross-init drag. --- docs/INITIATIVE_ORDERING.md | 59 +++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 docs/INITIATIVE_ORDERING.md diff --git a/docs/INITIATIVE_ORDERING.md b/docs/INITIATIVE_ORDERING.md new file mode 100644 index 0000000..77b65d1 --- /dev/null +++ b/docs/INITIATIVE_ORDERING.md @@ -0,0 +1,59 @@ +# Initiative Ordering — Design + +## Core Principle + +**Slot, never sort.** + +Initiative order = a single list. Participants occupy slots determined by +initiative value. The list is mutated by insert/move operations — never +re-sorted wholesale. + +## Single Source of Truth + +One list: `participants[]`. + +- Display order = `participants[]` order (both Player view + DM view). +- Turn order = `participants[]` order. +- No derived/re-sorted copy. `turnOrderIds`, if present, is always an exact + mirror (`participants.map(p => p.id)`) — never an independent ordering. + +## When Ordering Changes + +| Action | Effect on order | +|--------|-----------------| +| **Add** (roll or manual) | Insert participant into slot by initiative | +| **Edit initiative** | Move participant to new slot | +| **Drag** | Reorder within a tie (same initiative) only | +| **Remove** | Splice out; others keep position | +| **Start encounter** | Freeze current list. No re-sort. | +| **Round wrap** | No rebuild. Continue rotation through existing list. | +| **Damage/heal/death/save** | No order change. | +| **Toggle active** | No position change. Skip in rotation only. | + +## Slotting Rules + +- Insert/move positions participants so the list stays initiative-descending. +- **Tie-break = original add order.** Later additions slot *after* existing + same-init participants. Stable insertion. +- Tie order is only changed by explicit DM drag. Never auto-changed. + +## Drag (DM Tie-Break Override) + +- Only participants with the **same initiative** are draggable onto each other. +- Cross-initiative drag is **not allowed**. (Use edit-initiative field instead.) +- Drag persists in `participants[]`. Survives all subsequent operations. +- **Re-slotting on add/edit must preserve drag-established tie order.** + +## Explicitly Forbidden + +- `sort()` on every mutation. Overwrites drag order. Root cause of past drift. +- Separate display order vs turn order. Causes player/DM divergence. +- Re-sort on round wrap. Replays rounds, introduces skips. +- Cross-initiative drag. Contradicts initiative as the primary key. +- Auto-changing tie order on add/edit. Silently loses DM intent. + +## Why + +Sorting is destructive to manual ordering. A stable slot list with drag for +ties gives deterministic, DM-controllable order that never drifts between +display surfaces or combat rounds.