docs(archreview): P2 doc-drift sweep (IPC-06/07/17/21, SEC-09/22, CLI-12/16, TST-13)

Reconcile load-bearing docs with shipped behavior:
- IPC-06: gateway.md Worker Envelope sketch -> points to mxaccess_worker.proto
  as source of truth (string correlation_id, real oneof arms incl.
  worker_shutdown_ack/worker_ready).
- IPC-07: docs/Grpc.md six RPCs -> seven; document QueryActiveAlarms handler
  + validation row.
- IPC-21: gateway.md Session RPC moved from live API into a 'Future work: not
  implemented' subsection.
- TST-13: drop stale design-era sketches from gateway.md; correct the
  single-subscriber-default (config-gated fan-out) note.
- SEC-09: dashboard GroupToRole sample GwAdmin:Admin -> Administrator so it
  passes GatewayOptionsValidator; clarify Administrator is the canonical role.
- SEC-22: rewrite docs/Authentication.md to the pipeline that actually ships
  (ZB.MOM.WW.Auth.ApiKeys package + gateway-owned CachingApiKeyVerifier,
  CoalescingMarkApiKeyStore, CanonicalForwardingApiKeyAuditStore, etc.);
  remove 18 stale type names (grep-verified absent).
- IPC-17: correct wrong Python generated dir (mxgateway -> zb_mom_ww_mxgateway)
  in CLAUDE.md + 3 docs.
- CLI-12: Java docs Java 21 -> Java 17 (JDK17 retarget for Ignition 8.3).
- CLI-16: docs/ClientPackaging.md reconciled with real .slnx, Python package
  name, and gradle project names; fix stale generateProto task name.

Docs-only; type/path/version claims verified against source.

Claude-Session: https://claude.ai/code/session_01DMXXvNuPekkkrTEyPNxEkW
This commit is contained in:
Joseph Doherty
2026-07-09 14:46:15 -04:00
parent 4fe1917aa6
commit 06e1046317
10 changed files with 270 additions and 297 deletions
+57 -37
View File
@@ -297,43 +297,46 @@ Pipe security:
### Worker Envelope
Every IPC message uses a common envelope:
Every IPC message uses a common `WorkerEnvelope`. The authoritative definition
lives in `src/ZB.MOM.WW.MxGateway.Contracts/Protos/mxaccess_worker.proto` — treat
that file as the single source of truth and do not hand-copy the message here,
because an inlined copy drifts. The shape below describes the current contract so
this document explains *why* the envelope is structured the way it is.
```protobuf
message WorkerEnvelope {
uint32 protocol_version = 1;
string session_id = 2;
uint64 sequence = 3;
uint64 correlation_id = 4;
oneof body {
WorkerHello worker_hello = 10;
GatewayHello gateway_hello = 11;
WorkerReady worker_ready = 12;
WorkerCommand command = 20;
WorkerCommandReply command_reply = 21;
WorkerEvent event = 22;
WorkerHeartbeat heartbeat = 23;
WorkerCancel cancel = 24;
WorkerShutdown shutdown = 25;
WorkerFault fault = 26;
}
}
```
The envelope header carries four fields: `protocol_version`, `session_id`, a
`uint64 sequence`, and a **`string correlation_id`** (an opaque id, not a
numeric one). The `body` is a `oneof` whose arms are the handshake and traffic
messages, tagged from 10 upward:
- `gateway_hello` / `worker_hello` — the startup handshake pair.
- `worker_ready` — the worker signalling its MXAccess COM instance is live.
- `worker_command` / `worker_command_reply` — a command and its correlated reply.
- `worker_cancel` — best-effort cancellation of an in-flight command.
- `worker_shutdown` / `worker_shutdown_ack` — graceful shutdown request and its
acknowledgement.
- `worker_event` — a converted MXAccess event.
- `worker_heartbeat` — periodic worker liveness/state.
- `worker_fault` — a terminal worker fault report.
Rules:
- `sequence` is monotonic per sender.
- `correlation_id` links commands to replies.
- Events use their own correlation id or zero.
- `sequence` is a monotonic per-sender counter used as a diagnostic aid; it is
not validated for gaps or ordering on receive (the named pipe already
guarantees FIFO delivery).
- `correlation_id` links a command to its reply; it is authoritative on the
envelope, and the inner `MxCommandReply.correlation_id` echoes it for
MXAccess parity.
- Events carry their own correlation id or leave it empty.
- Replies must preserve MXAccess HRESULT/status information even when the
command is also represented as a protocol-level failure.
- Protocol version mismatch fails session creation.
## Public gRPC API
The external API should be session-oriented. A bidirectional stream is the best
long-term shape because it naturally carries commands, replies, events,
heartbeats, and cancellation.
The external API is session-oriented. The shipped service is unary plus
server-streaming; the authoritative definition is
`src/ZB.MOM.WW.MxGateway.Contracts/Protos/mxaccess_gateway.proto`. As built, the
`MxAccessGateway` service exposes seven RPCs:
```protobuf
service MxAccessGateway {
@@ -341,19 +344,34 @@ service MxAccessGateway {
rpc CloseSession(CloseSessionRequest) returns (CloseSessionReply);
rpc Invoke(MxCommandRequest) returns (MxCommandReply);
rpc StreamEvents(StreamEventsRequest) returns (stream MxEvent);
rpc Session(stream ClientMessage) returns (stream ServerMessage);
rpc AcknowledgeAlarm(AcknowledgeAlarmRequest) returns (AcknowledgeAlarmReply);
rpc StreamAlarms(StreamAlarmsRequest) returns (stream AlarmFeedMessage);
rpc QueryActiveAlarms(QueryActiveAlarmsRequest) returns (stream ActiveAlarmSnapshot);
}
```
Recommended rollout:
`OpenSession`, `CloseSession`, and `Invoke` are unary; `StreamEvents`,
`StreamAlarms`, and `QueryActiveAlarms` are server-streaming. `AcknowledgeAlarm`,
`StreamAlarms`, and `QueryActiveAlarms` are session-less — they route to the
gateway's always-on central alarm monitor rather than a client worker session.
The unary-plus-event-stream shape is easier to debug and reason about than a
single multiplexed channel.
1. Implement unary `OpenSession`, `CloseSession`, and `Invoke`.
2. Implement server-streaming `StreamEvents`.
3. Add bidirectional `Session` after the command/event model is stable.
### Future work: bidirectional `Session` (not implemented)
The unary plus event-stream shape is easier to debug initially. The
bidirectional stream can later reduce per-command overhead and improve
backpressure.
A single bidirectional `Session` stream carrying commands, replies, events,
heartbeats, and cancellation was considered as a possible long-term shape:
```protobuf
// Not implemented — design sketch only.
rpc Session(stream ClientMessage) returns (stream ServerMessage);
```
It is **not part of the shipped contract** and there are no `ClientMessage` /
`ServerMessage` types in `mxaccess_gateway.proto`. A bidirectional stream could
later reduce per-command overhead and improve backpressure, but it would only be
added after the command/event model is stable and if a concrete requirement
appears.
## Public MXAccess Command Surface
@@ -750,8 +768,10 @@ Gateway policy:
- one event sequencer per session,
- preserve per-session event order,
- allow one active client event subscriber per session,
- reject a second subscriber with a clear session error,
- allow one active client event subscriber per session **by default**, rejecting
a second subscriber with a clear session error; multi-subscriber fan-out is
config-gated (`AllowMultipleEventSubscribers`, off by default) — see the
fan-out and reconnect detail in [Sessions](docs/Sessions.md),
- use a bounded `EventStreamService` queue between worker events and gRPC
writes,
- fault the session when the bounded stream queue overflows,