docs(TST-27,WRK-26,CLI-42,CLI-43,IPC-28): P1 doc-drift batch, discharges IPC-29
ci / nightly-windev (push) Has been skipped
ci / windows-x86 (push) Successful in 1m17s
ci / java (push) Successful in 2m10s
ci / portable (push) Failing after 3m53s

TST-27: docs/GatewayConfiguration.md's ShowTagValues row no longer says
"Reserved" — it now states what false (default) does (DashboardEventBroadcaster
blanks tag values from a deep-cloned MxEvent before the SignalR events-hub
mirror), the security relevance (no per-session hub ACL yet, so this
redaction is the only thing between a low-trust Viewer and other sessions'
tag values), and the honest scope limit (does not cover /browse).

WRK-26 (discharges IPC-29): docs/MxAccessWorkerInstanceDesign.md's "Outbound
Queues" section rewritten from the stale five-level priority list to the
two-class Control/Event scheduler actually shipped, with the collapsed-
decision rationale, and the overflow paragraph rewritten to the implemented
fail-fast. docs/WorkerFrameProtocol.md gained a "Write Scheduling And
Sequencing" section describing HEAD truthfully: WRK-23's peek-stamp-commit
sequencing is live, WRK-25's event-batch flush coalescing is not (the drain
loop still awaits each event write individually), and WRK-22's cancellation
tombstone is not yet defined (noted as pending, not documented as shipped).

CLI-42: clients/rust/README.md and docs/ClientPackaging.md document the
vendored Rust proto layout matching build.rs — repo-path-first resolution
falling back to clients/rust/protos/, the check-codegen.ps1 Check 3 refresh
rule, and why cargo package/publish run without --no-verify.

CLI-43: docs/style-guides/JavaStyleGuide.md now says Java 17 (Ignition 8.3
baseline), mirroring CLI-12's wording, matching the shipped build.gradle.

IPC-28: docs/Grpc.md's exception-mapping prose gained CommandTooLarge ->
ResourceExhausted, and the Invoke section gained the oversized-payload
sentence, cross-referencing GatewayConfiguration.md's headroom rule.

Tracking: TST-27, WRK-26, CLI-42, CLI-43, IPC-28 flipped to Done and IPC-29
marked discharged-by-WRK-26 in 00-tracking.md and the 20/30/50/60 domain
registers, with a 2026-08-07 change-log entry.

Doc-only change; no source, proto, or test edits.
This commit is contained in:
Joseph Doherty
2026-08-07 07:26:58 -04:00
parent 97f79e79ef
commit 10534ec906
12 changed files with 148 additions and 37 deletions
+33 -18
View File
@@ -638,27 +638,42 @@ Rules:
## Outbound Queues
The worker should use bounded outbound queues for replies, events, heartbeats,
and faults.
`WorkerFrameWriter` is a two-class cooperative priority scheduler, not the
five-level queue an earlier design draft called for. Every outbound frame is
enqueued at one of two `WorkerFrameWritePriority` values:
Priority order when writing:
- **Control** — hello, ready, command replies, faults, heartbeats, shutdown
acknowledgements.
- **Event** — MXAccess events drained from the queue.
1. faults,
2. command replies,
3. shutdown acknowledgements,
4. heartbeats,
5. events.
A caller enqueues its frame under a lock, then contends for a single write
lock; whichever caller wins drains **every** currently-queued frame before
releasing the lock, so a reply, fault, or heartbeat enqueued while a large
event backlog is draining still gets written on the very next drain pass
rather than waiting behind it. Within a class the queue is strict FIFO — a
fault does not jump ahead of an already-queued heartbeat or reply. This
collapses the originally-specified five-level order (faults > replies >
shutdown acks > heartbeats > events) into two classes; the decision is
deliberate, not a shortfall: the control queue is shallow in practice (faults
and shutdown acks are rare, replies and heartbeats are the steady traffic), so
the FIFO delay within it is bounded, and a two-class scheduler is simpler to
reason about and test than a five-level one for that same bound. See
`docs/WorkerFrameProtocol.md`'s "Write scheduling and sequencing" section for
the wire-level detail (sequence stamping, per-frame vs. stream-failure
semantics, flush coalescing).
Event overflow policy defaults to fail-fast for parity testing. If the event
queue fills:
1. Capture overflow metrics.
2. Send `WorkerFault` if possible.
3. Stop accepting new commands.
4. Let the gateway close or kill the worker.
Production coalescing may be added later, but it must be explicit and tested.
Do not drop or coalesce events in v1.
Event overflow policy is fail-fast, not "stop accepting new commands and let
the gateway close or kill the worker." When `MxAccessEventQueue.Enqueue` finds
the queue full, it throws and the queue self-records a `WorkerFault` with
category `QueueOverflow`. The event drain loop's next pass observes the fault
through `DrainFault()`, writes the fault frame — a Control-priority frame, so
it is not stuck behind a queued event backlog — and then throws to unwind
`RunAsync`: the worker process exits rather than continuing in a state where
events are being silently lost. The exit currently uses the generic
`WorkerExitCode.UnexpectedFailure` rather than a dedicated overflow code; a
distinct exit code remains open (tracked separately). Do not drop or coalesce
events to avoid this exit — that is explicitly out of scope for v1. Production
coalescing may be added later, but it must be explicit and tested.
The gateway side of the event path is bounded to match. `WorkerClient` buffers
inbound events in a bounded consumer channel plus a staging channel bounded at