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:
+57
-37
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user