docs(audit): apply per-cluster judgment fixes across living docs

Resolve audit findings: correct WorkerEnvelope proto/route/metric/session
facts; rewrite auth (ZB.MOM.WW.Auth migration), dashboard (ZB.MOM.WW.Theme),
and StyleGuide (foreign-project copy-paste); document alarm subsystem, Ldap
options, and gateway alarm broker; fix client CLI flags and package paths.
This commit is contained in:
Joseph Doherty
2026-06-03 16:01:28 -04:00
parent f84e0c3474
commit e541339c07
29 changed files with 1102 additions and 432 deletions
+83 -27
View File
@@ -94,9 +94,11 @@ Expected protected environment values:
```text
MXGATEWAY_WORKER_NONCE=<random nonce>
MXGATEWAY_WORKER_LOG_CONTEXT=<optional context>
```
The nonce travels through the environment rather than the command line so it
never appears in process-listing tools that expose argument vectors.
Startup sequence:
1. Parse command-line arguments.
@@ -114,16 +116,26 @@ Startup sequence:
If validation fails before MXAccess creation, exit quickly with a non-zero exit
code. If MXAccess creation fails, send `WorkerFault` when possible and exit.
The bootstrap layer returns structured exit codes before it creates pipes,
starts the STA, or touches MXAccess:
`WorkerApplication.Run` returns one of the structured `WorkerExitCode` values.
Codes `2``4` are produced by the bootstrap parse phase before any pipe, STA, or
MXAccess work happens; codes `5``6` and a clean `0` only become reachable once
the parse succeeds and the worker runs its pipe session:
| Exit code | Name | Meaning |
|-----------|------|---------|
| `0` | `Success` | Required bootstrap options are valid. |
| `0` | `Success` | The pipe session ran to a clean close. |
| `1` | `UnexpectedFailure` | A non-bootstrap exception reaches the process boundary. |
| `2` | `InvalidArguments` | Required arguments are missing or unknown arguments are present. |
| `3` | `InvalidProtocolVersion` | `--protocol-version` is not numeric or does not match the supported worker protocol. |
| `4` | `MissingNonce` | `MXGATEWAY_WORKER_NONCE` is absent or empty. |
| `5` | `PipeConnectionFailed` | The pipe connection raised an `IOException` or `TimeoutException`. |
| `6` | `ProtocolViolation` | A `WorkerFrameProtocolException` escaped the pipe session. |
`WorkerBootstrapResult.Succeeded` is a separate parse-phase gate: it reports
whether argument parsing produced usable `WorkerOptions`. A `false` result
carries one of codes `2``4` and the worker exits before running a session, so a
successful parse is distinct from the `0` exit code, which only follows a clean
pipe-session close.
Bootstrap logs use `WorkerConsoleLogger` key/value output. `WorkerLogRedactor`
redacts fields whose names indicate nonce, secret, password, token,
@@ -133,30 +145,35 @@ credential, or API key values before the message is written.
```text
ZB.MOM.WW.MxGateway.Worker
Program
Program (calls WorkerApplication.Run)
WorkerApplication (parse, bootstrap, run pipe session, map exit code)
Bootstrap
WorkerOptionsParser (parse args + env into WorkerOptions)
WorkerOptions
WorkerHost
WorkerBootstrapResult (parse outcome + WorkerExitCode)
WorkerExitCode
WorkerConsoleLogger / WorkerLogRedactor
Ipc
PipeClient
FrameReader
FrameWriter
WorkerProtocol
WorkerPipeClient (named-pipe connect + retry, owns the session)
WorkerPipeSession (handshake, read/write/drain/heartbeat loops)
WorkerFrameReader / WorkerFrameWriter
WorkerEnvelopeValidator
WorkerContractInfo (protocol version + descriptor names)
Sta
StaRuntime
StaCommandQueue
MessagePump
StaWatchdog
StaRuntime (the dedicated STA thread + message pump loop)
StaCommandDispatcher
StaMessagePump
MxAccess
MxAccessSession
MxAccessCommandDispatcher
MxAccessEventSink
MxAccessStaSession (IWorkerRuntimeSession over the STA)
MxAccessSession (handle registry + COM-call orchestration)
MxAccessCommandExecutor (IStaCommandExecutor; runs commands on the STA)
MxAccessBaseEventSink (OnDataChange tag-data events)
MxAccessHandleRegistry
(alarm subsystem — see below)
Conversion
VariantConverter
SafeArrayConverter
StatusProxyConverter
HResultMapper
VariantConverter (MxValue <-> COM VARIANT, both directions)
MxStatusProxyConverter
HResultConverter / HResultConversion
```
## Threading Model
@@ -330,13 +347,19 @@ cleanup path completes.
## Event Sink
The worker must subscribe to every public MXAccess event family:
The worker subscribes to every public MXAccess event family through
`MxAccessBaseEventSink`:
- `OnDataChange`
- `OnWriteComplete`
- `OperationComplete`
- `OnBufferedDataChange`
Alarm transitions arrive on a separate path. They do not originate from the
`LMXProxyServerClass` connection points, so `MxAccessAlarmEventSink` (driven by
the alarm subsystem below) feeds them onto the same `MxAccessEventQueue` rather
than `MxAccessBaseEventSink`.
Forward these event families only when the native MXAccess COM object raises
them. Do not synthesize `OperationComplete` from write completion or command
status. `OnBufferedDataChange` must be represented in the protocol now, but
@@ -368,16 +391,49 @@ type on buffered events. `OperationComplete` is only emitted from the native
`MxAccessEventQueue` is the bounded outbound event queue for one worker
session. It assigns the monotonic `WorkerSequence` and `WorkerTimestamp` when an
event is accepted, preserving the order in which MXAccess handlers enqueue
events. The default capacity is `10000`. When the queue reaches capacity it
records a `WorkerFaultCategory.QueueOverflow` fault and rejects further events.
The event handler catches conversion and enqueue failures, records the first
fault on the queue, and returns to the STA message pump instead of writing to
the pipe.
events. The default capacity is `10000`. When the queue reaches capacity, `Enqueue`
records a `WorkerFaultCategory.QueueOverflow` fault and then throws
`MxAccessEventQueueOverflowException` so the caller cannot silently drop the
event. The event handler catches conversion and enqueue failures (including this
overflow exception), records the first fault on the queue, and returns to the
STA message pump instead of writing to the pipe.
If event conversion throws, catch it inside the event handler, record a
structured `WorkerFault`, and keep the worker alive only if the fault policy
allows it.
## Alarm Subsystem
Alarms come from a different COM surface than tag data, so the worker carries a
separate pipeline rather than folding alarms into `MxAccessBaseEventSink`. The
MXAccess `LMXProxyServerClass` does not expose alarm subscription, so the worker
hosts AVEVA's standalone alarm-consumer COM object instead.
- `WnWrapAlarmConsumer` is the production `IMxAccessAlarmConsumer`, backed by
`WNWRAPCONSUMERLib.wwAlarmConsumerClass`. It returns the active alarm set as a
BSTR XML string through `GetXmlCurrentAlarms2`, which avoids the FILETIME→
`DateTime` marshaling that crashed the earlier managed alarm client. The CLSID
is registered `ThreadingModel=Apartment`, so the consumer is created and
driven entirely on the worker's STA. It owns no internal timer.
- `MxAccessStaSession` drives the **STA alarm poll loop**: `RunAlarmPollLoopAsync`
awaits a fixed `500 ms` interval and then calls `IAlarmCommandHandler.PollOnce`
on the STA via the runtime, so every `GetXmlCurrentAlarms2` call stays on the
apartment that owns the consumer. A poll failure is recorded as a
`WorkerFault` on the event queue rather than terminating the worker.
- `AlarmCommandHandler` owns one `AlarmDispatcher` per session and is the entry
point for the alarm IPC commands (`SubscribeAlarms`, `AcknowledgeAlarm` by GUID
or name, `QueryActiveAlarms`, `Unsubscribe`). It rejects a second subscribe
before an unsubscribe, mirroring the consumer's non-idempotent `Subscribe`.
- `AlarmDispatcher` wires the consumer's `AlarmTransitionEmitted` stream onto
`MxAccessAlarmEventSink.EnqueueTransition`. It maps state transitions through
`AlarmRecordTransitionMapper`, composes the canonical
`\\<machine>\Galaxy!<area>` full reference, and projects active-alarm
snapshots to `ActiveAlarmSnapshot` protos for the `QueryActiveAlarms` refresh
stream.
- `MxAccessAlarmEventSink` enqueues each decoded transition onto the shared
`MxAccessEventQueue` as a proto alarm-transition event, stamping the session
id, so alarms ride the same outbound IPC path as tag-data events.
## Command Queue
The pipe reader converts `WorkerCommand` messages into `StaCommand` entries.