[Workbench] Session pickers default to the furthest-out session, not the next one #302

Closed
opened 2026-08-12 00:44:37 +00:00 by claude-bot · 3 comments
Contributor

Symptom

In the GM Workbench, the session dropdown (Session Prep, Beat Planner, Series Titles) defaults to the last occurrence of a recurring series — a month out — instead of the current/next session. Reported during real session prep: a prep sheet generated with the defaults is prepping for the wrong session.

Cause

GET /api/campaigns/{id}/sessions returns sessions newest-first by created_at:

Every consumer that picks "the first upcoming session" then gets the most recently created one. For a recurring series, materialize_session_series creates occurrences in date order in one batch, so the last-created row is the furthest-out occurrence — which lands at index 0.

Affected call sites:

The dropdown option order is wrong too, not just the default — the list reads furthest-out first, so scrolling to the right session is unintuitive.

The rule already exists

AddToShelf gets this right and is already exported for reuse — AddToShelf.jsx:24-32:

export function defaultSessionId(sessions) {
  const list = shelfSessions(sessions);
  const inProgress = list.find((s) => s.status === "in_progress");
  if (inProgress) return inProgress.id;
  const dated = list
    .filter((s) => s.confirmed_time)
    .sort((a, b) => new Date(a.confirmed_time) - new Date(b.confirmed_time));
  return (dated[0] || list[0])?.id ?? "";
}

Note the resulting inconsistency inside a single Session Prep panel: the "Add to shelf" picker at the bottom defaults to the next session while the "Session" picker at the top defaults to the furthest-out one.

Proposed fix

  1. Sort sessionSelect options by confirmed_time ascending (undated last) in sessionOptions() so the dropdown reads next-first.
  2. Have autoSelectFirst and Beat Planner's seed use the shared defaultSessionId rule (prefer in_progress, else earliest upcoming) rather than [0].
  3. Leave the API ordering as-is — created_at desc is right for the session list views; this is a Workbench-side selection bug.

Sorting client-side is enough given the page already fetches the session list; no API change needed.

  • Blocks getting useful output from #(session prep context issue — filed alongside this)
## Symptom In the GM Workbench, the session dropdown (Session Prep, Beat Planner, Series Titles) defaults to the **last** occurrence of a recurring series — a month out — instead of the current/next session. Reported during real session prep: a prep sheet generated with the defaults is prepping for the wrong session. ## Cause `GET /api/campaigns/{id}/sessions` returns sessions **newest-first** by `created_at`: - [sessions.py:74](webapp/backend/app/routers/sessions.py#L74) — "List sessions for a campaign, newest first" - [session_service.py:280-284](webapp/backend/app/services/session_service.py#L280-L284) — `.order_by(Session.created_at.desc(), Session.id)` Every consumer that picks "the first upcoming session" then gets the *most recently created* one. For a recurring series, `materialize_session_series` creates occurrences in date order in one batch, so the last-created row is the furthest-out occurrence — which lands at index 0. Affected call sites: - [GeneratorPanel.jsx:58-60](webapp/frontend/src/components/GeneratorPanel.jsx#L58-L60) — `autoSelectFirst` takes `opts[0].id`. Used by `session_prep` ([workbenchTools.jsx:691-703](webapp/frontend/src/components/workbenchTools.jsx#L691-L703)) and `series_titles`. - [CampaignPlanning.jsx:256-262](webapp/frontend/src/pages/CampaignPlanning.jsx#L256-L262) — Beat Planner seeds `selectedId` from `activeSessions[0]`. The **dropdown option order** is wrong too, not just the default — the list reads furthest-out first, so scrolling to the right session is unintuitive. ## The rule already exists `AddToShelf` gets this right and is already exported for reuse — [AddToShelf.jsx:24-32](webapp/frontend/src/components/AddToShelf.jsx#L24-L32): ```js export function defaultSessionId(sessions) { const list = shelfSessions(sessions); const inProgress = list.find((s) => s.status === "in_progress"); if (inProgress) return inProgress.id; const dated = list .filter((s) => s.confirmed_time) .sort((a, b) => new Date(a.confirmed_time) - new Date(b.confirmed_time)); return (dated[0] || list[0])?.id ?? ""; } ``` Note the resulting inconsistency inside a single Session Prep panel: the "Add to shelf" picker at the bottom defaults to the *next* session while the "Session" picker at the top defaults to the *furthest-out* one. ## Proposed fix 1. Sort `sessionSelect` options by `confirmed_time` ascending (undated last) in `sessionOptions()` so the dropdown reads next-first. 2. Have `autoSelectFirst` and Beat Planner's seed use the shared `defaultSessionId` rule (prefer `in_progress`, else earliest upcoming) rather than `[0]`. 3. Leave the API ordering as-is — `created_at desc` is right for the session *list* views; this is a Workbench-side selection bug. Sorting client-side is enough given the page already fetches the session list; no API change needed. ## Related - Blocks getting useful output from #(session prep context issue — filed alongside this)
Author
Contributor

Cross-reference for the "Related" placeholder in the body — all four came out of the same session-prep run on 2026-08-11:

  • #302 (this) — session pickers default to the furthest-out session
  • #303 — beat notes never reach the frontend; "append" silently replaces, Beat Planner can wipe notes
  • #304 — generated output lost on tool switch; "Re-open" doesn't restore it
  • #305 — prep sheet regurgitates last session; no working channel for GM intent

Suggested order: #303#302#305, since #305 is largely downstream of the other two. #304 is independent.

Cross-reference for the "Related" placeholder in the body — all four came out of the same session-prep run on 2026-08-11: - **#302** (this) — session pickers default to the furthest-out session - **#303** — beat notes never reach the frontend; "append" silently replaces, Beat Planner can wipe notes - **#304** — generated output lost on tool switch; "Re-open" doesn't restore it - **#305** — prep sheet regurgitates last session; no working channel for GM intent Suggested order: **#303 → #302 → #305**, since #305 is largely downstream of the other two. #304 is independent.
Author
Contributor

Picking this up as v4.3.0 phase 3 (#514), first on the Prep lane (#302#303#304#305#374#381). Client-side: the picker sorts by confirmed time, next first, and both the Session Prep picker and Beat Planner seed from the shared defaultSessionId rule AddToShelf already exports. API ordering unchanged.

Picking this up as v4.3.0 phase 3 (#514), first on the Prep lane (#302 → #303 → #304 → #305 → #374 → #381). Client-side: the picker sorts by confirmed time, next first, and both the Session Prep picker and Beat Planner seed from the shared `defaultSessionId` rule `AddToShelf` already exports. API ordering unchanged.
Author
Contributor

Fixed in the phase 3 PR (auto-merging on green); ships with v4.3.0.

GET /api/campaigns/{id}/sessions still returns newest-created-first; that ordering is right for the history list and is unchanged. What changed is that the pickers stopped trusting it. webapp/frontend/src/utils/sessionOrder.js (soonestFirst) is now the single rule: dated sessions ascending, undated last. GeneratorPanel.sessionOptions sorts with it, autoSelectFirst means "whatever AddToShelf.defaultSessionId would pick" (in progress, else soonest), and AddToShelf's own rule is re-expressed on top of the shared sort so the two cannot drift.

Three pickers fixed, not two: the Name Generator's session context had the identical bug, and leaving it on the old rule would have been exactly the drift this issue is about.

For the record: no existing test pinned the old behaviour. The session_prep fixture's sessions carry no confirmed_time, so a stable sort preserved their order and every assertion still passed. The new tests would have caught it: a weekly series in API order defaults to week 1 rather than week 3, and in-progress wins over soonest-upcoming.

Fixed in the phase 3 PR (auto-merging on green); ships with v4.3.0. `GET /api/campaigns/{id}/sessions` still returns newest-created-first; that ordering is right for the history list and is unchanged. What changed is that the pickers stopped trusting it. `webapp/frontend/src/utils/sessionOrder.js` (`soonestFirst`) is now the single rule: dated sessions ascending, undated last. `GeneratorPanel.sessionOptions` sorts with it, `autoSelectFirst` means "whatever `AddToShelf.defaultSessionId` would pick" (in progress, else soonest), and `AddToShelf`'s own rule is re-expressed on top of the shared sort so the two cannot drift. Three pickers fixed, not two: the Name Generator's session context had the identical bug, and leaving it on the old rule would have been exactly the drift this issue is about. For the record: **no existing test pinned the old behaviour.** The `session_prep` fixture's sessions carry no `confirmed_time`, so a stable sort preserved their order and every assertion still passed. The new tests would have caught it: a weekly series in API order defaults to week 1 rather than week 3, and in-progress wins over soonest-upcoming.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/Quest-Board#302
No description provided.