Describe the bug
A Multi choice reached from inside a Macro is fire-and-forget, so an interactive
or URI run reports its terminal result while the choice picker is still open on
the desktop - and a child choice can then run out of band, after the caller has
been told the run finished.
ChoiceExecutor.onChooseMultiType is not awaited and is not async
(src/choiceExecutor.ts:143):
this.onChooseMultiType(multiChoice); // no await
and it ends at ChoiceSuggester.Open(...) (src/choiceExecutor.ts:346), which is
new ChoiceSuggester(...).open() (src/gui/suggesters/choiceSuggester.ts:216) and
returns immediately.
quickadd:interactive refuses a Multi as the TOP-LEVEL choice
(registerQuickAddCliHandlers.ts, "Multi choices cannot be run interactively via
CLI"), but that guard does not cover a Multi reached from inside a run. Three
paths do:
MacroChoiceEngine executeChoice (a macro "Choice" command pointing at a Multi)
MacroChoiceEngine executeNestedChoice
quickAddApi.executeChoice(name)
Reproduction sketch (not yet run end to end - filed from a read of the code
while fixing #1614)
quickadd:interactive choice="MyMacro" where MyMacro's first command runs a Multi
folder. Expect the bridge to emit {"kind":"done","ok":true} while an unanswered
folder picker sits in the Obsidian window; answering it later executes a child
choice the caller has already stopped listening for.
Why it is filed rather than folded into #1614
#1614's fix routes prompts an ENGINE opens through the interactive prompt
provider. This one is not a routing gap: ChoiceSuggester is a GUI surface with
its own lifecycle, and making it awaitable changes semantics for the in-app path
too (today opening a Multi from a macro deliberately does not block the macro).
That is a design decision worth taking on its own, not a line inside a routing
change.
Shape of a fix
Two independent halves:
- Make
onChooseMultiType awaitable - ChoiceSuggester.Open resolving when the
picked child choice completes - so a run cannot report done while its own
picker is open. This is the real fix and it touches in-app behaviour.
- Until then, refuse the case that is provably wrong for a remote caller: when
choiceExecutor.promptProvider is set (or interactive === false), throw a
ChoiceAbortError naming the Multi, instead of opening a picker nobody can
answer.
Found while fixing #1614.
Describe the bug
A Multi choice reached from inside a Macro is fire-and-forget, so an interactive
or URI run reports its terminal result while the choice picker is still open on
the desktop - and a child choice can then run out of band, after the caller has
been told the run finished.
ChoiceExecutor.onChooseMultiTypeis not awaited and is not async(
src/choiceExecutor.ts:143):and it ends at
ChoiceSuggester.Open(...)(src/choiceExecutor.ts:346), which isnew ChoiceSuggester(...).open()(src/gui/suggesters/choiceSuggester.ts:216) andreturns immediately.
quickadd:interactiverefuses a Multi as the TOP-LEVEL choice(
registerQuickAddCliHandlers.ts, "Multi choices cannot be run interactively viaCLI"), but that guard does not cover a Multi reached from inside a run. Three
paths do:
MacroChoiceEngineexecuteChoice(a macro "Choice" command pointing at a Multi)MacroChoiceEngineexecuteNestedChoicequickAddApi.executeChoice(name)Reproduction sketch (not yet run end to end - filed from a read of the code
while fixing #1614)
quickadd:interactive choice="MyMacro"where MyMacro's first command runs a Multifolder. Expect the bridge to emit
{"kind":"done","ok":true}while an unansweredfolder picker sits in the Obsidian window; answering it later executes a child
choice the caller has already stopped listening for.
Why it is filed rather than folded into #1614
#1614's fix routes prompts an ENGINE opens through the interactive prompt
provider. This one is not a routing gap:
ChoiceSuggesteris a GUI surface withits own lifecycle, and making it awaitable changes semantics for the in-app path
too (today opening a Multi from a macro deliberately does not block the macro).
That is a design decision worth taking on its own, not a line inside a routing
change.
Shape of a fix
Two independent halves:
onChooseMultiTypeawaitable -ChoiceSuggester.Openresolving when thepicked child choice completes - so a run cannot report
donewhile its ownpicker is open. This is the real fix and it touches in-app behaviour.
choiceExecutor.promptProvideris set (orinteractive === false), throw aChoiceAbortErrornaming the Multi, instead of opening a picker nobody cananswer.
Found while fixing #1614.