|Your data structure is really a sparse matrix, right? It's a bit hidden behind the domain-specific terminology, but in the end it's a weighted graph represented as a sparse matrix. There's nothing wrong with that, it's a standard way to manipulate weighted (and even unweighted) graphs in both programming and mathematics.
Well I mean, there is some invariant on this matrix that you are maintaining, right? And it has something to do with the reciprocal edge (you called it that, I'm just going with it). If a weight somewhere is changed, then its "mirror image" (the reverse edge) needs to change in some way to restore that invariant. I didn't really get how it needs to be changed specifically (or what the invariant is that is being maintained by that change), but I suppose that's largely an implementation detail that doesn't need to affect the overall architecture.
BillWoodruff wrote:How can you have "reciprocity" and "invariant."
So essentially my suggestion is: make the overall matrix responsible for maintaining that invariant, not the edges. And so, the edges would not try to "fix themselves" in response to an event, you would tell the matrix to change an edge weight and it would directly do so in a way that maintains the invariant (by changing the weight of an edge and the corresponding reverse edge), with no events involved (of course you can still raise them, but that wouldn't be the mechanism for maintaining the invariant).