fix(client-cli): resolve Medium code-review findings (Client.CLI-001, Client.CLI-005)

Client.CLI-001: parse --start/--end with CultureInfo.InvariantCulture and
DateTimeStyles.AssumeUniversal|AdjustToUniversal so dates are culture-stable.
Client.CLI-005: SDK notification callbacks now hand off to an unbounded
channel drained on the main thread; handlers are unsubscribed before the
summary phase so no notification interleaves with console output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-22 08:08:25 -04:00
parent 9f5a5c9997
commit aa142f6dd4
4 changed files with 98 additions and 33 deletions

View File

@@ -7,7 +7,7 @@
| Review date | 2026-05-22 |
| Commit reviewed | `76d35d1` |
| Status | Reviewed |
| Open findings | 10 |
| Open findings | 8 |
## Checklist coverage
@@ -36,7 +36,7 @@ a category produced nothing rather than leaving it blank.
| Severity | Medium |
| Category | Correctness & logic bugs |
| Location | `Commands/HistoryReadCommand.cs:73`, `Commands/HistoryReadCommand.cs:76` |
| Status | Open |
| Status | Resolved |
**Description:** The start and end options are parsed with `DateTime.Parse(StartTime)` with
no `IFormatProvider` or `DateTimeStyles`. Parsing therefore depends on the current OS
@@ -53,7 +53,7 @@ ranges on machines in different time zones.
ISO 8601 via `DateTimeOffset.Parse`), and document the expected format and timezone
assumption precisely.
**Resolution:** _(open)_
**Resolution:** Resolved 2026-05-22 — `DateTime.Parse` replaced with `CultureInfo.InvariantCulture` + `DateTimeStyles.AssumeUniversal | AdjustToUniversal`; option descriptions updated to document ISO 8601 UTC format.
### Client.CLI-002
@@ -130,7 +130,7 @@ each of its option properties, matching the style used by the sibling commands.
| Severity | Medium |
| Category | Concurrency & thread safety |
| Location | `Commands/SubscribeCommand.cs:66-78`, `Commands/AlarmsCommand.cs:52-64` |
| Status | Open |
| Status | Resolved |
**Description:** The `DataChanged` and `AlarmEvent` handlers write to `console.Output`
(a `System.IO.TextWriter`) directly from the OPC UA SDK subscription/notification thread,
@@ -147,7 +147,7 @@ through a `Channel<T>` drained by the main thread, or guard every `console.Outpu
with a shared lock. At minimum, ensure handler exceptions cannot escape into the SDK
callback.
**Resolution:** _(open)_
**Resolution:** Resolved 2026-05-22 — notification handlers in `SubscribeCommand` and `AlarmsCommand` now enqueue lines to an `UnboundedChannel<string>` via `TryWrite`; the main thread drains the channel via `ReadAllAsync`. Handlers are named local functions so they can be unsubscribed before the summary phase; all handler exceptions are swallowed to protect the SDK callback.
### Client.CLI-006