docs: note operator_full_name not propagated; refresh stillpending and deferred-followups status
This commit is contained in:
@@ -146,7 +146,7 @@ the active alarms the gateway's central monitor currently holds),
|
||||
keyed by the same monitor), and `AcknowledgeAlarmAsync` (acknowledges as
|
||||
the operator: the gateway authenticates `OperatorUser`/`OperatorPassword` and
|
||||
writes the comment to the alarm's `AckMsg`, so the Historian records the
|
||||
operator). All three accept a cancellation
|
||||
operator). The operator's full name is not sent by the client and is not propagated to MXAccess (`operator_full_name` on the worker commands is accepted but ignored); the Historian takes it from the authenticated Galaxy account. All three accept a cancellation
|
||||
token and pass through the `MxGateway:Alarms` configuration on the
|
||||
server — when alarms are disabled, the gateway returns an empty list / empty
|
||||
stream rather than failing.
|
||||
|
||||
@@ -144,7 +144,7 @@ snapshots, `Client.StreamAlarms` for the server-streaming feed, and
|
||||
operator's Galaxy credentials (`OperatorUser` required, `OperatorPassword`,
|
||||
optional `OperatorDomain`) so the gateway authenticates as the operator and the
|
||||
Historian records that operator; an empty password is allowed, and the password
|
||||
is scrubbed from any returned error. The streaming
|
||||
is scrubbed from any returned error. The operator's full name is not sent by the client and is not propagated to MXAccess (`operator_full_name` on the worker commands is accepted but ignored); the Historian takes it from the authenticated Galaxy account. The streaming
|
||||
call returns a `StreamAlarmsClient`; cancel its context to terminate the
|
||||
stream. All three pass straight through to the gateway's central alarm
|
||||
monitor.
|
||||
|
||||
@@ -118,7 +118,7 @@ yields alarm-feed messages from the gateway's central monitor), and
|
||||
The ack carries operator credentials: `operator_user` is required, and
|
||||
`operator_password` / `operator_domain` let the gateway authenticate as that
|
||||
operator so the Historian records the real operator. An empty password is
|
||||
allowed. The password is scrubbed from exceptions the client throws. Close the subscription to cancel the underlying gRPC stream.
|
||||
allowed. The password is scrubbed from exceptions the client throws. The operator's full name is not sent by the client and is not propagated to MXAccess (`operator_full_name` on the worker commands is accepted but ignored); the Historian takes it from the authenticated Galaxy account. Close the subscription to cancel the underlying gRPC stream.
|
||||
|
||||
`ActiveAlarmSnapshot.getFromTruncatedSnapshot()` reports that the record came
|
||||
from a provider fetch which hit the per-fetch cap: the snapshot set may omit
|
||||
|
||||
@@ -116,7 +116,7 @@ comment). The ack is made as the operator: set `operator_user` (required) and
|
||||
`operator_password` (may be empty) and optionally `operator_domain` on
|
||||
`AcknowledgeAlarmRequest`. The gateway authenticates the operator and writes the
|
||||
comment to the alarm's `AckMsg`, so the alarm history records the operator. The
|
||||
password is redacted from any raised error.
|
||||
password is redacted from any raised error. The operator's full name is not sent by the client and is not propagated to MXAccess (`operator_full_name` on the worker commands is accepted but ignored); the Historian takes it from the authenticated Galaxy account.
|
||||
|
||||
Cancel the surrounding task or `aclose()` an alarm iterator to terminate the
|
||||
stream.
|
||||
|
||||
@@ -127,7 +127,7 @@ returns an `AlarmFeedStream` async stream of alarm-feed messages and
|
||||
shares the gateway's central alarm monitor with every other client.
|
||||
`acknowledge_alarm` requires `operator_user` and carries `operator_password` (may be
|
||||
empty) and `operator_domain`; the gateway authenticates as that operator so the Historian
|
||||
records them. The password is scrubbed from any returned error's `Display`/`Debug`.
|
||||
records them. The operator's full name is not sent by the client and is not propagated to MXAccess (`operator_full_name` on the worker commands is accepted but ignored); the Historian takes it from the authenticated Galaxy account. The password is scrubbed from any returned error's `Display`/`Debug`.
|
||||
|
||||
The `from_truncated_snapshot` field on `ActiveAlarmSnapshot` reports that the record came from
|
||||
a provider fetch which hit the per-fetch cap: the snapshot set may omit active
|
||||
|
||||
@@ -103,6 +103,7 @@ Request fields that identify the acknowledging operator:
|
||||
- `operator_user` (required): the Galaxy account name. An empty value is rejected with `InvalidArgument` so the real operator is always recorded.
|
||||
- `operator_password` (field 6): the operator's Galaxy password. May be empty because Galaxy accounts can have empty passwords. It is a credential and is never logged.
|
||||
- `operator_domain` (field 7): optional. When set, the worker authenticates `domain\user`; when empty it authenticates `user`.
|
||||
- `operator_full_name`: not a field on `AcknowledgeAlarmRequest`. The worker commands (`AcknowledgeAlarmCommand` field 6, `AcknowledgeAlarmByNameCommand` field 8) carry one, but it is accepted and **not propagated** to MXAccess: the 8-argument `AlarmAckByName` that carried it returns -55 (see [Alarm Client Discovery](./AlarmClientDiscovery.md)). `operator_domain` is used.
|
||||
|
||||
The worker calls `AuthenticateUser` as the operator, then writes `operator_comment` to `<TagName>.AckMsg` (subtag mode: the configured ack-comment subtag) on a dedicated MXAccess server registered as `MxGateway:Alarms:AckClientName`, and waits a bounded time for `OnWriteComplete`. The AVEVA runtime treats that write as the acknowledgement, and the Historian (`Runtime.dbo.v_AlarmEventHistory2`) records the operator name, domain and full name from the authenticated account, with the ack client name as `OperatorNode`. The alarm-client ack calls (`AlarmAckByName`, `AlarmAckByGUID`) are not used because a headless consumer's acks are accepted and dropped; see [Alarm Probe Findings](./AlarmProbeFindings.md).
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Deferred Follow-ups Implementation Plan
|
||||
|
||||
**Date:** 2026-06-14
|
||||
**Status:** D1 executed (commit 4af24b9 — `mxgateway.alarms.provider_switches` emitted in `DashboardSnapshotService.cs:198`). D2 resolved as no-op (see resolution section below). D3–D5 remain pending (ops/validation, no code).
|
||||
**Status:** D1 executed (commit 4af24b9 — `mxgateway.alarms.provider_switches` emitted in `DashboardSnapshotService.cs:198`). D2 resolved as no-op (see resolution section below). D3 (ForceSubtag validation) was exercised through the forced-subtag work (`2026-06-15-forced-subtag-mode-fix.md`); D4 (windev backup prune) has no completion record in the repo and is treated as pending; D5 (wonder redeploy) was superseded by later wonder deployments. D3–D5 are ops/validation with no code.
|
||||
**Context:** After the alarm-subtag-fallback cleanup (merged `5976770`) and its redeploy to
|
||||
windev (10.100.0.48), five items remain deferred. This plan handles all five. They are
|
||||
independent — execute in any order, or cherry-pick. Items D1–D2 are code (branch off `main`);
|
||||
|
||||
+7
-8
@@ -42,10 +42,9 @@ Items are graded by what they actually are, because most "pending" surface in th
|
||||
- **Location:** metric emitted in `Alarms/GatewayAlarmMonitor.cs` (failover/failback path); residual recorded in `docs/plans/2026-06-14-deferred-followups.md:124-125`.
|
||||
- **Evidence:** *"that counter's live exercise remains the one gap; record it explicitly rather than claiming coverage."* Unit-tested (Tests-032) but the dev rig can't drive a real alarmmgr→subtag failover (`project_rig_alarms_object_driven`), so the counter's `reason` tagging is unproven in production.
|
||||
|
||||
### 🟠 1.4 — Worker 8-arg alarm ack silently discards operator domain / full name
|
||||
- **Location:** `src/ZB.MOM.WW.MxGateway.Worker/MxAccess/WnWrapAlarmConsumer.cs:261-278` (`_ = ackOperatorDomain; _ = ackOperatorFullName;`).
|
||||
- **Evidence:** *"the IwwAlarmConsumer2 8-arg AlarmAckByName returns -55 on this AVEVA build (looks like a stub) … fields are accepted by the proto for forward-compat but are not propagated to AVEVA today."*
|
||||
- **Impact:** two contract fields are accepted on the wire and silently not delivered. Root cause is the vendor stub (see 3.5), but the drop is currently invisible to callers.
|
||||
### 🟡 1.4 — Operator full name is accepted but not propagated (domain is now consumed)
|
||||
- **Status (2026-10-22):** half-resolved. Acks now authenticate as the operator and write `<alarm>.AckMsg` (`Worker/MxAccess/AlarmAckOperator.cs`), and **`operator_domain` is consumed** (`domain\user` for `AuthenticateUser`). The older `WnWrapAlarmConsumer` 8-arg path that discarded both fields (`_ = ackOperatorDomain; _ = ackOperatorFullName;`) is no longer the ack path.
|
||||
- **Remaining:** `operator_full_name` on `AcknowledgeAlarmCommand` (field 6) / `AcknowledgeAlarmByNameCommand` (field 8) is still accepted and not propagated to MXAccess; the 8-arg `AlarmAckByName` that carried it returns -55 (`docs/AlarmClientDiscovery.md:743-748`). The public `AcknowledgeAlarmRequest` has no such field. The proto comments and `docs/Grpc.md` now state this.
|
||||
|
||||
---
|
||||
|
||||
@@ -76,8 +75,8 @@ Intentionally incomplete, awaiting a live capture or an AVEVA fix; raw payload/m
|
||||
- 🟡 **3.1 `OperationComplete` native trigger condition unknown** — modeled and emitted only from the real event (no synthesis), but the runtime condition that fires it isn't captured. `docs/DesignDecisions.md:280-289`, `gateway.md:1094`, `docs/MxAccessWorkerInstanceDesign.md:341,366`.
|
||||
- 🟡 **3.2 `OnBufferedDataChange` multi-sample conversion unvalidated — STILL OPEN (residual after B8)** — `AddBufferedItem`/`SetBufferedUpdateInterval` are now implemented and live-confirmed (§1.1), and the live B8 test (`f7ada90`) confirms the worker receives and cleanly converts the empty `NoData` bootstrap `OnBufferedDataChange` (no crash, no dropped payload). But the rig's object logic does not drive a multi-sample buffered batch on demand (same limitation as the alarm rig), so a real parallel quality/timestamp sample array (length > 1) has never been observed live — it is exercised only by the B-bundle unit tests against a fake `IMxAccessServer`. Re-run `GatewaySession_WithLiveWorker_BufferedItem_*` against a fast-changing simulated tag to close this. `docs/DesignDecisions.md:291-297`.
|
||||
- 🟡 **3.3 Completion-only status → `MXSTATUS_PROXY[]` mapping unproven** — completion-only operation-status bytes are kept as raw diagnostic metadata until the analysis proves an exact mapping. `docs/DesignDecisions.md:299-306`.
|
||||
- 🟡 **3.4 `AlarmAckByGUID` is `E_NOTIMPL` on this AVEVA build** — throws `NotImplementedException`; all acks route through `AlarmAckByName`. Proto/worker keep the path for forward-compat but it is dead today. `docs/AlarmClientDiscovery.md:750-763`.
|
||||
- 🟡 **3.5 8-arg `AlarmAckByName` v2 is a vendor stub (returns -55)** — worker uses the 6-arg method; the 8-arg `domain`/`full_name` fields are carried for forward-compat only (see 1.4). `docs/AlarmClientDiscovery.md:743-748`.
|
||||
- 🟡 **3.4 `AlarmAckByGUID` is `E_NOTIMPL` on this AVEVA build (historical; note corrected 2026-10-22)** — it throws `NotImplementedException`, but the worker no longer calls it. `MxCommandKind.AcknowledgeAlarm` has live dispatch (`Worker/MxAccess/MxAccessCommandExecutor.cs` `ExecuteAcknowledgeAlarm`, ~895-936): it parses `alarm_guid` and calls `alarmCommandHandler.Acknowledge(guid, comment, AlarmAckOperator)`, which acknowledges by writing `AckMsg` as the authenticated operator. A GUID ack therefore works; only the vendor `AlarmAckByGUID` call is dead. `docs/AlarmClientDiscovery.md:750-763`.
|
||||
- 🟡 **3.5 8-arg `AlarmAckByName` v2 is a vendor stub (returns -55)** — no longer on the ack path (acks write `AckMsg`); `operator_full_name` is carried for forward-compat only and is not propagated (see 1.4). `docs/AlarmClientDiscovery.md:743-748`.
|
||||
- 🟡 **3.6 Subtag degraded-mode fidelity limits** — `category`, `description`, `alarm_type_name`, operator fields, and `retrigger` are not populated/synthesized in subtag fallback (no subtag exists for them). Documented, by design. `docs/AlarmClientDiscovery.md:913-931`, `docs/plans/2026-06-13-alarm-subtag-fallback-design.md:292-298`.
|
||||
- 🟡 **3.7 Subtag `Clear` transition unvalidated live** — Raise/Ack/AckMsg are live-confirmed; Clear is externally undrivable on the rig (object logic owns alarm state). Environmental, not code. (`project_alarm_subtag_fallback`, `project_rig_alarms_object_driven`.)
|
||||
|
||||
@@ -132,7 +131,7 @@ No placeholder/empty/`Assert.True(true)` tests were found anywhere.
|
||||
|
||||
## 7. Stale docs, dead code, accepted gaps
|
||||
|
||||
- 📄 **7.1 D1 plan header stale** — `docs/plans/2026-06-14-deferred-followups.md:4` still says *"Plan only — NOT yet executed,"* but D1 is **done** (`Dashboard/DashboardSnapshotService.cs:198`, commit `4af24b9`). Update the plan status.
|
||||
- ✅ **7.1 D1 plan header stale — RESOLVED** (2026-10-22): `docs/plans/2026-06-14-deferred-followups.md` status line now records D1 executed (`4af24b9`) and D2 resolved as no-op, and no longer claims the plan is unexecuted.
|
||||
- 📄 **7.2 `AlarmClientDiscovery.md` STA "production fix needed" prose is stale** — `docs/AlarmClientDiscovery.md:765-774` reads as a pending follow-up, but alarms now run through the worker STA / `GatewayAlarmMonitor` (merged). Re-check against current code.
|
||||
- 📄 **7.3 EventsHub "publisher side is a follow-up" comment is stale** — `Dashboard/Hubs/EventsHub.cs:9-17`; the `DashboardEventBroadcaster` exists, is DI-registered (`Dashboard/DashboardServiceCollectionExtensions.cs:47`), runs in the live loop (`Grpc/EventStreamService.cs:133`), and `SessionDetailsPage.razor` renders the feed.
|
||||
- ✅ **7.4 CLAUDE.md project-name drift — RESOLVED** (verified 2026-08-07): CLAUDE.md now uses the actual `src/ZB.MOM.WW.MxGateway.*` project paths throughout.
|
||||
@@ -161,7 +160,7 @@ No placeholder/empty/`Assert.True(true)` tests were found anywhere.
|
||||
|
||||
**Still open (all deliberate or environment/vendor-gated):**
|
||||
- **§1.3** — `provider_switches` counter still only unit-tested; the dev rig can't drive a real alarmmgr→subtag failover, so live `reason`-tag coverage remains a recorded residual.
|
||||
- **§1.4 / §3.4 / §3.5** — the AVEVA 8-arg `AlarmAckByName` is a vendor stub (−55) and `AlarmAckByGUID` is `E_NOTIMPL`; the `domain`/`full_name` fields stay forward-compat-only until AVEVA implements them.
|
||||
- **§1.4 / §3.4 / §3.5** — the AVEVA 8-arg `AlarmAckByName` is a vendor stub (−55) and `AlarmAckByGUID` is `E_NOTIMPL`; `operator_domain` is consumed by the `AckMsg` path; `operator_full_name` stays forward-compat-only (not propagated).
|
||||
- **§3.2** — buffered commands work and the empty bootstrap converts cleanly live, but a multi-sample buffered batch is undrivable on the rig (unit-tested only).
|
||||
- **§3.1 / §3.3 / §3.6 / §3.7** — await live MXAccess captures.
|
||||
- **§2** — deliberate v1 scope. Multi-subscriber fan-out, reconnect, and the per-session dashboard ACL are resolved; orphan-worker reattach remains deliberately deferred and not planned. **§5** — opt-in verification gates. **§7.6** — accepted `Won't Fix` review findings.
|
||||
|
||||
Reference in New Issue
Block a user