Skip to content

[BUG] A Multi choice run from inside a macro is fire-and-forget, so the run reports done while its picker is still open #1630

Description

@chhoumann

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:

  1. 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.
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions