fix(archreview): gateway core P0 remediation (GWC-01/02/03, TST-02, TST-12)
Interlocking changes across the gateway server (shared GatewaySession.cs / SessionManager.cs), committed together: - GWC-01 (Critical): alarm monitor now attaches as an internal (non-counted) distributor subscriber instead of a second raw drain of the single worker event channel; WorkerClient._events -> SingleReader with a claimed-once guard so a future dual-consumer regression throws loudly. - GWC-02 (High): faulted sessions are swept in CloseExpiredLeasesAsync (IsFaultedReapable + FaultedReason); new FaultedGraceSeconds (default 0). - GWC-03 (High): configurable MaxSparseArrayLength (default 1_000_000) enforced before allocation. - TST-02 (High, security): StreamEvents attach now enforces the opening key id -> PermissionDenied on owner mismatch. - TST-12 (Medium): CLAUDE.md retention-defaults sentence corrected. Verified: NonWindows build clean; targeted tests 135/135 on macOS, plus WorkerClientTests 18/18 on the Windows host.
This commit is contained in:
+12
@@ -143,6 +143,17 @@ session if the worker faults. Gated by `MxGateway:Alarms:Enabled` — see
|
||||
`docs/DesignDecisions.md` for why this reverses the v1 single-subscriber rule
|
||||
for the alarm subsystem.
|
||||
|
||||
The monitor consumes its session's events as an **internal distributor
|
||||
subscriber** (`GatewaySession.AttachInternalEventSubscriber`), not by draining
|
||||
the worker event channel directly. The single worker event channel therefore has
|
||||
exactly one reader — the per-session `SessionEventDistributor` pump — which fans
|
||||
every event to both the dashboard mirror and the alarm feed; the alarm subscriber
|
||||
is internal (`isInternal: true`), so it is not counted against
|
||||
`MaxEventSubscribersPerSession` and a slow alarm reconcile can never fault the
|
||||
session. The worker event channel is single-reader and asserts it (a second
|
||||
`WorkerClient.ReadEventsAsync` consumer throws), so a regression cannot silently
|
||||
split the event stream between two drains.
|
||||
|
||||
### Alarm providers and failover
|
||||
|
||||
The alarm feed has two providers, both implemented worker-side:
|
||||
@@ -530,6 +541,7 @@ read, all of which contradict MXAccess semantics.
|
||||
- `element_data_type` that is `Raw` or `Unspecified`
|
||||
- an element `value` whose kind does not match `element_data_type`
|
||||
- `total_length` exceeds the gateway-configured maximum array length
|
||||
(`MxGateway:Events:MaxSparseArrayLength`, default 1,000,000)
|
||||
|
||||
An empty `elements` list with a non-zero `total_length` is valid — it writes an
|
||||
all-defaults array of length `total_length` (explicit reset). A `sparse_array_value`
|
||||
|
||||
Reference in New Issue
Block a user