Skip to content

Bug: ribbon-toggle-engine-fire-and-forget #506

Description

@drmoisan
  • Work Mode: minor-audit

Summary

RibbonViewer.SpamBayesEnabled_Click and RibbonViewer.TriageEnabled_Click are void methods whose body is an unawaited call to Controller.Engines.ToggleEngineAsync(...). The returned Task is discarded, so the toggle completes asynchronously with no ordering guarantee and any exception it raises is swallowed into an unobserved task.

Environment

  • OS/version: Windows 11, Outlook desktop (VSTO add-in host)
  • Runtime: .NET Framework 4.8.1, TaskMaster VSTO add-in
  • Command/flags used: Outlook Explorer ribbon, Spam Manager and Triage configuration menus
  • Data source or fixture: Live Outlook profile

Steps to Reproduce

  1. Open Outlook with the TaskMaster add-in loaded.
  2. Click the "SpamBayes Enabled" toggle button (or "Triage Enabled").
  3. Observe that the caller returns before ToggleEngineAsync has awaited Globals.AF.Manager.Configuration and flipped ClassifierActivated.
  4. Induce a failure inside the configuration load and observe that no error is surfaced.

Expected Behavior

The toggle either completes before the handler returns, or the handler is async void with an explicit await and a boundary try/catch that reports the failure through the project logging pattern. Either way an exception is observed and logged rather than discarded.

Actual Behavior

public void SpamBayesEnabled_Click(Office.IRibbonControl control, bool pressed) =>
    Controller.Engines.ToggleEngineAsync(SpamBayes.GroupName);

public void TriageEnabled_Click(Office.IRibbonControl control, bool pressed) =>
    Controller.Engines.ToggleEngineAsync("Triage");

(TaskMaster/Ribbon/RibbonViewer.cs, Spam Config and Triage Config regions.)

ToggleEngineAsync awaits Globals.AF.Manager.Configuration before mutating loader.Config.ClassifierActivated, so the state change is genuinely deferred. The discarded Task means a faulted toggle is silently lost; the user sees no error and the setting simply does not change.

The sibling handlers in the same regions (SpamSaveNetwork_Click, SpamSaveLocal_Click, TriageSaveNetwork_Click, TriageSaveLocal_Click) are correctly written as async void with await, which makes these two an inconsistency rather than a deliberate pattern.

Logs / Screenshots

  • Attached minimal logs or snippet
  • Snippet: see the source excerpt above. No log entry is produced on failure, which is the defect.

Impact / Severity

  • Blocker
  • High
  • Medium
  • Low

The happy path usually works because the configuration task is typically already complete by the time a user reaches the configuration menu. The defect is the swallowed failure and the absent ordering guarantee, not a routinely-observed break.

Source

From: docs/features/potential/2026-08-08-ribbon-toggle-engine-fire-and-forget.md

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