Repository navigation
refactor: delete three DaqifiViewModel members nothing can reach — and keep the fourth (#242) - #245
Conversation
RemoveChannelCommand, ToggleDebugModeCommand and LatestFirmwareVersionText have zero references of any kind: no C# call site, no XAML binding in any form, no DI registration, no reflection/EF/serialization path. Each is duplicated or superseded by a live path. ShutdownCommand, the issue's third command, is deliberately NOT touched: it is equally unreachable, but nothing else disconnects devices at exit, so removing it would drop a capability rather than a duplicate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
/agentic_review |
PR Summary by QodoRemove unreachable DaqifiViewModel members
AI Description
Diagram
High-Level Assessment
Files changed (1)
|
Code Review by Qodo🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)
Great, no issues found!Qodo reviewed your code and found no material issues that require reviewTip of the day💡 Did you know, you can route each action level your way: inline, summary, both, or drop |
Shepherd verification — re-derived independently, nothing taken on the builder's wordThis is a deletion PR against a view-model that XAML binds by reflection, so the build 1. Deletions re-provedReproduced the builder's approach (it is the right one — scan the base name across
The scanner was validated with positive controls, not assumed to work. 2.
|
| result | |
|---|---|
git merge |
auto-merged DaqifiViewModel.cs, no conflict |
| Desktop | succeeded, 0 errors, 192 warnings — identical to #245 alone |
iOS Release / iossimulator-arm64 |
succeeded, 0 errors, 193 warnings — identical to #245 alone |
dotnet test |
472 / 472 passed (#245's 467 + #239's 5 new cancellation tests) |
No CS0115, no warning regression on either head. The pair is safe to land in either
order. packages.lock.json confirmed unchanged after restore (restore run without -r).
6. #242's evidence — correction confirmed and forwarded
The builder filed a correction against the issue that filed it; spot-checked it because
#242's evidence came from coverage.py --bindings (#244) and a systematic flaw there
would affect future tickets.
Confirmed. #242 says MobileShellViewModel.cs:412 calls device.RemoveChannel(channel)
"after unsubscribing". It does not — that call sits in a pre-stream reconciliation loop
that aligns the device's active analog set with the current selection, and there is no
LoggingManager.Instance.Unsubscribe in that loop or anywhere around it.
ChannelsPaneViewModel.cs:326 alone carries the claim, and it does carry it (it runs
Unsubscribe then RemoveChannel on deactivation, on both heads). The verdict is
unaffected; one of its two citations was wrong.
The mechanism looks systematic rather than a slip — the sites were matched on the callee
name RemoveChannel while ignoring the declaring type, which is how a call on
IStreamingDevice got credited as a live equivalent for a view-model command. Recorded on
#244 for its author, since that is the direction that produces false "already covered, safe
to delete" conclusions: #244
7. Verification basis
I pushed nothing, so the gate behind this note is CI's own run on cce4fcb, not a local
re-run — re-deriving a tree CI has already built buys nothing and contends for a lock a
builder needs. I read the CI log rather than trusting the reported numbers; every warning
figure quoted above is lifted from it. The only builds I ran locally were the #245+#239
merge in §5, which CI has never seen.
CI on cce4fcb — 6 SUCCESS, 1 SKIPPED (Dependabot claims check; Android and iOS both
SUCCESS). cce4fcb is the current head, so this green covers the tree under review.
Qodo: 0 bugs / 0 rule violations / 0 requirement gaps, and 0 unresolved inline review
threads (thread filter validated against the #196 control, which returns its expected 3).
Both surfaces re-checked after settling — 20 minutes on, byte-identical, still anchored to
cce4fcb.
|
Qodo-clean, CI green — ready for review, on head |
Not merging — for review.
closes #242
Deletes three
DaqifiViewModelmembers that nothing in the app can reach.0 lines added, 31 deleted, one file touched.
#242 lists three commands. Two are deleted here; the third (
ShutdownCommand) isdeliberately left in place — see "What is not deleted" below. A fourth member,
LatestFirmwareVersionText, was carried forward from PR #235 and is deleted herebecause it is in the same file and clears the same bar.
Why the issue's evidence was not taken on trust
#242 was filed by
tools/parity-audit/coverage.py --bindings, which is itselfunmerged and under review in #244, and whose earlier parser is documented as having
silently miscounted four different ways. Every symbol below was re-proved from
scratch against this checkout. The method was an exhaustive substring scan of
every file in the repo (all 443 files, all extensions, skipping only
.git/,bin/,obj/,node_modules/) rather than agit grepover*.csand*.axaml— so the enumeration is closed by construction, not by my guessing whichbinding syntaxes to look for.
That scan searched the base names (
RemoveChannel,ToggleDebugMode,Shutdown,LatestFirmwareVersion), which are substrings of the source generator's…Commandnames, so it necessarily catches both the method-name andFooCommandspellings, in any of the forms XAML can use them:Command="{Binding X}", element syntax<Binding Path="X"/>,MultiBindingchildren,
$parent[…].DataContext.X,TemplatedParent,x:Key/StaticResource,CommandParameter, a bare name in a converter parameter, anameof(...), a[NotifyCanExecuteChangedFor]/[NotifyPropertyChangedFor]argument, or a plainstring literal built for a runtime
Binding. Anything containing the name in anyfile would have appeared.
Proof, per symbol
1.
RemoveChannelCommand—[RelayCommand] private void RemoveChannel(IChannel)RemoveChannelhits are the declarationitself and
IStreamingDevice.RemoveChannel/AbstractStreamingDevice.RemoveChannel— a different member on a different type, called by three unrelated sites
(
ChannelsPaneViewModel.cs:336,Views/MobileShellViewModel.cs:412, and theview-model's own now-deleted body). No occurrence of
RemoveChannelCommandexists anywhere in the repo.
.axamlbinding. Zero hits in any.axamlfile, in any of the formslisted above.
App.csholds the onlyServiceCollection; itregisters 7 services (
IFirmwareDownloadService,IHidTransport,IExternalProcessRunner,IFirmwareUpdateService,IBootloaderWatcher,LoggingManager,IDialogService) and no view-model.DaqifiViewModelis notDI-constructed at all —
MainWindow.axaml.csdoesDataContext = new DaqifiViewModel().member-by-name lookups are
ConnectionDialogViewModel-targeted test reflectionand
DaqifiViewModel.cs:1789'sGetProperty("DeviceVersion"). None names thismember. It is a private method, not a persisted or serialized property.
Live equivalent, verified reachable:
ChannelsPaneViewModel.ToggleChannel(
ChannelsPaneViewModel.cs:326) runs exactly the same two steps on deactivation —LoggingManager.Instance.Unsubscribe(channel); device.RemoveChannel(channel);. Itis reached through
ToggleChannelCommand, bound in both heads:View/Prototype/ChannelsPanePrototype.axaml:145(hosted byMainWindow.axaml:360)and
Views/Mobile/ChannelsMobileView.axaml:71.Correction to the issue: #242 also cites
MobileShellViewModel.cs:412as a liveequivalent. It is not one — that call is a pre-stream reconciliation of the
device's active analog set and does not unsubscribe. The
ChannelsPaneViewModelpath alone carries the claim, and it carries it on both heads.Extra evidence it never ran: the deleted body dereferenced
deviceon the linebefore its own
if (device != null && ...)check — a guaranteedNullReferenceExceptionfor any channel whose device is not connected. That is alatent crash no user has hit.
2.
ToggleDebugModeCommand—[RelayCommand] private void ToggleDebugMode()ToggleDebugModelines in theentire repo: the
@port:comment and the declaration. Nothing else, in any file..axamlbinding. Zero hits.Live equivalent, verified reachable:
MainWindow.axaml:232binds aToggleButton'sIsChecked="{Binding IsDebugModeEnabled}".ToggleButton.IsCheckedregisters
BindingMode.TwoWayby default, so clicking it writes the property andruns
OnIsDebugModeEnabledChanged(DaqifiViewModel.cs:2825), which is where everyside effect lives (WiFi-notification cleanup,
SetDebugModefan-out to devices).The deleted command's whole body was
IsDebugModeEnabled = !IsDebugModeEnabled—the identical effect through the identical setter. The debug UI it gates
(
OpenDebugWindowCommand, the console button, the mobile debug panels) all bindIsDebugModeEnabled, never the command.3.
LatestFirmwareVersionText—public string => _firmwareCoordinator.LatestFirmwareVersionCarried forward from #235, re-proved here rather than taken on the handoff's word.
LatestFirmwareVersionuses areFirmwareUpdateCoordinator.LatestFirmwareVersion(the coordinator property thisforwarded to, which stays) and
DaqifiViewModel.cs:1791, which reads thecoordinator's property directly rather than going through this wrapper.
.axamlbinding. Zero hits in any view, desktop or mobile.view-model; no EF model references it, no reflection names it.
Why deletion is right rather than "bind it": it is an
[ObservableProperty]-lesscomputed property that never raises
PropertyChanged— nothing anywhere callsOnPropertyChanged(nameof(LatestFirmwareVersionText)). Binding it today woulddisplay whatever the coordinator held at first read and never update. It is not
merely unused; as written it does not work.
Upstream note, stated plainly so the reviewer can overrule me: unlike the two
commands above, this member does exist upstream
(
daqifi-desktop/Daqifi.Desktop/ViewModels/DaqifiViewModel.cs:1407, identical body).A GitHub code search across the whole upstream repo returns that single hit — so it
is equally unbound upstream, and removing it costs no behavior. It will, however,
show up in the port's declared-level parity check as a symbol upstream has and the
port does not. If the project would rather keep the declared surface aligned with
upstream, drop this hunk and the other two still stand on their own.
What is not deleted, and why
ShutdownCommand/DaqifiViewModel.Shutdown()is left exactly as it is.It is genuinely unreachable — the scan's
Shutdownhits are allIAppLogger.Shutdown/AppLogger.Shutdown(a different method on a differenttype), Avalonia's own
desktop.Shutdown()/ShutdownMode, and test fakes. Thereis no
ShutdownCommandreference anywhere and no C# caller of the method.But the issue's own table says its live equivalent is "nothing", and I confirmed
that:
App.OnExit()(App.cs:378, wired fromApp.axaml.cs:27) calls onlyAppLogger.Instance.Shutdown(), and the one other exit path,MainWindow'sClosinghandler →DaqifiViewModel.Dispose(), tears down timers,coordinators and event subscriptions but never disconnects devices. So
Shutdown()'sforeach (var device in ConnectedDevices) device.Disconnect();is notduplicated by anything.
That makes it a product decision — wire it into app exit, or accept that devices
are never cleanly disconnected — not a dead-code deletion. Deleting it would remove
the evidence that the app-exit disconnect is missing, which is the opposite of what
this routine is for. #242 flags the same decision. Handing it back rather than
guessing.
The
@port:backlinksVerified independently against upstream's default branch via
gh api(decoding thefile rather than trusting a sibling checkout on disk, which can carry other agents'
branch worktrees):
Daqifi.Desktop.ViewModels.DaqifiViewModel.RemoveChannel— 0 hits in upstream'sDaqifiViewModel.cs. The backlink pointed at nothing.Daqifi.Desktop.ViewModels.DaqifiViewModel.ToggleDebugMode— 0 hits. Same.Daqifi.Desktop.ViewModels.DaqifiViewModel.LatestFirmwareVersionText— exists(line 1407), noted above.
Daqifi.Desktop.ViewModels.DaqifiViewModel.Shutdown— exists (line 883) as a plainpublic void, not a command. Not touched here.So for the two commands, deleting them improves the parity ledger: it removes two
backlinks that resolve to no upstream symbol.
Gate
Measured against this branch's own merge-base,
a74933d, first-party set only(
third_party/excluded — it is not rebuilt by these projects and contributes nofirst-party warning):
a74933dDaqifi.Avalonia.DesktopDaqifi.Avalonia.iOS(Release, iossimulator-arm64)0 warnings added. The one warning removed on each head is consistent with the
deleted
RemoveChannelbody's unguardeddevice.DataChannelsdereference (CS8602).dotnet test Daqifi.Avalonia.Tests— 467 passed, 0 failed, 0 skipped.The Android head is not buildable on this Mac; CI covers it. Nothing in this diff is
platform-specific — it deletes three members from a shared view-model with no
remaining references on any head.
packages.lock.jsonverified unchanged after restore (restore was run without-r).Coordination
Checked against PR #239, which edits this same file heavily: #239 touches
DaqifiViewModel.csaround line 220 (_firmwareUploadCts) and 2476–2562(
UpdateWifiFirmwareOnly). This PR touches lines 1029–1040, 1587–1593 and2857–2866. No overlap, and none of the deleted members is entangled with the
firmware-cancel work.
tools/parity-audit/andcoverage.pyare untouched.🤖 Generated with Claude Code