Adds alarm_ack.md documenting the two-way acknowledge flow (OPC UA client writes AckMsg, Galaxy confirms via Acked data change). Includes external code review fixes for subscriptions and node manager, and removes stale plan files now superseded by component documentation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
60 lines
4.0 KiB
JSON
60 lines
4.0 KiB
JSON
{
|
|
"findings": [
|
|
{
|
|
"title": "[P1] Synchronize dispatch lookups with address-space rebuilds",
|
|
"body": "The data-change dispatcher reads `_tagToVariableNode` and `_alarmInAlarmTags` here before taking `Lock`, while `BuildAddressSpace`, `SyncAddressSpace`, and `TearDownGobjects` mutate those same `Dictionary` instances under `Lock`. If a Galaxy rebuild lands while MXAccess is delivering changes, `TryGetValue` can observe concurrent mutation and throw; because these lookups sit outside the inner `try/catch`, the dispatch thread dies and all subscribed OPC UA items stop publishing until the service is restarted.",
|
|
"confidence_score": 0.98,
|
|
"priority": 1,
|
|
"code_location": {
|
|
"absolute_file_path": "C:\\Users\\dohertj2\\Desktop\\lmxopcua\\src\\ZB.MOM.WW.LmxOpcUa.Host\\OpcUa\\LmxNodeManager.cs",
|
|
"line_range": {
|
|
"start": 1516,
|
|
"end": 1530
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"title": "[P1] Guard subscription refcounts with the same mutex",
|
|
"body": "This block rewrites `_subscriptionRefCounts` while holding `Lock`, but the normal monitored-item paths (`SubscribeTag`, `UnsubscribeTag`, and `RestoreTransferredSubscriptions`) protect the same dictionary with `_lock` instead. A monitored-item create/delete that overlaps a rebuild can therefore race with the restore path here, losing counts or sending extra `SubscribeAsync`/`UnsubscribeAsync` calls. In a live system that leaves surviving subscriptions missing or leaked after a deploy even though the OPC UA client state never changed.",
|
|
"confidence_score": 0.93,
|
|
"priority": 1,
|
|
"code_location": {
|
|
"absolute_file_path": "C:\\Users\\dohertj2\\Desktop\\lmxopcua\\src\\ZB.MOM.WW.LmxOpcUa.Host\\OpcUa\\LmxNodeManager.cs",
|
|
"line_range": {
|
|
"start": 556,
|
|
"end": 557
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"title": "[P2] Skip duplicate runtime subscriptions for the same tag",
|
|
"body": "Once the client is connected, `SubscribeAsync` always opens a fresh COM item for the address instead of reusing an existing one. Callers can hit that through alarm auto-subscriptions, transferred-monitored-item recovery, or any repeated higher-level subscribe for the same tag. The new handle overwrites `_addressToHandle[address]`, so `UnsubscribeAsync` removes only the newest item while the original subscription keeps receiving callbacks until disconnect.",
|
|
"confidence_score": 0.97,
|
|
"priority": 2,
|
|
"code_location": {
|
|
"absolute_file_path": "C:\\Users\\dohertj2\\Desktop\\lmxopcua\\src\\ZB.MOM.WW.LmxOpcUa.Host\\MxAccess\\MxAccessClient.Subscription.cs",
|
|
"line_range": {
|
|
"start": 17,
|
|
"end": 20
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"title": "[P2] Detach MX callbacks before disposing the dispatch signal",
|
|
"body": "The node manager subscribes to `_mxAccessClient.OnTagValueChanged` in the constructor, but `Dispose(bool)` only stops the thread and disposes `_dataChangeSignal`. During `OpcUaService.Stop()`, the OPC UA server is stopped before the MXAccess client disconnects, so any runtime callback delivered in that window will call `OnMxAccessDataChange` and hit `Set()` on a disposed `AutoResetEvent`. That produces shutdown-time exceptions and keeps the dead node manager rooted by the event subscription.",
|
|
"confidence_score": 0.89,
|
|
"priority": 2,
|
|
"code_location": {
|
|
"absolute_file_path": "C:\\Users\\dohertj2\\Desktop\\lmxopcua\\src\\ZB.MOM.WW.LmxOpcUa.Host\\OpcUa\\LmxNodeManager.cs",
|
|
"line_range": {
|
|
"start": 1632,
|
|
"end": 1633
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"overall_correctness": "patch is incorrect",
|
|
"overall_explanation": "The solution has multiple runtime reliability issues in the MXAccess-to-OPC-UA bridge: address-space rebuilds race with live data dispatch, subscription bookkeeping is not synchronized consistently, and duplicate or stale subscriptions can be left behind. Those issues can break live publishing or leak runtime handles under ordinary reconnect and rebuild scenarios.",
|
|
"overall_confidence_score": 0.94
|
|
}
|