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)
This commit is contained in:
Joseph Doherty
2026-06-20 22:43:36 -04:00
parent 3cc6a5f30d
commit ab57e53b92
26 changed files with 577 additions and 220 deletions
@@ -11,7 +11,7 @@
| Review date | 2026-06-19 |
| Commit reviewed | `a19b0f86` |
| Status | Reviewed |
| Open findings | 4 |
| Open findings | 0 |
## Checklist coverage
@@ -44,7 +44,7 @@ a category produced nothing rather than leaving it blank.
| Severity | Medium |
| Category | Correctness & logic bugs |
| Location | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Contracts/AbCipEquipmentTagParser.cs:42` |
| Status | Open |
| Status | Resolved |
**Description:** `AbCipEquipmentTagParser.TryParse` hard-codes `Writable: true` on every
equipment-tag definition it produces, regardless of any `writable` field in the TagConfig JSON.
@@ -70,7 +70,14 @@ record's `Writable` parameter. (2) Either return `false` from `TryParse` when `d
to `AbCipDataType.Structure` (equipment-tag flow cannot declare members), or add an explicit
comment documenting the black-box dotted-path behaviour so the next reader understands the intent.
**Resolution:** _(empty until closed)_
**Resolution:** Resolved 2026-06-20 — (1) `TryParse` now reads the optional `"writable"` boolean
field from the TagConfig JSON and threads it into `AbCipTagDefinition.Writable`, defaulting to
`true` when the field is absent. The `<remarks>` on `TryParse` was updated to document this
behaviour. (2) For the Structure concern, zero-behaviour-change option taken: an inline comment
was added at the `dataType` parse site in `TryParse` documenting that a `Structure` dataType on an
equipment tag is treated as a black-box dotted-path read (libplctag resolves the full path; the
equipment-tag flow does not enumerate UDT members). New tests in `AbCipEquipmentTagParserTests`
cover `writable:false`, `writable` absent, and the `Structure` path. Suite green (322 tests).
---
@@ -81,7 +88,7 @@ comment documenting the black-box dotted-path behaviour so the next reader under
| Severity | Low |
| Category | Correctness & logic bugs |
| Location | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Contracts/AbCipDataType.cs:28` |
| Status | Open |
| Status | Resolved |
**Description:** The inline comment on `AbCipDataType.Dt` reads:
@@ -114,7 +121,9 @@ Dt, // Logix DATE (0xCD — 4-byte unsigned days since 1984-01-01) or DATE_A
No behaviour change; documentation only.
**Resolution:** _(empty until closed)_
**Resolution:** Resolved 2026-06-20 — replaced the inaccurate single-line comment on `Dt` with a
3-line comment describing both mapped CIP types (`0xCD` DATE / `0xCF` DT), the 4-byte read stride,
and the truncation note for DATE_AND_TIME. Build green (0 errors, 0 warnings).
---
@@ -125,7 +134,7 @@ No behaviour change; documentation only.
| Severity | Low |
| Category | Code organization & conventions |
| Location | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Contracts/AbCipDriverOptions.cs:84-85` |
| Status | Open |
| Status | Resolved |
**Description:** `AbCipDriverOptions.ProbeTimeoutSeconds` carries `[Display]` and `[Range(1, 60)]`
attributes from `System.ComponentModel.DataAnnotations`. No other driver contracts project
@@ -144,7 +153,11 @@ If the intent is to document the valid range, an `<remarks>` tag (e.g. "Valid ra
seconds; the AdminUI clamps to 60s server-side.") achieves the same goal without the attribute
dependency.
**Resolution:** _(empty until closed)_
**Resolution:** Resolved 2026-06-20 — removed `[Display]` and `[Range(1, 60)]` from
`ProbeTimeoutSeconds` and removed the `using System.ComponentModel.DataAnnotations;` directive
(confirmed it was used only by those two attributes). Added a `<remarks>` element reading
"Valid range: 160 seconds; the AdminUI clamps to 60s server-side." to preserve the intent
in documentation. Build green (0 errors, 0 warnings).
---
@@ -155,7 +168,7 @@ dependency.
| Severity | Low |
| Category | Testing coverage |
| Location | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Contracts/AbCipEquipmentTagParser.cs` (entire file) |
| Status | Open |
| Status | Resolved |
**Description:** The contracts module has no dedicated test project, and `AbCipEquipmentTagParser.TryParse`
is the module's only non-trivial logic. Its `ReadArrayShape` helper has four distinct outcome
@@ -175,7 +188,14 @@ is needed. Cover: valid scalar round-trip, 1-element array, N-element array, eac
array-shape combination, non-JSON and non-object input, missing/blank `tagPath`, the Structure
DataType path, and the `Writable` default.
**Resolution:** _(empty until closed)_
**Resolution:** Resolved 2026-06-20 — added `AbCipEquipmentTagParserTests.cs` to
`tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/` (15 tests). Covers: valid scalar
round-trip; 1-element array (`isArray:true, arrayLength:1`); N-element array; `isArray:true +
arrayLength:0` → scalar; `isArray:true + arrayLength absent` → scalar; non-JSON input → false;
non-object JSON array → false; non-object JSON string → false; missing `tagPath` → false; blank
`tagPath` → false; `tagPath` as number → false; `writable:false` honoured; `writable` absent
defaults to `true`; `writable:true` explicit; `dataType:"Structure"` accepted with `Members:null`
(documents current black-box behaviour). Suite green (322 tests).
---