9d589b92d3
The assistant footer and the user bubble each carried the same block: two metadata reads, the three-store merge, and a local-first toggle that paints before it persists. Same code, two files, and the next surface that wants to react would have been a third copy. useMessageReactions owns it now, with commitReaction as the single write path so every caller applies identical tapback semantics.