Files
lmxopcua/code-reviews/Driver.TwinCAT.Contracts/findings.md
T
Joseph Doherty 98b27fc1b6 fix(code-review): resolve Batch 1 open findings (AdminUI auth, AlarmHistorian dispose guards, docs)
- AdminUI-001: gate Script editor pages at Administrator,Designer + loosen ScriptAnalysis backend to match
- AdminUI-004: explicit [Authorize] on FleetStatus/Alert/ScriptLog hubs
- Core.AlarmHistorian-014: ObjectDisposedException guards on GetStatus/RetryDeadLettered (+ regression test)
- Core.Scripting.Abstractions-004/-007: Deadband tolerance doc + stale ScriptedAlarms.md path
- Host-003: correct config-overlay precedence in ServiceHosting.md
- Configuration-014: LdapGroupRoleMapping collation-dependency doc
- Driver.TwinCAT.Contracts-002: Structure enum doc (discovery-only sentinel)
2026-06-20 22:30:33 -04:00

117 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Code Review — Driver.TwinCAT.Contracts
| Field | Value |
|---|---|
| Module | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Contracts` |
| Reviewer | Claude Code |
| Review date | 2026-06-19 |
| Commit reviewed | `a19b0f86` |
| 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 | Driver.TwinCAT.Contracts-001 (Resolved) |
| 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 | No issues found |
| 8 | Code organization & conventions | No issues found |
| 9 | Testing coverage | No issues found (no test project; thin contracts module) |
| 10 | Documentation & comments | Driver.TwinCAT.Contracts-002 |
## Cross-module consistency (Driver.TwinCAT-017 context)
Driver.TwinCAT-017 added `int? ArrayLength` to `TwinCATTagDto` in the sibling driver project,
fixing the pre-declared-tag authoring gap. The Contracts module's two consumers of
`TwinCATTagDefinition.ArrayLength` are both consistent:
- `TwinCATEquipmentTagParser.ReadArrayLength` reads `isArray`+`arrayLength` from the
equipment-tag TagConfig JSON (the AdminUI TagModal's `TagArrayConfig` layer). Field names,
guard logic (isArray must be the JSON literal `true`; length must be a positive number), and
the return type (`int?`) all match the driver's consumption in `DiscoverAsync` /
`ReadValueAsync`. No gap.
- `TwinCATDriverOptions.TwinCATTagDefinition` (the record) receives `ArrayLength` from both
`BuildTag` (pre-declared JSON path, fixed by -017) and `TwinCATEquipmentTagParser.TryParse`
(equipment-tag JSON path). Both paths are consistent. No gap introduced by -017.
One minor comment inaccuracy found and fixed below (Driver.TwinCAT.Contracts-001).
## Findings
### Driver.TwinCAT.Contracts-001
| Field | Value |
|---|---|
| Severity | Low |
| Category | Correctness & logic bugs |
| Location | `TwinCATEquipmentTagParser.cs:56-66` (`ReadArrayLength`) |
| Status | Resolved |
**Description:** The XML doc comment for `ReadArrayLength` describes `arrayLength` as "a
positive uint", but the implementation calls `lEl.TryGetInt32(out var len)`. If `arrayLength`
in the TagConfig JSON holds a value greater than `int.MaxValue` (2 147 483 647), `TryGetInt32`
returns `false` and the method silently returns `null` — treating the tag as scalar instead of
returning an error. The comment implies uint semantics but the code applies int semantics,
creating a mismatch that would mislead a maintainer trying to understand the accepted range.
In practice the `TagArrayConfig` layer (AdminUI) writes `arrayLength` as a `uint`, so values
above `int.MaxValue` are theoretically possible in JSON (though no real PLC array would have
two billion elements). The discrepancy is documentation-level rather than a real data-loss risk.
**Recommendation:** Correct the comment to say "a positive int32 (values above `int.MaxValue`
are treated as absent/scalar)" to match the actual `TryGetInt32` call. The simplest safe fix
is the comment correction; the behaviour is acceptable in practice.
**Resolution:** Resolved 2026-06-19 — corrected the `ReadArrayLength` XML doc comment to say
"a positive int32 (values above `int.MaxValue` are treated as absent/scalar)" so it matches
the actual `TryGetInt32` call; no behaviour change. Verified by build: 0 errors, 0 warnings.
---
### Driver.TwinCAT.Contracts-002
| Field | Value |
|---|---|
| Severity | Low |
| Category | Documentation & comments |
| Location | `TwinCATDataType.cs:33` (`Structure` member) |
| Status | Resolved |
**Description:** The `Structure` enum member's XML summary says "UDT / FB instance. Resolved
per member at discovery time." This is accurate for the discovery path, but the comment omits
that `Structure` is **rejected at pre-declaration time** by
`TwinCATDriverFactoryExtensions.BuildTag` (with a clear `InvalidOperationException`), and that
it is also **not parseable as a valid data type by `TwinCATEquipmentTagParser`** (the parser
falls through to the `DInt` fallback because `Structure` is never written by the AdminUI typed
editor). A maintainer reading only the Contracts project will infer that `Structure` is a
usable user-facing data type, when in fact it is an internal-discovery-only sentinel that must
not appear in operator-authored config.
**Recommendation:** Expand the `Structure` XML doc to reflect its actual contract:
```csharp
/// <summary>
/// UDT / FB instance. Used internally by <c>DiscoverAsync</c> when browsing controller
/// symbols — members are resolved to atomic types and emitted individually. Must not be
/// used in pre-declared tags (rejected at initialisation by the factory with
/// <see cref="InvalidOperationException"/>) or in AdminUI equipment-tag configs (the typed
/// editor does not offer it; the parser falls back to <c>DInt</c>).
/// </summary>
Structure,
```
**Resolution:** Resolved 2026-06-20 — expanded the `Structure` XML doc on `TwinCATDataType.cs:33`
to document the full contract: discovery-only sentinel, rejected at pre-declaration by
`TwinCATDriverFactoryExtensions.BuildTag` (`InvalidOperationException`), and not offered by the
AdminUI typed editor (parser falls back to `DInt`). Facts verified against
`TwinCATDriverFactoryExtensions.cs` (line 9699) and `TwinCATEquipmentTagParser.cs` (line 31).
Build: 0 errors, 0 warnings.