docs(code-reviews): updated re-review at commit a9be809 — 12 new findings
Re-reviewed the four modules with source changes since the previous review commit76d35d1, per REVIEW-PROCESS.md section 6. Updated each findings.md header (date 2026-05-23, commita9be809) and appended new findings under continued numbering. Regenerated README.md. ## New findings — 12 total across 4 modules ### Core.Scripting (5 new, IDs -012 to -016) - **-012 High Security** — broadened BCL references (System.* + netstandard) re-expose System.Threading.ThreadPool / Timer / AssemblyLoadContext, which the analyzer's deny-list doesn't cover. Re-introduces the background-work threat Core.Scripting-003 closed via System.Threading.Tasks deny. - **-013 Medium Security** — hand-rolled wrapper-source generation lets brace-balanced user source inject sibling methods/classes alongside CompiledScript.Run. Analyzer still gates forbidden types, but the documented 'method body' authoring contract is silently relaxed. - **-014 Medium Concurrency** — CompiledScriptCache.Clear() uses key-only TryRemove(key, out _) — the same race the -006 resolution fixed in GetOrCompile's catch is latent here on publish-replace. - **-015 Low Correctness** — ToCSharpTypeName truncates at first backtick; silently drops closed type arguments of nested-generic shapes (Outer<>.Inner<>). Latent — no production caller uses this shape today. - **-016 Medium Performance** — VirtualTagEngine + ScriptedAlarmEngine call ScriptEvaluator.Compile directly without going through CompiledScriptCache, so the headline -008 collectible-ALC fix doesn't run on the actual production path — the per-publish leak is still in effect. ### Core.ScriptedAlarms (1 new, ID -013) - **-013 Low Documentation** — new internal test accessors return the live mutable scratch dictionary; XML docs don't warn future test authors about the synchronisation contract. ### Driver.Cli.Common (2 new, IDs -007, -008) - **-007 High Correctness** — 0x80550000 was added as BadDeviceFailure but the real OPC UA spec value for BadDeviceFailure is 0x808B0000 (verified against Driver.Galaxy.Runtime.StatusCodeMap and HistorianQualityMapper, both of which use the correct 0x808B0000). 0x80550000 is actually BadSecurityPolicyRejected. The native mappers (FOCAS / AbCip / AbLegacy) all use the wrong 0x80550000; this session's SnapshotFormatter extension propagated the wrong name and the test asserts against the same wrong value so CI is blind — same shape of bug as Driver.Cli.Common-001. - **-008 Low Testing** — new FormatStatus_names_native_driver_emitted_codes Theory is redundant with the existing well-known Theory (same five InlineData rows added to both) and uses weaker ShouldContain assertion than the well-known Theory's ShouldBe. ### Driver.Galaxy (4 new, IDs -015 to -018) - **-015 Medium Security** — vendored DLLs (libs/) have no recorded provenance: no source-commit SHA from the mxaccessgw repo, no SHA-256 checksum in libs/README.md. Tampering / accidental swap undetectable. - **-016 Medium Performance** — version skew between declared PackageReferences (Polly 8.5.2 / Grpc.Net.Client 2.71.0 / Microsoft.Extensions.Logging.Abstractions 10.0.0) and what the vendored DLL was actually built against (Polly.Core 8.6.6 / Grpc.Net.Client 2.76.0 / Microsoft.Extensions.Logging.Abstractions 10.0.7). Latent now (assembly-version refs are loose) but precise shape that produces a runtime MissingMethodException. - **-017 Low Design** — no contract-version handshake between the driver and the gateway; proto could evolve under the gateway without the driver noticing. - **-018 Low Documentation** — libs/README.md points at the wrong sibling csproj as the version source-of-truth; missing SpecificVersion=false on the Reference items; missing mxaccessgw source-commit SHA. ## Particularly notable Two findings undercut commits from this session: - Driver.Cli.Common-007 invalidates commit5a9c459(which named 0x80550000 as BadDeviceFailure across the cross-CLI shortlist). - Core.Scripting-016 invalidates the production effect of commit7b6ab2e(the collectible-ALC fix wired Dispose only via CompiledScriptCache, which the engines don't use). The wider native-mapper miscoding behind -007 also affects three driver modules outside this session's edit scope (FocasStatusMapper, AbCipStatusMapper, AbLegacyStatusMapper all carry the wrong code). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,10 +4,10 @@
|
||||
|---|---|
|
||||
| Module | `src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.Cli.Common` |
|
||||
| Reviewer | Claude Code |
|
||||
| Review date | 2026-05-22 |
|
||||
| Commit reviewed | `76d35d1` |
|
||||
| Review date | 2026-05-23 |
|
||||
| Commit reviewed | `a9be809` |
|
||||
| Status | Reviewed |
|
||||
| Open findings | 0 |
|
||||
| Open findings | 2 |
|
||||
|
||||
## Checklist coverage
|
||||
|
||||
@@ -16,7 +16,7 @@ a category produced nothing rather than leaving it blank.
|
||||
|
||||
| # | Category | Result |
|
||||
|---|---|---|
|
||||
| 1 | Correctness & logic bugs | Driver.Cli.Common-001, Driver.Cli.Common-002 |
|
||||
| 1 | Correctness & logic bugs | Driver.Cli.Common-001, Driver.Cli.Common-002, Driver.Cli.Common-007 |
|
||||
| 2 | OtOpcUa conventions | No issues found |
|
||||
| 3 | Concurrency & thread safety | Driver.Cli.Common-003 |
|
||||
| 4 | Error handling & resilience | Driver.Cli.Common-004 |
|
||||
@@ -24,9 +24,47 @@ a category produced nothing rather than leaving it blank.
|
||||
| 6 | Performance & resource management | No issues found |
|
||||
| 7 | Design-document adherence | No issues found |
|
||||
| 8 | Code organization & conventions | No issues found |
|
||||
| 9 | Testing coverage | Driver.Cli.Common-005 |
|
||||
| 9 | Testing coverage | Driver.Cli.Common-005, Driver.Cli.Common-008 |
|
||||
| 10 | Documentation & comments | Driver.Cli.Common-006 |
|
||||
|
||||
## Re-review 2026-05-23 (commit `a9be809`)
|
||||
|
||||
Delta scope: commit `5a9c459` extends the `FormatStatus` shortlist with five
|
||||
`Bad*` codes (`BadInternalError` 0x80020000, `BadNotWritable` 0x803B0000,
|
||||
`BadOutOfRange` 0x803C0000, `BadNotSupported` 0x803D0000, `BadDeviceFailure`
|
||||
0x80550000) the FOCAS / AbCip / AbLegacy native-protocol mappers emit. Tests
|
||||
extended with parallel `[InlineData]` rows on the well-known Theory plus a new
|
||||
`FormatStatus_names_native_driver_emitted_codes` Theory.
|
||||
|
||||
Cross-checked the five new hex literals against the OPC Foundation
|
||||
`Opc.Ua.StatusCodes` table via DeepWiki:
|
||||
|
||||
| Name added | Code in shortlist | Spec value | Verdict |
|
||||
|---|---|---|---|
|
||||
| `BadInternalError` | `0x80020000` | `0x80020000` | Correct |
|
||||
| `BadNotWritable` | `0x803B0000` | `0x803B0000` | Correct |
|
||||
| `BadOutOfRange` | `0x803C0000` | `0x803C0000` | Correct |
|
||||
| `BadNotSupported` | `0x803D0000` | `0x803D0000` | Correct |
|
||||
| `BadDeviceFailure` | `0x80550000` | **`0x808B0000`** | **WRONG — `0x80550000` is `BadSecurityPolicyRejected`** |
|
||||
|
||||
The `BadDeviceFailure` mismapping is the same shape of bug as the original
|
||||
Driver.Cli.Common-001 (wrong hex literal copied into the shortlist); recorded
|
||||
as Driver.Cli.Common-007. The wrong constant also lives in
|
||||
`FocasStatusMapper.cs`, `AbCipStatusMapper.cs`, `AbLegacyStatusMapper.cs`,
|
||||
`TwinCATStatusMapper.cs`, `S7Driver.cs`, and `ModbusDriver.cs` — those are in
|
||||
other modules' review scope but are noted here so future re-reviewers know
|
||||
this isn't isolated. (`StatusCodeMap.cs` in Driver.Galaxy + the Wonderware
|
||||
historian mappers use the correct `0x808B0000`, confirming the discrepancy.)
|
||||
|
||||
Testing observation: the new `FormatStatus_names_native_driver_emitted_codes`
|
||||
Theory is fully redundant with the well-known Theory (the five rows were also
|
||||
added there in the same commit) and uses `ShouldContain` rather than
|
||||
`ShouldBe` — recorded as Driver.Cli.Common-008.
|
||||
|
||||
Other categories (concurrency, security, performance, design-doc adherence,
|
||||
code organisation, documentation) are unchanged by this delta — no new
|
||||
issues found.
|
||||
|
||||
## Findings
|
||||
|
||||
### Driver.Cli.Common-001
|
||||
@@ -205,3 +243,92 @@ to state the source-time column is the right-most one and intentionally not
|
||||
measured/padded, calling out the null-timestamp `"-"` case explicitly. (2) FOCAS was
|
||||
added to the `DriverCommandBase` class-summary driver enumeration in commit `7ff356b`
|
||||
(landed alongside the -003 work).
|
||||
|
||||
### Driver.Cli.Common-007
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Severity | High |
|
||||
| Category | Correctness & logic bugs |
|
||||
| Location | `src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.Cli.Common/SnapshotFormatter.cs:129` |
|
||||
| Status | Open |
|
||||
|
||||
**Description:** Commit `5a9c459` added `0x80550000u => "BadDeviceFailure"` to the
|
||||
`FormatStatus` shortlist, but `0x80550000` is the canonical OPC UA spec value for
|
||||
`BadSecurityPolicyRejected`, not `BadDeviceFailure`. The correct spec value for
|
||||
`BadDeviceFailure` is `0x808B0000` (verified against the OPC Foundation
|
||||
`Opc.Ua.StatusCodes` table via DeepWiki; corroborated locally by
|
||||
`src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/Runtime/StatusCodeMap.cs:40`
|
||||
(`BadDeviceFailure = 0x808B0000u`) and the two Wonderware historian quality mappers,
|
||||
which all hand-pin the correct value).
|
||||
|
||||
This is the same shape of bug Driver.Cli.Common-001 closed: a wrong hex literal
|
||||
in the shortlist that the test theory (`SnapshotFormatterTests.cs:42`) blindly
|
||||
asserts against the same wrong value, so the bug is invisible to CI.
|
||||
|
||||
Practical impact, two-sided:
|
||||
1. A driver that returns the real spec `BadDeviceFailure` (`0x808B0000`) — e.g.
|
||||
the `Driver.Galaxy.StatusCodeMap` path on a deploy-time device fault — falls
|
||||
through the named shortlist entirely. Since Driver.Cli.Common-002 added the
|
||||
severity-class fallback, it now renders as `0x808B0000 (Bad)` instead of
|
||||
`0x808B0000 (BadDeviceFailure)` — operators lose the specific class label
|
||||
`docs/Driver.FOCAS.Cli.md:153` tells them to read off the output.
|
||||
2. A driver that returns `0x80550000` (which `FocasStatusMapper`, `AbCipStatusMapper`,
|
||||
`AbLegacyStatusMapper`, `TwinCATStatusMapper`, `S7Driver`, and `ModbusDriver` all
|
||||
misuse as "BadDeviceFailure") now renders as `0x80550000 (BadDeviceFailure)` —
|
||||
matching driver intent but contradicting the OPC UA spec, which says any client
|
||||
that decodes the same payload using the OPC Foundation stack will see
|
||||
`BadSecurityPolicyRejected`. A security-monitoring tool keying on
|
||||
`BadSecurityPolicyRejected` will fire on a CPU fault, while real
|
||||
`BadSecurityPolicyRejected` returns from the secure-channel layer would be
|
||||
mislabelled as a device fault. Operator-facing CLI output and machine-readable
|
||||
status semantics disagree.
|
||||
|
||||
The deeper bug is the wrong constant in the native-protocol mappers (out of scope
|
||||
for this module), but the `SnapshotFormatter` shortlist is its own
|
||||
spec-authoritative reference point — Driver.Cli.Common-001 explicitly framed the
|
||||
shortlist as canonical, with the in-line "keep [these literals] in sync with [the
|
||||
Opc.Ua.StatusCodes] table" comment at `SnapshotFormatter.cs:112-113`. That
|
||||
contract is now broken.
|
||||
|
||||
**Recommendation:** Change line 129 to `0x808B0000u => "BadDeviceFailure"`. Update
|
||||
the matching `[InlineData]` rows in `SnapshotFormatterTests.cs` (line 42 in the
|
||||
well-known Theory; line 60 in the redundant Theory — see Driver.Cli.Common-008).
|
||||
Also note in the resolution that the native-protocol mappers (FOCAS / AbCip /
|
||||
AbLegacy / TwinCAT / S7 / Modbus) need the same fix recorded against their own
|
||||
module reviews — the constant `0x80550000` should be replaced with `0x808B0000`
|
||||
everywhere it claims to mean `BadDeviceFailure`. Consider Driver.Cli.Common-001's
|
||||
original recommendation again: add a CI test that cross-checks every shortlist
|
||||
entry against `Opc.Ua.StatusCodes` reflection so this class of bug stops
|
||||
recurring.
|
||||
|
||||
### Driver.Cli.Common-008
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Severity | Low |
|
||||
| Category | Testing coverage |
|
||||
| Location | `tests/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.Cli.Common.Tests/SnapshotFormatterTests.cs:50-64` |
|
||||
| Status | Open |
|
||||
|
||||
**Description:** Commit `5a9c459` adds a new
|
||||
`FormatStatus_names_native_driver_emitted_codes` `[Theory]` whose five
|
||||
`[InlineData]` rows are identical to five rows added to the existing
|
||||
`FormatStatus_names_well_known_status_codes` `[Theory]` in the same commit
|
||||
(lines 32, 39, 40, 41, 42). The new Theory therefore adds no coverage. It is
|
||||
also weaker than the Theory it duplicates: it asserts
|
||||
`output.ShouldContain($"({expectedName})")` (substring match) where the
|
||||
well-known Theory asserts `output.ShouldBe($"0x{status:X8} ({expectedName})")`
|
||||
(exact match including the hex prefix). The substring form would not catch a
|
||||
regression where the hex literal renders wrong but the name is correct.
|
||||
|
||||
This is not a correctness problem — both Theories pass — but it's a
|
||||
copy-paste inconsistency that costs maintainer attention every time someone
|
||||
reads the test file and wonders which Theory is authoritative.
|
||||
|
||||
**Recommendation:** Either (a) delete the new Theory entirely — its five rows
|
||||
are already covered by the well-known Theory in the same commit — or (b) keep
|
||||
it but switch to `ShouldBe($"0x{status:X8} ({expectedName})")` so its
|
||||
assertion strength matches the rest of the file. Option (a) is cleaner: the
|
||||
commit's "operator workflow" intent is documented well enough in the
|
||||
well-known Theory comment block; the redundant Theory is dead weight.
|
||||
|
||||
Reference in New Issue
Block a user