23 KiB
Cluster 01 — Architecture
DOC: gateway.md
LINES: 737–769
CLAIM: Project layout lists src/MxGateway.Server, src/MxGateway.Worker, src/MxGateway.Contracts, src/MxGateway.Tests, src/MxGateway.Worker.Tests, src/MxGateway.IntegrationTests as suggested path names.
CLAIM_TYPE: path
VERDICT: stale
EVIDENCE: src/ directory listing — actual project directories are ZB.MOM.WW.MxGateway.Server, ZB.MOM.WW.MxGateway.Worker, ZB.MOM.WW.MxGateway.Contracts, ZB.MOM.WW.MxGateway.Tests, ZB.MOM.WW.MxGateway.Worker.Tests, ZB.MOM.WW.MxGateway.IntegrationTests
CODE_AREA: arch.layout
SEVERITY: medium
PROPOSED_FIX: Replace all short project names in the layout block with the fully-qualified names (e.g. src/ZB.MOM.WW.MxGateway.Server/, src/ZB.MOM.WW.MxGateway.Worker/, etc.).
DOC: gateway.md
LINES: 231–248
CLAIM: WorkerEnvelope has uint64 correlation_id = 4 and oneof body field numbers: worker_hello=10, gateway_hello=11, worker_ready=12, command=20, command_reply=21, event=22, heartbeat=23, cancel=24, shutdown=25, fault=26.
CLAIM_TYPE: rpc/proto
VERDICT: wrong
EVIDENCE: src/ZB.MOM.WW.MxGateway.Contracts/Protos/mxaccess_worker.proto:4,20–38 — actual proto has string correlation_id = 4 (not uint64); body fields are gateway_hello=10, worker_hello=11, worker_ready=12, worker_command=13, worker_command_reply=14, worker_cancel=15, worker_shutdown=16, worker_shutdown_ack=17, worker_event=18, worker_heartbeat=19, worker_fault=20; field names also differ (e.g. command → worker_command, event → worker_event).
CODE_AREA: arch.ipc
SEVERITY: high
PROPOSED_FIX: Replace the WorkerEnvelope protobuf block in gateway.md with the actual proto content from mxaccess_worker.proto, including the correct field type for correlation_id (string), the correct field numbers, and the correct field names. Also add the missing WorkerShutdownAck worker_shutdown_ack = 17 entry.
DOC: gateway.md
LINES: 898–913
CLAIM: Session state machine is Creating -> StartingWorker -> WaitingForPipe -> InitializingWorker -> Ready -> Closing -> Closed -> Faulted.
CLAIM_TYPE: behavior-rule
VERDICT: stale
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Sessions/SessionWorkerClientFactory.cs:75 — code transitions to SessionState.Handshaking between WaitingForPipe and InitializingWorker; this state also appears in the generated proto enum (MxaccessGateway.cs:726, SESSION_STATE_HANDSHAKING = 4).
CODE_AREA: arch.session
SEVERITY: medium
PROPOSED_FIX: Add -> Handshaking between WaitingForPipe and InitializingWorker in the state machine diagram, and add a description: "Handshaking: pipe is connected and protocol hello is being verified."
DOC: gateway.md
LINES: 119–121
CLAIM: Blazor dashboard mounts at the host root and renders pages at /, /sessions, /workers, /events, /galaxy, /alarms, /apikeys, and /settings.
CLAIM_TYPE: path
VERDICT: stale
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Pages/BrowsePage.razor:1 — there is also a /browse page (@page "/browse") that is not listed. /login is also present.
CODE_AREA: arch.layout
SEVERITY: low
PROPOSED_FIX: Add /browse (and /login) to the list of documented dashboard routes.
DOC: gateway.md
LINES: 662–663
CLAIM: Rejects valid keys lacking the required session, invoke, event, metadata, or admin scope with gRPC PermissionDenied.
CLAIM_TYPE: config-key
VERDICT: stale
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Security/Authorization/GatewayScopes.cs:5–12 — actual scopes are session:open, session:close, invoke:read, invoke:write, invoke:secure, events:read, metadata:read, admin. The simplified short-form names (session, invoke, event) do not match the canonical scope strings.
CODE_AREA: arch.auth
SEVERITY: medium
PROPOSED_FIX: Replace the simplified scope names with the canonical forms: session:open, session:close, invoke:read, invoke:write, invoke:secure, events:read, metadata:read, admin.
DOC: docs/DesignDecisions.md
LINES: 360–363
CLAIM: "Dashboard access should require API-key-backed dashboard authentication with admin scope when enabled."
CLAIM_TYPE: behavior-rule
VERDICT: wrong
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Dashboard/DashboardAuthenticator.cs:9 — dashboard authentication is LDAP-backed (bind + group-to-role mapping), not API-key-backed. This is also confirmed in GatewayProcessDesign.md lines 291–299 and gateway.md lines 147–156.
CODE_AREA: arch.auth
SEVERITY: high
PROPOSED_FIX: Replace "API-key-backed dashboard authentication with admin scope" with "LDAP-backed authentication with GroupToRole mapping to Admin or Viewer roles." Keep the note about AllowAnonymousLocalhost for local development.
DOC: docs/GatewayProcessDesign.md
LINES: 249–255
CLAIM: Dashboard suggested routes use a /dashboard prefix: /dashboard, /dashboard/sessions, /dashboard/sessions/{sessionId}, /dashboard/workers, /dashboard/events, /dashboard/settings.
CLAIM_TYPE: path
VERDICT: wrong
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Pages/ — actual Blazor pages are mounted at / (DashboardHome.razor), /sessions (SessionsPage.razor), /sessions/{SessionId} (SessionDetailsPage.razor), /workers (WorkersPage.razor), /events (EventsPage.razor), /settings (SettingsPage.razor), /alarms (AlarmsPage.razor), /galaxy (GalaxyPage.razor), /browse (BrowsePage.razor), /apikeys (ApiKeysPage.razor). None have a /dashboard prefix.
CODE_AREA: arch.layout
SEVERITY: high
PROPOSED_FIX: Replace the /dashboard-prefixed route table with the actual routes: /, /sessions, /sessions/{sessionId}, /workers, /events, /alarms, /galaxy, /browse, /apikeys, /settings.
DOC: docs/GatewayProcessDesign.md
LINES: 689
CLAIM: "Dashboard:AllowAnonymousLocalhost permits loopback requests to bypass the cookie requirement."
CLAIM_TYPE: config-key
VERDICT: stale
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Configuration/DashboardOptions.cs:9 — property is AllowAnonymousLocalhost under DashboardOptions, which maps to MxGateway:Dashboard:AllowAnonymousLocalhost. The shorthand Dashboard:AllowAnonymousLocalhost omits the root MxGateway: prefix used throughout the project (also confirmed in GatewayProcessDesign.md line 298 which correctly uses MxGateway:Dashboard:AllowAnonymousLocalhost).
CODE_AREA: arch.config
SEVERITY: low
PROPOSED_FIX: Standardize to MxGateway:Dashboard:AllowAnonymousLocalhost (the form used in GatewayOptions / the configuration section name) everywhere this key is referenced.
DOC: docs/GatewayProcessDesign.md
LINES: 854–855
CLAIM: Worker ExecutablePath default is src/ZB.MOM.WW.MxGateway.Worker/bin/x86/Release/ZB.MOM.WW.MxGateway.Worker.exe (forward-slash path shown in JSON block).
CLAIM_TYPE: config-key
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Configuration/WorkerOptions.cs:7 — actual default is src\ZB.MOM.WW.MxGateway.Worker\bin\x86\Release\ZB.MOM.WW.MxGateway.Worker.exe (backslashes on Windows). The path and filename match; only the separator style differs between the JSON doc sample and the C# literal.
CODE_AREA: arch.config
SEVERITY: low
PROPOSED_FIX: flag only
DOC: docs/DesignDecisions.md
LINES: 36
CLAIM: Interop assembly identity: ArchestrA.MxAccess, Version=3.2.0.0, PublicKeyToken=23106a86e706d0ae.
CLAIM_TYPE: version
VERDICT: unverifiable
EVIDENCE: src/ZB.MOM.WW.MxGateway.Worker/MxAccess/MxAccessInteropInfo.cs — the file records the assembly path and name (ArchestrA.MxAccess) but does not hard-code the version or public key token; InteropAssemblyVersion is read dynamically from the loaded assembly at runtime (typeof(LMXProxyServerClass).Assembly.GetName().Version). Cannot verify the exact version string without MXAccess installed.
CODE_AREA: arch.ipc
SEVERITY: low
PROPOSED_FIX: flag only
DOC: docs/DesignDecisions.md
LINES: 36–48
CLAIM: COM class ArchestrA.MxAccess.LMXProxyServerClass, CLSID {C30B52F5-2CB5-4760-AF0A-3A344A7EB5DC}, ProgID LMXProxy.LMXProxyServer.1, version-independent ProgID LMXProxy.LMXProxyServer, registered server C:\Program Files (x86)\ArchestrA\Framework\Bin\LmxProxy.dll, interop assembly C:\Program Files (x86)\ArchestrA\Framework\Bin\ArchestrA.MXAccess.dll.
CLAIM_TYPE: config-key
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Worker/MxAccess/MxAccessInteropInfo.cs:14,19,24,29–30,35–36,41 — ComClassName = "ArchestrA.MxAccess.LMXProxyServerClass", Clsid = "{C30B52F5-2CB5-4760-AF0A-3A344A7EB5DC}", ProgId = "LMXProxy.LMXProxyServer.1", VersionIndependentProgId = "LMXProxy.LMXProxyServer", RegisteredServerPath = @"C:\Program Files (x86)\ArchestrA\Framework\Bin\LmxProxy.dll", InteropAssemblyPath = @"C:\Program Files (x86)\ArchestrA\Framework\Bin\ArchestrA.MXAccess.dll". All match.
CODE_AREA: arch.ipc
SEVERITY: low
PROPOSED_FIX: flag only
DOC: docs/DesignDecisions.md
LINES: 55
CLAIM: Worker should reference ArchestrA.MXAccess.dll (upper-case MXAccess in filename).
CLAIM_TYPE: path
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Worker/ZB.MOM.WW.MxGateway.Worker.csproj:27 — <HintPath>C:\Program Files (x86)\ArchestrA\Framework\Bin\ArchestrA.MXAccess.dll</HintPath>. Matches.
CODE_AREA: arch.layout
SEVERITY: low
PROPOSED_FIX: flag only
DOC: gateway.md
LINES: 88–94
CLAIM: Gateway runtime is .NET 10, C#, x64 preferred, ASP.NET Core gRPC server.
CLAIM_TYPE: version
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/ZB.MOM.WW.MxGateway.Server.csproj:4 — <TargetFramework>net10.0</TargetFramework>; no explicit <PlatformTarget> is set (so the default is AnyCPU/x64-preferred on .NET 10). Grpc.AspNetCore is referenced. Matches.
CODE_AREA: arch.layout
SEVERITY: low
PROPOSED_FIX: flag only
DOC: gateway.md
LINES: 162–165
CLAIM: Worker runtime is .NET Framework 4.8, C#, x86 build by default.
CLAIM_TYPE: version
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Worker/ZB.MOM.WW.MxGateway.Worker.csproj:5–7 — <TargetFramework>net48</TargetFramework>, <PlatformTarget>x86</PlatformTarget>, <Prefer32Bit>true</Prefer32Bit>. Matches.
CODE_AREA: arch.layout
SEVERITY: low
PROPOSED_FIX: flag only
DOC: gateway.md
LINES: 198–210
CLAIM: Pipe name format is mxaccess-gateway-{gatewayProcessId}-{sessionId} and framing is uint32 little-endian payload_length followed by payload_length bytes protobuf WorkerEnvelope.
CLAIM_TYPE: rpc/proto
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Sessions/SessionManager.cs:433 — string pipeName = $"mxaccess-gateway-{Environment.ProcessId}-{sessionId}". Framing confirmed by WorkerFrameReader.cs and WorkerFrameWriter.cs in src/ZB.MOM.WW.MxGateway.Server/Workers/.
CODE_AREA: arch.ipc
SEVERITY: low
PROPOSED_FIX: flag only
DOC: gateway.md
LINES: 108
CLAIM: "The gateway must never instantiate or call MXAccess directly."
CLAIM_TYPE: behavior-rule
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/ZB.MOM.WW.MxGateway.Server.csproj — no reference to ArchestrA.MXAccess.dll. MXAccess COM is only referenced in the Worker project csproj (line 26–29).
CODE_AREA: arch.layout
SEVERITY: low
PROPOSED_FIX: flag only
DOC: gateway.md
LINES: 646–650
CLAIM: Gateway restart does not reattach old workers; OrphanWorkerCleanupHostedService runs OrphanWorkerTerminator once on startup to kill leftover ZB.MOM.WW.MxGateway.Worker.exe processes.
CLAIM_TYPE: behavior-rule
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Workers/OrphanWorkerCleanupHostedService.cs:7 — class exists and references OrphanWorkerTerminator. OrphanWorkerTerminator.cs:19 is present. Worker executable name ZB.MOM.WW.MxGateway.Worker.exe confirmed in IntegrationTestEnvironment.cs:66.
CODE_AREA: arch.layout
SEVERITY: low
PROPOSED_FIX: flag only
DOC: docs/GatewayProcessDesign.md
LINES: 420–428
CLAIM: Pipe name format is mxaccess-gateway-{gatewayProcessId}-{sessionId} and framing is uint32 little-endian payload_length followed by payload_length bytes protobuf WorkerEnvelope.
CLAIM_TYPE: rpc/proto
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Sessions/SessionManager.cs:433 — confirmed matching.
CODE_AREA: arch.ipc
SEVERITY: low
PROPOSED_FIX: flag only
DOC: docs/GatewayProcessDesign.md
LINES: 459–475
CLAIM: IWorkerClient has methods StartAsync, InvokeAsync(WorkerCommand, TimeSpan, CancellationToken), ReadEventsAsync(CancellationToken), ShutdownAsync(TimeSpan, CancellationToken), Kill(string).
CLAIM_TYPE: rpc/proto
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Workers/IWorkerClient.cs:22,28–31,35,40,44 — all five methods are present with matching signatures.
CODE_AREA: arch.ipc
SEVERITY: low
PROPOSED_FIX: flag only
DOC: docs/GatewayProcessDesign.md
LINES: 713–719
CLAIM: API-key admin CLI subcommands are init-db, create-key, list-keys, revoke-key, rotate-key on ZB.MOM.WW.MxGateway.Server apikey.
CLAIM_TYPE: command
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Security/Authentication/ApiKeyAdminCommandLineParser.cs:121–135 — all five subcommands are parsed. Matches.
CODE_AREA: arch.auth
SEVERITY: low
PROPOSED_FIX: flag only
DOC: docs/GatewayProcessDesign.md
LINES: 408–410
CLAIM: Nonce is passed via MXGATEWAY_WORKER_NONCE environment variable so the command line remains safe to log.
CLAIM_TYPE: config-key
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Workers/WorkerProcessLauncher.cs:17–18 — public const string WorkerNonceEnvironmentVariableName = "MXGATEWAY_WORKER_NONCE". Matches.
CODE_AREA: arch.ipc
SEVERITY: low
PROPOSED_FIX: flag only
DOC: docs/GatewayProcessDesign.md
LINES: 223–229
CLAIM: EventStreamService rejects a second subscriber with EventSubscriberAlreadyActive; faults the session with EventQueueOverflow if the queue fills.
CLAIM_TYPE: term
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Sessions/SessionManagerErrorCode.cs:7–8 — enum values EventSubscriberAlreadyActive and EventQueueOverflow present. Also used at MxAccessGatewayService.cs:929–930 and EventStreamService.cs:150,160.
CODE_AREA: arch.ipc
SEVERITY: low
PROPOSED_FIX: flag only
DOC: docs/GatewayProcessDesign.md
LINES: 291–299
CLAIM: Dashboard auth uses LDAP bind + role mapping (MxGateway:Dashboard:GroupToRole), issues HTTP-only secure cookie, allows Dashboard:AllowAnonymousLocalhost to default to true.
CLAIM_TYPE: behavior-rule
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Dashboard/DashboardAuthenticator.cs:9 (LDAP-backed); DashboardOptions.cs:9 (AllowAnonymousLocalhost defaults to true). Matches.
CODE_AREA: arch.auth
SEVERITY: low
PROPOSED_FIX: flag only
DOC: docs/GatewayProcessDesign.md
LINES: 527–530
CLAIM: "During shutdown the worker client treats WorkerShutdownAck as the protocol close signal."
CLAIM_TYPE: rpc/proto
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Contracts/Protos/mxaccess_worker.proto:34,80 — WorkerShutdownAck is field 17 in the oneof body and its message is defined at line 80.
CODE_AREA: arch.ipc
SEVERITY: low
PROPOSED_FIX: flag only
DOC: gateway.md
LINES: 301–314
CLAIM: Session state machine (in the "Session Manager" section): Creating -> StartingWorker -> WaitingForPipe -> InitializingWorker -> Ready -> Closing -> Closed -> Faulted.
CLAIM_TYPE: behavior-rule
VERDICT: stale
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Sessions/SessionWorkerClientFactory.cs:75 — session.TransitionTo(SessionState.Handshaking) is called between WaitingForPipe and InitializingWorker. The Handshaking state also exists in the public SessionState proto enum (MxaccessGateway.cs:726). The state machine in gateway.md at this location (the Gateway Implementation Plan / Session Manager section) is missing the Handshaking state exactly as in the earlier reference at lines 898–913.
CODE_AREA: arch.session
SEVERITY: medium
PROPOSED_FIX: Add -> Handshaking between WaitingForPipe and InitializingWorker in both state machine diagrams in gateway.md.
DOC: gateway.md
LINES: 1023–1025
CLAIM: "MXAccess COM target is ArchestrA.MxAccess.LMXProxyServerClass / LMXProxy.LMXProxyServer.1 from the installed 32-bit LmxProxy.dll."
CLAIM_TYPE: term
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Worker/MxAccess/MxAccessInteropInfo.cs:14,41 — ComClassName = "ArchestrA.MxAccess.LMXProxyServerClass", ProgId = "LMXProxy.LMXProxyServer.1", registered server LmxProxy.dll. Matches.
CODE_AREA: arch.ipc
SEVERITY: low
PROPOSED_FIX: flag only
DOC: docs/GatewayProcessDesign.md
LINES: 62–93
CLAIM: High-level component list references namespace ZB.MOM.WW.MxGateway.Server with sub-components including GatewayMetrics (under Metrics) and HealthChecks (under Diagnostics).
CLAIM_TYPE: term
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Metrics/GatewayMetrics.cs:4 — namespace ZB.MOM.WW.MxGateway.Server.Metrics; src/ZB.MOM.WW.MxGateway.Server/Diagnostics/AuthStoreHealthCheck.cs:5 — namespace ZB.MOM.WW.MxGateway.Server.Diagnostics. Matches.
CODE_AREA: arch.layout
SEVERITY: low
PROPOSED_FIX: flag only
DOC: gateway.md
LINES: 110–116
CLAIM: Gateway observability foundation lives in ZB.MOM.WW.MxGateway.Server.Diagnostics and ZB.MOM.WW.MxGateway.Server.Metrics; GatewayMetrics exposes counters/gauges/histograms through .NET Meter; DashboardSnapshotService projects sessions/workers/metrics into immutable DTOs.
CLAIM_TYPE: term
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Metrics/GatewayMetrics.cs:4; src/ZB.MOM.WW.MxGateway.Server/Dashboard/DashboardSnapshotService.cs:8. Both namespaces confirmed. Matches.
CODE_AREA: arch.layout
SEVERITY: low
PROPOSED_FIX: flag only
DOC: gateway.md
LINES: 119–121
CLAIM: SignalR hubs at /hubs/{snapshot,alarms,events} accept either the cookie or a 30-minute bearer minted at /hubs/token.
CLAIM_TYPE: path
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Dashboard/DashboardEndpointRouteBuilderExtensions.cs:63–65,73 — MapHub<DashboardSnapshotHub>("/hubs/snapshot"), MapHub<AlarmsHub>("/hubs/alarms"), MapHub<EventsHub>("/hubs/events"), /hubs/token endpoint mapped at line 73. Matches.
CODE_AREA: arch.layout
SEVERITY: low
PROPOSED_FIX: flag only
DOC: gateway.md
LINES: 121–122
CLAIM: "/hubs/events mirrors per-session MxEvent traffic from EventStreamService to clients subscribed to session:{id}."
CLAIM_TYPE: term
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Dashboard/Hubs/EventsHub.cs:27 — public static string GroupName(string sessionId) => $"session:{sessionId}". Matches.
CODE_AREA: arch.layout
SEVERITY: low
PROPOSED_FIX: flag only
DOC: docs/GatewayProcessDesign.md
LINES: 864–893
CLAIM: Configuration JSON block shows MxGateway:Worker:ExecutablePath, MxGateway:Sessions:AllowMultipleEventSubscribers, MxGateway:Events:QueueCapacity, MxGateway:Protocol:WorkerProtocolVersion, etc.
CLAIM_TYPE: config-key
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Configuration/WorkerOptions.cs:6–7,13 — ExecutablePath and RequiredArchitecture match; SessionOptions.cs and EventsOptions confirm the other keys through bound configuration.
CODE_AREA: arch.config
SEVERITY: low
PROPOSED_FIX: flag only
DOC: docs/DesignDecisions.md
LINES: 85–95
CLAIM: The single-subscriber rule for StreamEvents no longer applies to alarms. GatewayAlarmMonitor owns one gateway-managed worker session, fans alarm state to any number of clients through session-less StreamAlarms. AcknowledgeAlarm is session-less and routes through the monitor.
CLAIM_TYPE: behavior-rule
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Alarms/GatewayAlarmMonitor.cs:17 — class exists. MxAccessGatewayService.cs:167 — StreamAlarms and AcknowledgeAlarm are session-less. Matches.
CODE_AREA: arch.session
SEVERITY: low
PROPOSED_FIX: flag only
DOC: docs/DesignDecisions.md
LINES: 217–225
CLAIM: Bulk commands are AddItemBulk, AdviseItemBulk, RemoveItemBulk, UnAdviseItemBulk, SubscribeBulk, UnsubscribeBulk, WriteBulk, Write2Bulk, WriteSecuredBulk, WriteSecured2Bulk, ReadBulk. Each runs single-item MXAccess COM calls sequentially on the STA; per-entry failures are non-throwing.
CLAIM_TYPE: rpc/proto
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Contracts/Protos/mxaccess_gateway.proto — all eleven bulk command kinds are present in the MxCommandKind enum and corresponding request/reply messages. Verified by cross-referencing GatewayGrpcScopeResolver.cs:39 which maps WriteBulk, Write2Bulk, etc.
CODE_AREA: arch.ipc
SEVERITY: low
PROPOSED_FIX: flag only
DOC: gateway.md
LINES: 129–130
CLAIM: "/browse walks the IGalaxyHierarchyCache tree and reads subscribed tag values live through IDashboardLiveDataService."
CLAIM_TYPE: term
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Server/Dashboard/IDashboardBrowseService.cs — IDashboardBrowseService references IGalaxyHierarchyCache. IDashboardLiveDataService.cs exists in the same Dashboard directory. /browse page confirmed in BrowsePage.razor:1.
CODE_AREA: arch.layout
SEVERITY: low
PROPOSED_FIX: flag only
DOC: gateway.md LINES: 2–19 CLAIM: Gateway preserves MXAccess behavior first, including public MXAccess command semantics, native MXAccess event families, STA/message-pump delivery behavior, HRESULT/status/value marshaling, and per-client isolation. "Installed MXAccess COM component is the compatibility baseline." CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: src/ZB.MOM.WW.MxGateway.Worker/MxAccess/MxAccessInteropInfo.cs (installs/references real COM interop); docs/DesignDecisions.md:26–28 — "target the installed MXAccess COM interop surface directly from the x86 worker." Consistent across all three docs. CODE_AREA: arch.layout SEVERITY: low PROPOSED_FIX: flag only
DOC: docs/GatewayProcessDesign.md
LINES: 100–105
CLAIM: gRPC service surface at this stage is limited to OpenSession, CloseSession, Invoke, StreamEvents (with Session(stream ClientMessage) returns (stream ServerMessage) deferred).
CLAIM_TYPE: rpc/proto
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Contracts/Protos/mxaccess_gateway.proto — MxAccessGateway service defines OpenSession, CloseSession, Invoke, StreamEvents, and additional alarm/galaxy RPCs. The bidirectional Session RPC is not present in the current proto, consistent with the deferral noted in the doc.
CODE_AREA: arch.ipc
SEVERITY: low
PROPOSED_FIX: flag only
DOC: gateway.md
LINES: 266–273
CLAIM: Public gRPC service is MxAccessGateway with OpenSession, CloseSession, Invoke, StreamEvents, and deferred bidirectional Session RPC.
CLAIM_TYPE: rpc/proto
VERDICT: accurate
EVIDENCE: src/ZB.MOM.WW.MxGateway.Contracts/Protos/mxaccess_gateway.proto — confirmed. The Session bidirectional RPC is absent as expected for deferred rollout.
CODE_AREA: arch.ipc
SEVERITY: low
PROPOSED_FIX: flag only