Files
mxaccessgw/code-reviews
Joseph Doherty 3cc53a8c69 Harden code-review tooling and align REVIEW-PROCESS.md with mxaccessgw
- regen-readme.py: use `python` not the broken `python3` Store alias in
  the generated note and docstring; --check now also fails when a module
  header's "Open findings" count disagrees with finding statuses or a
  finding has an unrecognised Status (find_inconsistencies)
- REVIEW-PROCESS.md: rewritten for mxaccessgw (was describing ScadaLink)
  — MxGateway.* modules, "mxaccessgw conventions" checklist category,
  gateway.md/docs/ design context, `python` command
- scripts/check-code-reviews-readme.ps1: CI/pre-commit wrapper for
  regen-readme.py --check
- code-reviews/test_regen_readme.py: dependency-free parser tests
- code-reviews/README.md: regenerated

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 16:36:25 -04:00
..

Code Reviews

Cross-module code review index for the mxaccessgw codebase. The review process is defined in ../REVIEW-PROCESS.md.

Each module's findings.md is the source of truth; this file is generated from them by regen-readme.py and must not be edited by hand.

Module status

Module Reviewer Date Commit Status Open Total
Contracts Claude Code 2026-05-18 6c64030 Reviewed 8 8
IntegrationTests Claude Code 2026-05-18 6c64030 Reviewed 10 10
Server Claude Code 2026-05-18 6c64030 Reviewed 14 14
Tests Claude Code 2026-05-18 6c64030 Reviewed 12 12
Worker Claude Code 2026-05-18 6c64030 Reviewed 15 15
Worker.Tests Claude Code 2026-05-18 6c64030 Reviewed 15 15

Pending findings

Findings with status Open or In Progress, ordered by severity.

ID Severity Category Location Description
Server-001 Critical Security src/MxGateway.Server/GatewayApplication.cs:147-149, src/MxGateway.Server/Dashboard/DashboardEndpointRouteBuilderExtensions.cs:55-58, src/MxGateway.Server/Dashboard/Components/Routes.razor:1-15 The dashboard authorization policy (DashboardAuthenticationDefaults.AuthorizationPolicy), DashboardAuthorizationRequirement, and DashboardAuthorizationHandler are registered in DI but never applied to any endpoint. `MapRazorComponent…
IntegrationTests-001 High Design-document adherence src/MxGateway.IntegrationTests/Galaxy/LiveGalaxyRepositoryFactAttribute.cs:7, src/MxGateway.IntegrationTests/Galaxy/GalaxyRepositoryLiveTests.cs The Galaxy Repository live test suite and its gating env var MXGATEWAY_RUN_LIVE_GALAXY_TESTS (plus connection-string override MXGATEWAY_LIVE_GALAXY_CONN) are completely absent from docs/GatewayTesting.md. CLAUDE.md mandates updating…
IntegrationTests-002 High Design-document adherence src/MxGateway.IntegrationTests/DashboardLdapLiveTests.cs:13, src/MxGateway.Server/Configuration/LdapOptions.cs:27 DashboardLdapLiveTests builds the authenticator with new GatewayOptions(), so it relies on LdapOptions.RequiredGroup defaulting to GwAdmin and asserts the admin user is a member of a GwAdmin LDAP group. glauth.md does not lis…
Server-003 High Security src/MxGateway.Server/Dashboard/DashboardAuthorizationHandler.cs:39,54-59, src/MxGateway.Server/Dashboard/DashboardAuthenticator.cs:236-258 When Dashboard:RequireAdminScope is true (the default) and the request is not loopback, DashboardAuthorizationHandler succeeds only if HasAdminScope finds a claim of type "scope" with value "admin". But `DashboardAuthenticator.Cr…
Tests-001 High Testing coverage src/MxGateway.Tests/Gateway/Grpc/MxAccessGatewayServiceTests.cs:483-489 FakeSessionManager.TryGetSession unconditionally returns true and synthesizes a session for any id. As a result, Invoke_WhenSessionMissing_ThrowsNotFound (line 52) only passes because InvokeException is pre-seeded — it does not ver…
Tests-002 High Security src/MxGateway.Tests/Gateway/Grpc/GalaxyRepositoryGrpcServiceTests.cs:198-210 The Galaxy Repository RPCs browse a SQL Server database (ZB). Every test injects a StubGalaxyHierarchyCache, so actual SQL query construction, parameterization, and filter/glob translation are never exercised. No test demonstrates that…
Worker-001 High Concurrency & thread safety src/MxGateway.Worker/MxAccess/WnWrapAlarmConsumer.cs:204-207 When constructed with pollIntervalMilliseconds > 0, Subscribe starts a System.Threading.Timer whose OnPoll callback runs PollOnce() — which calls wwAlarmConsumerClass.GetXmlCurrentAlarms2 — on a thread-pool thread. The wnwrap C…
Worker-002 High Correctness & logic bugs src/MxGateway.Worker/Ipc/WorkerPipeSession.cs:545-549 RunHeartbeatLoopAsync calls await Task.Delay(_sessionOptions.HeartbeatInterval, ...) before sending the first heartbeat. The gateway therefore receives no heartbeat for the first full interval (default 5s) after the worker reaches `Rea…
Worker-003 High Correctness & logic bugs src/MxGateway.Worker/Ipc/WorkerPipeSession.cs:399-403, :416-419 ProcessCommandAsync checks _state after DispatchAsync completes and silently returns without writing a WorkerCommandReply (or fault) when _state is not Ready/ExecutingCommand. _state is a plain field mutated from multiple…
Worker.Tests-001 High Testing coverage src/MxGateway.Worker.Tests/Sta/ (no StaMessagePumpTests.cs) StaMessagePump — whose entire reason for existing is pumping Windows messages so MXAccess COM event sink calls deliver onto the STA — has no direct unit test. WaitForWorkOrMessages (timeout conversion, the MsgWaitForMultipleObjectsEx
Worker.Tests-002 High Testing coverage src/MxGateway.Worker.Tests/MxAccess/MxAccessStaSessionTests.cs, src/MxGateway.Worker.Tests/MxAccess/MxAccessEventMapperTests.cs No test verifies that a COM event raised on the STA thread is converted to protobuf and lands in the MxAccessEventQueue. MxAccessEventMapperTests exercises the mapper directly with hand-built fakes, and AlarmDispatcherTests covers th…
Contracts-002 Medium Error handling & resilience src/MxGateway.Contracts/Protos/mxaccess_gateway.proto:384-385, :95 MxCommandKind includes MX_COMMAND_KIND_ACKNOWLEDGE_ALARM_BY_NAME = 29 and MxCommand.payload carries AcknowledgeAlarmByNameCommand acknowledge_alarm_by_name_command = 38, but MxCommandReply.payload has only `acknowledge_alarm = 34…
IntegrationTests-003 Medium Correctness & logic bugs src/MxGateway.IntegrationTests/WorkerLiveMxAccessSmokeTests.cs:89-97 The test asserts only on the first MxEvent recorded by RecordingServerStreamWriter. A live MXAccess provider can deliver an initial state/quality event whose family or handles differ from the expected OnDataChange (e.g. a registratio…
IntegrationTests-004 Medium Error handling & resilience src/MxGateway.IntegrationTests/WorkerLiveMxAccessSmokeTests.cs:108-111 In the finally block, after CloseSessionAsync, the test does await streamTask.WaitAsync(StreamShutdownTimeout). If closing the session does not promptly complete the stream (or StreamEvents itself faults), this throws `TimeoutExcep…
IntegrationTests-005 Medium Testing coverage src/MxGateway.IntegrationTests/WorkerLiveMxAccessSmokeTests.cs The only live MXAccess test covers the Register→AddItem→Advise→one-OnDataChange→Close happy path. CLAUDE.md stresses that MXAccess parity is the contract and calls out non-obvious behaviors (WriteSecured ordering, OperationComplete sem…
IntegrationTests-006 Medium Testing coverage src/MxGateway.IntegrationTests/DashboardLdapLiveTests.cs LDAP live coverage is two cases: admin succeeds, readonly is denied for missing group. There is no coverage of a wrong password for a valid user, an unknown username, or the LDAP-server-unreachable path — all of which `DashboardAuthenticat…
Server-002 Medium Design-document adherence src/MxGateway.Server/Program.cs:24, src/MxGateway.Server/GatewayApplication.cs gateway.md:583 and CLAUDE.md state the first version "terminates orphaned workers on startup." No code in MxGateway.Server enumerates or kills leftover MxGateway.Worker.exe processes at startup — a grep for orphan/reattach/`termina…
Server-004 Medium Code organization & conventions src/MxGateway.Server/Security/Authentication/ApiKeyAdminCommandLineParser.cs:227-233, src/MxGateway.Server/Security/Authentication/ApiKeyAdminCliRunner.cs:53-77, src/MxGateway.Server/Dashboard/DashboardApiKeyManagementService.cs:21-67 ParseScopes accepts any comma-separated strings and CreateKeyAsync persists them verbatim; neither the CLI nor the dashboard create path validates scopes against GatewayScopes. A typo or non-canonical name (e.g. CLAUDE.md's example `…
Server-005 Medium Error handling & resilience src/MxGateway.Server/Galaxy/GalaxyHierarchyRefreshService.cs:22-28, src/MxGateway.Server/Galaxy/GalaxyHierarchyCache.cs:184 GalaxyHierarchyCache.RefreshCoreAsync only catches SqlException and InvalidOperationException. The initial cache.RefreshAsync call in GalaxyHierarchyRefreshService.ExecuteAsync is wrapped only for OperationCanceledException. A…
Server-006 Medium Correctness & logic bugs src/MxGateway.Server/Sessions/SessionManager.cs:84-114 In OpenSessionAsync, _metrics.SessionOpened() (line 89) increments the _openSessions gauge before TryAutoSubscribeAlarmsAsync runs. If auto-subscribe throws (which it does when Alarms.RequireSubscribeOnOpen is true and the worker…
Tests-003 Medium Performance & resource management src/MxGateway.Tests/Security/Authentication/SqliteAuthStoreTests.cs:170-176, src/MxGateway.Tests/Security/Authentication/ApiKeyAdminCliRunnerTests.cs:252-258 CreateTempDatabasePath creates a fresh directory under %TEMP%\mxgateway-auth-tests\<guid> (and ...-cli-tests) for every test but nothing ever deletes it. WorkerProcessLauncherTests.TestDirectory correctly implements IDisposable a…
Tests-004 Medium Testing coverage src/MxGateway.Tests/Security/Authorization/GatewayGrpcAuthorizationInterceptorTests.cs The authorization interceptor and MxAccessGatewayService are each tested in isolation, but no test composes the interceptor in front of the real service to confirm scope enforcement gates real RPCs end-to-end. A wiring mistake — intercep…
Tests-005 Medium Testing coverage src/MxGateway.Tests/Gateway/Grpc/EventStreamServiceTests.cs:239-261, src/MxGateway.Tests/Gateway/Sessions/SessionManagerTests.cs Worker-crash handling is only tested as a clean terminal exception from ReadEventsAsync or a pre-set ShutdownException. There is no test for a worker that faults mid-command — an InvokeAsync in flight when the pipe/worker dies — whic…
Tests-006 Medium Concurrency & thread safety src/MxGateway.Tests/Gateway/Workers/WorkerClientTests.cs:76, src/MxGateway.Tests/Gateway/Workers/FakeWorkerHarnessTests.cs:122 Several tests rely on fixed Task.Delay values: WorkerClientTests.InvokeAsync_WithLateReply… waits a hard-coded 50 ms after writing a late reply before issuing the second command, and the heartbeat tests use a 20 ms delay to make timest…
Worker-004 Medium Correctness & logic bugs src/MxGateway.Worker/Ipc/WorkerPipeSession.cs:565-588 After ReportWatchdogFaultIfNeededAsync sends an StaHung fault, the heartbeat loop continues sending normal heartbeats with State derived from _state, which the watchdog path never sets to Faulted. The heartbeat then keeps reporti…
Worker-005 Medium Error handling & resilience src/MxGateway.Worker/MxAccess/WnWrapAlarmConsumer.cs:297-313 OnPoll catches every exception from PollOnce() and discards it (_ = ex;). The production poll path (MxAccessStaSession.RunAlarmPollLoopAsyncAlarmCommandHandler.PollOnceAlarmDispatcher.PollOnceconsumer.PollOnce()) has…
Worker-006 Medium Correctness & logic bugs src/MxGateway.Worker/Ipc/WorkerPipeSession.cs:117-124, src/MxGateway.Worker/MxAccess/MxAccessStaSession.cs:386-491 RunAsync's finally calls _runtimeSession?.Dispose() unless _shutdownTimedOut. On the normal path ShutdownGracefullyAsync already disposed the STA runtime, so re-entering Dispose() is a harmless no-op only because `ShutdownGrace…
Worker-007 Medium mxaccessgw conventions src/MxGateway.Worker/MxAccess/MxAccessComServer.cs:130-150 Invoke uses late-bound Type.InvokeMember reflection as a fallback when the COM object does not cast to ILMXProxyServer*. In production the object is always LMXProxyServerClass, so the reflection path exists only for test doubles —…
Worker-008 Medium Concurrency & thread safety src/MxGateway.Worker/MxAccess/MxAccessStaSession.cs:205-249, :429-447 RunAlarmPollLoopAsync correctly marshals handler.PollOnce() onto the STA via staRuntime.InvokeAsync, and the cancel/await/dispose ordering in ShutdownGracefullyAsync is sound. However, nothing enforces that the consumerFactory an…
Worker.Tests-003 Medium Concurrency & thread safety src/MxGateway.Worker.Tests/Sta/StaRuntimeTests.cs:46-48 InvokeAsync_WakesIdlePumpForQueuedCommand asserts stopwatch.Elapsed < TimeSpan.FromSeconds(2) — a wall-clock assertion that on a loaded CI agent can exceed 2s, producing a false failure. The test also does not actually prove the wake e…
Worker.Tests-004 Medium Concurrency & thread safety src/MxGateway.Worker.Tests/MxAccess/MxAccessStaSessionTests.cs:281-329 StartAsync_WithAlarmCommandHandlerFactory_PollOnceCalledViaSta and Dispose_StopsAlarmPollLoop use poll-until loops, and Dispose_StopsAlarmPollLoop additionally does await Task.Delay(1000) then asserts PollCount is unchanged. The…
Worker.Tests-005 Medium Performance & resource management src/MxGateway.Worker.Tests/Ipc/WorkerFrameProtocolTests.cs:20-31,103-105, src/MxGateway.Worker.Tests/Ipc/WorkerPipeSessionTests.cs:28-31 MemoryStream instances are created and never disposed across the frame-protocol and pipe-session tests (MemoryStream stream = new(); with no using). Disposal is cheap so impact is low, but it is inconsistent with the rest of the suit…
Worker.Tests-006 Medium Performance & resource management src/MxGateway.Worker.Tests/MxAccess/MxAccessStaSessionTests.cs:282,305,315,323 Dispose_StopsAlarmPollLoop constructs MxAccessStaSession session without using (unlike every sibling test) and relies on an explicit session.Dispose(). If an assertion between StartAsync and Dispose() throws, the session — its…
Worker.Tests-007 Medium Design-document adherence docs/WorkerFrameProtocol.md:38-49 docs/WorkerFrameProtocol.md instructs running dotnet test src/MxGateway.Tests/MxGateway.Tests.csproj --filter WorkerFrameProtocolTests and states the frame protocol "is part of MxGateway.Server". The frame protocol actually lives in…
Contracts-001 Low Design-document adherence docs/Grpc.md:13 (and :3, :32, :39) mxaccess_gateway.proto now declares six RPCs on MxAccessGateway (OpenSession, CloseSession, Invoke, StreamEvents, AcknowledgeAlarm, QueryActiveAlarms). docs/Grpc.md still describes "the four MxAccessGateway RPCs" in its…
Contracts-003 Low Code organization & conventions src/MxGateway.Contracts/MxGateway.Contracts.csproj:10 The <Protobuf> item for mxaccess_worker.proto omits ProtoRoot="Protos", while the items for mxaccess_gateway.proto (line 9) and galaxy_repository.proto (line 11) both set it. mxaccess_worker.proto does `import "mxaccess_gateway…
Contracts-004 Low Documentation & comments src/MxGateway.Contracts/GatewayContractInfo.cs:3-6 The XML summary says the class exposes version metadata "before generated protobuf contracts are introduced." Generated protobuf contracts have long been introduced and are consumed across the solution. The comment is stale; the class now…
Contracts-005 Low mxaccessgw conventions src/MxGateway.Contracts/Protos/mxaccess_gateway.proto, src/MxGateway.Contracts/Protos/mxaccess_worker.proto The ProtobufStyleGuide mandates reserving removed field numbers / enum values. Evolution to date has been purely additive, so this is not a current violation — but none of the .proto files contain any reserved declarations, leaving no…
Contracts-006 Low Correctness & logic bugs src/MxGateway.Contracts/Protos/mxaccess_gateway.proto:647 MxStatusProxy.success is declared int32 success = 1 with no comment. The name reads like a boolean flag but the type is a 32-bit integer (mirroring MXAccess MXSTATUS_PROXY, which stores a numeric success/HResult-like value). Without…
Contracts-007 Low Testing coverage src/MxGateway.Tests/Contracts/ProtobufContractRoundTripTests.cs ProtobufContractRoundTripTests covers gateway command/reply/event, alarm transition, alarm ack request/reply, active-alarm snapshot, and the worker envelope. It has no coverage for: (a) any galaxy_repository.proto message (`DiscoverHie…
Contracts-008 Low Design-document adherence src/MxGateway.Contracts/Protos/mxaccess_gateway.proto:451-459, :627-636 The worker-side AcknowledgeAlarmReplyPayload carries the alarm-ack outcome as int32 native_status, while the public AcknowledgeAlarmReply carries it as MxStatusProxy status plus optional int32 hresult. The comment explains the wo…
IntegrationTests-007 Low Concurrency & thread safety src/MxGateway.IntegrationTests/WorkerLiveMxAccessSmokeTests.cs:20, src/MxGateway.IntegrationTests/Galaxy/GalaxyRepositoryLiveTests.cs:5, src/MxGateway.IntegrationTests/DashboardLdapLiveTests.cs:9 The live test classes contend for genuinely shared singletons — one MXAccess COM provider, one ZB SQL database, one GLAuth instance with a 3-fail/10-minute per-IP lockout. No [Collection] annotation or DisableTestParallelization is dec…
IntegrationTests-008 Low Code organization & conventions src/MxGateway.IntegrationTests/LiveLdapFactAttribute.cs, src/MxGateway.IntegrationTests/Galaxy/LiveGalaxyRepositoryFactAttribute.cs, src/MxGateway.IntegrationTests/LiveMxAccessFactAttribute.cs Three near-identical fact attributes each re-implement the same "compare env var to 1 with StringComparison.Ordinal, set Skip otherwise" pattern. LiveMxAccessFactAttribute delegates to IntegrationTestEnvironment while the other t…
IntegrationTests-009 Low Documentation & comments src/MxGateway.IntegrationTests/WorkerLiveMxAccessSmokeTests.cs:372-375 TestServerCallContext is XML-documented as a "Mock server call context," but it is a hand-written stub/fake with no mocking framework and no verification behavior. Per the style guides (accurate naming; explain why not what), calling it…
IntegrationTests-010 Low Correctness & logic bugs src/MxGateway.IntegrationTests/WorkerLiveMxAccessSmokeTests.cs:366-369 WaitForFirstMessageAsync accepts only a timeout and never observes a CancellationToken. There is no per-test cancellation propagation, so if the gateway/worker hangs without writing an event the test relies solely on the 15s `WaitAsy…
Server-007 Low Performance & resource management src/MxGateway.Server/Galaxy/GalaxyHierarchyProjector.cs:55-70 Project always iterates the full entry.Index.ObjectViews collection and re-applies all filters to skip offset matched items before collecting a page. Paging through a large Galaxy hierarchy is therefore O(total) per page and O(total²…
Server-008 Low Performance & resource management src/MxGateway.Server/Grpc/GalaxyRepositoryGrpcService.cs:111-134,160-189 WatchDeployEvents calls ResolveBrowseSubtrees() on every streamed event, and MapDeployEvent re-runs GalaxyHierarchyProjector.Project over the entire cached hierarchy (and Sums attribute counts) for every event of every constraine…
Server-009 Low Error handling & resilience src/MxGateway.Server/Security/Authentication/AuthSqliteConnectionFactory.cs:15-32 Each auth-store operation opens a fresh SqliteConnection with no busy timeout, no WAL journal mode, and default journaling. MarkKeyUsedAsync runs on every authenticated request and SqliteApiKeyAuditStore appends on every denial; unde…
Server-010 Low Security src/MxGateway.Server/Security/Authentication/SqliteApiKeyAdminStore.cs:91-114, src/MxGateway.Server/Dashboard/Components/Pages/ApiKeysPage.razor:168-172 RotateAsync sets revoked_utc = NULL, so rotating a previously revoked key silently reactivates it. This is documented intentional behavior in docs/Authentication.md:167, but the dashboard renders the "Rotate" button unconditionally —…
Server-011 Low Code organization & conventions src/MxGateway.Server/Sessions/WorkerAlarmRpcDispatcher.cs:1-46 WorkerAlarmRpcDispatcher deviates from the module's conventions: it fully-qualifies System.Guid, System.ArgumentNullException, and System.Threading types inline instead of relying on using directives, and uses an explicit constru…
Server-012 Low Documentation & comments CLAUDE.md (Authentication section and apikey create example) CLAUDE.md describes scopes as session, invoke, event, metadata, admin and shows apikey create --scopes session,invoke,event,metadata,admin. The actual canonical scope strings (used by GatewayScopes, GatewayGrpcScopeResolver
Server-013 Low Testing coverage src/MxGateway.Tests/Gateway/Dashboard/DashboardAuthorizationHandlerTests.cs, src/MxGateway.Tests/Gateway/GatewayApplicationTests.cs DashboardAuthorizationHandler is unit-tested in isolation, but no test exercises the dashboard routes end-to-end to confirm the policy is actually enforced — which is why Server-001 (policy registered but never wired) went uncaught. Ther…
Server-014 Low Documentation & comments src/MxGateway.Server/Grpc/MxAccessGatewayService.cs:162-171,191-198,206-214,229-237 The XML <remarks> and inline comments on AcknowledgeAlarm and QueryActiveAlarms describe the alarm path as not yet wired and say NotWiredAlarmRpcDispatcher is the default ("Clients calling this method today receive an OK reply with…
Tests-007 Low Code organization & conventions src/MxGateway.Tests/Gateway/Grpc/MxAccessGatewayServiceTests.cs:682, src/MxGateway.Tests/Gateway/Grpc/GalaxyRepositoryGrpcServiceTests.cs:324, src/MxGateway.Tests/Gateway/GatewayEndToEndFakeWorkerSmokeTests.cs:460, src/MxGateway.Tests/Security/Authorization/GatewayGrpcAuthorizationInterceptorTests.cs:233 A near-identical TestServerCallContext implementation is copy-pasted into at least four test files (and AllowAllConstraintEnforcer / TestServerStreamWriter / RecordingStreamWriter into several). Duplication risks the copies driftin…
Tests-008 Low mxaccessgw conventions src/MxGateway.Tests/Gateway/Sessions/WorkerAlarmRpcDispatcherTests.cs:1-9, src/MxGateway.Tests/Gateway/Sessions/NotWiredAlarmRpcDispatcherTests.cs:1-3, src/MxGateway.Tests/Gateway/Sessions/SessionManagerAlarmAutoSubscribeTests.cs:1 The alarm test files diverge from the project's C# style and the rest of the suite: snake_case test method names instead of the PascalCase Method_Condition_Result pattern; redundant explicit using System;/System.Threading; imports de…
Tests-009 Low Documentation & comments src/MxGateway.Tests/Gateway/Sessions/SessionManagerTests.cs:36-37,99,365 Several XML <summary> comments are copy-paste mismatches: the comment above OpenSessionAsync_SetsInitialDefaultLease describes correlation-ID generation; the comment above GatewaySessionSubscribeBulkAsync_ForwardsOneBulkCommand… desc…
Tests-010 Low Security src/MxGateway.Tests/Gateway/Dashboard/DashboardAuthorizationHandlerTests.cs:26-36 The anonymous-localhost bypass is tested only for the success case (allowAnonymousLocalhost: true + loopback succeeds) and the remote-unauthenticated denial. There is no test for the security-critical negatives: anonymous + loopback when…
Tests-011 Low Correctness & logic bugs src/MxGateway.Tests/Gateway/GatewayEndToEndFakeWorkerSmokeTests.cs:233-301 GatewayEndToEndFakeWorkerSmokeTests correctly stores and awaits launcher.WorkerTask, but SessionWorkerClientFactoryFakeWorkerTests uses _ = RunWorkerAsync(...) with no stored task (lines 152, 184, 220). An unhandled exception in th…
Tests-012 Low Concurrency & thread safety src/MxGateway.Tests/Gateway/Workers/Fakes/FakeWorkerHarness.cs:62, src/MxGateway.Tests/Gateway/Workers/WorkerClientTests.cs:472 Pipe names are uniquified per test with a GUID (good), but xUnit runs test classes in parallel by default and there is no xunit.runner.json or collection configuration. Tests that build a full WebApplication bind ephemeral ports (`--ur…
Worker-009 Low Performance & resource management src/MxGateway.Worker/Ipc/WorkerFrameReader.cs:31,49, src/MxGateway.Worker/Ipc/WorkerFrameWriter.cs:57-58 Every frame read allocates a fresh 4-byte length buffer and a payload byte[]; every write allocates ToByteArray() plus a 4-byte prefix. On the hot event-drain path (batches of up to 128 WorkerEvent frames every 25 ms) this produces s…
Worker-010 Low Correctness & logic bugs src/MxGateway.Worker/Conversion/VariantConverter.cs:204-226 ConvertInt64Scalar is reached for TypeCode.UInt32 and TypeCode.Int64. For a uint with expectedDataType == MxDataType.Time, the value is treated as a Windows FILETIME via DateTime.FromFileTimeUtc(longValue); a 32-bit FILETIME…
Worker-011 Low Correctness & logic bugs src/MxGateway.Worker/Ipc/WorkerPipeClient.cs:169-171 retryAttempts is computed as (connectTimeout / min(connectTimeout, attemptTimeout)) - 1. With defaults (30000 / 2000) this yields 14 retries, but each retry also incurs Polly exponential backoff. The overall connectDeadline (`CancelA…
Worker-012 Low Documentation & comments src/MxGateway.Worker/MxAccess/MxAccessAlarmEventSink.cs:44-55, src/MxGateway.Worker/MxAccess/WnWrapAlarmConsumer.cs:38-43, src/MxGateway.Worker/MxAccess/MxAccessEventMapper.cs:106-112 Multiple comments describe the alarm path as not-yet-wired future work ("PR A.2 — COM-side subscription scaffold … the worker advertises no alarm subscription", "the worker bootstrap will gain a thin 'run-on-STA' wrapper as part of A.3").…
Worker-013 Low Testing coverage src/MxGateway.Worker/Sta/StaMessagePump.cs StaMessagePump — the heart of COM event delivery (MsgWaitForMultipleObjectsEx + PeekMessage/DispatchMessage) — has no direct unit tests. StaRuntimeTests exercises it indirectly for command wake-up but never verifies that a posted…
Worker-014 Low Code organization & conventions src/MxGateway.Worker/MxAccess/AlarmCommandHandler.cs:33, :202 The file declares two public types — the AlarmCommandHandler class and the IAlarmCommandHandler interface. The C# style guide and the rest of the module follow one-public-type-per-file (e.g. interfaces in their own I*.cs files like `…
Worker-015 Low Correctness & logic bugs src/MxGateway.Worker/MxAccess/MxAccessEventQueue.cs:115-145 On overflow, Enqueue records the overflow fault and throws MxAccessEventQueueOverflowException; MxAccessBaseEventSink.EnqueueEvent catches it and calls RecordFault again. RecordFault is a no-op when a fault already exists, so the…
Worker.Tests-008 Low Documentation & comments src/MxGateway.Worker.Tests/Conversion/VariantConverterTests.cs:175-182 Redactor_WithCredentialBearingValueFields_RedactsBeforeLogging lives in VariantConverterTests but asserts on WorkerLogRedactor.RedactValue, which has nothing to do with VariantConverter. It is also a near-duplicate of coverage in `…
Worker.Tests-009 Low Code organization & conventions src/MxGateway.Worker.Tests/MxAccess/AlarmCommandHandlerTests.cs, AlarmDispatcherTests.cs, AlarmCommandExecutorTests.cs, AlarmRecordTransitionMapperTests.cs, WnWrapAlarmConsumerXmlTests.cs The alarm-related test files use snake_case method names while the rest of the project uses the Method_State_Result PascalCase convention. docs/style-guides/CSharpStyleGuide.md and the surrounding code establish PascalCase as the pro…
Worker.Tests-010 Low Correctness & logic bugs src/MxGateway.Worker.Tests/MxAccess/MxAccessStaSessionTests.cs:230-258 StartAsync_WithoutAlarmCommandHandlerFactory_SubscribeAlarmsReturnsInvalidRequest asserts Assert.Contains("alarm", reply.DiagnosticMessage, StringComparison.OrdinalIgnoreCase). The XML doc claims it verifies the diagnostic says "alarm…
Worker.Tests-011 Low Documentation & comments src/MxGateway.Worker.Tests/Sta/StaCommandDispatcherTests.cs:92-112 DispatchAsync_WhenCanceledAfterExecutionStarts_StillReturnsLateReply is named and documented as if it proves cancellation arrived after execution began. The test does Started.Wait(...) then cancellation.Cancel(), which proves executi…
Worker.Tests-012 Low Testing coverage src/MxGateway.Worker.Tests/Ipc/WorkerFrameProtocolTests.cs docs/WorkerFrameProtocol.md states the reader "rejects zero-length payloads and payloads larger than the configured maximum (default 16 MiB) before allocating the payload buffer." WorkerFrameProtocolTests covers malformed-length, wrong…
Worker.Tests-013 Low Concurrency & thread safety src/MxGateway.Worker.Tests/Ipc/WorkerPipeSessionTests.cs:539-546 ThrowIfCompletedAsync does an unconditional await Task.Delay(TimeSpan.FromMilliseconds(100)) then checks task.IsCompleted. This adds a fixed 100 ms to the test and only catches a RunAsync that fails within that arbitrary window; a…
Worker.Tests-014 Low Code organization & conventions src/MxGateway.Worker.Tests/Ipc/WorkerPipeClientTests.cs:194, WorkerPipeSessionTests.cs:622, Sta/StaCommandDispatcherTests.cs:348, MxAccess/MxAccessStaSessionTests.cs:334, MxAccess/MxAccessCommandExecutorTests.cs:1124 FakeRuntimeSession, NoopComApartmentInitializer, NoopEventSink/NullEventSink, and the CreateFrame/WriteUInt32LittleEndian helpers are re-implemented independently in multiple test files. The two FakeRuntimeSession implementat…
Worker.Tests-015 Low Testing coverage src/MxGateway.Worker.Tests/MxAccess/MxAccessEventQueueTests.cs MxAccessEventQueueTests covers monotonic sequencing, drain, capacity overflow, and first-fault-wins, but does not cover Drain with maxEvents: 0 (drain-all) — a branch FakeRuntimeSession.DrainEvents even special-cases — nor draining…

Closed findings

Findings with status Resolved, Won't Fix, or Deferred.

No closed findings.