refactor(device): extract device administration into a collaborator (part of #344) - #436
Conversation
…part of #344) Moves the reboot, ADC-calibration, voltage-precision and friendly-name commands out of DaqifiStreamingDevice into DeviceAdministrationOperations. This is the "device admin" block named in #344's body that #422 left behind while extracting SD card, diagnostics, network config and LAN chip info. DaqifiStreamingDevice: 1,385 -> 1,271 lines against the issue's ~800 target. The IDeviceOperationHost seam gains exactly two members, both forwarding to device members that already existed: Metadata (the device's own object, since the friendly-name write updates it optimistically) and Disconnect (reboot has to tear the local link down after the device drops its link). Public API is unchanged: all eleven members stay on the device as one-line delegations, so every command still passes through the device's own virtual Send and any subclass override of it. Verified as a move mechanically rather than by eye: a normalized statement multiset diff of what the device lost against what the collaborator gained leaves zero residue on the device side. No existing test changed. The +16 new cases test the collaborator directly and cover only what a direct test can see - the ordering and the total set of calls back into the host - with a fake host that throws on every seam member outside this block's remit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
/agentic_review |
PR Summary by QodoRefactor: move device-administration commands into DeviceAdministrationOperations
AI Description
Diagram
High-Level Assessment
Files changed (6)
|
Code Review by Qodo
1.
|
|
Ready for review: Qodo review came back clean (0 bugs, 0 rule violations, 0 requirement gaps, no unresolved threads) and CI |
…dministration-operations # Conflicts: # SESSION_LOG.md
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit 18e9670 |
|
Ready for review (supersedes the earlier note, which pinned This PR was The conflict was diagnosed before anything was touched: Resolved chronologically, keeping both entry blocks in full (this PR's entry is from the 22:32 fire, so it sorts before main's #437-era entries). Verified lossless mechanically rather than by eye: every non-blank line of both parents is still present — 0 missing against each. Merged-vs-branch shows exactly main's Current head
|
SESSION_LOG.md is an agent scratch journal, not a project artifact. Every branch that appends to it conflicts every other open PR. Removing the delta here; a follow-up untracks it and adds it to .gitignore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Part of #344. Not merging — opened for review.
Problem
DaqifiStreamingDeviceis still 1,385 lines against #344's ~800 target. #422 extracted four of the five blocks the issue names — SD card, diagnostics, network config, LAN chip info — and #432/#435 took channel control and the frame decode path. The device-administration block named in the issue body was left behind: reboot, the six ADC-calibration bank commands, the two voltage-precision commands, the two per-channel calibration setters, and the friendly-name write.They belong together and they belong out: every one is a guarded fire-and-forget SCPI command with no reply to parse, and none of them touches the channel collection, the streaming session, or any device state.
Change
New internal
DeviceAdministrationOperations(Device/Internal/).DaqifiStreamingDevicedrops to 1,271 lines.IDeviceOperationHostgains exactly two members, both forwarding to device members that already existed:Metadata— the device's own object, not a copy. The friendly-name write updates it optimistically because the firmware never echoes the new name back.Disconnect()— reboot has to tear the local link down after the device drops its own. Routed through the device so the full disconnect path (lifecycle lock, message pumps, status event) runs exactly as it does for a caller-issuedDisconnect.Public API is unchanged. All eleven members stay on the device as one-line delegations, so every command still passes through the device's own virtual
Sendand any subclass override of it.Why this block and not a bigger one
DaqifiDeviceis still the largest file at 4,193 lines, but its remaining blocks are the reconnect loop (entangled with_sessionEpoch,ConnectAsyncand the protected virtual snapshot hooks), the text-exchange core (consumer swap plus two locks plus disposal state) and the lifecycle/deferral gates. Each is a place where a compile-clean move can deadlock. The discipline that has worked on this issue — pure translation, no lock, no event, no device state — is what picked this block, not the line count.Verification
The move is verified mechanically, not by eye. A normalized statement multiset diff of what the device lost against what the collaborator gained leaves zero residue on the device side: every removed statement appears in the collaborator. The collaborator-only residues are class/constructor scaffolding plus three signature lines git treated as unchanged context because they are textually identical either side of the move.
No existing test changed.
DaqifiStreamingDeviceTests(command text),DaqifiStreamingDeviceFriendlyNameTestsandDeviceNotConnectedExceptionTests(all ten disconnected-guard sites) still drive the same behavior through the device — that is the extraction evidence, so they are untouched and deliberately not duplicated.+16 new cases test the collaborator directly and cover only what a direct test can see: the ordering and the total set of calls back into the host. The fake host throws on every seam member outside this block's remit, so a future change that grabs the channels lock or stops a stream fails loudly instead of passing quietly.
The two ordering assertions were mutation-verified rather than trusted green:
Rebootto disconnect-then-send failsReboot_SendsTheRebootCommandBeforeTearingTheConnectionDown— disconnecting first closes the transport the reboot command still has to travel over;SetFriendlyNameAsync_WhenTheSaveSendFails_LeavesMetadataUnchanged.Full suite green on net9 + net10 (2,583 passed, 2 skipped each) plus
Daqifi.Mcp.Tests(23). Release solution build: 0 warnings, both TFMs.Bench (real Nq1, fw 3.7.2, USB, non-destructive)
Run as a true A/B against
origin/main— the only thing that actually proves a refactor changed nothing on hardware. The same harness was built twice, once against this branch's Core and once against a throwawayorigin/mainworktree, and both were run on the same board: byte-for-byte identical output.Only RAM-load commands were issued (
CONFigure:ADC:LOADcal,CONFigure:VOLTage:LOAD— NVM read, RAM write). No NVM write, no bank selection, no friendly-name write, no reboot.SetAdcCalibrationSlope(-1)andUseAdcCalibration(2)both threwArgumentOutOfRangeException, the connection stayed up, and the SCPI error queue stayed clean — so nothing reached the wire.SaveAdcCalibrationandRebootboth refused a disconnected device, so neither an NVM write nor a reboot was ever issued.Observation, not a defect and not filed: this bench unit answers
CONFigure:ADC:LOADcalwith-200,"Execution error".-200rather than-113means the firmware recognized the header and failed to execute it — consistent with the unit having no saved user ADC-calibration bank.CONFigure:VOLTage:LOADis accepted cleanly on the same unit, and the identical-200appears onorigin/main, so it is device state, not something this change introduced.Scope
Touches no file that PR #434 touches.