[Workbench] Generated output is lost when switching tools or leaving the page, and "Re-open" from history doesn't restore it #304

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

Symptom

A generated Session Prep sheet disappears if you switch to another Workbench tool (or navigate away) and come back. Reported during real session prep — the sheet is gone and has to be regenerated, which costs another async LLM run.

Cause

Output lives only in GeneratorPanel component state (GeneratorPanel.jsx:177-183), and the panel is deliberately unmounted on every tool switch — CampaignPlanning renders only the active tool and keys the panel by toolId (CampaignPlanning.jsx:884-891), with a belt-and-braces reset effect at GeneratorPanel.jsx:186-196. activeToolId is page state, so a route change loses it too.

The result is persisted server-side — generation_results rows, surfaced in the history rail — so nothing is actually lost, but there's no way back to it. The "Re-open" action only switches the active tool; it never rehydrates the output (CampaignPlanning.jsx:858-863):

const handleReopen = useCallback((result) => {
  if (result?.tool_id && WORKBENCH_REOPEN_TOOL_IDS.has(result.tool_id)) {
    setActiveToolId(result.tool_id);   // ← switches tool, discards result.output
  }
}, []);

So "Re-open" lands the GM on an empty panel, which reads as the same bug.

Proposed fix

Smallest useful change: make handleReopen actually reopen — pass the history row's id/output into GeneratorPanel as an initial result (plus params to rehydrate the input values), so clicking "Re-open" restores the sheet. That alone recovers everything, since results are already persisted.

Optionally on top of that, restore the last run per tool on mount (GET the latest generation_results row for (campaign_id, tool_id)), so the panel repopulates on a plain tool switch without a trip through the history rail. Worth confirming that's desirable — an auto-restored stale result can be confusing if the target session has changed since; if so, gate it on the params still matching the current selection.

Same session-prep report as the session-picker default and beat-notes round-trip issues.

## Symptom A generated Session Prep sheet disappears if you switch to another Workbench tool (or navigate away) and come back. Reported during real session prep — the sheet is gone and has to be regenerated, which costs another async LLM run. ## Cause Output lives only in `GeneratorPanel` component state ([GeneratorPanel.jsx:177-183](webapp/frontend/src/components/GeneratorPanel.jsx#L177-L183)), and the panel is deliberately unmounted on every tool switch — `CampaignPlanning` renders only the active tool and keys the panel by `toolId` ([CampaignPlanning.jsx:884-891](webapp/frontend/src/pages/CampaignPlanning.jsx#L884-L891)), with a belt-and-braces reset effect at [GeneratorPanel.jsx:186-196](webapp/frontend/src/components/GeneratorPanel.jsx#L186-L196). `activeToolId` is page state, so a route change loses it too. The result *is* persisted server-side — `generation_results` rows, surfaced in the history rail — so nothing is actually lost, but there's no way back to it. The "Re-open" action only switches the active tool; it never rehydrates the output ([CampaignPlanning.jsx:858-863](webapp/frontend/src/pages/CampaignPlanning.jsx#L858-L863)): ```js const handleReopen = useCallback((result) => { if (result?.tool_id && WORKBENCH_REOPEN_TOOL_IDS.has(result.tool_id)) { setActiveToolId(result.tool_id); // ← switches tool, discards result.output } }, []); ``` So "Re-open" lands the GM on an empty panel, which reads as the same bug. ## Proposed fix Smallest useful change: make `handleReopen` actually reopen — pass the history row's `id`/`output` into `GeneratorPanel` as an initial result (plus `params` to rehydrate the input `values`), so clicking "Re-open" restores the sheet. That alone recovers everything, since results are already persisted. Optionally on top of that, restore the last run per tool on mount (`GET` the latest `generation_results` row for `(campaign_id, tool_id)`), so the panel repopulates on a plain tool switch without a trip through the history rail. Worth confirming that's desirable — an auto-restored stale result can be confusing if the target session has changed since; if so, gate it on the params still matching the current selection. ## Related Same session-prep report as the session-picker default and beat-notes round-trip issues.
Author
Contributor

Cluster cross-reference — all four came out of the same session-prep run on 2026-08-11:

  • #302 — session pickers default to the furthest-out session
  • #303 — beat notes round-trip / append-is-really-replace / Beat Planner wipe
  • #304 (this) — generated output lost on tool switch; "Re-open" doesn't restore it
  • #305 — prep sheet regurgitates last session; no working channel for GM intent

This one is independent of the other three and can land on its own.

Cluster cross-reference — all four came out of the same session-prep run on 2026-08-11: - **#302** — session pickers default to the furthest-out session - **#303** — beat notes round-trip / append-is-really-replace / Beat Planner wipe - **#304** (this) — generated output lost on tool switch; "Re-open" doesn't restore it - **#305** — prep sheet regurgitates last session; no working channel for GM intent This one is independent of the other three and can land on its own.
Author
Contributor

Picking this up as v4.3.0 phase 3 (#514). "Re-open" will pass the stored row's output and params into the panel so it actually restores the sheet, and the last run per tool is restored on mount only when its params still match the current selection, so a stale sheet for a different session never appears.

Picking this up as v4.3.0 phase 3 (#514). "Re-open" will pass the stored row's output and params into the panel so it actually restores the sheet, and the last run per tool is restored on mount only when its params still match the current selection, so a stale sheet for a different session never appears.
Author
Contributor

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

Configs gain restore: { toValues, matches }, because only the tool knows how to invert its own buildParams. "Re-open" now hands the row to the panel as initialRun, keyed by run id so a second Re-open remounts and re-seeds rather than leaving the first sheet on screen. On mount, a panel asks history for its tool's newest ready run and restores it only if matches says it is still about what the panel is pointed at.

Two judgement calls: matches is declared only for the session-keyed tools, since for a free-text tool there is no "current selection" to compare against and any predicate would either never fire or resurrect a stale sheet; and session_prep / series_titles return null from toValues when the run's session is no longer one the picker offers, because every action on a prep sheet writes to the session it names, so a sheet shown against the wrong one is worse than no sheet.

Known limitation, documented at the top of workbenchTools.jsx: wiki-article grounding is not restored. A run records entry_id / entry_ids; a picker's value is the entry object it renders the title from, and there is nothing to hydrate that from at mount. A grounded run reopens with its output intact and the grounding cleared.

Done in the phase 3 PR (auto-merging on green); ships with v4.3.0. Configs gain `restore: { toValues, matches }`, because only the tool knows how to invert its own `buildParams`. "Re-open" now hands the row to the panel as `initialRun`, keyed by run id so a second Re-open remounts and re-seeds rather than leaving the first sheet on screen. On mount, a panel asks history for its tool's newest ready run and restores it **only if `matches` says it is still about what the panel is pointed at**. Two judgement calls: `matches` is declared only for the session-keyed tools, since for a free-text tool there is no "current selection" to compare against and any predicate would either never fire or resurrect a stale sheet; and `session_prep` / `series_titles` return `null` from `toValues` when the run's session is no longer one the picker offers, because every action on a prep sheet writes to the session it names, so a sheet shown against the wrong one is worse than no sheet. Known limitation, documented at the top of `workbenchTools.jsx`: **wiki-article grounding is not restored.** A run records `entry_id` / `entry_ids`; a picker's value is the entry *object* it renders the title from, and there is nothing to hydrate that from at mount. A grounded run reopens with its output intact and the grounding cleared.
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#304
No description provided.