Repository navigation
chore(warning-zero): MVVMTK0034 x5 — read the generated properties, not the [ObservableProperty] backing fields - #368
Conversation
…leProperty] backing fields MVVMTK0034 x5, every instance in the codebase, all in one file and all READS: TruncatedSerialNo reads _deviceSerialNo three times, and the minimap-sync callback in IsVisible's setter reads _deviceSerialNo and _channelName. The generated getters are get => _field, so each substitution is value-identical; no write is touched, so no change notification moves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Requesting a Qodo round on |
|
/agentic_review |
PR Summary by QodoEliminate MVVMTK0034 warnings in logged-series legend items
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
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 enable the Remediation agent and Qodo fixes findings in a dedicated fix PR |
…ain field read The PR argues the substitution is behaviour-preserving because reading a generated [ObservableProperty] getter is a field read with no side effect. That was prose; now it is asserted. Six reads raise nothing and return the same instances, and the test carries its own control — a WRITE through the generated setter must raise, or the subscription proving the reads silent would be proving nothing. That asymmetry is also the reason reads are safe to substitute and the constructor's direct field writes were left alone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Pushed Round 1 on The new commit exists because of that hand-review. The PR's entire behaviour-preservation argument rested on one unasserted premise — that reading a generated Positive control re-run against this final state: mutating the property to |
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit 0b77c4f |
|
Shepherd round on Re-derived every claim in the body against the final tree rather than taking it on trust, and all of it holds:
Worth an adversarial look at the one thing I cannot fully discharge by inspection: the test block is +118 against a +4/−4 production change. I read it as earning its keep — |
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit 0b77c4f |
|
Qodo-clean, CI green — ready for review. Three rounds now, all I re-ran the mutation control locally rather than relying on CI (took One thing for whoever sequences the merges: #368 has been built with none of #338 / #365 / #367 — the sweep that built |
Not merging — for review.
warning-zeroroutine, one coherent class.The class
MVVMTK0034— "field annotated with[ObservableProperty]should not be directly referenced (use the generated property instead)". Five instances, which is every instance in the repo, all inDaqifi.Avalonia/Daqifi.Desktop/Loggers/LoggedSeriesLegendItem.cs. After this the code is absent from the build entirely rather than reduced.All five are reads, not writes:
TruncatedSerialNoreads_deviceSerialNothree timesIsVisible's setter passes_deviceSerialNoand_channelNametoDatabaseLogger.SetMinimapSeriesVisibilityWhy this is behaviour-preserving
The generated getter is
get => _deviceSerialNo;— a field read with no side effect — so each substitution is value-identical by construction.No write is touched, which is the part that would have mattered. MVVMTK0034 on a write is a behaviour change: the generated setter raises
PropertyChangedwhere a direct field write does not. There are no flagged writes here — the analyzer exempts the declaring type's own constructor, which is why the four direct field assignments on lines 102–105 carry no warning. Those are deliberately left alone; routing them through the generated setters would start raising notifications during construction, which is a real change and not what this routine is for.Nothing else moved:
[NotifyPropertyChangedFor]was added — that would change whenTruncatedSerialNore-renders;_isVisiblereads on lines 53 and 58 stay field reads, because_isVisiblebacks a hand-written property, not an[ObservableProperty];NoWarnor#pragmaappears anywhere in the diff.Tests
TruncatedSerialNohad no coverage at all, so the substitution was unwitnessed. Ten test cases were added to the existingLegendFormattingTests— the file that already characterises the other two legend formatters, for exactly this reason.They have teeth. Mutating the production property to
>= 4and dropping the?? string.Emptyguard fails exactly 2 of the 29 tests in that class —A_serial_of_four_characters_or_fewer_is_shown_whole(serial: "4104"), the boundary, andA_missing_serial_renders_as_an_empty_string— and the other 27 pass. That control was run after the final state of the fix, not only before it.The null case is not hypothetical:
PlotModelFactory.cs:173carries a liveCS8604for passing a possibly-nulldeviceSerialNointo this constructor, so the property's two null guards are load-bearing and are now pinned.The measurement
Derived from CI's own logs at both ends. That avoids the incremental-rebuild trap (CI builds cold, so nothing is skipped as up to date) and needs no
third_partyheuristic (the totals are all-project).74308c5, run351619373260b77c4f, run35192368199Warning lines are de-duplicated on
(file, line, col, code, message). MSBuild prints every warning twice — once inline and once in the trailing summary block — so the raw matched-line count is exactly 2× the truth (348 → 174 at the base, 338 → 169 on this branch).Reconciliation, so the extraction is checkable rather than asserted:
74308c50b77c4fthird_party/oxyplot-avaloniaAVLN3001(carries no line/col)RuntimeIdentifieroverride warning)Every head moves by the same −5.
The vendored block is the known 20 — 13
AVP1002plus 4CS0108, 2CS0169and 1CS0618— identical on both sides. (Filtering it onAVP1002alone would come up 7 short, and theAVLN3001line carries no(line,col), so a parser that requires one silently loses it and reports 174 against MSBuild's 175. Both were caught by the identity above before any figure was written here.)Delta: −5 on the first-party set, and the set diff is a PURE DELETION — 5 removed, all five
MVVMTK0034, 0 added, no line-number shift. All 149 first-party warnings on this branch appear in the base's 154 at the same file, line, column, code and message; the edit replaces identifiers in place and changes no line count.MVVMTK0034goes 5 → 0.Denominator named: these are the all-project de-duplicated figures for the whole build, not the desktop head project alone.
Diffstat
The production change is +4/−4 across two hunks — five identifiers, no lines added or removed, no logic. The other 118 added lines are the tests and their documentation.
Gate
Daqifi.Avalonia.Desktop— succeededDaqifi.Avalonia.iOSReleaseiossimulator-arm64(restore without-r, build with it under--no-restore) — succeeded;packages.lock.jsonunchanged afterwards, confirmed cleandotnet test— 875 passed, 0 failediosworkload is installed), so no local claim is made about it — but CI'sAndroid headjob is green on this commit, which is where the 181 → 176 figure above comes from.All six CI jobs are green on
0b77c4f.Qodo
Two rounds, both on this branch's own head SHAs, both Bugs (0) / Rule violations (0) / Requirement gaps (0) with zero inline review threads on either surface.
Grade disclosed: both rounds graded
🚀 Fast, not Deep — which is what a delta this small earns, and it is the reason the behaviour-preservation argument above is backed by a positive control and a pinning test rather than by the review outcome. Round 1's grade was not rendered at the time; it only became visible once round 2 created the "Previous reviews" block, which now showsFastfor both.Round 2 exists because the hand-review found that this PR's central premise — that a generated getter is a side-effect-free field read — was asserted in prose and nowhere tested. It is now tested.
Scope
Deliberately clear of every open PR:
AppLogger.cs(#367),MainWindow.axamland the binding tests (#338),SdCardFailureClassifierand its tests (#365), and the Dependabot branch (#363) — checked by diffing each. This PR touches two files, neither of which appears in any of them.🤖 Generated with Claude Code