diff --git a/code-reviews/README.md b/code-reviews/README.md index 7dc32a9b..8158cc61 100644 --- a/code-reviews/README.md +++ b/code-reviews/README.md @@ -33,8 +33,8 @@ Each module's `findings.md` is the source of truth; this file is generated from | [Driver.AbLegacy](Driver.AbLegacy/findings.md) | Claude Code | 2026-06-19 | `7286d320` | Reviewed | 0 | 15 | | [Driver.AbLegacy.Cli](Driver.AbLegacy.Cli/findings.md) | Claude Code | 2026-06-19 | `111d6983` | Reviewed | 0 | 8 | | [Driver.AbLegacy.Contracts](Driver.AbLegacy.Contracts/findings.md) | Claude Code | 2026-06-19 | `a19b0f86` | Reviewed | 0 | 4 | -| [Driver.Calculation](Driver.Calculation/findings.md) | Claude (automated review agent) | 2026-08-10 | `b990adae` | Reviewed | 1 | 5 | -| [Driver.Calculation.Contracts](Driver.Calculation.Contracts/findings.md) | Claude (automated review agent) | 2026-08-10 | `b990adae` | Reviewed | 1 | 1 | +| [Driver.Calculation](Driver.Calculation/findings.md) | Claude (automated review agent) | 2026-08-10 | `b990adae` | Reviewed | 0 | 5 | +| [Driver.Calculation.Contracts](Driver.Calculation.Contracts/findings.md) | Claude (automated review agent) | 2026-08-10 | `b990adae` | Reviewed | 0 | 1 | | [Driver.Cli.Common](Driver.Cli.Common/findings.md) | Claude Code | 2026-06-19 | `7286d320` | Reviewed | 0 | 10 | | [Driver.FOCAS](Driver.FOCAS/findings.md) | Claude Code | 2026-06-19 | `04e0877b` (re-review; prior `76d35d1`) | Reviewed | 0 | 12 | | [Driver.FOCAS.Cli](Driver.FOCAS.Cli/findings.md) | Claude Code | 2026-06-19 | `7286d320` | Reviewed | 0 | 7 | @@ -46,16 +46,16 @@ Each module's `findings.md` is the source of truth; this file is generated from | [Driver.Historian.Wonderware](Driver.Historian.Wonderware/findings.md) | Claude Code | 2026-06-19 | `7286d320` | Reviewed | 0 | 12 | | [Driver.Historian.Wonderware.Client](Driver.Historian.Wonderware.Client/findings.md) | Claude Code | 2026-06-19 | `7286d320` | Reviewed | 0 | 13 | | [Driver.Historian.Wonderware.Client.Contracts](Driver.Historian.Wonderware.Client.Contracts/findings.md) | Claude Code | 2026-06-19 | `a19b0f86` | Reviewed | 0 | 4 | -| [Driver.MTConnect](Driver.MTConnect/findings.md) | Claude (per-module review) | 2026-08-10 | `b990adae` | Complete | 4 | 8 | +| [Driver.MTConnect](Driver.MTConnect/findings.md) | Claude (per-module review) | 2026-08-10 | `b990adae` | Complete | 0 | 8 | | [Driver.MTConnect.Contracts](Driver.MTConnect.Contracts/findings.md) | Claude (per-module review) | 2026-08-10 | `b990adae` | Complete | 0 | 1 | | [Driver.Modbus](Driver.Modbus/findings.md) | Claude Code | 2026-06-19 | `7286d320` | Reviewed | 0 | 14 | | [Driver.Modbus.Addressing](Driver.Modbus.Addressing/findings.md) | Claude Code | 2026-06-19 | `7286d320` | Reviewed | 0 | 11 | | [Driver.Modbus.Cli](Driver.Modbus.Cli/findings.md) | Claude Code | 2026-06-19 | `7286d320` | Reviewed | 0 | 11 | | [Driver.Modbus.Contracts](Driver.Modbus.Contracts/findings.md) | Claude Code | 2026-06-19 | `a19b0f86` | Reviewed | 0 | 4 | -| [Driver.Mqtt](Driver.Mqtt/findings.md) | Claude Code | 2026-08-10 | `b990adae` | Reviewed | 2 | 10 | -| [Driver.Mqtt.Browser](Driver.Mqtt.Browser/findings.md) | Claude | 2026-08-10 | `b990adae` | Reviewed | 4 | 5 | -| [Driver.Mqtt.Contracts](Driver.Mqtt.Contracts/findings.md) | Claude | 2026-08-10 | `b990adae` | Reviewed | 4 | 7 | -| [Driver.Mqtt.Transport](Driver.Mqtt.Transport/findings.md) | Claude Code | 2026-08-10 | `b990adae` | Reviewed | 1 | 2 | +| [Driver.Mqtt](Driver.Mqtt/findings.md) | Claude Code | 2026-08-10 | `b990adae` | Reviewed | 0 | 10 | +| [Driver.Mqtt.Browser](Driver.Mqtt.Browser/findings.md) | Claude | 2026-08-10 | `b990adae` | Reviewed | 0 | 5 | +| [Driver.Mqtt.Contracts](Driver.Mqtt.Contracts/findings.md) | Claude | 2026-08-10 | `b990adae` | Reviewed | 0 | 7 | +| [Driver.Mqtt.Transport](Driver.Mqtt.Transport/findings.md) | Claude Code | 2026-08-10 | `b990adae` | Reviewed | 0 | 2 | | [Driver.OpcUaClient](Driver.OpcUaClient/findings.md) | Claude Code | 2026-06-19 | `7286d320` | Reviewed | 0 | 16 | | [Driver.OpcUaClient.Browser](Driver.OpcUaClient.Browser/findings.md) | Claude Code | 2026-06-19 | `7286d320` | Reviewed | 0 | 3 | | [Driver.OpcUaClient.Contracts](Driver.OpcUaClient.Contracts/findings.md) | Claude Code | 2026-06-19 | `a19b0f86` | Reviewed | 0 | 3 | @@ -63,10 +63,10 @@ Each module's `findings.md` is the source of truth; this file is generated from | [Driver.S7](Driver.S7/findings.md) | Claude Code | 2026-06-19 | `7286d320` | Reviewed | 0 | 16 | | [Driver.S7.Cli](Driver.S7.Cli/findings.md) | Claude Code | 2026-06-19 | `111d6983` | Reviewed | 0 | 12 | | [Driver.S7.Contracts](Driver.S7.Contracts/findings.md) | Claude Code | 2026-06-19 | `a19b0f86` | Reviewed | 0 | 3 | -| [Driver.Sql](Driver.Sql/findings.md) | Claude Code | 2026-08-10 | `b990adae` | Reviewed | 7 | 10 | -| [Driver.Sql.Browser](Driver.Sql.Browser/findings.md) | Claude Code | 2026-08-10 | `b990adae` | Reviewed | 3 | 3 | -| [Driver.Sql.Contracts](Driver.Sql.Contracts/findings.md) | Claude Code | 2026-08-10 | `b990adae` | Reviewed | 2 | 2 | -| [Driver.Sql.Dialect](Driver.Sql.Dialect/findings.md) | Claude Code | 2026-08-10 | `b990adae` | Reviewed | 3 | 3 | +| [Driver.Sql](Driver.Sql/findings.md) | Claude Code | 2026-08-10 | `b990adae` | Reviewed | 0 | 10 | +| [Driver.Sql.Browser](Driver.Sql.Browser/findings.md) | Claude Code | 2026-08-10 | `b990adae` | Reviewed | 0 | 3 | +| [Driver.Sql.Contracts](Driver.Sql.Contracts/findings.md) | Claude Code | 2026-08-10 | `b990adae` | Reviewed | 0 | 2 | +| [Driver.Sql.Dialect](Driver.Sql.Dialect/findings.md) | Claude Code | 2026-08-10 | `b990adae` | Reviewed | 0 | 3 | | [Driver.TwinCAT](Driver.TwinCAT/findings.md) | Claude Code | 2026-06-19 | `04e0877b` | Reviewed | 0 | 17 | | [Driver.TwinCAT.Cli](Driver.TwinCAT.Cli/findings.md) | Claude Code | 2026-06-19 | `111d6983` | Reviewed | 0 | 9 | | [Driver.TwinCAT.Contracts](Driver.TwinCAT.Contracts/findings.md) | Claude Code | 2026-06-19 | `a19b0f86` | Reviewed | 0 | 2 | @@ -80,40 +80,7 @@ Each module's `findings.md` is the source of truth; this file is generated from Findings with status `Open` or `In Progress`, ordered by severity. -| ID | Severity | Category | Location | Description | -|---|---|---|---|---| -| Driver.Calculation-005 | Medium | Concurrency & thread safety | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Calculation/CalculationDriver.cs:300-314` (`OnDependencyValue`), `:374-410` (`EvaluateTag`); cross-module: `src/Server/ZB.MOM.WW.OtOpcUa.Runtime/VirtualTags/DependencyConsumerMuxAdapter.cs` | `OnDependencyValue` evaluates every change-triggered dependent tag **inline, under `_lock`**, and `EvaluateTag`'s call into `CalculationEvaluator.Evaluate` ultimately runs `TimedScriptEvaluator<...>.RunAsync(context).GetAwaiter().GetResult… | -| Driver.MTConnect-004 | Medium | Design-document adherence | `src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Drivers/Forms/MTConnectDriverForm.razor:1` · `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Contracts/MTConnectDriverOptions.cs:146` | `IWritable` shipped for this driver on 2026-08-05 (`b29623cf`) behind `Write.Enabled`, and `docs/drivers/MTConnect.md` §"Two independent gates" tells the operator to set `"Write": { "Enabled": true }` in the driver config. **There is no wa… | -| Driver.Sql-002 | Medium | Error handling & resilience | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/SqlGroupPlanner.cs:127` | `BuildKeyValuePlan` emits one bind parameter per distinct `keyValue` in a group, with no upper bound and no chunking. Every provider caps this: `Microsoft.Data.SqlClient` allows 2100 parameters per command, and Oracle limits an `IN` expres… | -| Driver.Calculation.Contracts-001 | Low | Performance & resource management | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Calculation.Contracts/CalculationTagDefinitionFactory.cs:107-160` (`Inspect`) | `Inspect` parses `reference` with `JsonDocument.Parse` once directly (to check the root kind and read `changeTriggered`/`timerIntervalMs` for the "present-but-discarded" warnings), and then — when the object parsed cleanly — calls `TryRead… | -| Driver.MTConnect-005 | Low | Concurrency & thread safety | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect/MTConnectDriver.cs:2655` · `:689` · `:797` · `:1425` | `_options` is the one piece of shared driver state published by a **plain** field write (`_options = options;` at the `StartCoreAsync` commit point) and read lock-free from other threads — `ReadAsync`, `WriteAsync`, `DiscoverAsync`, `HostN… | -| Driver.MTConnect-006 | Low | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect/MTConnectDriver.cs:914` | `TryFormatValue` refuses `null` and `Array`, then renders everything else with `Convert.ToString(value, InvariantCulture)`. Its own remark gives the right reason for the array guard — `Convert.ToString` falls back to `object.ToString()` fo… | -| Driver.MTConnect-007 | Low | Performance & resource management | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect/MTConnectAgentClient.cs:85` | `MTConnectAgentClient.Dispose()` is a plain check-then-set on a non-volatile `_disposed` field, so two concurrent disposals can both pass the guard. The second then calls `_disposeCts.Cancel()` on an already-disposed `CancellationTokenSour… | -| Driver.Mqtt-006 | Low | Concurrency & thread safety | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt/Sparkplug/SparkplugPrimaryHost.cs:278` | `DisposeAsync` calls `_gate.Dispose()`. `StopAsync` cancels the reconcile loop but does not await it, so a `ReconcileAsync` already in flight can be sitting in `ClaimAsync`/`ReleaseAsync`'s `_gate.WaitAsync(...)`, or on its way to the `fin… | -| Driver.Mqtt-007 | Low | Error handling & resilience | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt/MqttSubscriptionManager.cs:406-424` (`OnReconnectedAsync`) | When the reconnect path finds live subscribed topics but resolves **zero** filters for them, it logs a warning and returns normally. The type's own contract, stated two paragraphs later, is that a reconnect which re-establishes nothing mus… | -| Driver.Mqtt.Browser-002 | Low | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Browser/MqttBrowseSession.cs:469` | The plain-mode and Sparkplug-mode paths disagree about what may become a tree label. `ObserveSparkplugBirth` runs every group/edge-node/device/metric identifier through `IsUsableLabel`, whose doc explains the reason: "a metric name is arbi… | -| Driver.Mqtt.Browser-003 | Low | Concurrency & thread safety | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Browser/MqttBrowseSession.cs:685` | `GetOrCreate` reads `_nodeCount` and compares it to `_nodeCap`, then increments after a successful `GetOrAdd`. The read and the increment are not atomic with respect to each other, so N threads can each observe `_nodeCount == _nodeCap - 1`… | -| Driver.Mqtt.Browser-004 | Low | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Browser/MqttBrowseSession.cs:1079` | `Project` orders a level by `n.Segment`, but the dictionary is keyed by `n.Path` — and the whole reason for that keying (documented on `GetOrCreate`) is that in Sparkplug mode two siblings *can* share a `Segment`: a device folder `Plant1/E… | -| Driver.Mqtt.Browser-005 | Low | Performance & resource management | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Browser/MqttBrowseSession.cs:59`, `:81` | The per-session memory ceiling is higher than the constants suggest at a glance. `DefaultNodeCap` is 50,000 nodes, and each `TopicNode` retains its full `Path` (up to `MaxTopicChars` = 1,024 chars), its `Segment` (up to 256) and a snippet… | -| Driver.Mqtt.Contracts-004 | Low | Documentation & comments | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Contracts/MqttTagDefinitionFactory.cs:124`, `:234`, `:476` | `retainSeed` is the one behavioural key still read leniently. `ReadBoolOrDefault` returns the default for any non-boolean JSON value, so `"retainSeed": "false"` (a string, which a CSV import or a hand-edited blob produces naturally) silent… | -| Driver.Mqtt.Contracts-005 | Low | Testing coverage | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Contracts/MqttDriverOptions.cs:25`, `:71`, `:75`, `:79`, `:83`, `:99`, `:229` | `MqttDriverOptions` / `MqttPlainOptions` carry seven `System.ComponentModel.DataAnnotations` `[Range]` attributes and **nothing ever runs them**. Grepping `Validator.TryValidateObject` / `ValidationContext` across all four MQTT projects re… | -| Driver.Mqtt.Contracts-006 | Low | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Contracts/MqttWriteEncoder.cs:281` | Two edge cases in the `DriverDataType.DateTime` write arm. First, `(ulong)…ToUnixTimeMilliseconds()` on a pre-1970 value wraps a negative `long` into a very large `ulong`, so writing `1969-12-31` publishes a timestamp roughly 584 million y… | -| Driver.Mqtt.Contracts-007 | Low | Error handling & resilience | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Contracts/Sparkplug/SparkplugTopic.cs:202`, `:232` | `SparkplugTopic` validates asymmetrically. `TryParse` enforces `IsValidSegment` (non-empty, no `+`/`#`) on every segment it reads, but `Format` and `FormatState` enforce only `ArgumentException.ThrowIfNullOrEmpty` on `groupId`/`edgeNodeId`… | -| Driver.Mqtt.Transport-002 | Low | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Transport/MqttClientOptionsFactory.cs:97-100` | Credentials are attached only when `Username` is non-empty: `if (!string.IsNullOrEmpty(options.Username)) builder.WithCredentials(options.Username, options.Password ?? "")`. A config carrying a `Password` and **no** `Username` therefore co… | -| Driver.Sql-004 | Low | Error handling & resilience | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/SqlDriver.cs:651` | `HandlePollError` skips the connection class by testing `ex is DbException`, on the stated premise that "a subscribed-read outage surfaces as a DbException the reader threw, which ReadAsync has ALREADY classified". Not every unreachable-da… | -| Driver.Sql-005 | Low | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/SqlDriver.cs:641` | `IsConnectionClass` treats `BadCommunicationError` as "the database did not answer", so a poll carrying it reports the endpoint `Stopped`. But that code is minted by `GroupResult.Failed`, which the reader raises only after the connection h… | -| Driver.Sql-006 | Low | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/SqlDriver.cs:599` | `ObservePollOutcome` advances `LastSuccessfulRead` only when at least one snapshot is Good. Several codes are proof the database answered without being Good: `BadNoData` (the query ran, the row is absent), `Uncertain`/`Bad` (a present row… | -| Driver.Sql-008 | Low | Documentation & comments | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/SqlPollReader.cs:556` | `SelectWideRow`'s remarks justify giving the `topByTimestamp` form the dialect's single-row limit on the grounds that "there the `ORDER BY` makes 'the first row' a defined answer". That holds only when the ordering column is unique. `ORDER… | -| Driver.Sql-009 | Low | Security | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/SqlDriverProbe.cs:83` | The probe surfaces the raw parser text on a malformed config ("Config JSON is invalid: " + `ex.Message`) where `SqlDriverBrowser.ParseDocument` deliberately withholds the identical message "because the malformed text may carry a connection… | -| Driver.Sql-010 | Low | Concurrency & thread safety | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/SqlDriver.cs:675` | Every health transition is a read-modify-write over a `Volatile`-accessed field with no compare-and-swap: `Degrade`, `TouchLastSuccessfulRead` and `SetHealthUnlessFaulted` each `ReadHealth()`, build a new record and `WriteHealth()` it. Con… | -| Driver.Sql.Browser-001 | Low | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Browser/SqlBrowseSession.cs:290` | `PreferredTimestampColumn` nominates the first column whose dialect-mapped type is `DriverDataType.DateTime`. That set includes **date-only** types: `SqlServerDialect.MapColumnType` maps `"date"` to DateTime, and so does `PostgresDialect`… | -| Driver.Sql.Browser-002 | Low | Concurrency & thread safety | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Browser/SqlBrowseSession.cs:204`, `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Browser/SqlBrowseSession.cs:325` | Two small races around the registry reaper. (1) `DisposeAsync` disposes `_gate` unconditionally; a call already blocked in `_gate.WaitAsync` then throws `ObjectDisposedException` from inside the semaphore rather than the guarded `ObjectDis… | -| Driver.Sql.Browser-003 | Low | Security | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Browser/SqlDriverBrowser.cs:262` | `OpenAsync` accepts an ad-hoc `connectionString` literal from the browse form and dials it verbatim. That is an unrestricted outbound-connect primitive on the AdminUI host: an arbitrary host and port, plus whatever the provider's keyword s… | -| Driver.Sql.Contracts-001 | Low | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Contracts/SqlEquipmentTagParser.cs:65`, `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Contracts/SqlTagDefinitionFactory.cs:132` | The two value-bearing fields are read asymmetrically and nothing documents it. `whereValue` goes through `ReadScalar`, which accepts a JSON string, number or boolean and captures the raw token — the design doc's own wide-row example author… | -| Driver.Sql.Contracts-002 | Low | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Contracts/SqlEquipmentTagParser.cs:50` | Cross-module, and reachable through every driver rather than only this one. The strict enum read is `TagConfigJson.TryReadEnumStrict`, which classifies via `Enum.TryParse(text, ignoreCase: true, …)` — and that method accepts a **numeric st… | -| Driver.Sql.Dialect-001 | Low | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Dialect/PostgresDialect.cs:178`, `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Dialect/OracleDialect.cs:212` | Both identifier ceilings are enforced as `ident.Length`, i.e. UTF-16 code units, but the server limits they stand in for are **byte** limits: PostgreSQL's `NAMEDATALEN - 1` is 63 bytes and Oracle 12.2's is 128 bytes, both measured in the d… | -| Driver.Sql.Dialect-002 | Low | Code organization & conventions | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Dialect/ISqlDialect.cs:29` | The seam models identifier quoting, catalog SQL, row-limit syntax, parameter spelling and command setup — everything that differs per backend *except* the per-command bind-parameter ceiling, which also differs per backend (2100 for `Micros… | -| Driver.Sql.Dialect-003 | Low | Documentation & comments | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Dialect/OracleDialect.cs:135` | `OracleDialect.ListSchemasSql` reads `ALL_USERS`, and its remarks justify the divergence from the other two dialects (which list only schemas that own a visible relation) purely from the catalog gate's point of view: "harmless here — the l… | +_No pending findings._ ## Closed findings @@ -269,6 +236,7 @@ Findings with status `Resolved`, `Won't Fix`, or `Deferred`. | Driver.Calculation-001 | Medium | Resolved | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Calculation/CalculationDriver.cs:103-106` (pre-fix), `CalculationEvaluator.cs:47,56-59` (pre-fix) | | Driver.Calculation-003 | Medium | Resolved | Correctness & logic bugs / Code organization & conventions | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Calculation/CalculationDriverProbe.cs:16-21` (pre-fix) | | Driver.Calculation-004 | Medium | Resolved | Testing coverage | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Calculation/CalculationDriverProbe.cs`, `CalculationDriver.cs` (`ISkippedTagReporter`/`GetSkippedTags()`), `CalculationTimerScheduler.cs` (`SkippedTickCount`) | +| Driver.Calculation-005 | Medium | Resolved | Concurrency & thread safety | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Calculation/CalculationDriver.cs:300-314` (`OnDependencyValue`), `:374-410` (`EvaluateTag`); cross-module: `src/Server/ZB.MOM.WW.OtOpcUa.Runtime/VirtualTags/DependencyConsumerMuxAdapter.cs` | | Driver.Cli.Common-002 | Medium | Resolved | Correctness & logic bugs | `src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.Cli.Common/SnapshotFormatter.cs:101-122` | | Driver.Cli.Common-003 | Medium | Resolved | Concurrency & thread safety | `src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.Cli.Common/DriverCommandBase.cs:51-59` | | Driver.Cli.Common-005 | Medium | Resolved | Testing coverage | `tests/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.Cli.Common.Tests/SnapshotFormatterTests.cs:27-37` | @@ -300,6 +268,7 @@ Findings with status `Resolved`, `Won't Fix`, or `Deferred`. | Driver.Historian.Wonderware.Client.Contracts-003 | Medium | Resolved | Correctness & logic bugs | `WonderwareHistorianClientOptions.cs:26` | | Driver.MTConnect-001 | Medium | Resolved | Error handling & resilience | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect/MTConnectDriver.cs:1932` | | Driver.MTConnect-002 | Medium | Resolved | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect/MTConnectDriverProbe.cs:192` | +| Driver.MTConnect-004 | Medium | Resolved | Design-document adherence | `src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Drivers/Forms/MTConnectDriverForm.razor:1` · `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Contracts/MTConnectDriverOptions.cs:146` | | Driver.Modbus-002 | Medium | Resolved | Correctness & logic bugs | `ModbusDriver.cs:127-186` | | Driver.Modbus-004 | Medium | Resolved | Performance & resource management | `ModbusDriver.cs:1468-1473` | | Driver.Modbus-005 | Medium | Resolved | Correctness & logic bugs | `ModbusDriver.cs:777-798,323-330` | @@ -339,6 +308,7 @@ Findings with status `Resolved`, `Won't Fix`, or `Deferred`. | Driver.S7.Cli-003 | Medium | Resolved | Error handling & resilience | `src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.S7.Cli/Commands/ProbeCommand.cs:38-50` | | Driver.S7.Cli-008 | Medium | Resolved | Error handling & resilience | `src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.S7.Cli/S7CommandBase.cs` | | Driver.Sql-001 | Medium | Resolved | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/SqlCatalogLoader.cs:139` | +| Driver.Sql-002 | Medium | Resolved | Error handling & resilience | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/SqlGroupPlanner.cs:127` | | Driver.Sql-003 | Medium | Resolved | Design-document adherence | `docs/drivers/Sql.md:55`, `docs/drivers/Sql.md:90` | | Driver.TwinCAT-003 | Medium | Resolved | Correctness & logic bugs | `AdsTwinCATClient.cs:264-281`, `283-300` | | Driver.TwinCAT-005 | Medium | Resolved | OtOpcUa conventions | `TwinCATDriver.cs` (whole file), `AdsTwinCATClient.cs` (whole file) | @@ -502,6 +472,7 @@ Findings with status `Resolved`, `Won't Fix`, or `Deferred`. | Driver.AbLegacy.Contracts-002 | Low | Resolved | Documentation & comments | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Contracts/AbLegacyEquipmentTagParser.cs:15` | | Driver.AbLegacy.Contracts-003 | Low | Resolved | OtOpcUa conventions | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Contracts/AbLegacyPlcFamilyProfile.cs:10` | | Driver.AbLegacy.Contracts-004 | Low | Resolved | Code organization & conventions | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Contracts/AbLegacyPlcFamilyProfile.cs:22` | +| Driver.Calculation.Contracts-001 | Low | Resolved | Performance & resource management | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Calculation.Contracts/CalculationTagDefinitionFactory.cs:107-160` (`Inspect`) | | Driver.Cli.Common-004 | Low | Resolved | Error handling & resilience | `src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.Cli.Common/SnapshotFormatter.cs:68-70` | | Driver.Cli.Common-006 | Low | Resolved | Documentation & comments | `src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.Cli.Common/SnapshotFormatter.cs:71`, `src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.Cli.Common/DriverCommandBase.cs:9` | | Driver.Cli.Common-008 | Low | Resolved | Testing coverage | `tests/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.Cli.Common.Tests/SnapshotFormatterTests.cs:50-64` | @@ -551,6 +522,9 @@ Findings with status `Resolved`, `Won't Fix`, or `Deferred`. | Driver.Historian.Wonderware.Client-012 | Low | Resolved | Performance & resource management | `Internal/FrameChannel.cs:38` | | Driver.Historian.Wonderware.Client-013 | Low | Resolved | Testing coverage | `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware.Client.Tests/ContractsWireParityTests.cs` | | Driver.Historian.Wonderware.Client.Contracts-004 | Low | Resolved | Documentation & comments | `WonderwareHistorianClientOptions.cs:50-54` | +| Driver.MTConnect-005 | Low | Resolved | Concurrency & thread safety | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect/MTConnectDriver.cs:2655` · `:689` · `:797` · `:1425` | +| Driver.MTConnect-006 | Low | Resolved | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect/MTConnectDriver.cs:914` | +| Driver.MTConnect-007 | Low | Resolved | Performance & resource management | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect/MTConnectAgentClient.cs:85` | | Driver.MTConnect-008 | Low | Resolved | Documentation & comments | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect/MTConnectDriver.cs:3210` · `docs/drivers/MTConnect.md:169` · `MTConnectDriver.cs:1227`/`:1245`/`:1255` | | Driver.MTConnect.Contracts-001 | Low | Resolved | Documentation & comments | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Contracts/MTConnectDataTypeInference.cs:31` · `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.MTConnect.Contracts/MTConnectDriverOptions.cs:86` | | Driver.Modbus-003 | Low | Resolved | Concurrency & thread safety | `ModbusDriver.cs:59,188,241,259,266,726,745,759` | @@ -580,9 +554,20 @@ Findings with status `Resolved`, `Won't Fix`, or `Deferred`. | Driver.Modbus.Contracts-004 | Low | Resolved | Documentation & comments | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Contracts/ModbusDriverOptions.cs:53-60` | | Driver.Mqtt-004 | Low | Resolved | Error handling & resilience | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt/MqttDriver.cs:375` (`ShutdownAsync`) | | Driver.Mqtt-005 | Low | Resolved | Code organization & conventions | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt/MqttConnection.cs:1-4` | +| Driver.Mqtt-006 | Low | Resolved | Concurrency & thread safety | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt/Sparkplug/SparkplugPrimaryHost.cs:278` | +| Driver.Mqtt-007 | Low | Resolved | Error handling & resilience | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt/MqttSubscriptionManager.cs:406-424` (`OnReconnectedAsync`) | | Driver.Mqtt-008 | Low | Resolved | Testing coverage | `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Tests/` (708 tests at `b990adae`) | | Driver.Mqtt-009 | Low | Resolved | Documentation & comments | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt/MqttConnection.cs:241-248` (type remarks) | | Driver.Mqtt-010 | Low | Resolved | Documentation & comments | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt/Sparkplug/SequenceTracker.cs:294` (`Reset`) | +| Driver.Mqtt.Browser-002 | Low | Resolved | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Browser/MqttBrowseSession.cs:469` | +| Driver.Mqtt.Browser-003 | Low | Resolved | Concurrency & thread safety | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Browser/MqttBrowseSession.cs:685` | +| Driver.Mqtt.Browser-004 | Low | Resolved | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Browser/MqttBrowseSession.cs:1079` | +| Driver.Mqtt.Browser-005 | Low | Resolved | Performance & resource management | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Browser/MqttBrowseSession.cs:59`, `:81` | +| Driver.Mqtt.Contracts-004 | Low | Resolved | Documentation & comments | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Contracts/MqttTagDefinitionFactory.cs:124`, `:234`, `:476` | +| Driver.Mqtt.Contracts-005 | Low | Resolved | Testing coverage | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Contracts/MqttDriverOptions.cs:25`, `:71`, `:75`, `:79`, `:83`, `:99`, `:229` | +| Driver.Mqtt.Contracts-006 | Low | Resolved | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Contracts/MqttWriteEncoder.cs:281` | +| Driver.Mqtt.Contracts-007 | Low | Resolved | Error handling & resilience | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Contracts/Sparkplug/SparkplugTopic.cs:202`, `:232` | +| Driver.Mqtt.Transport-002 | Low | Resolved | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.Transport/MqttClientOptionsFactory.cs:97-100` | | Driver.OpcUaClient-011 | Low | Resolved | Documentation & comments | `OpcUaClientDriver.cs:1007-1015` | | Driver.OpcUaClient-014 | Low | Resolved | Performance & resource management | `OpcUaClientDriver.cs:1138`, `:1314` | | Driver.OpcUaClient-016 | Low | Resolved | Performance & resource management / Error handling & resilience | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient/OpcUaClientDriver.cs:934-948` | @@ -607,7 +592,21 @@ Findings with status `Resolved`, `Won't Fix`, or `Deferred`. | Driver.S7.Contracts-001 | Low | Resolved | Documentation & comments | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts/S7DriverOptions.cs:107` | | Driver.S7.Contracts-002 | Low | Resolved | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts/S7EquipmentTagParser.cs:38` | | Driver.S7.Contracts-003 | Low | Deferred | Design-document adherence | `docs/v2/driver-specs.md:369` | +| Driver.Sql-004 | Low | Resolved | Error handling & resilience | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/SqlDriver.cs:651` | +| Driver.Sql-005 | Low | Resolved | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/SqlDriver.cs:641` | +| Driver.Sql-006 | Low | Resolved | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/SqlDriver.cs:599` | | Driver.Sql-007 | Low | Resolved | Code organization & conventions | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/ZB.MOM.WW.OtOpcUa.Driver.Sql.csproj:21` | +| Driver.Sql-008 | Low | Resolved | Documentation & comments | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/SqlPollReader.cs:556` | +| Driver.Sql-009 | Low | Resolved | Security | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/SqlDriverProbe.cs:83` | +| Driver.Sql-010 | Low | Resolved | Concurrency & thread safety | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql/SqlDriver.cs:675` | +| Driver.Sql.Browser-001 | Low | Resolved | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Browser/SqlBrowseSession.cs:290` | +| Driver.Sql.Browser-002 | Low | Resolved | Concurrency & thread safety | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Browser/SqlBrowseSession.cs:204`, `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Browser/SqlBrowseSession.cs:325` | +| Driver.Sql.Browser-003 | Low | Won't Fix | Security | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Browser/SqlDriverBrowser.cs:262` | +| Driver.Sql.Contracts-001 | Low | Resolved | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Contracts/SqlEquipmentTagParser.cs:65`, `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Contracts/SqlTagDefinitionFactory.cs:132` | +| Driver.Sql.Contracts-002 | Low | Resolved | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Contracts/SqlEquipmentTagParser.cs:50` | +| Driver.Sql.Dialect-001 | Low | Resolved | Correctness & logic bugs | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Dialect/PostgresDialect.cs:178`, `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Dialect/OracleDialect.cs:212` | +| Driver.Sql.Dialect-002 | Low | Resolved | Code organization & conventions | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Dialect/ISqlDialect.cs:29` | +| Driver.Sql.Dialect-003 | Low | Resolved | Documentation & comments | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Dialect/OracleDialect.cs:135` | | Driver.TwinCAT-004 | Low | Resolved | Correctness & logic bugs | `TwinCATDataType.cs:24-27` | | Driver.TwinCAT-006 | Low | Resolved | OtOpcUa conventions | `TwinCATDriver.cs:406-411` | | Driver.TwinCAT-014 | Low | Resolved | Design-document adherence | `TwinCATDriverOptions.cs:41-43`, `TwinCATDriverOptions.cs:57-62`, `AdsTwinCATClient.cs:145` |