AuxiliaryBackchannelMonitor may silently disable itself when command selection loses a race with the first-run banner
- Dominant language
- C#
- Stars
- 6.3k
- Forks
- 991
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 196
Description
`AuxiliaryBackchannelMonitor` waits one second for the command to be selected, then treats "didn't get one" as "not `mcp start`, disable monitoring":
```csharp
// src/Aspire.Cli/Backchannel/AuxiliaryBackchannelMonitor.cs:229-238
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(1));
using var combined = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken, timeout.Token);
var command = await executionContext.CommandSelected.Task.WaitAsync(combined.Token).ConfigureAwait(false);
if (command is not McpStartCommand)
{
logger.LogDebug("Current command is not MCP start command. Auxiliary backchannel monitoring disabled.");
return;
}
```
On timeout the `await` throws, `command` is never assigned, and the service returns. Monitoring is off and the only trace is one debug-level line.
I have not reproduced it. I am filing it because I just fixed the identical pattern in `NuGetPackagePrefetcher` (#18958), where it was a real defect — there the timeout made the service do work it should have skipped, here it would make it skip work it should do.
### Why one second can lose
Command selection happens when the command's action runs (`BaseCommand.cs:61`). This `BackgroundService` starts earlier at `Program.cs:1061`, and the first-run banner plays between the two at `Program.cs:1093`.
`BannerService.DisplayBannerAsync` spends **1660 ms** in fixed `Task.Delay` calls — 80 + (5 x 40) + (7 x 70) + (8 x 50) + (14 x 35), using `BannerWelcomeText` = "Welcome to the" (14 chars), `s_letterPositions.Length` = 6, and `s_aspireLines[0].TrimEnd().Length` = 41. Against a 1000 ms timeout, the timeout loses every time. That arithmetic is not theoretical: it is what made the `ls`/`ps` opt-out in #18958 fail on a first run.
### What I did not check
Whether the banner renders at all for `aspire mcp start`. `DisplayFirstTimeUseNoticeIfNeededAsync` gates on `isFirstRun`, `noLogo`, `HasMachineReadableOutput(args)`, informational options and `hostEnvironment.SupportsInteractiveOutput`, and I did not work out whether `mcp start`'s arguments and stdio environment trip any of them. If they always do, this lead is empty.
No repro steps either — I have not run it.
### Suggested direction
The banner is only the trigger I can point at. The shape is the real problem: guessing the command after a fixed timeout is unsound whenever something slow can run between host start and the command's action, and anything added to that window later re-opens it.
#18958 drops the pattern by waiting for selection until shutdown and treating "never selected" as "the CLI is shutting down, do nothing". The same fits here, since a monitor that starts late beats one that silently never starts. Selecting the parsed command earlier in `Program` would close both call sites at once.
I can send a PR, but someone who can run `aspire mcp start` on a genuine first run should confirm the trigger is real first.
Contributor guide
Assessment
This issue has not been assessed yet.