Resolve Contracts-002 code-review finding
MxCommandReply.payload has no by-name ack case: MX_COMMAND_KIND_ACKNOWLEDGE_ ALARM_BY_NAME reuses the acknowledge_alarm reply payload. Verified the worker (MxAccessCommandExecutor.ExecuteAcknowledgeAlarmByName) and gateway (WorkerAlarmRpcDispatcher) already implement this correctly — the gap was purely undocumented contract asymmetry. Documented the reuse on the proto oneof case and the AcknowledgeAlarmReplyPayload message comment (regenerating the .NET contract), and in docs/AlarmClientDiscovery.md. Added ProtobufContractRoundTripTests.MxCommandReply_AcknowledgeAlarmByName_Reuses AcknowledgeAlarmPayloadCase to pin the contract. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13388,6 +13388,17 @@ namespace MxGateway.Contracts.Proto {
|
||||
|
||||
/// <summary>Field number for the "acknowledge_alarm" field.</summary>
|
||||
public const int AcknowledgeAlarmFieldNumber = 34;
|
||||
/// <summary>
|
||||
/// Reply payload for BOTH MX_COMMAND_KIND_ACKNOWLEDGE_ALARM (by GUID)
|
||||
/// and MX_COMMAND_KIND_ACKNOWLEDGE_ALARM_BY_NAME. There is intentionally
|
||||
/// no by-name-specific reply case: the by-name ack carries no outcome
|
||||
/// detail beyond the native ack return code, so the worker reuses this
|
||||
/// `acknowledge_alarm` payload for both command kinds (the worker's
|
||||
/// MxAccessCommandExecutor sets `acknowledge_alarm` for the by-name arm
|
||||
/// too). Consumers must dispatch on MxCommandReply.kind, not on the
|
||||
/// payload case, to tell the two acks apart. The top-level `hresult`
|
||||
/// mirrors AcknowledgeAlarmReplyPayload.native_status and is preferred.
|
||||
/// </summary>
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public global::MxGateway.Contracts.Proto.AcknowledgeAlarmReplyPayload AcknowledgeAlarm {
|
||||
@@ -17339,12 +17350,16 @@ namespace MxGateway.Contracts.Proto {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reply payload for AcknowledgeAlarmCommand. Surfaces AVEVA's native
|
||||
/// AlarmAckByGUID return code; 0 means success. The MxCommandReply's
|
||||
/// hresult field carries the same value and is preferred for protocol
|
||||
/// consumers — this payload exists so the gateway-side
|
||||
/// WorkerAlarmRpcDispatcher can echo native_status into
|
||||
/// AcknowledgeAlarmReply.hresult without unpacking the outer envelope.
|
||||
/// Reply payload for AcknowledgeAlarmCommand AND
|
||||
/// AcknowledgeAlarmByNameCommand — both ack command kinds reuse this
|
||||
/// payload case (`MxCommandReply.acknowledge_alarm`); there is no
|
||||
/// dedicated by-name reply case. Surfaces AVEVA's native ack return
|
||||
/// code (AlarmAckByGUID for the GUID arm, AlarmAckByName for the
|
||||
/// by-name arm); 0 means success. The MxCommandReply's hresult field
|
||||
/// carries the same value and is preferred for protocol consumers —
|
||||
/// this payload exists so the gateway-side WorkerAlarmRpcDispatcher
|
||||
/// can echo native_status into AcknowledgeAlarmReply.hresult without
|
||||
/// unpacking the outer envelope.
|
||||
/// </summary>
|
||||
[global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")]
|
||||
public sealed partial class AcknowledgeAlarmReplyPayload : pb::IMessage<AcknowledgeAlarmReplyPayload>
|
||||
|
||||
@@ -381,6 +381,15 @@ message MxCommandReply {
|
||||
BulkSubscribeReply un_advise_item_bulk = 31;
|
||||
BulkSubscribeReply subscribe_bulk = 32;
|
||||
BulkSubscribeReply unsubscribe_bulk = 33;
|
||||
// Reply payload for BOTH MX_COMMAND_KIND_ACKNOWLEDGE_ALARM (by GUID)
|
||||
// and MX_COMMAND_KIND_ACKNOWLEDGE_ALARM_BY_NAME. There is intentionally
|
||||
// no by-name-specific reply case: the by-name ack carries no outcome
|
||||
// detail beyond the native ack return code, so the worker reuses this
|
||||
// `acknowledge_alarm` payload for both command kinds (the worker's
|
||||
// MxAccessCommandExecutor sets `acknowledge_alarm` for the by-name arm
|
||||
// too). Consumers must dispatch on MxCommandReply.kind, not on the
|
||||
// payload case, to tell the two acks apart. The top-level `hresult`
|
||||
// mirrors AcknowledgeAlarmReplyPayload.native_status and is preferred.
|
||||
AcknowledgeAlarmReplyPayload acknowledge_alarm = 34;
|
||||
QueryActiveAlarmsReplyPayload query_active_alarms = 35;
|
||||
SessionStateReply session_state = 100;
|
||||
@@ -448,12 +457,16 @@ message DrainEventsReply {
|
||||
repeated MxEvent events = 1;
|
||||
}
|
||||
|
||||
// Reply payload for AcknowledgeAlarmCommand. Surfaces AVEVA's native
|
||||
// AlarmAckByGUID return code; 0 means success. The MxCommandReply's
|
||||
// hresult field carries the same value and is preferred for protocol
|
||||
// consumers — this payload exists so the gateway-side
|
||||
// WorkerAlarmRpcDispatcher can echo native_status into
|
||||
// AcknowledgeAlarmReply.hresult without unpacking the outer envelope.
|
||||
// Reply payload for AcknowledgeAlarmCommand AND
|
||||
// AcknowledgeAlarmByNameCommand — both ack command kinds reuse this
|
||||
// payload case (`MxCommandReply.acknowledge_alarm`); there is no
|
||||
// dedicated by-name reply case. Surfaces AVEVA's native ack return
|
||||
// code (AlarmAckByGUID for the GUID arm, AlarmAckByName for the
|
||||
// by-name arm); 0 means success. The MxCommandReply's hresult field
|
||||
// carries the same value and is preferred for protocol consumers —
|
||||
// this payload exists so the gateway-side WorkerAlarmRpcDispatcher
|
||||
// can echo native_status into AcknowledgeAlarmReply.hresult without
|
||||
// unpacking the outer envelope.
|
||||
message AcknowledgeAlarmReplyPayload {
|
||||
int32 native_status = 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user