AlarmAckWriter: stale late write completion can be credited to the next ack if MXAccess reuses an item handle number #166

Open
opened 2026-10-20 07:04:22 -04:00 by dohertj2 · 1 comment
Owner

AlarmAckWriter waits for OnWriteComplete through MxAccessWriteCompletionCache.TryWaitForCompletion (src/ZB.MOM.WW.MxGateway.Worker/MxAccess/AlarmAckWriter.cs:207). The cache matches completions only on (serverHandle, itemHandle) plus a version baseline; there is no per-write id.

Current mitigation (PR #162): after an Unconfirmed ack the item is marked Dirty. The next ack removes it and re-adds it, so a late completion for the old handle should not match the new write.

Remaining risk: the mitigation assumes MXAccess hands out a new handle number on re-add. If MXAccess reuses the number, or delivers a completion for a removed handle that is later reused, the stale completion can still be credited to the next ack. The next ack would then report a false Applied or a false WriteRejected.

To do:

  1. Check on live MXAccess (windev) whether RemoveItem + AddItem of the same <tag>.AckMsg reuses the handle number. A small probe that adds, removes and re-adds, logging the handles, is enough.
  2. If handles are reused, add a correlation that survives reuse. For example, record the drop time and ignore completions whose arrival predates the new Write, or keep a per-handle generation counter in the cache that is bumped on re-add.

Found in the final review of PR #162 (feat/ackmsg-as-operator); left unfixed by decision as Minor.

https://claude.ai/code/session_016J6isfcgqy4SB2RK3ZvFvT

`AlarmAckWriter` waits for `OnWriteComplete` through `MxAccessWriteCompletionCache.TryWaitForCompletion` (`src/ZB.MOM.WW.MxGateway.Worker/MxAccess/AlarmAckWriter.cs:207`). The cache matches completions only on `(serverHandle, itemHandle)` plus a version baseline; there is no per-write id. **Current mitigation (PR #162):** after an `Unconfirmed` ack the item is marked `Dirty`. The next ack removes it and re-adds it, so a late completion for the old handle should not match the new write. **Remaining risk:** the mitigation assumes MXAccess hands out a *new* handle number on re-add. If MXAccess reuses the number, or delivers a completion for a removed handle that is later reused, the stale completion can still be credited to the next ack. The next ack would then report a false `Applied` or a false `WriteRejected`. **To do:** 1. Check on live MXAccess (windev) whether `RemoveItem` + `AddItem` of the same `<tag>.AckMsg` reuses the handle number. A small probe that adds, removes and re-adds, logging the handles, is enough. 2. If handles are reused, add a correlation that survives reuse. For example, record the drop time and ignore completions whose arrival predates the new `Write`, or keep a per-handle generation counter in the cache that is bumped on re-add. Found in the final review of PR #162 (feat/ackmsg-as-operator); left unfixed by decision as Minor. https://claude.ai/code/session_016J6isfcgqy4SB2RK3ZvFvT
Author
Owner

Probe run on windev 2026-10-20 (Probes/ItemHandleReuseProbeTests.cs, bd82036/463748e): MXAccess does NOT reuse item handle numbers within a registration (remove/re-add of the same AckMsg item gave 1..15 strictly increasing). Numbering restarts on a new registration, which is safe because teardown unhooks OnWriteComplete and clears that server's cache entries. No generation counter needed; the evidence is in docs/AlarmProbeFindings.md and the probe now asserts strictly increasing handles so a re-run is a regression check. Closes when PR #162 merges.

https://claude.ai/code/session_016J6isfcgqy4SB2RK3ZvFvT

Probe run on windev 2026-10-20 (Probes/ItemHandleReuseProbeTests.cs, bd82036/463748e): MXAccess does NOT reuse item handle numbers within a registration (remove/re-add of the same AckMsg item gave 1..15 strictly increasing). Numbering restarts on a new registration, which is safe because teardown unhooks OnWriteComplete and clears that server's cache entries. No generation counter needed; the evidence is in docs/AlarmProbeFindings.md and the probe now asserts strictly increasing handles so a re-run is a regression check. Closes when PR #162 merges. https://claude.ai/code/session_016J6isfcgqy4SB2RK3ZvFvT
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/mxaccessgw#166