From cef5338cfe80a636f07a3c16d7c137669a3e1403 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Wed, 8 Apr 2026 12:26:22 +0000 Subject: [PATCH] types/change: panic on Merge with conflicting TargetNode values Merging two changes targeted at different nodes is not supported because the result can only carry one TargetNode. The second target's content would be silently misrouted. Add a panic guard that catches this at the Merge call site rather than allowing silent data loss. In production, Merge is only called with broadcast changes (TargetNode=0) so the guard acts as insurance against future misuse. --- hscontrol/types/change/change.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hscontrol/types/change/change.go b/hscontrol/types/change/change.go index c6ab9daa..7014a6a8 100644 --- a/hscontrol/types/change/change.go +++ b/hscontrol/types/change/change.go @@ -1,6 +1,7 @@ package change import ( + "fmt" "slices" "time" @@ -78,6 +79,16 @@ func (r Change) Merge(other Change) Change { } // Preserve TargetNode for targeted responses. + // Merging two changes targeted at different nodes is not supported + // because the merged result can only have one TargetNode, which + // would cause the other target's content to be misrouted. + if merged.TargetNode != 0 && other.TargetNode != 0 && merged.TargetNode != other.TargetNode { + panic(fmt.Sprintf( + "cannot merge changes with different TargetNode: %d != %d", + merged.TargetNode, other.TargetNode, + )) + } + if merged.TargetNode == 0 { merged.TargetNode = other.TargetNode }