app.openSavedQuery(queryId) switches to the Query surface before it knows the
query exists, and reports nothing when it does not:
// src/ui/app.ts (openSavedQuery)
const query = app.state.savedQueries.find((saved) => saved.id === queryId);
app.showQuerySurface(); // <- unconditional
if (query) { loadIntoNewTab(app, { ...query }); toEditorOnMobile(); }
So an unresolved id yanks the user off whatever surface they were on — pushing a
history entry — opens no tab, and shows no diagnostic. It reads as a dead click
that also loses your place.
Why deferred
Pre-existing behaviour, unrelated to #426's scope (a read-only tree). Surfaced by a
review of PR for #426, where it was the tail of a now-fixed problem: a deferred
tree single-click could fire after a workspace switch and reach this path with an id
the new workspace does not contain. That trigger is gone — the tree now cancels
pending clicks on a workspace switch and on disposal — so this is no longer
reachable that way, and fixing the primitive itself belongs in its own change.
Every current caller resolves the id first (the tree only emits open-query for a
query it resolved; saved-history.ts clicks a row it just rendered), which is why
it has not bitten in practice.
Suggested fix
Resolve first: on a miss, report through the shared diagnostic path
(flashToast) and change no surface. Worth checking whether any caller depends on
the current "always switch" behaviour before tightening it.
Acceptance
openSavedQuery with an id absent from state.savedQueries leaves
app.mainSurface and the route untouched and surfaces one diagnostic.
- A resolving id behaves exactly as today.
app.openSavedQuery(queryId)switches to the Query surface before it knows thequery exists, and reports nothing when it does not:
So an unresolved id yanks the user off whatever surface they were on — pushing a
history entry — opens no tab, and shows no diagnostic. It reads as a dead click
that also loses your place.
Why deferred
Pre-existing behaviour, unrelated to #426's scope (a read-only tree). Surfaced by a
review of PR for #426, where it was the tail of a now-fixed problem: a deferred
tree single-click could fire after a workspace switch and reach this path with an id
the new workspace does not contain. That trigger is gone — the tree now cancels
pending clicks on a workspace switch and on disposal — so this is no longer
reachable that way, and fixing the primitive itself belongs in its own change.
Every current caller resolves the id first (the tree only emits
open-queryfor aquery it resolved;
saved-history.tsclicks a row it just rendered), which is whyit has not bitten in practice.
Suggested fix
Resolve first: on a miss, report through the shared diagnostic path
(
flashToast) and change no surface. Worth checking whether any caller depends onthe current "always switch" behaviour before tightening it.
Acceptance
openSavedQuerywith an id absent fromstate.savedQueriesleavesapp.mainSurfaceand the route untouched and surfaces one diagnostic.