Skip to content

fix: skip redundant WiFi version probe during firmware update#552

Open
tylerkron wants to merge 3 commits into
mainfrom
fix/skip-redundant-wifi-version-probe
Open

fix: skip redundant WiFi version probe during firmware update#552
tylerkron wants to merge 3 commits into
mainfrom
fix/skip-redundant-wifi-version-probe

Conversation

@tylerkron
Copy link
Copy Markdown
Contributor

@tylerkron tylerkron commented Jun 2, 2026

Summary

DaqifiViewModel.UpdateWifiModuleAsync already probes the WiFi firmware version (via ILanChipInfoProvider) to decide whether to skip the update and to surface the current/target version in the UI — it returns early when the module is already up to date (DaqifiViewModel.cs:803). It then called Core's UpdateWifiModuleAsync, which — as of Daqifi.Core 0.22.0 — runs its own internal version probe by default, so the device was queried twice per WiFi update.

This passes the new skipVersionCheck: true parameter so Core flashes directly without re-probing. The 0.22.0 XML docs explicitly recommend this for callers that already did the check ("Pass skipVersionCheck: true to that call to avoid a second probe — see issue #143 for the motivating callsite").

Behavioral note (important for review + on-device testing)

The flag is passed unconditionally. The desktop reaches the Core call in four paths, but has only truly "done the version check" in the first:

Path Desktop state Effect of skipVersionCheck: true
chip info present, update needed Flash confirmed No behavior change
chip info null (probe failed after retries) Unsure — "continuing with update" Was: Core re-probes (may skip). Now: always flashes
latest-release metadata null Unsure — "continuing" Same as above
device is not ILanChipInfoProvider Never probed Moot — Core can't probe coreDevice either

In the two "unsure" paths this removes Core's fallback probe: a user-initiated update will now re-flash the WiFi module even if it happened to already be current, rather than Core short-circuiting. This is idempotent and matches the desktop's logged intent in those paths, so it is considered acceptable — but it is a real behavioral change, and there is no unit coverage for the probe-failure paths.

⚠️ Needs hardware validation before merge

I do not have a device attached, so this has not been validated against hardware. Per CLAUDE.md / Daqifi.Desktop.UITest/README.md, run it through the FlaUI integration gate against a physically connected device, and specifically exercise:

  1. The normal path (out-of-date WiFi module flashes and reports progress correctly).
  2. A probe-failure path (device that doesn't report chip info, or with release metadata unavailable) to confirm the now-unconditional flash behaves acceptably.

Compile + unit tests pass on CI; that does not cover the on-device flash path.

Changes

  • DaqifiViewModel.cs: pass skipVersionCheck: true; update the now-stale comment that said Core also probes.
  • DaqifiViewModelFirmwareUpdateTests.cs: tighten the UpdateWifiModuleAsync Verify to assert the flag is true (the Setup/Callback stay permissive so they still exercise device routing).

Stacking

Stacked on #551 (base branch deps/nuget-version-alignment) because skipVersionCheck only exists in Daqifi.Core 0.22.0, which #551 introduces — it will not compile against current main. After #551 squash-merges and its branch is deleted, GitHub auto-retargets this PR to main; confirm the diff still shows only the 2 files (rebase onto main only if the squash causes divergence).

🤖 Generated with Claude Code

tylerkron and others added 3 commits June 2, 2026 08:50
Consolidates the still-relevant version bumps from Dependabot PRs #533,
#536, and #539, which were all failing build-and-test with NU1605
package-downgrade errors.

Root cause: Dependabot bumped Daqifi.Core in the DataModel and IO library
projects but left the direct reference in Daqifi.Desktop (and, transitively,
Daqifi.Desktop.UITest) at 0.21.0. NuGet treats a transitive version that is
higher than a direct reference as a downgrade, which is an error by default.
Aligning all three direct Daqifi.Core references clears it.

Changes:
- Daqifi.Core 0.21.0 -> 0.22.0 (DataModel, IO, Daqifi.Desktop) [non-breaking]
- Microsoft.NET.Test.Sdk 18.5.1 -> 18.6.0 (all 5 test projects)
- Sentry 6.5.0 -> 6.6.0 (Common)

The Google.Protobuf 3.34.1 -> 3.35.0 bumps from #533/#536 are dropped: #537
removed all direct Google.Protobuf references (it now resolves transitively
via Daqifi.Core). The coverlet.collector and System.Management bumps already
landed in #538.

Verified locally: dotnet restore on the full solution now exits 0 with no
NU1605 errors (restore is where all three PRs failed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Daqifi.Core 0.22.0 added a fifth optional `bool skipVersionCheck` parameter
to IFirmwareUpdateService.UpdateWifiModuleAsync (part of the "WiFi planning
split from execution" work). Production calls the method with the default, so
it compiles unchanged, but Moq validates a .Callback delegate against the
method's full parameter list at setup time, so the four-parameter callback
threw at runtime:

  System.ArgumentException: Invalid callback. Setup on method with parameters
  (IStreamingDevice, string, IProgress<FirmwareUpdateProgress>,
  CancellationToken, bool) cannot invoke callback with parameters
  (IStreamingDevice, string, IProgress<FirmwareUpdateProgress>,
  CancellationToken).

Update the Setup, Callback, and Verify for UpdateWifiModuleAsync to the
five-parameter signature (It.IsAny<bool>() for the new arg). UpdateFirmwareAsync
is unchanged in 0.22.0, so its mocks are left as-is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DaqifiViewModel.UpdateWifiModuleAsync already probes the WiFi firmware version
(via ILanChipInfoProvider) to decide whether to skip the update and to surface
versions in the UI, returning early when the module is already up to date. It
then called Daqifi.Core's UpdateWifiModuleAsync which, as of 0.22.0, performs
its own internal version probe by default, so the device was queried twice.

Pass skipVersionCheck: true (added in Daqifi.Core 0.22.0) so Core flashes
directly without re-probing. This is safe because the desktop only reaches the
Core call once it has decided a flash is needed. Tighten the test's Verify to
assert the flag is passed as true.

Requires the Daqifi.Core 0.22.0 bump from #551 (the parameter does not exist in
0.21.0); stacked on that branch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@tylerkron tylerkron requested a review from a team as a code owner June 2, 2026 15:16
@qodo-code-review
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Skip redundant WiFi version probe during firmware update

🐞 Bug fix ✨ Enhancement

Grey Divider

Walkthroughs

Description
• Skip redundant WiFi version probe during firmware update
• Pass skipVersionCheck: true to Core's UpdateWifiModuleAsync
• Desktop already probes version before calling Core, eliminating duplicate device queries
• Tighten test verification to assert flag is passed correctly
Diagram
flowchart LR
  A["Desktop probes WiFi version"] --> B{"Update needed?"}
  B -->|No| C["Return early"]
  B -->|Yes| D["Call Core UpdateWifiModuleAsync"]
  D --> E["skipVersionCheck: true"]
  E --> F["Flash without re-probing"]

Loading

Grey Divider

File Changes

1. Daqifi.Desktop/ViewModels/DaqifiViewModel.cs 🐞 Bug fix +5/-4

Pass skipVersionCheck flag to Core WiFi update

• Updated comment to clarify desktop owns version check and Core skips redundant probe
• Added skipVersionCheck: true parameter to UpdateWifiModuleAsync call
• Removed outdated comment about Core performing its own version probe

Daqifi.Desktop/ViewModels/DaqifiViewModel.cs


2. Daqifi.Desktop.Test/ViewModels/DaqifiViewModelFirmwareUpdateTests.cs 🧪 Tests +1/-1

Assert skipVersionCheck flag in test verification

• Tightened Verify assertion to explicitly check skipVersionCheck: true
• Changed from It.IsAny() to true to enforce correct parameter passing

Daqifi.Desktop.Test/ViewModels/DaqifiViewModelFirmwareUpdateTests.cs


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review Bot commented Jun 2, 2026

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0)

Context used
✅ Compliance rules (platform): 47 rules

Grey Divider


Remediation recommended

1. Always flashes on unknown versions 🐞 Bug ☼ Reliability
Description
UpdateWifiModuleAsync now passes skipVersionCheck: true unconditionally, so when the desktop
cannot determine whether an update is needed (e.g., chipInfo == null or latestRelease == null)
it will still proceed to flash without any version-gating. This can cause unnecessary WiFi reflashes
(and added update risk) specifically in the “probe/metadata unavailable” paths.
Code

Daqifi.Desktop/ViewModels/DaqifiViewModel.cs[R859-860]

Evidence
The WiFi probe/compare is not guaranteed to produce a definitive “update needed” decision: the code
explicitly continues when chipInfo is null or when latestRelease is null, and then always calls
Core with skipVersionCheck: true, preventing any further version-gating before flashing.

Daqifi.Desktop/ViewModels/DaqifiViewModel.cs[775-815]
Daqifi.Desktop/ViewModels/DaqifiViewModel.cs[855-861]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`skipVersionCheck: true` is currently passed to Core unconditionally, even in code paths where the desktop-side logic explicitly **could not** decide whether the device is already up-to-date (chip probe returned null, latest release metadata unavailable, or version parsing fails). In those paths, Core is prevented from performing any version-gating and the flow will always flash.

## Issue Context
The desktop-side check only returns early when both the device version and latest version are known and comparable. Otherwise it logs a warning and continues the update flow.

## Fix Focus Areas
- Daqifi.Desktop/ViewModels/DaqifiViewModel.cs[772-815]
- Daqifi.Desktop/ViewModels/DaqifiViewModel.cs[845-861]

## Recommended change
Introduce a local boolean (e.g., `skipCoreVersionCheck`) that is set to `true` only when the desktop has confidently determined that an update is required (e.g., `chipInfo != null`, `latestRelease != null`, and the compare logic executed and did *not* early-return). Pass that flag into the Core call.

This preserves the optimization (no double probe) on the common “version known + update needed” path, while keeping Core’s version-gating as a fallback on the “unknown” paths.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 2, 2026

📊 Code Coverage Report

Summary

Summary
Generated on: 6/2/2026 - 3:19:05 PM
Coverage date: 6/2/2026 - 3:18:27 PM - 6/2/2026 - 3:18:59 PM
Parser: MultiReport (5x Cobertura)
Assemblies: 3
Classes: 121
Files: 150
Line coverage: 19.4% (1666 of 8586)
Covered lines: 1666
Uncovered lines: 6920
Coverable lines: 8586
Total lines: 26662
Branch coverage: 19.6% (559 of 2852)
Covered branches: 559
Total branches: 2852
Method coverage: Feature is only available for sponsors

Coverage

DAQiFi - 19.1%
Name Line Branch
DAQiFi 19.1% 19.6%
Daqifi.Desktop.App 3.9% 0%
Daqifi.Desktop.Channel.AbstractChannel 40.9% 22.2%
Daqifi.Desktop.Channel.AnalogChannel 58.7% 12.5%
Daqifi.Desktop.Channel.Channel 11.5% 0%
Daqifi.Desktop.Channel.ChannelColorManager 100% 100%
Daqifi.Desktop.Channel.DataSample 91.6%
Daqifi.Desktop.Channel.DigitalChannel 65.2% 12.5%
Daqifi.Desktop.Commands.CompositeCommand 0% 0%
Daqifi.Desktop.Commands.HostCommands 0%
Daqifi.Desktop.Commands.WeakEventHandlerManager 0% 0%
Daqifi.Desktop.Configuration.FirewallConfiguration 90.6% 66.6%
Daqifi.Desktop.Configuration.WindowsFirewallWrapper 64% 68.4%
Daqifi.Desktop.ConnectionManager 42.4% 39.2%
Daqifi.Desktop.Converters.BoolToActiveStatusConverter 0% 0%
Daqifi.Desktop.Converters.BoolToConnectionStatusConverter 0% 0%
Daqifi.Desktop.Converters.BoolToStatusColorConverter 0% 0%
Daqifi.Desktop.Converters.BrushColorMatchConverter 0% 0%
Daqifi.Desktop.Converters.ConnectionTypeToColorConverter 0% 0%
Daqifi.Desktop.Converters.ConnectionTypeToUsbConverter 0% 0%
Daqifi.Desktop.Converters.InvertedBoolToVisibilityConverter 0% 0%
Daqifi.Desktop.Converters.ListToStringConverter 0% 0%
Daqifi.Desktop.Converters.NotNullToVisibilityConverter 0% 0%
Daqifi.Desktop.Converters.OxyColorToBrushConverter 0% 0%
Daqifi.Desktop.Device.AbstractStreamingDevice 42.8% 33.3%
Daqifi.Desktop.Device.DeviceMessage 0%
Daqifi.Desktop.Device.Firmware.BootloaderSessionStreamingDeviceAdapter 0% 0%
Daqifi.Desktop.Device.Firmware.WifiPromptDelayProcessRunner 0% 0%
Daqifi.Desktop.Device.NativeMethods 100%
Daqifi.Desktop.Device.SerialDevice.SerialStreamingDevice 27.6% 29.4%
Daqifi.Desktop.Device.WiFiDevice.DaqifiStreamingDevice 40.9% 39.4%
Daqifi.Desktop.DialogService.DialogService 0% 0%
Daqifi.Desktop.DialogService.ServiceLocator 0% 0%
Daqifi.Desktop.DiskSpace.DiskSpaceCheckResult 100%
Daqifi.Desktop.DiskSpace.DiskSpaceEventArgs 100%
Daqifi.Desktop.DiskSpace.DiskSpaceMonitor 88.2% 86.6%
Daqifi.Desktop.DuplicateDeviceCheckResult 100%
Daqifi.Desktop.Exporter.OptimizedLoggingSessionExporter 66.5% 60.9%
Daqifi.Desktop.Exporter.SampleData 100%
Daqifi.Desktop.Helpers.BooleanConverter`1 0% 0%
Daqifi.Desktop.Helpers.BooleanToInverseBoolConverter 0% 0%
Daqifi.Desktop.Helpers.BooleanToVisibilityConverter 0%
Daqifi.Desktop.Helpers.EnumDescriptionConverter 100% 100%
Daqifi.Desktop.Helpers.IntToVisibilityConverter 0% 0%
Daqifi.Desktop.Helpers.MinMaxDownsampler 98.6% 93.7%
Daqifi.Desktop.Helpers.MyMultiValueConverter 0%
Daqifi.Desktop.Helpers.NaturalSortHelper 100% 100%
Daqifi.Desktop.Helpers.OxyPlotDarkTheme 0%
Daqifi.Desktop.Helpers.VersionHelper 98.2% 66.2%
Daqifi.Desktop.Logger.DatabaseLogger 0% 0%
Daqifi.Desktop.Logger.DatabaseMigrator 0% 0%
Daqifi.Desktop.Logger.DeviceLegendGroup 100% 100%
Daqifi.Desktop.Logger.LoggedSeriesLegendItem 0% 0%
Daqifi.Desktop.Logger.LoggingContext 100%
Daqifi.Desktop.Logger.LoggingContextDesignTimeFactory 0%
Daqifi.Desktop.Logger.LoggingManager 0% 0%
Daqifi.Desktop.Logger.LoggingSession 16% 5%
Daqifi.Desktop.Logger.PlotLogger 0% 0%
Daqifi.Desktop.Logger.SessionDeviceMetadata 80%
Daqifi.Desktop.Logger.SummaryLogger 0% 0%
Daqifi.Desktop.Logger.TimestampGapDetector 95% 83.3%
Daqifi.Desktop.Loggers.ImportOptions 0%
Daqifi.Desktop.Loggers.ImportProgress 0% 0%
Daqifi.Desktop.Loggers.SdCardSessionImporter 0% 0%
Daqifi.Desktop.MainWindow 0% 0%
Daqifi.Desktop.Migrations.AddSamplesSessionTimeIndex 0%
Daqifi.Desktop.Migrations.AddSessionDeviceMetadata 0%
Daqifi.Desktop.Migrations.AddSessionSampleCount 0%
Daqifi.Desktop.Migrations.InitialSQLiteMigration 0%
Daqifi.Desktop.Migrations.LoggingContextModelSnapshot 0%
Daqifi.Desktop.Models.AddProfileModel 0%
Daqifi.Desktop.Models.DaqifiSettings 80.5% 83.3%
Daqifi.Desktop.Models.DebugDataCollection 6.6% 0%
Daqifi.Desktop.Models.DebugDataModel 0% 0%
Daqifi.Desktop.Models.Notifications 0%
Daqifi.Desktop.Models.SdCardFile 16.6% 0%
Daqifi.Desktop.Services.NoOpMessageBoxService 0%
Daqifi.Desktop.Services.WindowsPrincipalAdminChecker 0%
Daqifi.Desktop.Services.WpfMessageBoxService 0%
Daqifi.Desktop.UpdateVersion.VersionNotification 85.7% 54.1%
Daqifi.Desktop.View.ConnectionDialog 0% 0%
Daqifi.Desktop.View.DebugWindow 0% 0%
Daqifi.Desktop.View.DeviceLogsView 0% 0%
Daqifi.Desktop.View.DuplicateDeviceDialog 0% 0%
Daqifi.Desktop.View.ErrorDialog 0% 0%
Daqifi.Desktop.View.ExportDialog 0% 0%
Daqifi.Desktop.View.FirmwareDialog 0% 0%
Daqifi.Desktop.View.Flyouts.FirmwareFlyout 0% 0%
Daqifi.Desktop.View.Flyouts.LiveGraphFlyout 0% 0%
Daqifi.Desktop.View.Flyouts.NotificationsFlyout 0% 0%
Daqifi.Desktop.View.Flyouts.SummaryFlyout 0% 0%
Daqifi.Desktop.View.MigrationStatusWindow 0% 0%
Daqifi.Desktop.View.MinimapInteractionController 0% 0%
Daqifi.Desktop.View.ProfilesPane 0% 0%
Daqifi.Desktop.View.Prototype.ChannelsPanePrototype 0% 0%
Daqifi.Desktop.View.Prototype.DevicesPanePrototype 0% 0%
Daqifi.Desktop.View.Prototype.LiveGraphPane 0% 0%
Daqifi.Desktop.View.Prototype.LoggedDataPanePrototype 0% 0%
Daqifi.Desktop.View.SuccessDialog 0% 0%
Daqifi.Desktop.ViewModels.ChannelsPaneViewModel 0% 0%
Daqifi.Desktop.ViewModels.ChannelTileViewModel 0% 0%
Daqifi.Desktop.ViewModels.ConnectionDialogViewModel 37.3% 36.1%
Daqifi.Desktop.ViewModels.DaqifiViewModel 17.4% 10.5%
Daqifi.Desktop.ViewModels.DeviceLogsViewModel 52.5% 46%
Daqifi.Desktop.ViewModels.DevicesPaneViewModel 0% 0%
Daqifi.Desktop.ViewModels.DeviceTileViewModel 0% 0%
Daqifi.Desktop.ViewModels.DuplicateDeviceDialogViewModel 0%
Daqifi.Desktop.ViewModels.ErrorDialogViewModel 0%
Daqifi.Desktop.ViewModels.ExportDialogViewModel 0% 0%
Daqifi.Desktop.ViewModels.FirmwareDialogViewModel 0% 0%
Daqifi.Desktop.ViewModels.NewProfileChannelItem 0%
Daqifi.Desktop.ViewModels.NewProfileDeviceItem 0% 0%
Daqifi.Desktop.ViewModels.ProfilesPaneViewModel 0% 0%
Daqifi.Desktop.ViewModels.SettingsViewModel 0% 0%
Daqifi.Desktop.ViewModels.SuccessDialogViewModel 85.7%
Daqifi.Desktop.WindowViewModelMapping.IWindowViewModelMappingsContract 0%
Daqifi.Desktop.WindowViewModelMapping.WindowViewModelMappings 0%
Sentry.Generated.BuildPropertyInitializer 100%
Daqifi.Desktop.Common - 38.1%
Name Line Branch
Daqifi.Desktop.Common 38.1% 18.4%
Daqifi.Desktop.Common.AppDataPaths 81.2% 50%
Daqifi.Desktop.Common.Loggers.AppLogger 33.7% 16.6%
Daqifi.Desktop.Common.Loggers.NoOpLogger 0%
Daqifi.Desktop.IO - 100%
Name Line Branch
Daqifi.Desktop.IO 100% ****
Daqifi.Desktop.IO.Messages.MessageEventArgs`1 100%

Coverage report generated by ReportGeneratorView full report in build artifacts

Base automatically changed from deps/nuget-version-alignment to main June 2, 2026 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant