# Code Review — Driver.Galaxy.Contracts | Field | Value | |---|---| | Module | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Contracts` | | Reviewer | Claude Code | | Review date | 2026-06-19 | | Commit reviewed | `7286d320` | | Status | Reviewed | | Open findings | 1 | ## 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.Galaxy.Contracts-002 (Medium): EventPumpChannelCapacity has no Range guard; EventPump enforces ≥ 1 at runtime | | 2 | OtOpcUa conventions | No issues found | | 3 | Concurrency & thread safety | No issues found (pure data-contract records; no mutable shared state) | | 4 | Error handling & resilience | No issues found | | 5 | Security | No issues found (ApiKeySecretRef is documented as an indirection reference; no defaults store a cleartext secret; no ToString override leaks the ref) | | 6 | Performance & resource management | No issues found (pure records; no allocations, disposables, or resource lifetimes) | | 7 | Design-document adherence | No issues found (records match CLAUDE.md Gateway/MxAccess/Repository/Reconnect section layout) | | 8 | Code organization & conventions | Driver.Galaxy.Contracts-003 (Low, Open): ResolveApiKey helper duplicated between GalaxyDriver and GalaxyBrowseSession; Contracts is the natural home | | 9 | Testing coverage | No issues found (no logic to test; pure data records with default values) | | 10 | Documentation & comments | Driver.Galaxy.Contracts-001 (Low, Resolved): Internal code-review finding ID `(Driver.Galaxy-010)` in shipped XML doc | ## Findings ### Driver.Galaxy.Contracts-001 | Field | Value | |---|---| | Severity | Low | | Category | Documentation & comments | | Location | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Contracts/GalaxyDriverOptions.cs:43` | | Status | Resolved | **Description:** The XML doc on `GalaxyGatewayOptions.ApiKeySecretRef` contained the parenthetical `(Driver.Galaxy-010)` — an internal code-review finding ID — embedded in the shipped `` tag. Once emitted via `dotnet doc` or IntelliSense, this noise is meaningless to any consumer of the contracts assembly (AdminUI, Driver.Galaxy, Driver.Galaxy.Browser) and will become stale if the finding ID is ever renumbered or retired. The underlying issue that spawned Driver.Galaxy-010 (startup warning on cleartext-literal API key) was resolved in that review; the reference in source code is now pure noise. **Recommendation:** Remove the parenthetical `(Driver.Galaxy-010)` from the XML doc. The surrounding sentence already explains the behavior; the cross-reference adds no value. **Resolution:** Fixed 2026-06-19 in this review pass. Removed `(Driver.Galaxy-010)` from the `ApiKeySecretRef` doc comment. Verified by build (no test project). --- ### Driver.Galaxy.Contracts-002 | Field | Value | |---|---| | Severity | Medium | | Category | Correctness & logic bugs | | Location | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Contracts/GalaxyDriverOptions.cs:91` | | Status | Resolved | **Description:** `GalaxyMxAccessOptions.EventPumpChannelCapacity` defaults to `50_000` but has no `[Range]` annotation. `EventPump` (the consumer) enforces `channelCapacity >= 1` via `ArgumentOutOfRangeException` at construction: ```csharp if (channelCapacity < 1) throw new ArgumentOutOfRangeException(nameof(channelCapacity), "channelCapacity must be >= 1; ..."); ``` An operator who enters `0` or a negative number in the AdminUI Galaxy driver form will pass Blazor's `DataAnnotationsValidator` silently (no annotation to check), save the config to the central config DB, and only encounter the failure at `GalaxyDriver.InitializeAsync` time — surfaced as a cryptic internal `ArgumentOutOfRangeException` rather than a friendly form-validation message. The gap between the option's declared type (`int`) and the consumer's enforced floor (`>= 1`) is not visible at the contracts layer. **Recommendation:** Add `[Range(1, int.MaxValue)]` to `EventPumpChannelCapacity` and update the `` doc to state the minimum. The `[Range]` attribute is already used on `ProbeTimeoutSeconds` in the same class; the pattern is established. **Resolution:** Fixed 2026-06-19 in this review pass. Added `[Range(1, int.MaxValue)]` to the `EventPumpChannelCapacity` positional parameter and extended the `` doc to note the minimum and that `EventPump` enforces it at construction. Verified by build (no test project). --- ### Driver.Galaxy.Contracts-003 | Field | Value | |---|---| | Severity | Low | | Category | Code organization & conventions | | Location | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Browser/GalaxyDriverBrowser.cs:149` (duplicate) and `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/GalaxyDriver.cs:472` (original) | | Status | Open | **Description:** `GalaxyDriver.ResolveApiKey` (the four-form `env:`/`file:`/`dev:`/literal resolver, ~45 LOC) is duplicated verbatim as `GalaxyDriverBrowser.ResolveApiKey`. The Browser copy acknowledges this in its XML doc ("Slim mirror of `GalaxyDriver.ResolveApiKey` — the runtime version lives in a sibling project the Browser intentionally doesn't reference"). The duplication is intentional to avoid a project reference from `Driver.Galaxy.Browser` to `Driver.Galaxy`, but the `Driver.Galaxy.Contracts` project is already referenced by both (and by `AdminUI`). If a new secret-ref prefix (e.g. `vault:`) is added to the runtime resolver, the Browser copy will silently fall through to the back-compat literal arm and emit a spurious startup warning — exactly the drift that `MapSecurityClass` suffered in `Driver.Galaxy.Browser-001`. This finding was first raised in the sibling review (Driver.Galaxy.Browser-003), which identified `Driver.Galaxy.Contracts` as the natural home. Extracting the helper into Contracts would be a one-file change with no public-contract break; both `Driver.Galaxy` and `Driver.Galaxy.Browser` would lose their copies and delegate to the single authoritative implementation. The current project has no package references beyond `System.ComponentModel.DataAnnotations` (in-box). Adding a pure-BCL static helper (`File.ReadAllText`, `Environment.GetEnvironmentVariable`) fits within this scope; the `ILogger?` overload would require importing `Microsoft.Extensions.Logging.Abstractions`, which ships in-box with .NET 10's BCL and adds no new NuGet dependency. **Recommendation:** Move `ResolveApiKey(string, ILogger?)` (and its `ILogger`-less overload) into a `GalaxySecretRef` static class in this project; update both call sites to delegate to it. **Resolution:** _(deferred — cross-module coordination change; Driver.Galaxy and Driver.Galaxy.Browser must both be updated in the same commit. Tracked for a future consolidation pass. See also Driver.Galaxy.Browser-003.)_