To understand what's going on at this level of detail, I think you have to reach for the source code. So, citing vim-7.1.314/src/ex_cmds.c (comment at the head of the definition of ex_global()):
This is implemented in two passes: first we scan the file for the pattern and
set a mark for each line that (not) matches. secondly we execute the command
for each line that has a mark. This is required because after deleting
lines we do not know where to search for the next match.
Thus, if you delete a line in the :g'ed command, the mark for this line goes away too. If you create a line in the :g'ed command, it won't be marked, so the command won't execute on it. In your example, line 3 is joined with line 2, so the mark on line 3 disappears, and the next mark after line 2 is the one originally put on line 4.
Also, ex_global sets the global_busy variable, which causes a few commands, including :s, to behave slightly differently. I don't think the difference is relevant here though.