Files
lmxopcua/code-reviews/Driver.FOCAS.Contracts/findings.md
T
Joseph Doherty ab57e53b92 fix(code-review): resolve Batch 2 open findings (AbCip, AbLegacy, Galaxy, FOCAS)
- Driver.AbCip.Contracts-001: parse 'writable' from TagConfig JSON (default true) instead of hardcoding
- Driver.AbCip.Contracts-002/-003: Dt type comment; drop dead [Display]/[Range] annotations
- Driver.AbCip.Contracts-004: dedicated AbCipEquipmentTagParser test class (+15)
- Driver.AbCip-017: document Tick severity Low-fallback on Bad severity read
- Driver.AbLegacy.Contracts-002/-003/-004: isArray-scalar remarks (+tests), MaxTagBytes/ForFamily docs
- Driver.Galaxy.Browser-003 + Driver.Galaxy.Contracts-003: extract ResolveApiKey -> GalaxySecretRef (dedup)
- Driver.Galaxy-019: cache buffered-interval only on Ok + ILogger warnings + ClassifyIntervalReply (+tests)
- Driver.FOCAS.Contracts-002: thread WriteIdempotent through DiscoverAsync (+test)
2026-06-20 22:43:36 -04:00

6.9 KiB

Code Review — Driver.FOCAS.Contracts

Field Value
Module src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Contracts
Reviewer Claude Code
Review date 2026-06-19
Commit reviewed 7286d320
Status Reviewed
Open findings 0

Checklist coverage

A comprehensive review completes every category, recording "No issues found" where a category produced nothing rather than leaving it blank.

# Category Result
1 Correctness & logic bugs 1 finding (Driver.FOCAS.Contracts-001)
2 OtOpcUa conventions No issues found
3 Concurrency & thread safety No issues found
4 Error handling & resilience No issues found
5 Security No issues found
6 Performance & resource management No issues found
7 Design-document adherence 1 finding (Driver.FOCAS.Contracts-002)
8 Code organization & conventions No issues found
9 Testing coverage No test project — findings recorded, deferred by task scope
10 Documentation & comments 2 findings (Driver.FOCAS.Contracts-003, Driver.FOCAS.Contracts-004)

Findings

Driver.FOCAS.Contracts-001

Field Value
Severity Low
Category Correctness & logic bugs
Location src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Contracts/FocasDriverOptions.cs:144
Status Won't Fix

Description: FocasTagDefinition's positional parameter Writable defaults to true. The original review hypothesised that FOCAS is read-only by design (claiming WireFocasClient.WriteAsync always returns BadNotWritable and the def.Writable gate is dead code) and that the default should therefore be false. That premise was wrong — FOCAS supports PMC/data writes, the def.Writable gate is live, and six Driver.FOCAS.Tests write tests (FocasPmcBitRmwTests, FocasReadWriteTests) rely on Writable defaulting to true.

Recommendation: Leave the default at true. (The original recommendation to flip it to false is withdrawn.)

Resolution: Won't Fix (re-triaged 2026-06-19). The "FOCAS is read-only" premise was incorrect — the consuming Driver.FOCAS.Tests write suites failed when the default was flipped to false. The default Writable = true is intentional and correct; the change was reverted. The accompanying <param> doc was kept but corrected to describe the live write path. (Caught by the orchestrator's consuming-driver-test safety net, which the no-test-project Contracts build could not exercise.)


Driver.FOCAS.Contracts-002

Field Value
Severity Low
Category Design-document adherence
Location src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Contracts/FocasDriverOptions.cs:139-145
Status Resolved

Description: FocasTagDefinition carries a WriteIdempotent field (default false) that the FOCAS driver never reads anywhere — neither in DiscoverAsync, ReadAsync, nor WriteAsync. DiscoverAsync always passes WriteIdempotent: false to DriverAttributeInfo (hardcoded), so the field has no runtime effect. docs/drivers/FOCAS.md does not mention WriteIdempotent in its configuration tables, making its purpose undiscoverable to operators.

Recommendation: Either (a) thread FocasTagDefinition.WriteIdempotent through to DriverAttributeInfo in DiscoverAsync so the field has runtime effect and matches the pattern of other drivers, or (b) remove it from the record and the FocasDriverConfigDto wire DTO. Option (a) is the safer fix and matches the design of Modbus and other drivers. This is deferred because the fix touches FocasDriver.DiscoverAsync outside this module and requires a driver-level test change.

Resolution: Fixed (option a). In FocasDriver.DiscoverAsync the hardcoded WriteIdempotent: false was replaced with tag.WriteIdempotent so each user-authored tag's per-tag value is now threaded through to DriverAttributeInfo. The <param name="WriteIdempotent"> doc on FocasTagDefinition was updated to state it is now threaded through DiscoverAsync to DriverAttributeInfo. A new test DiscoverAsync_surfaces_WriteIdempotent_from_tag_definition was added to FocasDriverMediumFindingsTests asserting both the true and false cases surface correctly. The full Driver.FOCAS.Tests suite (including FocasPmcBitRmwTests and FocasReadWriteTests write tests) passes.


Driver.FOCAS.Contracts-003

Field Value
Severity Low
Category Documentation & comments
Location src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Contracts/FocasDriverOptions.cs:147-155
Status Resolved

Description: FocasProbeOptions is the only class in this module without a class-level XML <summary> comment. All other options classes (FocasDriverOptions, FocasFixedTreeOptions, FocasHandleRecycleOptions, FocasAlarmProjectionOptions) have class-level summaries. This inconsistency causes IDE tooltips and XML-doc generators to produce a blank description for FocasProbeOptions.

Recommendation: Add a class-level <summary> consistent with the pattern of the other options types: Controls periodic connectivity probing. One <c>cnc_rdcncstat</c> call per configured device per tick; transitions fire <c>OnHostStatusChanged</c>.

Resolution: Fixed in the same commit as this review. Added XML <summary> to FocasProbeOptions. Verified by build (no test project).


Driver.FOCAS.Contracts-004

Field Value
Severity Low
Category Documentation & comments
Location src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Contracts/FocasDriverOptions.cs:107-131
Status Resolved

Description: FocasDeviceOptions's class-level <summary> references <paramref name="Series"/> but there is no corresponding <param name="Series"> documentation block. Only PositionDecimalPlaces has a <param> entry; HostAddress, DeviceName, and Series are all undocumented at the parameter level. This leaves the expected URI form of HostAddress (focas://{ip}[:{port}]) and the valid values of Series undiscoverable from the XML doc.

Recommendation: Add <param> entries for HostAddress, DeviceName, and Series documenting the expected URI form for HostAddress and referring to FocasCncSeries.Unknown as the permissive default for Series.

Resolution: Fixed in the same commit as this review. Added <param> doc entries for HostAddress, DeviceName, and Series to FocasDeviceOptions. Verified by build (no test project).